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.CallbackExecutor; 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.RequiresPermission; 22 import android.annotation.SuppressLint; 23 import android.annotation.SystemApi; 24 import android.annotation.SystemService; 25 import android.content.Context; 26 import android.os.Handler; 27 import android.os.HandlerExecutor; 28 import android.os.Looper; 29 import android.os.RemoteException; 30 import android.os.ServiceManager; 31 import android.os.ServiceManager.ServiceNotFoundException; 32 import android.util.Log; 33 34 import com.android.internal.util.Preconditions; 35 36 import java.util.List; 37 import java.util.concurrent.Executor; 38 39 /** 40 * A class that exposes the Context hubs on a device to applications. 41 * 42 * Please note that this class is not expected to be used by unbundled applications. Also, calling 43 * applications are expected to have LOCATION_HARDWARE permissions to use this class. 44 * 45 * @hide 46 */ 47 @SystemApi 48 @SystemService(Context.CONTEXTHUB_SERVICE) 49 public final class ContextHubManager { 50 private static final String TAG = "ContextHubManager"; 51 52 private final Looper mMainLooper; 53 private final IContextHubService mService; 54 private Callback mCallback; 55 private Handler mCallbackHandler; 56 57 /** 58 * @deprecated Use {@code mCallback} instead. 59 */ 60 @Deprecated 61 private ICallback mLocalCallback; 62 63 /** 64 * An interface to receive asynchronous communication from the context hub. 65 * 66 * @deprecated Use the more refined {@link android.hardware.location.ContextHubClientCallback} 67 * instead for notification callbacks. 68 */ 69 @Deprecated 70 public abstract static class Callback { Callback()71 protected Callback() {} 72 73 /** 74 * Callback function called on message receipt from context hub. 75 * 76 * @param hubHandle Handle (system-wide unique identifier) of the hub of the message. 77 * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message. 78 * @param message The context hub message. 79 * 80 * @see ContextHubMessage 81 */ onMessageReceipt( int hubHandle, int nanoAppHandle, @NonNull ContextHubMessage message)82 public abstract void onMessageReceipt( 83 int hubHandle, 84 int nanoAppHandle, 85 @NonNull ContextHubMessage message); 86 } 87 88 /** 89 * @deprecated Use {@link Callback} instead. 90 * @hide 91 */ 92 @Deprecated 93 public interface ICallback { 94 /** 95 * Callback function called on message receipt from context hub. 96 * 97 * @param hubHandle Handle (system-wide unique identifier) of the hub of the message. 98 * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message. 99 * @param message The context hub message. 100 * 101 * @see ContextHubMessage 102 */ onMessageReceipt(int hubHandle, int nanoAppHandle, ContextHubMessage message)103 void onMessageReceipt(int hubHandle, int nanoAppHandle, ContextHubMessage message); 104 } 105 106 /** 107 * Get a handle to all the context hubs in the system 108 * 109 * @return array of context hub handles 110 * 111 * @deprecated Use {@link #getContextHubs()} instead. The use of handles are deprecated in the 112 * new APIs. 113 */ 114 @Deprecated 115 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) getContextHubHandles()116 public int[] getContextHubHandles() { 117 try { 118 return mService.getContextHubHandles(); 119 } catch (RemoteException e) { 120 throw e.rethrowFromSystemServer(); 121 } 122 } 123 124 /** 125 * Get more information about a specific hub. 126 * 127 * @param hubHandle Handle (system-wide unique identifier) of a context hub. 128 * @return ContextHubInfo Information about the requested context hub. 129 * 130 * @see ContextHubInfo 131 * 132 * @deprecated Use {@link #getContextHubs()} instead. The use of handles are deprecated in the 133 * new APIs. 134 */ 135 @Deprecated 136 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) getContextHubInfo(int hubHandle)137 public ContextHubInfo getContextHubInfo(int hubHandle) { 138 try { 139 return mService.getContextHubInfo(hubHandle); 140 } catch (RemoteException e) { 141 throw e.rethrowFromSystemServer(); 142 } 143 } 144 145 /** 146 * Load a nano app on a specified context hub. 147 * 148 * Note that loading is asynchronous. When we return from this method, 149 * the nano app (probably) hasn't loaded yet. Assuming a return of 0 150 * from this method, then the final success/failure for the load, along 151 * with the "handle" for the nanoapp, is all delivered in a byte 152 * string via a call to Callback.onMessageReceipt. 153 * 154 * TODO(b/30784270): Provide a better success/failure and "handle" delivery. 155 * 156 * @param hubHandle handle of context hub to load the app on. 157 * @param app the nanoApp to load on the hub 158 * 159 * @return 0 if the command for loading was sent to the context hub; 160 * -1 otherwise 161 * 162 * @see NanoApp 163 * 164 * @deprecated Use {@link #loadNanoApp(ContextHubInfo, NanoAppBinary)} instead. 165 */ 166 @Deprecated 167 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) loadNanoApp(int hubHandle, @NonNull NanoApp app)168 public int loadNanoApp(int hubHandle, @NonNull NanoApp app) { 169 try { 170 return mService.loadNanoApp(hubHandle, app); 171 } catch (RemoteException e) { 172 throw e.rethrowFromSystemServer(); 173 } 174 } 175 176 /** 177 * Unload a specified nanoApp 178 * 179 * Note that unloading is asynchronous. When we return from this method, 180 * the nano app (probably) hasn't unloaded yet. Assuming a return of 0 181 * from this method, then the final success/failure for the unload is 182 * delivered in a byte string via a call to Callback.onMessageReceipt. 183 * 184 * TODO(b/30784270): Provide a better success/failure delivery. 185 * 186 * @param nanoAppHandle handle of the nanoApp to unload 187 * 188 * @return 0 if the command for unloading was sent to the context hub; 189 * -1 otherwise 190 * 191 * @deprecated Use {@link #unloadNanoApp(ContextHubInfo, long)} instead. 192 */ 193 @Deprecated 194 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) unloadNanoApp(int nanoAppHandle)195 public int unloadNanoApp(int nanoAppHandle) { 196 try { 197 return mService.unloadNanoApp(nanoAppHandle); 198 } catch (RemoteException e) { 199 throw e.rethrowFromSystemServer(); 200 } 201 } 202 203 /** 204 * get information about the nano app instance 205 * 206 * NOTE: The returned NanoAppInstanceInfo does _not_ contain correct 207 * information for several fields, specifically: 208 * - getName() 209 * - getPublisher() 210 * - getNeededExecMemBytes() 211 * - getNeededReadMemBytes() 212 * - getNeededWriteMemBytes() 213 * 214 * For example, say you call loadNanoApp() with a NanoApp that has 215 * getName() returning "My Name". Later, if you call getNanoAppInstanceInfo 216 * for that nanoapp, the returned NanoAppInstanceInfo's getName() 217 * method will claim "Preloaded app, unknown", even though you would 218 * have expected "My Name". For now, as the user, you'll need to 219 * separately track the above fields if they are of interest to you. 220 * 221 * TODO(b/30943489): Have the returned NanoAppInstanceInfo contain the 222 * correct information. 223 * 224 * @param nanoAppHandle handle of the nanoapp instance 225 * @return NanoAppInstanceInfo the NanoAppInstanceInfo of the nanoapp, or null if the nanoapp 226 * does not exist 227 * 228 * @see NanoAppInstanceInfo 229 * 230 * @deprecated Use {@link #queryNanoApps(ContextHubInfo)} instead to explicitly query the hub 231 * for loaded nanoapps. 232 */ 233 @Deprecated 234 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) getNanoAppInstanceInfo(int nanoAppHandle)235 @Nullable public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) { 236 try { 237 return mService.getNanoAppInstanceInfo(nanoAppHandle); 238 } catch (RemoteException e) { 239 throw e.rethrowFromSystemServer(); 240 } 241 } 242 243 /** 244 * Find a specified nano app on the system 245 * 246 * @param hubHandle handle of hub to search for nano app 247 * @param filter filter specifying the search criteria for app 248 * 249 * @see NanoAppFilter 250 * 251 * @return int[] Array of handles to any found nano apps 252 * 253 * @deprecated Use {@link #queryNanoApps(ContextHubInfo)} instead to explicitly query the hub 254 * for loaded nanoapps. 255 */ 256 @Deprecated 257 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) findNanoAppOnHub(int hubHandle, @NonNull NanoAppFilter filter)258 @NonNull public int[] findNanoAppOnHub(int hubHandle, @NonNull NanoAppFilter filter) { 259 try { 260 return mService.findNanoAppOnHub(hubHandle, filter); 261 } catch (RemoteException e) { 262 throw e.rethrowFromSystemServer(); 263 } 264 } 265 266 /** 267 * Send a message to a specific nano app instance on a context hub. 268 * 269 * Note that the return value of this method only speaks of success 270 * up to the point of sending this to the Context Hub. It is not 271 * an assurance that the Context Hub successfully sent this message 272 * on to the nanoapp. If assurance is desired, a protocol should be 273 * established between your code and the nanoapp, with the nanoapp 274 * sending a confirmation message (which will be reported via 275 * Callback.onMessageReceipt). 276 * 277 * @param hubHandle handle of the hub to send the message to 278 * @param nanoAppHandle handle of the nano app to send to 279 * @param message Message to be sent 280 * 281 * @see ContextHubMessage 282 * 283 * @return int 0 on success, -1 otherwise 284 * 285 * @deprecated Use {@link android.hardware.location.ContextHubClient#sendMessageToNanoApp( 286 * NanoAppMessage)} instead, after creating a 287 * {@link android.hardware.location.ContextHubClient} with 288 * {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)} 289 * or {@link #createClient(ContextHubInfo, ContextHubClientCallback)}. 290 */ 291 @Deprecated 292 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) sendMessage(int hubHandle, int nanoAppHandle, @NonNull ContextHubMessage message)293 public int sendMessage(int hubHandle, int nanoAppHandle, @NonNull ContextHubMessage message) { 294 try { 295 return mService.sendMessage(hubHandle, nanoAppHandle, message); 296 } catch (RemoteException e) { 297 throw e.rethrowFromSystemServer(); 298 } 299 } 300 301 /** 302 * Returns the list of ContextHubInfo objects describing the available Context Hubs. 303 * 304 * @return the list of ContextHubInfo objects 305 * 306 * @see ContextHubInfo 307 */ 308 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) getContextHubs()309 @NonNull public List<ContextHubInfo> getContextHubs() { 310 try { 311 return mService.getContextHubs(); 312 } catch (RemoteException e) { 313 throw e.rethrowFromSystemServer(); 314 } 315 } 316 317 /** 318 * Helper function to generate a stub for a non-query transaction callback. 319 * 320 * @param transaction the transaction to unblock when complete 321 * 322 * @return the callback 323 * 324 * @hide 325 */ createTransactionCallback( ContextHubTransaction<Void> transaction)326 private IContextHubTransactionCallback createTransactionCallback( 327 ContextHubTransaction<Void> transaction) { 328 return new IContextHubTransactionCallback.Stub() { 329 @Override 330 public void onQueryResponse(int result, List<NanoAppState> nanoappList) { 331 Log.e(TAG, "Received a query callback on a non-query request"); 332 transaction.setResponse(new ContextHubTransaction.Response<Void>( 333 ContextHubTransaction.RESULT_FAILED_SERVICE_INTERNAL_FAILURE, null)); 334 } 335 336 @Override 337 public void onTransactionComplete(int result) { 338 transaction.setResponse(new ContextHubTransaction.Response<Void>(result, null)); 339 } 340 }; 341 } 342 343 /** 344 * Helper function to generate a stub for a query transaction callback. 345 * 346 * @param transaction the transaction to unblock when complete 347 * 348 * @return the callback 349 * 350 * @hide 351 */ 352 private IContextHubTransactionCallback createQueryCallback( 353 ContextHubTransaction<List<NanoAppState>> transaction) { 354 return new IContextHubTransactionCallback.Stub() { 355 @Override 356 public void onQueryResponse(int result, List<NanoAppState> nanoappList) { 357 transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>( 358 result, nanoappList)); 359 } 360 361 @Override 362 public void onTransactionComplete(int result) { 363 Log.e(TAG, "Received a non-query callback on a query request"); 364 transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>( 365 ContextHubTransaction.RESULT_FAILED_SERVICE_INTERNAL_FAILURE, null)); 366 } 367 }; 368 } 369 370 /** 371 * Loads a nanoapp at the specified Context Hub. 372 * 373 * After the nanoapp binary is successfully loaded at the specified hub, the nanoapp will be in 374 * the enabled state. 375 * 376 * @param hubInfo the hub to load the nanoapp on 377 * @param appBinary The app binary to load 378 * 379 * @return the ContextHubTransaction of the request 380 * 381 * @throws NullPointerException if hubInfo or NanoAppBinary is null 382 * 383 * @see NanoAppBinary 384 */ 385 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) 386 @NonNull public ContextHubTransaction<Void> loadNanoApp( 387 @NonNull ContextHubInfo hubInfo, @NonNull NanoAppBinary appBinary) { 388 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null"); 389 Preconditions.checkNotNull(appBinary, "NanoAppBinary cannot be null"); 390 391 ContextHubTransaction<Void> transaction = 392 new ContextHubTransaction<>(ContextHubTransaction.TYPE_LOAD_NANOAPP); 393 IContextHubTransactionCallback callback = createTransactionCallback(transaction); 394 395 try { 396 mService.loadNanoAppOnHub(hubInfo.getId(), callback, appBinary); 397 } catch (RemoteException e) { 398 throw e.rethrowFromSystemServer(); 399 } 400 401 return transaction; 402 } 403 404 /** 405 * Unloads a nanoapp at the specified Context Hub. 406 * 407 * @param hubInfo the hub to unload the nanoapp from 408 * @param nanoAppId the app to unload 409 * 410 * @return the ContextHubTransaction of the request 411 * 412 * @throws NullPointerException if hubInfo is null 413 */ 414 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) 415 @NonNull public ContextHubTransaction<Void> unloadNanoApp( 416 @NonNull ContextHubInfo hubInfo, long nanoAppId) { 417 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null"); 418 419 ContextHubTransaction<Void> transaction = 420 new ContextHubTransaction<>(ContextHubTransaction.TYPE_UNLOAD_NANOAPP); 421 IContextHubTransactionCallback callback = createTransactionCallback(transaction); 422 423 try { 424 mService.unloadNanoAppFromHub(hubInfo.getId(), callback, nanoAppId); 425 } catch (RemoteException e) { 426 throw e.rethrowFromSystemServer(); 427 } 428 429 return transaction; 430 } 431 432 /** 433 * Enables a nanoapp at the specified Context Hub. 434 * 435 * @param hubInfo the hub to enable the nanoapp on 436 * @param nanoAppId the app to enable 437 * 438 * @return the ContextHubTransaction of the request 439 * 440 * @throws NullPointerException if hubInfo is null 441 */ 442 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) 443 @NonNull public ContextHubTransaction<Void> enableNanoApp( 444 @NonNull ContextHubInfo hubInfo, long nanoAppId) { 445 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null"); 446 447 ContextHubTransaction<Void> transaction = 448 new ContextHubTransaction<>(ContextHubTransaction.TYPE_ENABLE_NANOAPP); 449 IContextHubTransactionCallback callback = createTransactionCallback(transaction); 450 451 try { 452 mService.enableNanoApp(hubInfo.getId(), callback, nanoAppId); 453 } catch (RemoteException e) { 454 throw e.rethrowFromSystemServer(); 455 } 456 457 return transaction; 458 } 459 460 /** 461 * Disables a nanoapp at the specified Context Hub. 462 * 463 * @param hubInfo the hub to disable the nanoapp on 464 * @param nanoAppId the app to disable 465 * 466 * @return the ContextHubTransaction of the request 467 * 468 * @throws NullPointerException if hubInfo is null 469 */ 470 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) 471 @NonNull public ContextHubTransaction<Void> disableNanoApp( 472 @NonNull ContextHubInfo hubInfo, long nanoAppId) { 473 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null"); 474 475 ContextHubTransaction<Void> transaction = 476 new ContextHubTransaction<>(ContextHubTransaction.TYPE_DISABLE_NANOAPP); 477 IContextHubTransactionCallback callback = createTransactionCallback(transaction); 478 479 try { 480 mService.disableNanoApp(hubInfo.getId(), callback, nanoAppId); 481 } catch (RemoteException e) { 482 throw e.rethrowFromSystemServer(); 483 } 484 485 return transaction; 486 } 487 488 /** 489 * Requests a query for nanoapps loaded at the specified Context Hub. 490 * 491 * @param hubInfo the hub to query a list of nanoapps from 492 * 493 * @return the ContextHubTransaction of the request 494 * 495 * @throws NullPointerException if hubInfo is null 496 */ 497 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) 498 @NonNull public ContextHubTransaction<List<NanoAppState>> queryNanoApps( 499 @NonNull ContextHubInfo hubInfo) { 500 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null"); 501 502 ContextHubTransaction<List<NanoAppState>> transaction = 503 new ContextHubTransaction<>(ContextHubTransaction.TYPE_QUERY_NANOAPPS); 504 IContextHubTransactionCallback callback = createQueryCallback(transaction); 505 506 try { 507 mService.queryNanoApps(hubInfo.getId(), callback); 508 } catch (RemoteException e) { 509 throw e.rethrowFromSystemServer(); 510 } 511 512 return transaction; 513 } 514 515 /** 516 * Set a callback to receive messages from the context hub 517 * 518 * @param callback Callback object 519 * 520 * @see Callback 521 * 522 * @return int 0 on success, -1 otherwise 523 * 524 * @deprecated Use {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)} 525 * or {@link #createClient(ContextHubInfo, ContextHubClientCallback)} instead to 526 * register a {@link android.hardware.location.ContextHubClientCallback}. 527 */ 528 @Deprecated 529 @SuppressLint("Doclava125") 530 public int registerCallback(@NonNull Callback callback) { 531 return registerCallback(callback, null); 532 } 533 534 /** 535 * @deprecated Use {@link #registerCallback(Callback)} instead. 536 * @hide 537 */ 538 @Deprecated 539 public int registerCallback(ICallback callback) { 540 if (mLocalCallback != null) { 541 Log.w(TAG, "Max number of local callbacks reached!"); 542 return -1; 543 } 544 mLocalCallback = callback; 545 return 0; 546 } 547 548 /** 549 * Set a callback to receive messages from the context hub 550 * 551 * @param callback Callback object 552 * @param handler Handler object 553 * 554 * @see Callback 555 * 556 * @return int 0 on success, -1 otherwise 557 * 558 * @deprecated Use {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)} 559 * or {@link #createClient(ContextHubInfo, ContextHubClientCallback)} instead to 560 * register a {@link android.hardware.location.ContextHubClientCallback}. 561 */ 562 @Deprecated 563 @SuppressLint("Doclava125") 564 public int registerCallback(Callback callback, Handler handler) { 565 synchronized(this) { 566 if (mCallback != null) { 567 Log.w(TAG, "Max number of callbacks reached!"); 568 return -1; 569 } 570 mCallback = callback; 571 mCallbackHandler = handler; 572 } 573 return 0; 574 } 575 576 /** 577 * Creates an interface to the ContextHubClient to send down to the service. 578 * 579 * @param client the ContextHubClient object associated with this callback 580 * @param callback the callback to invoke at the client process 581 * @param executor the executor to invoke callbacks for this client 582 * 583 * @return the callback interface 584 */ 585 private IContextHubClientCallback createClientCallback( 586 ContextHubClient client, ContextHubClientCallback callback, Executor executor) { 587 return new IContextHubClientCallback.Stub() { 588 @Override 589 public void onMessageFromNanoApp(NanoAppMessage message) { 590 executor.execute(() -> callback.onMessageFromNanoApp(client, message)); 591 } 592 593 @Override 594 public void onHubReset() { 595 executor.execute(() -> callback.onHubReset(client)); 596 } 597 598 @Override 599 public void onNanoAppAborted(long nanoAppId, int abortCode) { 600 executor.execute(() -> callback.onNanoAppAborted(client, nanoAppId, abortCode)); 601 } 602 603 @Override 604 public void onNanoAppLoaded(long nanoAppId) { 605 executor.execute(() -> callback.onNanoAppLoaded(client, nanoAppId)); 606 } 607 608 @Override 609 public void onNanoAppUnloaded(long nanoAppId) { 610 executor.execute(() -> callback.onNanoAppUnloaded(client, nanoAppId)); 611 } 612 613 @Override 614 public void onNanoAppEnabled(long nanoAppId) { 615 executor.execute(() -> callback.onNanoAppEnabled(client, nanoAppId)); 616 } 617 618 @Override 619 public void onNanoAppDisabled(long nanoAppId) { 620 executor.execute(() -> callback.onNanoAppDisabled(client, nanoAppId)); 621 } 622 }; 623 } 624 625 /** 626 * Creates and registers a client and its callback with the Context Hub Service. 627 * 628 * A client is registered with the Context Hub Service for a specified Context Hub. When the 629 * registration succeeds, the client can send messages to nanoapps through the returned 630 * {@link ContextHubClient} object, and receive notifications through the provided callback. 631 * 632 * @param hubInfo the hub to attach this client to 633 * @param callback the notification callback to register 634 * @param executor the executor to invoke the callback 635 * @return the registered client object 636 * 637 * @throws IllegalArgumentException if hubInfo does not represent a valid hub 638 * @throws IllegalStateException if there were too many registered clients at the service 639 * @throws NullPointerException if callback, hubInfo, or executor is null 640 * 641 * @see ContextHubClientCallback 642 */ 643 @NonNull public ContextHubClient createClient( 644 @NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback, 645 @NonNull @CallbackExecutor Executor executor) { 646 Preconditions.checkNotNull(callback, "Callback cannot be null"); 647 Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null"); 648 Preconditions.checkNotNull(executor, "Executor cannot be null"); 649 650 ContextHubClient client = new ContextHubClient(hubInfo); 651 IContextHubClientCallback clientInterface = createClientCallback( 652 client, callback, executor); 653 654 IContextHubClient clientProxy; 655 try { 656 clientProxy = mService.createClient(clientInterface, hubInfo.getId()); 657 } catch (RemoteException e) { 658 throw e.rethrowFromSystemServer(); 659 } 660 661 client.setClientProxy(clientProxy); 662 return client; 663 } 664 665 /** 666 * Equivalent to {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)} 667 * with the executor using the main thread's Looper. 668 * 669 * @param hubInfo the hub to attach this client to 670 * @param callback the notification callback to register 671 * @return the registered client object 672 * 673 * @throws IllegalArgumentException if hubInfo does not represent a valid hub 674 * @throws IllegalStateException if there were too many registered clients at the service 675 * @throws NullPointerException if callback or hubInfo is null 676 * 677 * @see ContextHubClientCallback 678 */ 679 @NonNull public ContextHubClient createClient( 680 @NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback) { 681 return createClient(hubInfo, callback, new HandlerExecutor(Handler.getMain())); 682 } 683 684 /** 685 * Unregister a callback for receive messages from the context hub. 686 * 687 * @see Callback 688 * 689 * @param callback method to deregister 690 * 691 * @return int 0 on success, -1 otherwise 692 * 693 * @deprecated Use {@link android.hardware.location.ContextHubClient#close()} to unregister 694 * a {@link android.hardware.location.ContextHubClientCallback}. 695 */ 696 @SuppressLint("Doclava125") 697 @Deprecated 698 public int unregisterCallback(@NonNull Callback callback) { 699 synchronized(this) { 700 if (callback != mCallback) { 701 Log.w(TAG, "Cannot recognize callback!"); 702 return -1; 703 } 704 705 mCallback = null; 706 mCallbackHandler = null; 707 } 708 return 0; 709 } 710 711 /** 712 * @deprecated Use {@link #unregisterCallback(Callback)} instead. 713 * @hide 714 */ 715 @Deprecated 716 public synchronized int unregisterCallback(ICallback callback) { 717 if (callback != mLocalCallback) { 718 Log.w(TAG, "Cannot recognize local callback!"); 719 return -1; 720 } 721 mLocalCallback = null; 722 return 0; 723 } 724 725 private final IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() { 726 @Override 727 public void onMessageReceipt(final int hubId, final int nanoAppId, 728 final ContextHubMessage message) { 729 if (mCallback != null) { 730 synchronized(this) { 731 final Callback callback = mCallback; 732 Handler handler = mCallbackHandler == null ? 733 new Handler(mMainLooper) : mCallbackHandler; 734 handler.post(new Runnable() { 735 @Override 736 public void run() { 737 callback.onMessageReceipt(hubId, nanoAppId, message); 738 } 739 }); 740 } 741 } else if (mLocalCallback != null) { 742 // we always ensure that mCallback takes precedence, because mLocalCallback is only 743 // for internal compatibility 744 synchronized (this) { 745 mLocalCallback.onMessageReceipt(hubId, nanoAppId, message); 746 } 747 } 748 } 749 }; 750 751 /** @throws ServiceNotFoundException 752 * @hide */ 753 public ContextHubManager(Context context, Looper mainLooper) throws ServiceNotFoundException { 754 mMainLooper = mainLooper; 755 mService = IContextHubService.Stub.asInterface( 756 ServiceManager.getServiceOrThrow(Context.CONTEXTHUB_SERVICE)); 757 try { 758 mService.registerCallback(mClientCallback); 759 } catch (RemoteException e) { 760 throw e.rethrowFromSystemServer(); 761 } 762 } 763 } 764