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.CONNECTION_TIME_OUT_MS;
20 import static com.example.android.wearable.geofencing.Constants.GEOFENCE_DATA_ITEM_PATH;
21 import static com.example.android.wearable.geofencing.Constants.GEOFENCE_DATA_ITEM_URI;
22 import static com.example.android.wearable.geofencing.Constants.KEY_GEOFENCE_ID;
23 import static com.example.android.wearable.geofencing.Constants.TAG;
24 
25 import android.app.IntentService;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.os.Looper;
31 import android.util.Log;
32 import android.widget.Toast;
33 
34 import com.google.android.gms.common.ConnectionResult;
35 import com.google.android.gms.common.api.GoogleApiClient;
36 import com.google.android.gms.location.Geofence;
37 import com.google.android.gms.location.GeofencingEvent;
38 import com.google.android.gms.wearable.PutDataMapRequest;
39 import com.google.android.gms.wearable.Wearable;
40 
41 import java.util.concurrent.TimeUnit;
42 
43 /**
44  * Listens for geofence transition changes.
45  */
46 public class GeofenceTransitionsIntentService extends IntentService
47         implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
48 
49     private GoogleApiClient mGoogleApiClient;
50 
GeofenceTransitionsIntentService()51     public GeofenceTransitionsIntentService() {
52         super(GeofenceTransitionsIntentService.class.getSimpleName());
53     }
54 
55     @Override
onCreate()56     public void onCreate() {
57         super.onCreate();
58         mGoogleApiClient = new GoogleApiClient.Builder(this)
59                 .addApi(Wearable.API)
60                 .addConnectionCallbacks(this)
61                 .addOnConnectionFailedListener(this)
62                 .build();
63     }
64 
65     /**
66      * Handles incoming intents.
67      * @param intent The Intent sent by Location Services. This Intent is provided to Location
68      * Services (inside a PendingIntent) when addGeofences() is called.
69      */
70     @Override
onHandleIntent(Intent intent)71     protected void onHandleIntent(Intent intent) {
72         GeofencingEvent geoFenceEvent = GeofencingEvent.fromIntent(intent);
73         if (geoFenceEvent.hasError()) {
74             int errorCode = geoFenceEvent.getErrorCode();
75             Log.e(TAG, "Location Services error: " + errorCode);
76         } else {
77 
78             int transitionType = geoFenceEvent.getGeofenceTransition();
79             if (Geofence.GEOFENCE_TRANSITION_ENTER == transitionType) {
80                 // Connect to the Google Api service in preparation for sending a DataItem.
81                 mGoogleApiClient.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
82                 // Get the geofence id triggered. Note that only one geofence can be triggered at a
83                 // time in this example, but in some cases you might want to consider the full list
84                 // of geofences triggered.
85                 String triggeredGeoFenceId = geoFenceEvent.getTriggeringGeofences().get(0)
86                         .getRequestId();
87                 // Create a DataItem with this geofence's id. The wearable can use this to create
88                 // a notification.
89                 final PutDataMapRequest putDataMapRequest =
90                         PutDataMapRequest.create(GEOFENCE_DATA_ITEM_PATH);
91                 putDataMapRequest.getDataMap().putString(KEY_GEOFENCE_ID, triggeredGeoFenceId);
92                 putDataMapRequest.setUrgent();
93                 if (mGoogleApiClient.isConnected()) {
94                     Wearable.DataApi.putDataItem(
95                             mGoogleApiClient, putDataMapRequest.asPutDataRequest()).await();
96                 } else {
97                     Log.e(TAG, "Failed to send data item: " + putDataMapRequest
98                             + " - Client disconnected from Google Play Services");
99                 }
100                 Toast.makeText(this, getString(R.string.entering_geofence),
101                         Toast.LENGTH_SHORT).show();
102                 mGoogleApiClient.disconnect();
103             } else if (Geofence.GEOFENCE_TRANSITION_EXIT == transitionType) {
104                 // Delete the data item when leaving a geofence region.
105                 mGoogleApiClient.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
106                 Wearable.DataApi.deleteDataItems(mGoogleApiClient, GEOFENCE_DATA_ITEM_URI).await();
107                 showToast(this, R.string.exiting_geofence);
108                 mGoogleApiClient.disconnect();
109             }
110         }
111     }
112 
113     /**
114      * Showing a toast message, using the Main thread
115      */
showToast(final Context context, final int resourceId)116     private void showToast(final Context context, final int resourceId) {
117         Handler mainThread = new Handler(Looper.getMainLooper());
118         mainThread.post(new Runnable() {
119             @Override
120             public void run() {
121                 Toast.makeText(context, context.getString(resourceId), Toast.LENGTH_SHORT).show();
122             }
123         });
124     }
125 
126     @Override
onConnected(Bundle connectionHint)127     public void onConnected(Bundle connectionHint) {
128     }
129 
130     @Override
onConnectionSuspended(int cause)131     public void onConnectionSuspended(int cause) {
132     }
133 
134     @Override
onConnectionFailed(ConnectionResult result)135     public void onConnectionFailed(ConnectionResult result) {
136     }
137 
138 }
139