1 /*
2  * Copyright (C) 2014 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.wearable.speedtracker;
18 
19 import com.google.android.gms.maps.CameraUpdateFactory;
20 import com.google.android.gms.maps.GoogleMap;
21 import com.google.android.gms.maps.SupportMapFragment;
22 import com.google.android.gms.maps.OnMapReadyCallback;
23 import com.google.android.gms.maps.model.LatLng;
24 import com.google.android.gms.maps.model.LatLngBounds;
25 import com.google.android.gms.maps.model.PolylineOptions;
26 
27 import android.app.DatePickerDialog;
28 import android.os.AsyncTask;
29 import android.os.Bundle;
30 import android.support.v7.app.AppCompatActivity;
31 import android.text.format.DateUtils;
32 import android.util.Log;
33 import android.view.View;
34 import android.widget.DatePicker;
35 import android.widget.TextView;
36 
37 import com.example.android.wearable.speedtracker.common.LocationEntry;
38 
39 import java.util.ArrayList;
40 import java.util.Calendar;
41 import java.util.List;
42 
43 /**
44  * The main activity for the handset application. When a watch device reconnects to the handset
45  * app, the collected GPS data on the watch, if any, is synced up and user can see his/her track on
46  * a map. This data is then saved into an internal database and the corresponding data items are
47  * deleted.
48  */
49 public class PhoneMainActivity extends AppCompatActivity implements
50         DatePickerDialog.OnDateSetListener, OnMapReadyCallback {
51 
52     private static final String TAG = "PhoneMainActivity";
53     private static final int BOUNDING_BOX_PADDING_PX = 50;
54     private TextView mSelectedDateText;
55     private GoogleMap mMap;
56     private SupportMapFragment mMapFragment;
57 
58     @Override
onCreate(Bundle savedInstanceState)59     protected void onCreate(Bundle savedInstanceState) {
60         super.onCreate(savedInstanceState);
61         setContentView(R.layout.main_activity);
62         mSelectedDateText = (TextView) findViewById(R.id.selected_date);
63         mMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
64         mMapFragment.getMapAsync(this);
65     }
66 
onClick(View view)67     public void onClick(View view) {
68         Calendar calendar = Calendar.getInstance();
69         calendar.setTimeInMillis(System.currentTimeMillis());
70         new DatePickerDialog(PhoneMainActivity.this, PhoneMainActivity.this,
71                 calendar.get(Calendar.YEAR),
72                 calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)).show();
73     }
74 
75     @Override
onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth)76     public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
77         // the following if-clause is to get around a bug that causes this callback to be called
78         // twice
79         if (view.isShown()) {
80             Calendar calendar = Calendar.getInstance();
81             calendar.setTimeInMillis(System.currentTimeMillis());
82             calendar.set(Calendar.YEAR, year);
83             calendar.set(Calendar.MONTH, monthOfYear);
84             calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
85             String date = DateUtils.formatDateTime(this, calendar.getTimeInMillis(),
86                     DateUtils.FORMAT_SHOW_DATE);
87             mSelectedDateText.setText(getString(R.string.showing_for_date, date));
88             showTrack(calendar);
89         }
90     }
91 
92     /**
93      * An {@link android.os.AsyncTask} that is responsible for getting a list of {@link
94      * com.example.android.wearable.speedtracker.common.LocationEntry} objects for a given day and
95      * building a track from those points. In addition, it sets the smallest bounding box for the
96      * map that covers all the points on the track.
97      */
showTrack(Calendar calendar)98     private void showTrack(Calendar calendar) {
99         new AsyncTask<Calendar, Void, Void>() {
100 
101             private List<LatLng> coordinates;
102             private LatLngBounds bounds;
103 
104             @Override
105             protected Void doInBackground(Calendar... params) {
106                 LocationDataManager dataManager = ((PhoneApplication) getApplicationContext())
107                         .getDataManager();
108                 List<LocationEntry> entries = dataManager.getPoints(params[0]);
109                 if (entries != null && !entries.isEmpty()) {
110                     coordinates = new ArrayList<LatLng>();
111                     LatLngBounds.Builder builder = new LatLngBounds.Builder();
112                     for (LocationEntry entry : entries) {
113                         LatLng latLng = new LatLng(entry.latitude, entry.longitude);
114                         builder.include(latLng);
115                         coordinates.add(latLng);
116                     }
117                     bounds = builder.build();
118                 }
119                 return null;
120             }
121 
122             @Override
123             protected void onPostExecute(Void aVoid) {
124                 mMap.clear();
125                 if (coordinates == null || coordinates.isEmpty()) {
126                     if (Log.isLoggable(TAG, Log.DEBUG)) {
127                         Log.d(TAG, "No Entries found for that date");
128                     }
129                 } else {
130                     mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds,
131                             BOUNDING_BOX_PADDING_PX));
132                     mMap.addPolyline(new PolylineOptions().geodesic(true).addAll(coordinates));
133                 }
134             }
135 
136         }.execute(calendar);
137     }
138 
139     @Override
onMapReady(GoogleMap googleMap)140     public void onMapReady(GoogleMap googleMap) {
141         mMap = googleMap;
142     }
143 }
144