• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.geofencing;
18 
19 import static com.example.android.geofencing.Constants.ANDROID_BUILDING_ID;
20 import static com.example.android.geofencing.Constants.ANDROID_BUILDING_LATITUDE;
21 import static com.example.android.geofencing.Constants.ANDROID_BUILDING_LONGITUDE;
22 import static com.example.android.geofencing.Constants.ANDROID_BUILDING_RADIUS_METERS;
23 import static com.example.android.geofencing.Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST;
24 import static com.example.android.geofencing.Constants.GEOFENCE_EXPIRATION_TIME;
25 import static com.example.android.geofencing.Constants.TAG;
26 import static com.example.android.geofencing.Constants.YERBA_BUENA_ID;
27 import static com.example.android.geofencing.Constants.YERBA_BUENA_LATITUDE;
28 import static com.example.android.geofencing.Constants.YERBA_BUENA_LONGITUDE;
29 import static com.example.android.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.GooglePlayServicesClient.ConnectionCallbacks;
41 import com.google.android.gms.common.GooglePlayServicesUtil;
42 import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
43 import com.google.android.gms.location.Geofence;
44 import com.google.android.gms.location.LocationClient;
45 import com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener;
46 import com.google.android.gms.location.LocationStatusCodes;
47 
48 import java.util.ArrayList;
49 import java.util.List;
50 
51 public class MainActivity extends Activity implements ConnectionCallbacks,
52         OnConnectionFailedListener, OnAddGeofencesResultListener {
53 
54     // Internal List of Geofence objects. In a real app, these might be provided by an API based on
55     // locations within the user's proximity.
56     List<Geofence> mGeofenceList;
57 
58     // These will store hard-coded geofences in this sample app.
59     private SimpleGeofence mAndroidBuildingGeofence;
60     private SimpleGeofence mYerbaBuenaGeofence;
61 
62     // Persistent storage for geofences.
63     private SimpleGeofenceStore mGeofenceStorage;
64 
65     private LocationClient mLocationClient;
66     // Stores the PendingIntent used to request geofence monitoring.
67     private PendingIntent mGeofenceRequestIntent;
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     // Flag that indicates if a request is underway.
73     private boolean mInProgress;
74 
75 
76     @Override
onCreate(Bundle savedInstanceState)77     protected void onCreate(Bundle savedInstanceState) {
78         super.onCreate(savedInstanceState);
79         // Rather than displayng this activity, simply display a toast indicating that the geofence
80         // service is being created. This should happen in less than a second.
81         Toast.makeText(this, getString(R.string.start_geofence_service), Toast.LENGTH_SHORT).show();
82 
83         // Instantiate a new geofence storage area.
84         mGeofenceStorage = new SimpleGeofenceStore(this);
85         // Instantiate the current List of geofences.
86         mGeofenceList = new ArrayList<Geofence>();
87         // Start with the request flag set to false.
88         mInProgress = false;
89 
90         createGeofences();
91         addGeofences();
92 
93         finish();
94     }
95 
96     /**
97      * In this sample, the geofences are predetermined and are hard-coded here. A real app might
98      * dynamically create geofences based on the user's location.
99      */
createGeofences()100     public void createGeofences() {
101         // Create internal "flattened" objects containing the geofence data.
102         mAndroidBuildingGeofence = new SimpleGeofence(
103                 ANDROID_BUILDING_ID,                // geofenceId.
104                 ANDROID_BUILDING_LATITUDE,
105                 ANDROID_BUILDING_LONGITUDE,
106                 ANDROID_BUILDING_RADIUS_METERS,
107                 GEOFENCE_EXPIRATION_TIME,
108                 Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT
109         );
110         mYerbaBuenaGeofence = new SimpleGeofence(
111                 YERBA_BUENA_ID,                // geofenceId.
112                 YERBA_BUENA_LATITUDE,
113                 YERBA_BUENA_LONGITUDE,
114                 YERBA_BUENA_RADIUS_METERS,
115                 GEOFENCE_EXPIRATION_TIME,
116                 Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT
117         );
118 
119         // Store these flat versions in SharedPreferences and add them to the geofence list.
120         mGeofenceStorage.setGeofence(ANDROID_BUILDING_ID, mAndroidBuildingGeofence);
121         mGeofenceStorage.setGeofence(YERBA_BUENA_ID, mYerbaBuenaGeofence);
122         mGeofenceList.add(mAndroidBuildingGeofence.toGeofence());
123         mGeofenceList.add(mYerbaBuenaGeofence.toGeofence());
124     }
125 
126     /**
127      * Start a request for geofence monitoring by calling LocationClient.connect().
128      */
addGeofences()129     public void addGeofences() {
130         // Start a request to add geofences.
131         mRequestType = REQUEST_TYPE.ADD;
132         // Test for Google Play services after setting the request type.
133         if (!isGooglePlayServicesAvailable()) {
134             Log.e(TAG, "Unable to add geofences - Google Play services unavailable.");
135             return;
136         }
137         // Create a new location client object. Since this activity class implements
138         // ConnectionCallbacks and OnConnectionFailedListener, it can be used as the listener for
139         // both parameters.
140         mLocationClient = new LocationClient(this, this, this);
141         // If a request is not already underway.
142         if (!mInProgress) {
143             // Indicate that a request is underway.
144             mInProgress = true;
145             // Request a connection from the client to Location Services.
146             mLocationClient.connect();
147         // A request is already underway, so disconnect the client and retry the request.
148         } else {
149             mLocationClient.disconnect();
150             mLocationClient.connect();
151         }
152     }
153 
154     @Override
onConnectionFailed(ConnectionResult connectionResult)155     public void onConnectionFailed(ConnectionResult connectionResult) {
156         mInProgress = false;
157         // If the error has a resolution, start a Google Play services activity to resolve it.
158         if (connectionResult.hasResolution()) {
159             try {
160                 connectionResult.startResolutionForResult(this,
161                         CONNECTION_FAILURE_RESOLUTION_REQUEST);
162             } catch (IntentSender.SendIntentException e) {
163                 Log.e(TAG, "Exception while resolving connection error.", e);
164             }
165         } else {
166             int errorCode = connectionResult.getErrorCode();
167             Log.e(TAG, "Connection to Google Play services failed with error code " + errorCode);
168         }
169     }
170 
171     /**
172      * Called by Location Services if the location client disconnects.
173      */
174     @Override
onDisconnected()175     public void onDisconnected() {
176         // Turn off the request flag.
177         mInProgress = false;
178         // Destroy the current location client.
179         mLocationClient = null;
180     }
181 
182     /**
183      * Once the connection is available, send a request to add the Geofences.
184      */
185     @Override
onConnected(Bundle connectionHint)186     public void onConnected(Bundle connectionHint) {
187         // Use mRequestType to determine what action to take. Only ADD is used in this sample.
188         if (REQUEST_TYPE.ADD == mRequestType) {
189             // Get the PendingIntent for the geofence monitoring request.
190             mGeofenceRequestIntent = getGeofenceTransitionPendingIntent();
191             // Send a request to add the current geofences.
192             mLocationClient.addGeofences(mGeofenceList, mGeofenceRequestIntent, this);
193         }
194     }
195 
196     /**
197      * Called when request to add geofences is complete, with a result status code.
198      */
199     @Override
onAddGeofencesResult(int statusCode, String[] geofenceRequestIds)200     public void onAddGeofencesResult(int statusCode, String[] geofenceRequestIds) {
201         // Log if adding the geofences was successful.
202         if (LocationStatusCodes.SUCCESS == statusCode) {
203             if (Log.isLoggable(TAG, Log.DEBUG)) {
204                 Log.d(TAG, "Added geofences successfully.");
205             }
206         } else {
207             Log.e(TAG, "Failed to add geofences. Status code: " + statusCode);
208         }
209         // Turn off the in progress flag and disconnect the client.
210         mInProgress = false;
211         mLocationClient.disconnect();
212     }
213 
214     /**
215      * Checks if Google Play services is available.
216      * @return true if it is.
217      */
isGooglePlayServicesAvailable()218     private boolean isGooglePlayServicesAvailable() {
219         int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
220         if (ConnectionResult.SUCCESS == resultCode) {
221             if (Log.isLoggable(TAG, Log.DEBUG)) {
222                 Log.d(TAG, "Google Play services is available.");
223             }
224             return true;
225         } else {
226             Log.e(TAG, "Google Play services is unavailable.");
227             return false;
228         }
229     }
230 
231     /**
232      * Create a PendingIntent that triggers GeofenceTransitionIntentService when a geofence
233      * transition occurs.
234      */
getGeofenceTransitionPendingIntent()235     private PendingIntent getGeofenceTransitionPendingIntent() {
236         Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
237         return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
238     }
239 
240 }
241