| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.example.android.wearable.geofencing; |
| |
| import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_ID; |
| import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_LATITUDE; |
| import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_LONGITUDE; |
| import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_RADIUS_METERS; |
| import static com.example.android.wearable.geofencing.Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST; |
| import static com.example.android.wearable.geofencing.Constants.GEOFENCE_EXPIRATION_TIME; |
| import static com.example.android.wearable.geofencing.Constants.TAG; |
| import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_ID; |
| import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_LATITUDE; |
| import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_LONGITUDE; |
| import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_RADIUS_METERS; |
| |
| import android.app.Activity; |
| import android.app.PendingIntent; |
| import android.content.Intent; |
| import android.content.IntentSender; |
| import android.os.Bundle; |
| import android.util.Log; |
| import android.widget.Toast; |
| |
| import com.google.android.gms.common.ConnectionResult; |
| import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks; |
| import com.google.android.gms.common.GooglePlayServicesUtil; |
| import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; |
| import com.google.android.gms.location.Geofence; |
| import com.google.android.gms.location.LocationClient; |
| import com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener; |
| import com.google.android.gms.location.LocationStatusCodes; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public class MainActivity extends Activity implements ConnectionCallbacks, |
| OnConnectionFailedListener, OnAddGeofencesResultListener { |
| |
| // Internal List of Geofence objects. In a real app, these might be provided by an API based on |
| // locations within the user's proximity. |
| List<Geofence> mGeofenceList; |
| |
| // These will store hard-coded geofences in this sample app. |
| private SimpleGeofence mAndroidBuildingGeofence; |
| private SimpleGeofence mYerbaBuenaGeofence; |
| |
| // Persistent storage for geofences. |
| private SimpleGeofenceStore mGeofenceStorage; |
| |
| private LocationClient mLocationClient; |
| // Stores the PendingIntent used to request geofence monitoring. |
| private PendingIntent mGeofenceRequestIntent; |
| |
| // Defines the allowable request types (in this example, we only add geofences). |
| private enum REQUEST_TYPE {ADD} |
| private REQUEST_TYPE mRequestType; |
| // Flag that indicates if a request is underway. |
| private boolean mInProgress; |
| |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| // Rather than displayng this activity, simply display a toast indicating that the geofence |
| // service is being created. This should happen in less than a second. |
| Toast.makeText(this, getString(R.string.start_geofence_service), Toast.LENGTH_SHORT).show(); |
| |
| // Instantiate a new geofence storage area. |
| mGeofenceStorage = new SimpleGeofenceStore(this); |
| // Instantiate the current List of geofences. |
| mGeofenceList = new ArrayList<Geofence>(); |
| // Start with the request flag set to false. |
| mInProgress = false; |
| |
| createGeofences(); |
| addGeofences(); |
| |
| finish(); |
| } |
| |
| /** |
| * In this sample, the geofences are predetermined and are hard-coded here. A real app might |
| * dynamically create geofences based on the user's location. |
| */ |
| public void createGeofences() { |
| // Create internal "flattened" objects containing the geofence data. |
| mAndroidBuildingGeofence = new SimpleGeofence( |
| ANDROID_BUILDING_ID, // geofenceId. |
| ANDROID_BUILDING_LATITUDE, |
| ANDROID_BUILDING_LONGITUDE, |
| ANDROID_BUILDING_RADIUS_METERS, |
| GEOFENCE_EXPIRATION_TIME, |
| Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT |
| ); |
| mYerbaBuenaGeofence = new SimpleGeofence( |
| YERBA_BUENA_ID, // geofenceId. |
| YERBA_BUENA_LATITUDE, |
| YERBA_BUENA_LONGITUDE, |
| YERBA_BUENA_RADIUS_METERS, |
| GEOFENCE_EXPIRATION_TIME, |
| Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT |
| ); |
| |
| // Store these flat versions in SharedPreferences and add them to the geofence list. |
| mGeofenceStorage.setGeofence(ANDROID_BUILDING_ID, mAndroidBuildingGeofence); |
| mGeofenceStorage.setGeofence(YERBA_BUENA_ID, mYerbaBuenaGeofence); |
| mGeofenceList.add(mAndroidBuildingGeofence.toGeofence()); |
| mGeofenceList.add(mYerbaBuenaGeofence.toGeofence()); |
| } |
| |
| /** |
| * Start a request for geofence monitoring by calling LocationClient.connect(). |
| */ |
| public void addGeofences() { |
| // Start a request to add geofences. |
| mRequestType = REQUEST_TYPE.ADD; |
| // Test for Google Play services after setting the request type. |
| if (!isGooglePlayServicesAvailable()) { |
| Log.e(TAG, "Unable to add geofences - Google Play services unavailable."); |
| return; |
| } |
| // Create a new location client object. Since this activity class implements |
| // ConnectionCallbacks and OnConnectionFailedListener, it can be used as the listener for |
| // both parameters. |
| mLocationClient = new LocationClient(this, this, this); |
| // If a request is not already underway. |
| if (!mInProgress) { |
| // Indicate that a request is underway. |
| mInProgress = true; |
| // Request a connection from the client to Location Services. |
| mLocationClient.connect(); |
| // A request is already underway, so disconnect the client and retry the request. |
| } else { |
| mLocationClient.disconnect(); |
| mLocationClient.connect(); |
| } |
| } |
| |
| @Override |
| public void onConnectionFailed(ConnectionResult connectionResult) { |
| mInProgress = false; |
| // If the error has a resolution, start a Google Play services activity to resolve it. |
| if (connectionResult.hasResolution()) { |
| try { |
| connectionResult.startResolutionForResult(this, |
| CONNECTION_FAILURE_RESOLUTION_REQUEST); |
| } catch (IntentSender.SendIntentException e) { |
| Log.e(TAG, "Exception while resolving connection error.", e); |
| } |
| } else { |
| int errorCode = connectionResult.getErrorCode(); |
| Log.e(TAG, "Connection to Google Play services failed with error code " + errorCode); |
| } |
| } |
| |
| /** |
| * Called by Location Services if the location client disconnects. |
| */ |
| @Override |
| public void onDisconnected() { |
| // Turn off the request flag. |
| mInProgress = false; |
| // Destroy the current location client. |
| mLocationClient = null; |
| } |
| |
| /** |
| * Once the connection is available, send a request to add the Geofences. |
| */ |
| @Override |
| public void onConnected(Bundle connectionHint) { |
| // Use mRequestType to determine what action to take. Only ADD is used in this sample. |
| if (REQUEST_TYPE.ADD == mRequestType) { |
| // Get the PendingIntent for the geofence monitoring request. |
| mGeofenceRequestIntent = getGeofenceTransitionPendingIntent(); |
| // Send a request to add the current geofences. |
| mLocationClient.addGeofences(mGeofenceList, mGeofenceRequestIntent, this); |
| } |
| } |
| |
| /** |
| * Called when request to add geofences is complete, with a result status code. |
| */ |
| @Override |
| public void onAddGeofencesResult(int statusCode, String[] geofenceRequestIds) { |
| // Log if adding the geofences was successful. |
| if (LocationStatusCodes.SUCCESS == statusCode) { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Added geofences successfully."); |
| } |
| } else { |
| Log.e(TAG, "Failed to add geofences. Status code: " + statusCode); |
| } |
| // Turn off the in progress flag and disconnect the client. |
| mInProgress = false; |
| mLocationClient.disconnect(); |
| } |
| |
| /** |
| * Checks if Google Play services is available. |
| * @return true if it is. |
| */ |
| private boolean isGooglePlayServicesAvailable() { |
| int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); |
| if (ConnectionResult.SUCCESS == resultCode) { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Google Play services is available."); |
| } |
| return true; |
| } else { |
| Log.e(TAG, "Google Play services is unavailable."); |
| return false; |
| } |
| } |
| |
| /** |
| * Create a PendingIntent that triggers GeofenceTransitionIntentService when a geofence |
| * transition occurs. |
| */ |
| private PendingIntent getGeofenceTransitionPendingIntent() { |
| Intent intent = new Intent(this, GeofenceTransitionsIntentService.class); |
| return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); |
| } |
| |
| } |