public class MainActivity extends Activity implements OnClickListener { private static final Log log = Logs.getLog(MainActivity.class); private Calendar mDate; private PresenceManager mPresenceManager; private LocationManager mLocationManager; private LocationChecker locationChecker = new LocationChecker(); private Handler mHandler; private Geocoder mGeocoder; private List<LocationListener> locationListeners = new ArrayList<LocationListener>(); private class MyLocationListener implements LocationListener { @Override public void onLocationChanged(Location location) { if (!locationChecker.isFineLocation(location)) { log.debug("SKIP BAD " + location); return; } GPSHelper.addLocation(location, mGeocoder); updateList(); } @Override public void onProviderDisabled(String provider) {} @Override public void onProviderEnabled(String provider) {} @Override public void onStatusChanged(String provider, int status, Bundle extras) {} }; private static class MyAdapter extends BaseAdapter { private Context context; private List<TrackingData> items; public MyAdapter(Context context, List<TrackingData> items) { this.context = context; this.items = items; } public void setItems(List<TrackingData> items) { this.items = items; } @Override public int getCount() { return items.size(); } @Override public Object getItem(int position) { return items.get(getCount() - 1 - position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { TwoLineListItem twoLineListItem; if (convertView == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); twoLineListItem = (TwoLineListItem) inflater.inflate(android.R.layout.simple_list_item_2, null); twoLineListItem.getText1().setTextSize(14); twoLineListItem.getText2().setTextSize(12); } else { twoLineListItem = (TwoLineListItem) convertView; } TextView text1 = twoLineListItem.getText1(); TextView text2 = twoLineListItem.getText2(); TrackingData td = (TrackingData) getItem(position); text1.setText(td.toMain()); text2.setText(td.toSub()); return twoLineListItem; } } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDate = Calendar.getInstance(); findViewById(R.id.btnStart).setOnClickListener(this); findViewById(R.id.btnStop).setOnClickListener(this); TextView txtDate = (TextView) findViewById(R.id.txtDate); txtDate.setText(DateTimes.dateFormat().format(mDate)); txtDate.setOnClickListener(this); buttonVisible(false); mHandler = new Handler(getMainLooper()); mGeocoder = new Geocoder(this, Locale.getDefault()); mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); // // Criteriaオブジェクトを生成 // Criteria criteria = new Criteria(); // criteria.setAccuracy(Criteria.ACCURACY_FINE); // criteria.setPowerRequirement(Criteria.POWER_LOW); // locationProvider = mLocationManager.getBestProvider(criteria, true); // log.debug("Location Provider: " + locationProvider); // setTitle(getTitle() + " - " + locationProvider); mPresenceManager = PresenceManager.getInstance(getApplicationContext()); MyAdapter adapter = new MyAdapter(this, GPSHelper.getTrackings()); ListView listView = (ListView) findViewById(R.id.listTracking); listView.setAdapter(adapter); listView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // ListView listView = (ListView)parent; // TrackingData item = (TrackingData)listView.getItemAtPosition(position); if (position % 2 == 0) { startActivity(new Intent(MainActivity.this, MapLineActivity.class)); } else { startActivity(new Intent(MainActivity.this, MapCircleActivity.class)); } } }); mHandler.postDelayed( new Runnable() { @Override public void run() { GPSHelper.loadTrackings(mDate); updateList(); } }, 100); } public void onStart() { super.onStart(); } private static BroadcastReceiver mIspReceiver = new PresenceReceiver(); public void onResume() { super.onResume(); buttonVisible(isPresenceServiceRunning()); } public void onDestory() { super.onDestroy(); } public void onStop() { super.onStop(); } public void onPause() { super.onPause(); } public void onClick(View v) { switch (v.getId()) { case R.id.btnStart: startTrackingService(); break; case R.id.btnStop: stopTrackingService(); break; case R.id.txtDate: showDatepicker(); break; } } private void showDatepicker() { if (!locationListeners.isEmpty()) { return; } final DatePickerDialog datePickerDialog = new DatePickerDialog( this, new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { Calendar c = Calendar.getInstance(); c.set(year, monthOfYear, dayOfMonth); if (DateTimes.isSameDay(mDate, c)) { return; } mDate.set(year, monthOfYear, dayOfMonth); final TextView txtDate = (TextView) findViewById(R.id.txtDate); txtDate.setText(DateTimes.dateFormat().format(mDate)); GPSHelper.loadTrackings(mDate); updateList(); } }, mDate.get(Calendar.YEAR), mDate.get(Calendar.MONTH), mDate.get(Calendar.DAY_OF_MONTH)); datePickerDialog.show(); } private void stopTrackingService() { getApplicationContext().unregisterReceiver(mIspReceiver); mPresenceManager.stopPresence(); for (LocationListener ll : locationListeners) { mLocationManager.removeUpdates(ll); } locationListeners.clear(); buttonVisible(false); } private void startTrackingService() { if (!DateTimes.isSameDay(mDate, Calendar.getInstance())) { mDate = Calendar.getInstance(); TextView txtDate = (TextView) findViewById(R.id.txtDate); txtDate.setText(DateTimes.dateFormat().format(mDate)); GPSHelper.loadTrackings(mDate); updateList(); } IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(PresenceManagerUtil.CHANGE_STATUS); getApplicationContext().registerReceiver(mIspReceiver, intentFilter); mPresenceManager.startPresence(); for (String p : mLocationManager.getAllProviders()) { LocationListener ll = new MyLocationListener(); mLocationManager.requestLocationUpdates( p, 60000, // 通知のための最小時間間隔(ミリ秒) 30, // 通知のための最小距離間隔(メートル) ll); locationListeners.add(ll); } buttonVisible(true); } private void buttonVisible(boolean stop) { findViewById(R.id.btnStart).setEnabled(!stop); findViewById(R.id.btnStop).setEnabled(stop); } private void updateList() { ListView listView = (ListView) findViewById(R.id.listTracking); ((MyAdapter) listView.getAdapter()).notifyDataSetChanged(); } private boolean isPresenceServiceRunning() { ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(Service.ACTIVITY_SERVICE); List<ActivityManager.RunningServiceInfo> runningServiceInfo = am.getRunningServices(Integer.MAX_VALUE); int serviceNum = runningServiceInfo.size(); for (int i = 0; i < serviceNum; i++) { if (runningServiceInfo .get(i) .service .getClassName() .equals(PresenceService.class.getName())) { return true; } } return false; } }
public class GPSHelper { private static final Log log = Logs.getLog(GPSHelper.class); private static List<TrackingData> trackings = new ArrayList<TrackingData>(); @SuppressLint("UseSparseArrays") private static Map<Integer, Long> states = new HashMap<Integer, Long>(); private static int lastState; private static long lastStart; public static List<TrackingData> getTrackings() { return trackings; } public static String getTrackingFile(Calendar c) { String fn = GPSHelper.class.getPackage().getName() + "/gpstracking." + DateTimes.dateLogFormat().format(c) + ".txt"; return FileNames.concat(Environment.getExternalStorageDirectory().getAbsolutePath(), fn); } public static void loadTrackings(Calendar c) { trackings.clear(); File file = new File(getTrackingFile(c)); if (!file.exists()) { log.warn(file + "does not exist"); return; } log.info("Loading " + file); float[] results = new float[1]; LineIterator li = null; try { li = Files.lineIterator(file); while (li.hasNext()) { String line = li.next(); if (Strings.isEmpty(line)) { continue; } TrackingData td = Jsons.fromJson(line, TrackingData.class); TrackingData ltd = getLastLocation(); if (ltd != null) { Location.distanceBetween( ltd.getLatitude(), ltd.getLongitude(), td.getLatitude(), td.getLongitude(), results); td.setDistance(results[0]); td.setSpeed(td.getDistance() / DateTimes.subSeconds(td.getDate(), ltd.getDate())); } trackings.add(td); } } catch (IOException e) { log.error(e); } finally { Streams.safeClose(li); } } public static TrackingData getLastLocation() { if (Collections.isNotEmpty(trackings)) { return trackings.get(trackings.size() - 1); } return null; } public static TrackingData getFirstLocation() { if (Collections.isNotEmpty(trackings)) { return trackings.get(0); } return null; } public static boolean addLocation(Location location, Geocoder geocoder) { TrackingData ltd = getLastLocation(); float distance = 0.0f; float speed = 0.0f; if (ltd != null) { float[] results = new float[1]; Location.distanceBetween( ltd.getLatitude(), ltd.getLongitude(), location.getLatitude(), location.getLongitude(), results); distance = results[0]; if (distance < 100) { log.debug("SKIP SAME " + location + ": " + distance); return false; } long delta = DateTimes.subSeconds(new Date(location.getTime()), ltd.getDate()); // less than 30 minutes if (delta < 30 * 60) { speed = distance / delta; // if (lastState == DetectedActivity.STILL) { // // } // great than 120km/h if (speed >= 33) { log.debug("SKIP FAST " + location + ": " + distance); return false; } } } String address = ""; try { List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1); if (Collections.isNotEmpty(addresses)) { Address a = addresses.get(0); address = toAddress(a); } // if (ltd != null && Strings.isNotEmpty(address)) { // if (ltd.getAddress().equals(address)) { // log.debug("Skip (" + location + "): " + address); // return; // } // } } catch (Exception e) { // Catch network or other I/O problems. log.error( "Failed to get address of (" + location.getLatitude() + ", " + location.getLongitude(), e); } TrackingData td = new TrackingData(); td.setDate(new Date(location.getTime())); td.setState(getBestState()); td.setLatitude(location.getLatitude()); td.setLongitude(location.getLongitude()); td.setAddress(address); if (ltd != null) { float[] results = new float[1]; Location.distanceBetween( ltd.getLatitude(), ltd.getLongitude(), td.getLatitude(), td.getLongitude(), results); td.setDistance(results[0]); td.setSpeed(td.getDistance() / DateTimes.subSeconds(td.getDate(), ltd.getDate())); } trackings.add(td); saveTrackingData(td); return true; } private static void saveTrackingData(TrackingData td) { String s = Jsons.toJson(td); Writer r = null; try { log.info("ADD: " + s); File file = new File(getTrackingFile(Calendar.getInstance())); r = new OutputStreamWriter(new FileOutputStream(file, true), Charsets.UTF_8); r.append(s); r.append(Streams.LINE_SEPARATOR); } catch (IOException e) { log.error("Failed to save " + s, e); } finally { Streams.safeClose(r); } } private static int getBestState() { if (Collections.isEmpty(states)) { return DetectedActivity.UNKNOWN; } long max = 0; for (Long time : states.values()) { if (time > max) { max = time; } } int state = DetectedActivity.UNKNOWN; for (Entry<Integer, Long> en : states.entrySet()) { if (max == en.getValue()) { state = en.getKey(); break; } } states.clear(); states.put(lastState, 0L); lastStart = System.currentTimeMillis(); return state; } public static void setState(ActivityRecognitionResult result) { DetectedActivity da = result.getMostProbableActivity(); int state = da.getType(); log.debug( "DetectedActivity: " + DateTimes.timeFormat().format(result.getTime()) + " - " + getStateText(state) + ", " + da.getConfidence() + ", " + DateTimes.timeFormat().format(result.getElapsedRealtimeMillis())); if (Collections.isEmpty(states)) { states.put(state, 0L); lastState = state; lastStart = System.currentTimeMillis(); return; } Long ltime = states.get(lastState); if (ltime != null) { ltime += (System.currentTimeMillis() - lastStart); states.put(lastState, ltime); } lastState = state; lastStart = System.currentTimeMillis(); if (!states.containsKey(state)) { states.put(state, 0L); } } public static String toAddress(Address a) { StringBuilder sb = new StringBuilder(); // if (Strings.isNotEmpty(a.getPostalCode())) { // sb.append(a.getPostalCode()).append(' '); // } // if (Strings.isNotEmpty(a.getCountryName())) { // sb.append(a.getCountryName()).append(' '); // } // if (Strings.isNotEmpty(a.getAdminArea())) { // sb.append(a.getAdminArea()).append(' '); // } // if (Strings.isNotEmpty(a.getSubAdminArea())) { // sb.append(a.getSubAdminArea()).append(' '); // } // if (Strings.isNotEmpty(a.getLocality())) { // sb.append(a.getLocality()).append(' '); // } // if (Strings.isNotEmpty(a.getSubLocality())) { // sb.append(a.getSubLocality()).append(' '); // } // if (Strings.isNotEmpty(a.getThoroughfare())) { // sb.append(a.getThoroughfare()).append(' '); // } for (int i = 0; i <= a.getMaxAddressLineIndex(); i++) { String line = a.getAddressLine(i); if (Strings.isEmpty(line)) { continue; } sb.append(line).append(' '); } return sb.toString().trim(); } public static String getStateText(int status) { switch (status) { case DetectedActivity.IN_VEHICLE: return "in_vehicle"; case DetectedActivity.ON_BICYCLE: return "on_bicycle"; case DetectedActivity.RUNNING: return "running"; case DetectedActivity.ON_FOOT: return "on_foot"; case DetectedActivity.TILTING: return "tilting"; case DetectedActivity.STILL: return "still"; case DetectedActivity.UNKNOWN: return "unknown"; default: return "unknown(" + status + ")"; } } public static int getStateColor(int status) { switch (status) { case DetectedActivity.TILTING: return Color.LTGRAY; case DetectedActivity.STILL: return Color.GRAY; case DetectedActivity.UNKNOWN: return Color.DKGRAY; case DetectedActivity.ON_FOOT: return Color.GREEN; case DetectedActivity.RUNNING: return Color.BLUE; case DetectedActivity.ON_BICYCLE: return Color.YELLOW; case DetectedActivity.IN_VEHICLE: return Color.MAGENTA; default: return Color.WHITE; } } public static BitmapDescriptor getStateIcon(int status) { switch (status) { case DetectedActivity.STILL: return BitmapDescriptorFactory.fromResource(R.drawable.rest); case DetectedActivity.TILTING: return BitmapDescriptorFactory.fromResource(R.drawable.rest); case DetectedActivity.UNKNOWN: return BitmapDescriptorFactory.fromResource(R.drawable.stop); case DetectedActivity.ON_FOOT: return BitmapDescriptorFactory.fromResource(R.drawable.walk); case DetectedActivity.RUNNING: return BitmapDescriptorFactory.fromResource(R.drawable.run); case DetectedActivity.ON_BICYCLE: return BitmapDescriptorFactory.fromResource(R.drawable.run); case DetectedActivity.IN_VEHICLE: return BitmapDescriptorFactory.fromResource(R.drawable.vehicle); default: return BitmapDescriptorFactory.fromResource(R.drawable.stop); } } }