1 /* 2 * Copyright (C) 2016 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 package android.hardware.location; 17 18 import android.annotation.RequiresPermission; 19 import android.annotation.SuppressLint; 20 import android.annotation.SystemApi; 21 import android.annotation.SystemService; 22 import android.content.Context; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.os.RemoteException; 26 import android.os.ServiceManager; 27 import android.os.ServiceManager.ServiceNotFoundException; 28 import android.util.Log; 29 30 /** 31 * A class that exposes the Context hubs on a device to applications. 32 * 33 * Please note that this class is not expected to be used by unbundled applications. Also, calling 34 * applications are expected to have LOCATION_HARDWARE permissions to use this class. 35 * 36 * @hide 37 */ 38 @SystemApi 39 @SystemService(Context.CONTEXTHUB_SERVICE) 40 public final class ContextHubManager { 41 42 private static final String TAG = "ContextHubManager"; 43 44 private final Looper mMainLooper; 45 private final IContextHubService mService; 46 private Callback mCallback; 47 private Handler mCallbackHandler; 48 49 /** 50 * @deprecated Use {@code mCallback} instead. 51 */ 52 @Deprecated 53 private ICallback mLocalCallback; 54 55 /** 56 * An interface to receive asynchronous communication from the context hub. 57 */ 58 public abstract static class Callback { Callback()59 protected Callback() {} 60 61 /** 62 * Callback function called on message receipt from context hub. 63 * 64 * @param hubHandle Handle (system-wide unique identifier) of the hub of the message. 65 * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message. 66 * @param message The context hub message. 67 * 68 * @see ContextHubMessage 69 */ onMessageReceipt( int hubHandle, int nanoAppHandle, ContextHubMessage message)70 public abstract void onMessageReceipt( 71 int hubHandle, 72 int nanoAppHandle, 73 ContextHubMessage message); 74 } 75 76 /** 77 * @deprecated Use {@link Callback} instead. 78 * @hide 79 */ 80 @Deprecated 81 public interface ICallback { 82 /** 83 * Callback function called on message receipt from context hub. 84 * 85 * @param hubHandle Handle (system-wide unique identifier) of the hub of the message. 86 * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message. 87 * @param message The context hub message. 88 * 89 * @see ContextHubMessage 90 */ onMessageReceipt(int hubHandle, int nanoAppHandle, ContextHubMessage message)91 void onMessageReceipt(int hubHandle, int nanoAppHandle, ContextHubMessage message); 92 } 93 94 /** 95 * Get a handle to all the context hubs in the system 96 * @return array of context hub handles 97 */ 98 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) getContextHubHandles()99 public int[] getContextHubHandles() { 100 try { 101 return mService.getContextHubHandles(); 102 } catch (RemoteException e) { 103 throw e.rethrowFromSystemServer(); 104 } 105 } 106 107 /** 108 * Get more information about a specific hub. 109 * 110 * @param hubHandle Handle (system-wide unique identifier) of a context hub. 111 * @return ContextHubInfo Information about the requested context hub. 112 * 113 * @see ContextHubInfo 114 */ 115 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) getContextHubInfo(int hubHandle)116 public ContextHubInfo getContextHubInfo(int hubHandle) { 117 try { 118 return mService.getContextHubInfo(hubHandle); 119 } catch (RemoteException e) { 120 throw e.rethrowFromSystemServer(); 121 } 122 } 123 124 /** 125 * Load a nano app on a specified context hub. 126 * 127 * Note that loading is asynchronous. When we return from this method, 128 * the nano app (probably) hasn't loaded yet. Assuming a return of 0 129 * from this method, then the final success/failure for the load, along 130 * with the "handle" for the nanoapp, is all delivered in a byte 131 * string via a call to Callback.onMessageReceipt. 132 * 133 * TODO(b/30784270): Provide a better success/failure and "handle" delivery. 134 * 135 * @param hubHandle handle of context hub to load the app on. 136 * @param app the nanoApp to load on the hub 137 * 138 * @return 0 if the command for loading was sent to the context hub; 139 * -1 otherwise 140 * 141 * @see NanoApp 142 */ 143 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) loadNanoApp(int hubHandle, NanoApp app)144 public int loadNanoApp(int hubHandle, NanoApp app) { 145 try { 146 return mService.loadNanoApp(hubHandle, app); 147 } catch (RemoteException e) { 148 throw e.rethrowFromSystemServer(); 149 } 150 } 151 152 /** 153 * Unload a specified nanoApp 154 * 155 * Note that unloading is asynchronous. When we return from this method, 156 * the nano app (probably) hasn't unloaded yet. Assuming a return of 0 157 * from this method, then the final success/failure for the unload is 158 * delivered in a byte string via a call to Callback.onMessageReceipt. 159 * 160 * TODO(b/30784270): Provide a better success/failure delivery. 161 * 162 * @param nanoAppHandle handle of the nanoApp to unload 163 * 164 * @return 0 if the command for unloading was sent to the context hub; 165 * -1 otherwise 166 */ 167 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) unloadNanoApp(int nanoAppHandle)168 public int unloadNanoApp(int nanoAppHandle) { 169 try { 170 return mService.unloadNanoApp(nanoAppHandle); 171 } catch (RemoteException e) { 172 throw e.rethrowFromSystemServer(); 173 } 174 } 175 176 /** 177 * get information about the nano app instance 178 * 179 * NOTE: The returned NanoAppInstanceInfo does _not_ contain correct 180 * information for several fields, specifically: 181 * - getName() 182 * - getPublisher() 183 * - getNeededExecMemBytes() 184 * - getNeededReadMemBytes() 185 * - getNeededWriteMemBytes() 186 * 187 * For example, say you call loadNanoApp() with a NanoApp that has 188 * getName() returning "My Name". Later, if you call getNanoAppInstanceInfo 189 * for that nanoapp, the returned NanoAppInstanceInfo's getName() 190 * method will claim "Preloaded app, unknown", even though you would 191 * have expected "My Name". For now, as the user, you'll need to 192 * separately track the above fields if they are of interest to you. 193 * 194 * TODO(b/30943489): Have the returned NanoAppInstanceInfo contain the 195 * correct information. 196 * 197 * @param nanoAppHandle handle of the nanoAppInstance 198 * @return NanoAppInstanceInfo Information about the nano app instance. 199 * 200 * @see NanoAppInstanceInfo 201 */ 202 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) getNanoAppInstanceInfo(int nanoAppHandle)203 public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) { 204 try { 205 return mService.getNanoAppInstanceInfo(nanoAppHandle); 206 } catch (RemoteException e) { 207 throw e.rethrowFromSystemServer(); 208 } 209 } 210 211 /** 212 * Find a specified nano app on the system 213 * 214 * @param hubHandle handle of hub to search for nano app 215 * @param filter filter specifying the search criteria for app 216 * 217 * @see NanoAppFilter 218 * 219 * @return int[] Array of handles to any found nano apps 220 */ 221 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) findNanoAppOnHub(int hubHandle, NanoAppFilter filter)222 public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) { 223 try { 224 return mService.findNanoAppOnHub(hubHandle, filter); 225 } catch (RemoteException e) { 226 throw e.rethrowFromSystemServer(); 227 } 228 } 229 230 /** 231 * Send a message to a specific nano app instance on a context hub. 232 * 233 * Note that the return value of this method only speaks of success 234 * up to the point of sending this to the Context Hub. It is not 235 * an assurance that the Context Hub successfully sent this message 236 * on to the nanoapp. If assurance is desired, a protocol should be 237 * established between your code and the nanoapp, with the nanoapp 238 * sending a confirmation message (which will be reported via 239 * Callback.onMessageReceipt). 240 * 241 * @param hubHandle handle of the hub to send the message to 242 * @param nanoAppHandle handle of the nano app to send to 243 * @param message Message to be sent 244 * 245 * @see ContextHubMessage 246 * 247 * @return int 0 on success, -1 otherwise 248 */ 249 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message)250 public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message) { 251 try { 252 return mService.sendMessage(hubHandle, nanoAppHandle, message); 253 } catch (RemoteException e) { 254 throw e.rethrowFromSystemServer(); 255 } 256 } 257 258 /** 259 * Set a callback to receive messages from the context hub 260 * 261 * @param callback Callback object 262 * 263 * @see Callback 264 * 265 * @return int 0 on success, -1 otherwise 266 */ 267 @SuppressLint("Doclava125") registerCallback(Callback callback)268 public int registerCallback(Callback callback) { 269 return registerCallback(callback, null); 270 } 271 272 /** 273 * @deprecated Use {@link #registerCallback(Callback)} instead. 274 * @hide 275 */ 276 @Deprecated registerCallback(ICallback callback)277 public int registerCallback(ICallback callback) { 278 if (mLocalCallback != null) { 279 Log.w(TAG, "Max number of local callbacks reached!"); 280 return -1; 281 } 282 mLocalCallback = callback; 283 return 0; 284 } 285 286 /** 287 * Set a callback to receive messages from the context hub 288 * 289 * @param callback Callback object 290 * @param handler Handler object 291 * 292 * @see Callback 293 * 294 * @return int 0 on success, -1 otherwise 295 */ 296 @SuppressLint("Doclava125") registerCallback(Callback callback, Handler handler)297 public int registerCallback(Callback callback, Handler handler) { 298 synchronized(this) { 299 if (mCallback != null) { 300 Log.w(TAG, "Max number of callbacks reached!"); 301 return -1; 302 } 303 mCallback = callback; 304 mCallbackHandler = handler; 305 } 306 return 0; 307 } 308 309 /** 310 * Unregister a callback for receive messages from the context hub. 311 * 312 * @see Callback 313 * 314 * @param callback method to deregister 315 * 316 * @return int 0 on success, -1 otherwise 317 */ 318 @SuppressLint("Doclava125") unregisterCallback(Callback callback)319 public int unregisterCallback(Callback callback) { 320 synchronized(this) { 321 if (callback != mCallback) { 322 Log.w(TAG, "Cannot recognize callback!"); 323 return -1; 324 } 325 326 mCallback = null; 327 mCallbackHandler = null; 328 } 329 return 0; 330 } 331 332 /** 333 * @deprecated Use {@link #unregisterCallback(Callback)} instead. 334 * @hide 335 */ 336 @Deprecated unregisterCallback(ICallback callback)337 public synchronized int unregisterCallback(ICallback callback) { 338 if (callback != mLocalCallback) { 339 Log.w(TAG, "Cannot recognize local callback!"); 340 return -1; 341 } 342 mLocalCallback = null; 343 return 0; 344 } 345 346 private final IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() { 347 @Override 348 public void onMessageReceipt(final int hubId, final int nanoAppId, 349 final ContextHubMessage message) { 350 if (mCallback != null) { 351 synchronized(this) { 352 final Callback callback = mCallback; 353 Handler handler = mCallbackHandler == null ? 354 new Handler(mMainLooper) : mCallbackHandler; 355 handler.post(new Runnable() { 356 @Override 357 public void run() { 358 callback.onMessageReceipt(hubId, nanoAppId, message); 359 } 360 }); 361 } 362 } else if (mLocalCallback != null) { 363 // we always ensure that mCallback takes precedence, because mLocalCallback is only 364 // for internal compatibility 365 synchronized (this) { 366 mLocalCallback.onMessageReceipt(hubId, nanoAppId, message); 367 } 368 } else { 369 Log.d(TAG, "Context hub manager client callback is NULL"); 370 } 371 } 372 }; 373 374 /** @throws ServiceNotFoundException 375 * @hide */ ContextHubManager(Context context, Looper mainLooper)376 public ContextHubManager(Context context, Looper mainLooper) throws ServiceNotFoundException { 377 mMainLooper = mainLooper; 378 mService = IContextHubService.Stub.asInterface( 379 ServiceManager.getServiceOrThrow(Context.CONTEXTHUB_SERVICE)); 380 try { 381 mService.registerCallback(mClientCallback); 382 } catch (RemoteException e) { 383 Log.w(TAG, "Could not register callback:" + e); 384 } 385 } 386 } 387