1 /* 2 * Copyright 2015 Google Inc. All rights reserved. 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.xyztouristattractions.service; 18 19 import android.app.IntentService; 20 import android.app.NotificationManager; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.util.Log; 24 25 import com.example.android.xyztouristattractions.R; 26 import com.example.android.xyztouristattractions.common.Constants; 27 import com.example.android.xyztouristattractions.common.Utils; 28 import com.google.android.gms.common.ConnectionResult; 29 import com.google.android.gms.common.api.GoogleApiClient; 30 import com.google.android.gms.wearable.CapabilityApi; 31 import com.google.android.gms.wearable.Node; 32 import com.google.android.gms.wearable.Wearable; 33 34 import java.util.Iterator; 35 import java.util.Set; 36 import java.util.concurrent.TimeUnit; 37 38 /** 39 * A utility IntentService, used for a variety of asynchronous background 40 * operations that do not necessarily need to be tied to a UI. 41 */ 42 public class UtilityService extends IntentService { 43 44 private static final String TAG = UtilityService.class.getSimpleName(); 45 46 private static final String ACTION_CLEAR_NOTIFICATION = "clear_notification"; 47 private static final String ACTION_CLEAR_REMOTE_NOTIFICATIONS = "clear_remote_notifications"; 48 private static final String ACTION_START_DEVICE_ACTIVITY = "start_device_activity"; 49 private static final String EXTRA_START_PATH = "start_path"; 50 private static final String EXTRA_START_ACTIVITY_INFO = "start_activity_info"; 51 private static final long GET_CAPABILITY_TIMEOUT_S = 10; 52 clearNotification(Context context)53 public static void clearNotification(Context context) { 54 Intent intent = new Intent(context, UtilityService.class); 55 intent.setAction(UtilityService.ACTION_CLEAR_NOTIFICATION); 56 context.startService(intent); 57 } 58 clearRemoteNotifications(Context context)59 public static void clearRemoteNotifications(Context context) { 60 context.startService(getClearRemoteNotificationsIntent(context)); 61 } 62 getClearRemoteNotificationsIntent(Context context)63 public static Intent getClearRemoteNotificationsIntent(Context context) { 64 Intent intent = new Intent(context, UtilityService.class); 65 intent.setAction(UtilityService.ACTION_CLEAR_REMOTE_NOTIFICATIONS); 66 return intent; 67 } 68 69 /** 70 * Trigger a message that asks the master device to start an activity. 71 * 72 * @param context the context 73 * @param path the path that will be sent via the wearable message API 74 * @param name the tourist attraction name 75 * @param city the tourist attraction city 76 */ startDeviceActivity(Context context, String path, String name, String city)77 public static void startDeviceActivity(Context context, String path, String name, String city) { 78 Intent intent = new Intent(context, UtilityService.class); 79 intent.setAction(UtilityService.ACTION_START_DEVICE_ACTIVITY); 80 String extraInfo; 81 if (Constants.START_ATTRACTION_PATH.equals(path)) { 82 extraInfo = name; 83 } else { 84 extraInfo = name + ", " + city; 85 } 86 intent.putExtra(EXTRA_START_ACTIVITY_INFO, extraInfo); 87 intent.putExtra(EXTRA_START_PATH, path); 88 context.startService(intent); 89 } 90 UtilityService()91 public UtilityService() { 92 super(TAG); 93 } 94 95 @Override onHandleIntent(Intent intent)96 protected void onHandleIntent(Intent intent) { 97 String action = intent != null ? intent.getAction() : null; 98 if (ACTION_CLEAR_NOTIFICATION.equals(action)) { 99 clearNotificationInternal(); 100 } else if (ACTION_CLEAR_REMOTE_NOTIFICATIONS.equals(action)) { 101 clearRemoteNotificationsInternal(); 102 } else if (ACTION_START_DEVICE_ACTIVITY.equals(action)) { 103 startDeviceActivityInternal(intent.getStringExtra(EXTRA_START_PATH), 104 intent.getStringExtra(EXTRA_START_ACTIVITY_INFO)); 105 } 106 } 107 108 /** 109 * Clear the local notifications 110 */ clearNotificationInternal()111 private void clearNotificationInternal() { 112 NotificationManager notificationManager = 113 (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 114 notificationManager.cancel(Constants.WEAR_NOTIFICATION_ID); 115 } 116 117 /** 118 * Trigger a message to ask other devices to clear their notifications 119 */ clearRemoteNotificationsInternal()120 private void clearRemoteNotificationsInternal() { 121 GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this) 122 .addApi(Wearable.API) 123 .build(); 124 125 ConnectionResult connectionResult = googleApiClient.blockingConnect( 126 Constants.GOOGLE_API_CLIENT_TIMEOUT_S, TimeUnit.SECONDS); 127 128 if (connectionResult.isSuccess() && googleApiClient.isConnected()) { 129 Iterator<String> itr = Utils.getNodes(googleApiClient).iterator(); 130 while (itr.hasNext()) { 131 // Loop through all connected nodes 132 Wearable.MessageApi.sendMessage( 133 googleApiClient, itr.next(), Constants.CLEAR_NOTIFICATIONS_PATH, null); 134 } 135 } 136 137 googleApiClient.disconnect(); 138 } 139 140 /** 141 * Sends the actual message to ask other devices that are capable of showing "details" to start 142 * the appropriate activity 143 * 144 * @param path the path to pass to the wearable message API 145 * @param extraInfo extra info that varies based on the path being sent 146 */ startDeviceActivityInternal(String path, String extraInfo)147 private void startDeviceActivityInternal(String path, String extraInfo) { 148 GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this) 149 .addApi(Wearable.API) 150 .build(); 151 152 ConnectionResult connectionResult = googleApiClient.blockingConnect( 153 Constants.GOOGLE_API_CLIENT_TIMEOUT_S, TimeUnit.SECONDS); 154 155 if (connectionResult.isSuccess() && googleApiClient.isConnected()) { 156 CapabilityApi.GetCapabilityResult result = Wearable.CapabilityApi.getCapability( 157 googleApiClient, 158 getApplicationContext().getString(R.string.show_detail_capability_name), 159 CapabilityApi.FILTER_REACHABLE) 160 .await(GET_CAPABILITY_TIMEOUT_S, TimeUnit.SECONDS); 161 if (result.getStatus().isSuccess()) { 162 Set<Node> nodes = result.getCapability().getNodes(); 163 for (Node node : nodes) { 164 Wearable.MessageApi.sendMessage( 165 googleApiClient, node.getId(), path, extraInfo.getBytes()); 166 } 167 } else { 168 Log.e(TAG, "startDeviceActivityInternal() Failed to get capabilities, status: " 169 + result.getStatus().getStatusMessage()); 170 } 171 172 googleApiClient.disconnect(); 173 } 174 } 175 176 } 177