1 /* 2 * Copyright (C) 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.wearable.runtimepermissions; 18 19 import android.Manifest; 20 import android.content.Intent; 21 import android.content.pm.PackageManager; 22 import android.hardware.Sensor; 23 import android.hardware.SensorManager; 24 import android.support.v4.app.ActivityCompat; 25 import android.util.Log; 26 27 import com.example.android.wearable.runtimepermissions.common.Constants; 28 29 import com.google.android.gms.common.ConnectionResult; 30 import com.google.android.gms.common.api.GoogleApiClient; 31 import com.google.android.gms.common.api.PendingResult; 32 import com.google.android.gms.wearable.CapabilityApi; 33 import com.google.android.gms.wearable.CapabilityInfo; 34 import com.google.android.gms.wearable.DataMap; 35 import com.google.android.gms.wearable.MessageApi; 36 import com.google.android.gms.wearable.MessageEvent; 37 import com.google.android.gms.wearable.Node; 38 import com.google.android.gms.wearable.Wearable; 39 import com.google.android.gms.wearable.WearableListenerService; 40 41 import java.util.List; 42 import java.util.Set; 43 import java.util.concurrent.TimeUnit; 44 45 /** 46 * Handles all incoming requests for wear data (and permissions) from phone devices. 47 */ 48 public class IncomingRequestWearService extends WearableListenerService { 49 50 private static final String TAG = "IncomingRequestService"; 51 IncomingRequestWearService()52 public IncomingRequestWearService() { 53 Log.d(TAG, "IncomingRequestWearService()"); 54 } 55 56 @Override onCreate()57 public void onCreate() { 58 super.onCreate(); 59 Log.d(TAG, "onCreate()"); 60 } 61 62 @Override onMessageReceived(MessageEvent messageEvent)63 public void onMessageReceived(MessageEvent messageEvent) { 64 Log.d(TAG, "onMessageReceived(): " + messageEvent); 65 66 String messagePath = messageEvent.getPath(); 67 68 if (messagePath.equals(Constants.MESSAGE_PATH_WEAR)) { 69 DataMap dataMap = DataMap.fromByteArray(messageEvent.getData()); 70 71 int requestType = dataMap.getInt(Constants.KEY_COMM_TYPE); 72 73 if (requestType == Constants.COMM_TYPE_REQUEST_PROMPT_PERMISSION) { 74 promptUserForSensorPermission(); 75 76 } else if (requestType == Constants.COMM_TYPE_REQUEST_DATA) { 77 respondWithSensorInformation(); 78 } 79 } 80 } 81 promptUserForSensorPermission()82 private void promptUserForSensorPermission() { 83 Log.d(TAG, "promptUserForSensorPermission()"); 84 85 boolean sensorPermissionApproved = 86 ActivityCompat.checkSelfPermission(this, Manifest.permission.BODY_SENSORS) 87 == PackageManager.PERMISSION_GRANTED; 88 89 if (sensorPermissionApproved) { 90 DataMap dataMap = new DataMap(); 91 dataMap.putInt(Constants.KEY_COMM_TYPE, 92 Constants.COMM_TYPE_RESPONSE_USER_APPROVED_PERMISSION); 93 sendMessage(dataMap); 94 } else { 95 // Launch Activity to grant sensor permissions. 96 Intent startIntent = new Intent(this, MainWearActivity.class); 97 startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 98 startIntent.putExtra(MainWearActivity.EXTRA_PROMPT_PERMISSION_FROM_PHONE, true); 99 startActivity(startIntent); 100 } 101 } 102 respondWithSensorInformation()103 private void respondWithSensorInformation() { 104 Log.d(TAG, "respondWithSensorInformation()"); 105 106 boolean sensorPermissionApproved = 107 ActivityCompat.checkSelfPermission(this, Manifest.permission.BODY_SENSORS) 108 == PackageManager.PERMISSION_GRANTED; 109 110 if (!sensorPermissionApproved) { 111 DataMap dataMap = new DataMap(); 112 dataMap.putInt(Constants.KEY_COMM_TYPE, 113 Constants.COMM_TYPE_RESPONSE_PERMISSION_REQUIRED); 114 sendMessage(dataMap); 115 } else { 116 /* To keep the sample simple, we are only displaying the number of sensors. You could do 117 * something much more complicated. 118 */ 119 SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); 120 List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL); 121 int numberOfSensorsOnDevice = sensorList.size(); 122 123 String sensorSummary = numberOfSensorsOnDevice + " sensors on wear device(s)!"; 124 DataMap dataMap = new DataMap(); 125 dataMap.putInt(Constants.KEY_COMM_TYPE, 126 Constants.COMM_TYPE_RESPONSE_DATA); 127 dataMap.putString(Constants.KEY_PAYLOAD, sensorSummary); 128 sendMessage(dataMap); 129 } 130 } 131 sendMessage(DataMap dataMap)132 private void sendMessage(DataMap dataMap) { 133 134 Log.d(TAG, "sendMessage(): " + dataMap); 135 136 GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this) 137 .addApi(Wearable.API) 138 .build(); 139 ConnectionResult connectionResult = 140 googleApiClient.blockingConnect( 141 Constants.CONNECTION_TIME_OUT_MS, 142 TimeUnit.MILLISECONDS); 143 144 if (!connectionResult.isSuccess()) { 145 Log.d(TAG, "Google API Client failed to connect."); 146 return; 147 } 148 149 PendingResult<CapabilityApi.GetCapabilityResult> pendingCapabilityResult = 150 Wearable.CapabilityApi.getCapability( 151 googleApiClient, 152 Constants.CAPABILITY_PHONE_APP, 153 CapabilityApi.FILTER_REACHABLE); 154 155 CapabilityApi.GetCapabilityResult getCapabilityResult = 156 pendingCapabilityResult.await( 157 Constants.CONNECTION_TIME_OUT_MS, 158 TimeUnit.MILLISECONDS); 159 160 if (!getCapabilityResult.getStatus().isSuccess()) { 161 Log.d(TAG, "CapabilityApi failed to return any results."); 162 googleApiClient.disconnect(); 163 return; 164 } 165 166 CapabilityInfo capabilityInfo = getCapabilityResult.getCapability(); 167 String phoneNodeId = pickBestNodeId(capabilityInfo.getNodes()); 168 169 PendingResult<MessageApi.SendMessageResult> pendingMessageResult = 170 Wearable.MessageApi.sendMessage( 171 googleApiClient, 172 phoneNodeId, 173 Constants.MESSAGE_PATH_PHONE, 174 dataMap.toByteArray()); 175 176 MessageApi.SendMessageResult sendMessageResult = 177 pendingMessageResult.await(Constants.CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS); 178 179 if (!sendMessageResult.getStatus().isSuccess()) { 180 Log.d(TAG, "Sending message failed, onResult: " + sendMessageResult.getStatus()); 181 } else { 182 Log.d(TAG, "Message sent successfully"); 183 } 184 185 googleApiClient.disconnect(); 186 } 187 188 /* 189 * There should only ever be one phone in a node set (much less w/ the correct capability), so 190 * I am just grabbing the first one (which should be the only one). 191 */ pickBestNodeId(Set<Node> nodes)192 private String pickBestNodeId(Set<Node> nodes) { 193 194 Log.d(TAG, "pickBestNodeId: " + nodes); 195 196 197 String bestNodeId = null; 198 /* Find a nearby node or pick one arbitrarily. There should be only one phone connected 199 * that supports this sample. 200 */ 201 for (Node node : nodes) { 202 if (node.isNearby()) { 203 return node.getId(); 204 } 205 bestNodeId = node.getId(); 206 } 207 return bestNodeId; 208 } 209 }