Home | History | Annotate | Download | only in com.example.android.wearable.geofencing
      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.GooglePlayServicesClient.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, GoogleApiClient.ConnectionCallbacks {
     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
     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      */
    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
    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     @Override
    147     public void onDisconnected() {
    148     }
    149 
    150     /**
    151      * Once the connection is available, send a request to add the Geofences.
    152      */
    153     @Override
    154     public void onConnected(Bundle connectionHint) {
    155         // Get the PendingIntent for the geofence monitoring request.
    156         // Send a request to add the current geofences.
    157         mGeofenceRequestIntent = getGeofenceTransitionPendingIntent();
    158         LocationServices.GeofencingApi.addGeofences(mApiClient, mGeofenceList,
    159                 mGeofenceRequestIntent);
    160         Toast.makeText(this, getString(R.string.start_geofence_service), Toast.LENGTH_SHORT).show();
    161         finish();
    162     }
    163 
    164     @Override
    165     public void onConnectionSuspended(int i) {
    166         if (null != mGeofenceRequestIntent) {
    167             LocationServices.GeofencingApi.removeGeofences(mApiClient, mGeofenceRequestIntent);
    168         }
    169     }
    170 
    171 
    172     /**
    173      * Checks if Google Play services is available.
    174      * @return true if it is.
    175      */
    176     private boolean isGooglePlayServicesAvailable() {
    177         int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    178         if (ConnectionResult.SUCCESS == resultCode) {
    179             if (Log.isLoggable(TAG, Log.DEBUG)) {
    180                 Log.d(TAG, "Google Play services is available.");
    181             }
    182             return true;
    183         } else {
    184             Log.e(TAG, "Google Play services is unavailable.");
    185             return false;
    186         }
    187     }
    188 
    189     /**
    190      * Create a PendingIntent that triggers GeofenceTransitionIntentService when a geofence
    191      * transition occurs.
    192      */
    193     private PendingIntent getGeofenceTransitionPendingIntent() {
    194         Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
    195         return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    196     }
    197 
    198 }
    199