1 /*
2  * Copyright (C) 2014 The Android Open Source Project
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.geofencing;
18 
19 import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_ID;
20 import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_LATITUDE;
21 import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_LONGITUDE;
22 import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_RADIUS_METERS;
23 import static com.example.android.wearable.geofencing.Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST;
24 import static com.example.android.wearable.geofencing.Constants.GEOFENCE_EXPIRATION_TIME;
25 import static com.example.android.wearable.geofencing.Constants.TAG;
26 import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_ID;
27 import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_LATITUDE;
28 import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_LONGITUDE;
29 import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_RADIUS_METERS;
30 
31 import android.app.Activity;
32 import android.app.PendingIntent;
33 import android.content.Intent;
34 import android.content.IntentSender;
35 import android.os.Bundle;
36 import android.util.Log;
37 import android.widget.Toast;
38 
39 import com.google.android.gms.common.ConnectionResult;
40 import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
41 import com.google.android.gms.common.GooglePlayServicesUtil;
42 import com.google.android.gms.common.api.GoogleApiClient;
43 import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
44 import com.google.android.gms.location.Geofence;
45 import com.google.android.gms.location.LocationServices;
46 
47 import java.util.ArrayList;
48 import java.util.List;
49 
50 public class MainActivity extends Activity implements ConnectionCallbacks,
51         OnConnectionFailedListener {
52 
53     // Internal List of Geofence objects. In a real app, these might be provided by an API based on
54     // locations within the user's proximity.
55     List<Geofence> mGeofenceList;
56 
57     // These will store hard-coded geofences in this sample app.
58     private SimpleGeofence mAndroidBuildingGeofence;
59     private SimpleGeofence mYerbaBuenaGeofence;
60 
61     // Persistent storage for geofences.
62     private SimpleGeofenceStore mGeofenceStorage;
63 
64     private LocationServices mLocationService;
65     // Stores the PendingIntent used to request geofence monitoring.
66     private PendingIntent mGeofenceRequestIntent;
67     private GoogleApiClient mApiClient;
68 
69     // Defines the allowable request types (in this example, we only add geofences).
70     private enum REQUEST_TYPE {ADD}
71     private REQUEST_TYPE mRequestType;
72 
73     @Override
onCreate(Bundle savedInstanceState)74     protected void onCreate(Bundle savedInstanceState) {
75         super.onCreate(savedInstanceState);
76         // Rather than displayng this activity, simply display a toast indicating that the geofence
77         // service is being created. This should happen in less than a second.
78         if (!isGooglePlayServicesAvailable()) {
79             Log.e(TAG, "Google Play services unavailable.");
80             finish();
81             return;
82         }
83 
84         mApiClient = new GoogleApiClient.Builder(this)
85                 .addApi(LocationServices.API)
86                 .addConnectionCallbacks(this)
87                 .addOnConnectionFailedListener(this)
88                 .build();
89 
90         mApiClient.connect();
91 
92         // Instantiate a new geofence storage area.
93         mGeofenceStorage = new SimpleGeofenceStore(this);
94         // Instantiate the current List of geofences.
95         mGeofenceList = new ArrayList<Geofence>();
96         createGeofences();
97     }
98 
99     /**
100      * In this sample, the geofences are predetermined and are hard-coded here. A real app might
101      * dynamically create geofences based on the user's location.
102      */
createGeofences()103     public void createGeofences() {
104         // Create internal "flattened" objects containing the geofence data.
105         mAndroidBuildingGeofence = new SimpleGeofence(
106                 ANDROID_BUILDING_ID,                // geofenceId.
107                 ANDROID_BUILDING_LATITUDE,
108                 ANDROID_BUILDING_LONGITUDE,
109                 ANDROID_BUILDING_RADIUS_METERS,
110                 GEOFENCE_EXPIRATION_TIME,
111                 Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT
112         );
113         mYerbaBuenaGeofence = new SimpleGeofence(
114                 YERBA_BUENA_ID,                // geofenceId.
115                 YERBA_BUENA_LATITUDE,
116                 YERBA_BUENA_LONGITUDE,
117                 YERBA_BUENA_RADIUS_METERS,
118                 GEOFENCE_EXPIRATION_TIME,
119                 Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT
120         );
121 
122         // Store these flat versions in SharedPreferences and add them to the geofence list.
123         mGeofenceStorage.setGeofence(ANDROID_BUILDING_ID, mAndroidBuildingGeofence);
124         mGeofenceStorage.setGeofence(YERBA_BUENA_ID, mYerbaBuenaGeofence);
125         mGeofenceList.add(mAndroidBuildingGeofence.toGeofence());
126         mGeofenceList.add(mYerbaBuenaGeofence.toGeofence());
127     }
128 
129 
130     @Override
onConnectionFailed(ConnectionResult connectionResult)131     public void onConnectionFailed(ConnectionResult connectionResult) {
132         // If the error has a resolution, start a Google Play services activity to resolve it.
133         if (connectionResult.hasResolution()) {
134             try {
135                 connectionResult.startResolutionForResult(this,
136                         CONNECTION_FAILURE_RESOLUTION_REQUEST);
137             } catch (IntentSender.SendIntentException e) {
138                 Log.e(TAG, "Exception while resolving connection error.", e);
139             }
140         } else {
141             int errorCode = connectionResult.getErrorCode();
142             Log.e(TAG, "Connection to Google Play services failed with error code " + errorCode);
143         }
144     }
145 
146     /**
147      * Once the connection is available, send a request to add the Geofences.
148      */
149     @Override
onConnected(Bundle connectionHint)150     public void onConnected(Bundle connectionHint) {
151         // Get the PendingIntent for the geofence monitoring request.
152         // Send a request to add the current geofences.
153         mGeofenceRequestIntent = getGeofenceTransitionPendingIntent();
154         LocationServices.GeofencingApi.addGeofences(mApiClient, mGeofenceList,
155                 mGeofenceRequestIntent);
156         Toast.makeText(this, getString(R.string.start_geofence_service), Toast.LENGTH_SHORT).show();
157         finish();
158     }
159 
160     @Override
onConnectionSuspended(int i)161     public void onConnectionSuspended(int i) {
162         if (null != mGeofenceRequestIntent) {
163             LocationServices.GeofencingApi.removeGeofences(mApiClient, mGeofenceRequestIntent);
164         }
165     }
166 
167 
168     /**
169      * Checks if Google Play services is available.
170      * @return true if it is.
171      */
isGooglePlayServicesAvailable()172     private boolean isGooglePlayServicesAvailable() {
173         int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
174         if (ConnectionResult.SUCCESS == resultCode) {
175             if (Log.isLoggable(TAG, Log.DEBUG)) {
176                 Log.d(TAG, "Google Play services is available.");
177             }
178             return true;
179         } else {
180             Log.e(TAG, "Google Play services is unavailable.");
181             return false;
182         }
183     }
184 
185     /**
186      * Create a PendingIntent that triggers GeofenceTransitionIntentService when a geofence
187      * transition occurs.
188      */
getGeofenceTransitionPendingIntent()189     private PendingIntent getGeofenceTransitionPendingIntent() {
190         Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
191         return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
192     }
193 
194 }
195