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.ACTION_CHECK_IN;
20 import static com.example.android.wearable.geofencing.Constants.ACTION_DELETE_DATA_ITEM;
21 import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_ID;
22 import static com.example.android.wearable.geofencing.Constants.KEY_GEOFENCE_ID;
23 import static com.example.android.wearable.geofencing.Constants.NOTIFICATION_ID;
24 import static com.example.android.wearable.geofencing.Constants.TAG;
25 import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_ID;
26 
27 import android.app.Notification;
28 import android.app.Notification.Action;
29 import android.app.NotificationManager;
30 import android.app.PendingIntent;
31 import android.content.Intent;
32 import android.graphics.Bitmap;
33 import android.graphics.BitmapFactory;
34 import android.net.Uri;
35 import android.text.Spannable;
36 import android.text.SpannableString;
37 import android.text.style.RelativeSizeSpan;
38 import android.util.Log;
39 
40 import com.google.android.gms.common.api.GoogleApiClient;
41 import com.google.android.gms.wearable.DataEvent;
42 import com.google.android.gms.wearable.DataEventBuffer;
43 import com.google.android.gms.wearable.DataItem;
44 import com.google.android.gms.wearable.DataMap;
45 import com.google.android.gms.wearable.Wearable;
46 import com.google.android.gms.wearable.WearableListenerService;
47 
48 /**
49  * Listens to DataItem events on the wearable device.
50  */
51 public class HomeListenerService extends WearableListenerService {
52 
53     private GoogleApiClient mGoogleApiClient;
54 
55     @Override
onCreate()56     public void onCreate() {
57         super.onCreate();
58         mGoogleApiClient = new GoogleApiClient.Builder(this.getApplicationContext())
59                 .addApi(Wearable.API)
60                 .build();
61         mGoogleApiClient.connect();
62     }
63 
64     /**
65      * Listen for DataItems added/deleted from the geofence service running on the companion.
66      */
67     @Override
onDataChanged(DataEventBuffer dataEvents)68     public void onDataChanged(DataEventBuffer dataEvents) {
69         if (Log.isLoggable(TAG, Log.DEBUG)) {
70             Log.d(TAG, "onDataChanged: " + dataEvents + " for " + getPackageName());
71         }
72         for (DataEvent event : dataEvents) {
73             if (event.getType() == DataEvent.TYPE_DELETED) {
74                 cancelNotificationForDataItem(event.getDataItem());
75             } else if (event.getType() == DataEvent.TYPE_CHANGED) {
76                 // The user has entered a geofence - post a notification!
77                 String geofenceId = DataMap.fromByteArray(event.getDataItem().getData())
78                         .getString(KEY_GEOFENCE_ID);
79                 postNotificationForGeofenceId(geofenceId, event.getDataItem().getUri());
80             }
81         }
82     }
83 
84     /**
85      * Deletes the check-in notification when the DataItem is deleted.
86      * @param dataItem Used only for logging in this sample, but could be used to identify which
87      *                 notification to cancel (in this case, there is at most 1 notification).
88      */
cancelNotificationForDataItem(DataItem dataItem)89     private void cancelNotificationForDataItem(DataItem dataItem) {
90         if (Log.isLoggable(TAG, Log.VERBOSE)) {
91             Log.v(TAG, "onDataItemDeleted:DataItem=" + dataItem.getUri());
92         }
93         ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID);
94     }
95 
96     /**
97      * Posts a local notification for the given geofence id, with an option to check in.
98      * @param geofenceId The geofence id that the user has triggered.
99      * @param dataItemUri The Uri for the DataItem that triggered this notification. Used to delete
100      *                    this DataItem when the notification is dismissed.
101      */
postNotificationForGeofenceId(String geofenceId, Uri dataItemUri)102     private void postNotificationForGeofenceId(String geofenceId, Uri dataItemUri) {
103         // Use the geofenceId to determine the title and background of the check-in notification.
104         // A SpannableString is used for the notification title for resizing capabilities.
105         SpannableString checkInTitle;
106         Bitmap notificationBackground;
107         if (ANDROID_BUILDING_ID.equals(geofenceId)) {
108             checkInTitle = new SpannableString(getText(R.string.android_building_title));
109             notificationBackground =
110                     BitmapFactory.decodeResource(getResources(), R.drawable.android_building);
111         } else if (YERBA_BUENA_ID.equals(geofenceId)) {
112             checkInTitle = new SpannableString(getText(R.string.yerba_buena_title));
113             notificationBackground =
114                     BitmapFactory.decodeResource(getResources(), R.drawable.yerba_buena);
115         } else {
116             Log.e(TAG, "Unrecognized geofence id: " + geofenceId);
117             return;
118         }
119         // Resize the title to avoid truncation.
120         checkInTitle.setSpan(new RelativeSizeSpan(0.8f), 0, checkInTitle.length(),
121                 Spannable.SPAN_POINT_MARK);
122 
123         Intent checkInOperation =
124                 new Intent(this, CheckInAndDeleteDataItemsService.class).setData(dataItemUri);
125         PendingIntent checkInIntent = PendingIntent.getService(this, 0,
126                 checkInOperation.setAction(ACTION_CHECK_IN), PendingIntent.FLAG_CANCEL_CURRENT);
127         PendingIntent deleteDataItemIntent = PendingIntent.getService(this, 1,
128                 checkInOperation.setAction(ACTION_DELETE_DATA_ITEM),
129                 PendingIntent.FLAG_CANCEL_CURRENT);
130         // This action will be embedded into the notification.
131         Action checkInAction = new Action(R.drawable.ic_action_check_in,
132                 getText(R.string.check_in_prompt), checkInIntent);
133 
134         Notification notification = new Notification.Builder(this)
135                 .setContentTitle(checkInTitle)
136                 .setContentText(getText(R.string.check_in_prompt))
137                 .setSmallIcon(R.drawable.ic_launcher)
138                 .setDeleteIntent(deleteDataItemIntent)
139                 .extend(new Notification.WearableExtender()
140                         .setBackground(notificationBackground)
141                         .addAction(checkInAction)
142                         .setContentAction(0)
143                         .setHintHideIcon(true))
144                 .setLocalOnly(true)
145                 .build();
146 
147         ((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
148                 .notify(NOTIFICATION_ID, notification);
149     }
150 
151 }
152