1 /* 2 * Copyright (C) 2015 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 android.car.content.pm; 18 19 import static android.car.Car.PERMISSION_CONTROL_APP_BLOCKING; 20 import static android.car.Car.PERMISSION_MANAGE_DISPLAY_COMPATIBILITY; 21 import static android.car.CarLibLog.TAG_CAR; 22 23 import android.Manifest; 24 import android.annotation.CallbackExecutor; 25 import android.annotation.FlaggedApi; 26 import android.annotation.IntDef; 27 import android.annotation.NonNull; 28 import android.annotation.RequiresPermission; 29 import android.annotation.SystemApi; 30 import android.annotation.TestApi; 31 import android.annotation.UserIdInt; 32 import android.app.PendingIntent; 33 import android.car.Car; 34 import android.car.CarManagerBase; 35 import android.car.CarVersion; 36 import android.car.feature.Flags; 37 import android.content.ComponentName; 38 import android.content.pm.PackageManager.NameNotFoundException; 39 import android.os.Binder; 40 import android.os.IBinder; 41 import android.os.Looper; 42 import android.os.Process; 43 import android.os.RemoteException; 44 import android.os.ServiceSpecificException; 45 import android.util.ArrayMap; 46 import android.util.Slog; 47 48 import com.android.car.internal.ICarBase; 49 import com.android.internal.annotations.GuardedBy; 50 import com.android.internal.annotations.VisibleForTesting; 51 52 import java.lang.annotation.Retention; 53 import java.lang.annotation.RetentionPolicy; 54 import java.util.Collections; 55 import java.util.List; 56 import java.util.Map; 57 import java.util.concurrent.Executor; 58 59 /** 60 * Provides car specific API related with package management. 61 */ 62 public final class CarPackageManager extends CarManagerBase { 63 64 private static final String TAG = CarPackageManager.class.getSimpleName(); 65 66 /** 67 * Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this 68 * flag is set, the call will be blocked until policy is set to system. This can take time 69 * and the flag cannot be used in main thread. 70 * 71 * @hide 72 * @deprecated see the {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)} 73 * documentation for alternative mechanism. 74 */ 75 @SystemApi 76 @Deprecated 77 public static final int FLAG_SET_POLICY_WAIT_FOR_CHANGE = 0x1; 78 /** 79 * Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this 80 * flag is set, passed policy is added to existing policy set from the current package. 81 * If none of {@link #FLAG_SET_POLICY_ADD} or {@link #FLAG_SET_POLICY_REMOVE} is set, existing 82 * policy is replaced. Note that policy per each package is always replaced and will not be 83 * added. 84 * 85 * @hide 86 * @deprecated see the {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)} 87 * documentation for alternative mechanism. 88 */ 89 @SystemApi 90 @Deprecated 91 public static final int FLAG_SET_POLICY_ADD = 0x2; 92 /** 93 * Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this 94 * flag is set, passed policy is removed from existing policy set from the current package. 95 * If none of {@link #FLAG_SET_POLICY_ADD} or {@link #FLAG_SET_POLICY_REMOVE} is set, existing 96 * policy is replaced. 97 * 98 * @hide 99 * @deprecated see the {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)} 100 * documentation for alternative mechanism. 101 */ 102 @SystemApi 103 @Deprecated 104 public static final int FLAG_SET_POLICY_REMOVE = 0x4; 105 106 /** 107 * Name of blocked activity. 108 * 109 * @hide 110 */ 111 public static final String BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME = "blocked_activity"; 112 /** 113 * int task id of the blocked task. 114 * 115 * @hide 116 */ 117 public static final String BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID = "blocked_task_id"; 118 /** 119 * Name of root activity of blocked task. 120 * 121 * @hide 122 */ 123 public static final String BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME = "root_activity_name"; 124 /** 125 * Boolean indicating whether the root activity is distraction-optimized (DO). 126 * Blocking screen should show a button to restart the task if {@code true}. 127 * 128 * @hide 129 */ 130 public static final String BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO = "is_root_activity_do"; 131 132 /** 133 * int display id of the blocked task. 134 * 135 * @hide 136 */ 137 public static final String BLOCKING_INTENT_EXTRA_DISPLAY_ID = "display_id"; 138 139 /** 140 * Represents support of all regions for driving safety. 141 * 142 * @hide 143 */ 144 public static final String DRIVING_SAFETY_REGION_ALL = "android.car.drivingsafetyregion.all"; 145 146 /** 147 * Metadata which Activity can use to specify the driving safety regions it is supporting. 148 * 149 * <p>Definition of driving safety region is car OEM specific for now and only OEM apps 150 * should use this. If there are multiple regions, it should be comma separated. Not specifying 151 * this means supporting all regions. 152 * 153 * <p>Some examples are: 154 * <meta-data android:name="android.car.drivingsafetyregions" 155 * android:value="com.android.drivingsafetyregion.1,com.android.drivingsafetyregion.2"/> 156 * 157 * @hide 158 */ 159 public static final String DRIVING_SAFETY_ACTIVITY_METADATA_REGIONS = 160 "android.car.drivingsafetyregions"; 161 162 /** 163 * Internal error code for throwing {@code NameNotFoundException} from service. 164 * 165 * @hide 166 */ 167 public static final int ERROR_CODE_NO_PACKAGE = -100; 168 169 /** 170 * Manifest metadata used to specify the minimum major and minor Car API version an app is 171 * targeting. 172 * 173 * <p>Format is in the form {@code major:minor} or {@code major}. 174 * 175 * <p>For example, for {@link android.os.Build.VERSION_CODES#TIRAMISU Android 13}, it would be: 176 * <code> 177 * <meta-data android:name="android.car.targetCarVersion" android:value="33"/> 178 * </code> 179 * 180 * <p>Or: 181 * 182 * <code> 183 * <meta-data android:name="android.car.targetCarVersion" android:value="33:0"/> 184 * </code> 185 * 186 * <p>And for {@link android.os.Build.VERSION_CODES#TIRAMISU Android 13} first update: 187 * 188 * <code> 189 * <meta-data android:name="android.car.targetCarVersion" android:value="33:1"/> 190 * </code> 191 * 192 * @deprecated Car version is no longer supported by the CarService. 193 */ 194 @Deprecated 195 public static final String MANIFEST_METADATA_TARGET_CAR_VERSION = 196 "android.car.targetCarVersion"; 197 198 199 /** @hide */ 200 @IntDef(flag = true, 201 value = {FLAG_SET_POLICY_WAIT_FOR_CHANGE, FLAG_SET_POLICY_ADD, FLAG_SET_POLICY_REMOVE}) 202 @Retention(RetentionPolicy.SOURCE) 203 public @interface SetPolicyFlags {} 204 205 private final ICarPackageManager mService; 206 private final Object mLock = new Object(); 207 /** 208 * Map that stores externally created {@link ICarBlockingUiCommandListener} objects keyed by 209 * their corresponding internally provided {@link BlockingUiCommandListener} objects. Since 210 * ArrayMap's initial size is 10, and the blocking ui will have at most 1~2 listeners, 211 * initialize size of the map to be 2. 212 */ 213 @GuardedBy("mLock") 214 private final Map<BlockingUiCommandListener, ICarBlockingUiCommandListener> 215 mICarBlockingUiCommandListener = new ArrayMap<>(2); 216 217 /** @hide */ CarPackageManager(ICarBase car, IBinder service)218 public CarPackageManager(ICarBase car, IBinder service) { 219 this(car, ICarPackageManager.Stub.asInterface(service)); 220 } 221 222 /** @hide */ 223 @VisibleForTesting CarPackageManager(ICarBase car, ICarPackageManager service)224 public CarPackageManager(ICarBase car, ICarPackageManager service) { 225 super(car); 226 mService = service; 227 } 228 229 /** @hide */ 230 @Override onCarDisconnected()231 public void onCarDisconnected() { 232 // nothing to do 233 } 234 235 /** 236 * Set Application blocking policy for system app. {@link #FLAG_SET_POLICY_ADD} or 237 * {@link #FLAG_SET_POLICY_REMOVE} flag allows adding or removing from already set policy. When 238 * none of these flags are set, it will completely replace existing policy for each package 239 * specified. 240 * When {@link #FLAG_SET_POLICY_WAIT_FOR_CHANGE} flag is set, this call will be blocked 241 * until the policy is set to system and become effective. Otherwise, the call will start 242 * changing the policy but it will be completed asynchronously and the call will return 243 * without waiting for system level policy change. 244 * 245 * @param packageName Package name of the client. If wrong package name is passed, exception 246 * will be thrown. This name is used to update the policy. 247 * @param policy 248 * @param flags 249 * @throws SecurityException if caller has no permission. 250 * @throws IllegalArgumentException For wrong or invalid arguments. 251 * @throws IllegalStateException If {@link #FLAG_SET_POLICY_WAIT_FOR_CHANGE} is set while 252 * called from main thread. 253 * @hide 254 * @deprecated It is no longer possible to change the app blocking policy at runtime. The first 255 * choice to mark an activity as safe for driving should always be to to include 256 * {@code <meta-data android:name="distractionOptimized" android:value="true"/>} in its 257 * manifest. All other activities will be blocked whenever driving restrictions are required. If 258 * an activity's manifest cannot be changed, then you can explicitly make an exception to its 259 * behavior using the build-time XML configuration. Allow or deny specific activities by 260 * changing the appropriate value ({@code R.string.activityAllowlist}, 261 * {@code R.string.activityDenylist}) within the 262 * {@code packages/services/Car/service/res/values/config.xml} overlay. 263 */ 264 @SystemApi 265 @Deprecated setAppBlockingPolicy( String packageName, CarAppBlockingPolicy policy, @SetPolicyFlags int flags)266 public void setAppBlockingPolicy( 267 String packageName, CarAppBlockingPolicy policy, @SetPolicyFlags int flags) { 268 if ((flags & FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0 269 && Looper.getMainLooper().isCurrentThread()) { 270 throw new IllegalStateException( 271 "FLAG_SET_POLICY_WAIT_FOR_CHANGE cannot be used in main thread"); 272 } 273 try { 274 mService.setAppBlockingPolicy(packageName, policy, flags); 275 } catch (RemoteException e) { 276 handleRemoteExceptionFromCarService(e); 277 } 278 } 279 280 /** 281 * Restarts the requested task. If task with {@code taskId} does not exist, do nothing. 282 * 283 * <p>This requires {@code android.permission.REAL_GET_TASKS} permission. 284 * 285 * @hide 286 */ restartTask(int taskId)287 public void restartTask(int taskId) { 288 try { 289 mService.restartTask(taskId); 290 } catch (RemoteException e) { 291 handleRemoteExceptionFromCarService(e); 292 } 293 } 294 295 /** 296 * Check if finishing Activity will lead into safe Activity (=allowed Activity) to be shown. 297 * This can be used by unsafe activity blocking Activity to check if finishing itself can 298 * lead into being launched again due to unsafe activity shown. Note that checking this does not 299 * guarantee that blocking will not be done as driving state can change after this call is made. 300 * 301 * @param activityName 302 * @return true if there is a safe Activity (or car is stopped) in the back of task stack 303 * so that finishing the Activity will not trigger another Activity blocking. If 304 * the given Activity is not in foreground, then it will return true as well as 305 * finishing the Activity will not make any difference. 306 * 307 * @hide 308 */ 309 @SystemApi isActivityBackedBySafeActivity(ComponentName activityName)310 public boolean isActivityBackedBySafeActivity(ComponentName activityName) { 311 try { 312 return mService.isActivityBackedBySafeActivity(activityName); 313 } catch (RemoteException e) { 314 return handleRemoteExceptionFromCarService(e, false); 315 } 316 } 317 318 /** 319 * Enable/Disable Activity Blocking. This is to provide an option for toggling app blocking 320 * behavior for development purposes. 321 * @hide 322 */ 323 @TestApi setEnableActivityBlocking(boolean enable)324 public void setEnableActivityBlocking(boolean enable) { 325 try { 326 mService.setEnableActivityBlocking(enable); 327 } catch (RemoteException e) { 328 handleRemoteExceptionFromCarService(e); 329 } 330 } 331 332 /** 333 * Returns whether an activity is distraction optimized, i.e, allowed in a restricted 334 * driving state. 335 * 336 * @param packageName the activity's {@link android.content.pm.ActivityInfo#packageName}. 337 * @param className the activity's {@link android.content.pm.ActivityInfo#name}. 338 * @return true if the activity is distraction optimized, false if it isn't or if the value 339 * could not be determined. 340 */ isActivityDistractionOptimized(String packageName, String className)341 public boolean isActivityDistractionOptimized(String packageName, String className) { 342 try { 343 return mService.isActivityDistractionOptimized(packageName, className); 344 } catch (RemoteException e) { 345 return handleRemoteExceptionFromCarService(e, false); 346 } 347 } 348 349 /** 350 * Returns whether the given {@link PendingIntent} represents an activity that is distraction 351 * optimized, i.e, allowed in a restricted driving state. 352 * 353 * @param pendingIntent the {@link PendingIntent} to check. 354 * @return true if the pending intent represents an activity that is distraction optimized, 355 * false if it isn't or if the value could not be determined. 356 */ isPendingIntentDistractionOptimized(@onNull PendingIntent pendingIntent)357 public boolean isPendingIntentDistractionOptimized(@NonNull PendingIntent pendingIntent) { 358 try { 359 return mService.isPendingIntentDistractionOptimized(pendingIntent); 360 } catch (RemoteException e) { 361 return handleRemoteExceptionFromCarService(e, false); 362 } 363 } 364 365 /** 366 * Check if given service is distraction optimized, i.e, allowed in a restricted 367 * driving state. 368 * 369 * @param packageName 370 * @param className 371 * @return 372 */ isServiceDistractionOptimized(String packageName, String className)373 public boolean isServiceDistractionOptimized(String packageName, String className) { 374 try { 375 return mService.isServiceDistractionOptimized(packageName, className); 376 } catch (RemoteException e) { 377 return handleRemoteExceptionFromCarService(e, false); 378 } 379 } 380 381 /** 382 * Returns the current driving safety region of the system. It will return OEM specific regions 383 * or {@link #DRIVING_SAFETY_REGION_ALL} when all regions are supported. 384 * 385 * <p> System's driving safety region is static and does not change until system restarts. 386 * 387 * @hide 388 */ 389 @RequiresPermission(anyOf = {PERMISSION_CONTROL_APP_BLOCKING, 390 Car.PERMISSION_CAR_DRIVING_STATE}) 391 @NonNull getCurrentDrivingSafetyRegion()392 public String getCurrentDrivingSafetyRegion() { 393 try { 394 return mService.getCurrentDrivingSafetyRegion(); 395 } catch (RemoteException e) { 396 return handleRemoteExceptionFromCarService(e, DRIVING_SAFETY_REGION_ALL); 397 } 398 } 399 400 /** 401 * Enables or disables bypassing of unsafe {@code Activity} blocking for a specific 402 * {@code Activity} temporarily. 403 * 404 * <p> Enabling bypassing only lasts until the user stops using the car or until a user 405 * switching happens. Apps like launcher may ask user's consent to bypass. Note that bypassing 406 * is done for the package for all android users including the current user and user 0. 407 * <p> If bypassing is disabled and if the unsafe app is in foreground with driving state, the 408 * app will be immediately blocked. 409 * 410 * @param packageName Target package name. 411 * @param activityClassName Target Activity name (in full class name). 412 * @param bypass Bypass {@code Activity} blocking when true. Do not bypass anymore when false. 413 * @param userId User Id where the package is installed. Even if the bypassing is enabled for 414 * all android users, the package should be available for the specified user id. 415 * 416 * @throws NameNotFoundException If the given package / Activity class does not exist for the 417 * user. 418 * 419 * @hide 420 */ 421 @RequiresPermission(allOf = {PERMISSION_CONTROL_APP_BLOCKING, 422 android.Manifest.permission.QUERY_ALL_PACKAGES}) controlTemporaryActivityBlockingBypassingAsUser(String packageName, String activityClassName, boolean bypass, @UserIdInt int userId)423 public void controlTemporaryActivityBlockingBypassingAsUser(String packageName, 424 String activityClassName, boolean bypass, @UserIdInt int userId) 425 throws NameNotFoundException { 426 try { 427 mService.controlOneTimeActivityBlockingBypassingAsUser(packageName, activityClassName, 428 bypass, userId); 429 } catch (ServiceSpecificException e) { 430 handleServiceSpecificFromCarService(e, packageName, activityClassName, userId); 431 } catch (RemoteException e) { 432 handleRemoteExceptionFromCarService(e); 433 } 434 } 435 436 /** 437 * Returns all supported driving safety regions for the given Activity. If the Activity supports 438 * all regions, it will only include {@link #DRIVING_SAFETY_REGION_ALL}. 439 * 440 * <p> The permission specification requires {@code PERMISSION_CONTROL_APP_BLOCKING} and 441 * {@code QUERY_ALL_PACKAGES} but this API will also work if the client has 442 * {@link Car#PERMISSION_CAR_DRIVING_STATE} and {@code QUERY_ALL_PACKAGES} permissions. 443 * 444 * @param packageName Target package name. 445 * @param activityClassName Target Activity name (in full class name). 446 * @param userId Android user Id to check the package. 447 * 448 * @return Empty list if the Activity does not support driving safety (=no 449 * {@code distractionOptimized} metadata). Otherwise returns full list of all supported 450 * regions. 451 * 452 * @throws NameNotFoundException If the given package / Activity class does not exist for the 453 * user. 454 * 455 * @hide 456 */ 457 @RequiresPermission(allOf = {PERMISSION_CONTROL_APP_BLOCKING, 458 android.Manifest.permission.QUERY_ALL_PACKAGES}) 459 @NonNull getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, String activityClassName, @UserIdInt int userId)460 public List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, 461 String activityClassName, @UserIdInt int userId) throws NameNotFoundException { 462 try { 463 return mService.getSupportedDrivingSafetyRegionsForActivityAsUser(packageName, 464 activityClassName, userId); 465 } catch (ServiceSpecificException e) { 466 handleServiceSpecificFromCarService(e, packageName, activityClassName, userId); 467 } catch (RemoteException e) { 468 return handleRemoteExceptionFromCarService(e, Collections.EMPTY_LIST); 469 } 470 return Collections.EMPTY_LIST; // cannot reach here but the compiler complains. 471 } 472 473 /** 474 * Gets the Car API version targeted by the given package (as defined by 475 * {@link #MANIFEST_METADATA_TARGET_CAR_VERSION}. 476 * 477 * <p>If the app manifest doesn't contain the {@link #MANIFEST_METADATA_TARGET_CAR_VERSION} 478 * metadata attribute or if the attribute format is invalid, the returned {@code CarVersion} 479 * will be using the 480 * {@link android.content.pm.ApplicationInfo#targetSdkVersion target platform version} as major 481 * and {@code 0} as minor instead. 482 * 483 * <p><b>Note: </b>to get the target {@link CarVersion} for your own app, use 484 * {@link #getTargetCarVersion()} instead. 485 * @return Car API version targeted by the given package (as described above). 486 * 487 * @throws NameNotFoundException If the given package does not exist for the user. 488 * 489 * @hide 490 * @deprecated CarVersion is no longer supported by the CarService. 491 */ 492 @SystemApi 493 @RequiresPermission(Manifest.permission.QUERY_ALL_PACKAGES) 494 @NonNull 495 @Deprecated getTargetCarVersion(@onNull String packageName)496 public CarVersion getTargetCarVersion(@NonNull String packageName) 497 throws NameNotFoundException { 498 try { 499 return mService.getTargetCarVersion(packageName); 500 } catch (ServiceSpecificException e) { 501 Slog.w(TAG, "Failed to get CarVersion for " + packageName, e); 502 handleServiceSpecificFromCarService(e, packageName); 503 } catch (RemoteException e) { 504 e.rethrowFromSystemServer(); 505 } 506 return null; // cannot reach here but the compiler complains. 507 } 508 509 /** 510 * Gets the Car API version targeted by app (as defined by 511 * {@link #MANIFEST_METADATA_TARGET_CAR_VERSION}. 512 * 513 * <p>If the app manifest doesn't contain the {@link #MANIFEST_METADATA_TARGET_CAR_VERSION} 514 * metadata attribute or if the attribute format is invalid, the returned {@code CarVersion} 515 * will be using the {@link android.content.pm.ApplicationInfo#targetSdkVersion target platform 516 * version} as major and {@code 0} as minor instead. 517 * 518 * @return targeted Car API version (as defined above) 519 * @deprecated CarVersion is no longer supported by the CarService. 520 */ 521 @NonNull 522 @Deprecated getTargetCarVersion()523 public CarVersion getTargetCarVersion() { 524 String pkgName = mCar.getContext().getPackageName(); 525 try { 526 return mService.getSelfTargetCarVersion(pkgName); 527 } catch (RemoteException e) { 528 Slog.w(TAG_CAR, "Car service threw exception calling getTargetCarVersion(" + pkgName 529 + ")", e); 530 e.rethrowFromSystemServer(); 531 return null; 532 } 533 } 534 535 /** 536 * @return true if a package requires launching in automotive display compatibility mode. 537 * false otherwise. 538 * 539 * @hide 540 */ 541 @FlaggedApi(Flags.FLAG_DISPLAY_COMPATIBILITY) 542 @SystemApi 543 @RequiresPermission(allOf = {PERMISSION_MANAGE_DISPLAY_COMPATIBILITY, 544 android.Manifest.permission.QUERY_ALL_PACKAGES}) requiresDisplayCompat(@onNull String packageName)545 public boolean requiresDisplayCompat(@NonNull String packageName) throws NameNotFoundException { 546 if (!Flags.displayCompatibility()) { 547 return false; 548 } 549 try { 550 return mService.requiresDisplayCompat(packageName); 551 } catch (ServiceSpecificException e) { 552 Slog.w(TAG_CAR, "Car service threw exception calling requiresDisplayCompat(" 553 + packageName + ")", e); 554 if (e.errorCode == ERROR_CODE_NO_PACKAGE) { 555 throw new NameNotFoundException("cannot find " + packageName); 556 } 557 throw new RuntimeException(e); 558 } catch (SecurityException e) { 559 Slog.w(TAG_CAR, "Car service threw exception calling requiresDisplayCompat(" 560 + packageName + ")", e); 561 throw e; 562 } catch (RemoteException e) { 563 Slog.w(TAG_CAR, "Car service threw exception calling requiresDisplayCompat(" 564 + packageName + ")", e); 565 e.rethrowFromSystemServer(); 566 } 567 return false; 568 } 569 handleServiceSpecificFromCarService(ServiceSpecificException e, String packageName)570 private void handleServiceSpecificFromCarService(ServiceSpecificException e, 571 String packageName) throws NameNotFoundException { 572 if (e.errorCode == ERROR_CODE_NO_PACKAGE) { 573 throw new NameNotFoundException( 574 "cannot find " + packageName + " for user " + Process.myUserHandle()); 575 } 576 // don't know what this is 577 throw new IllegalStateException(e); 578 } 579 handleServiceSpecificFromCarService(ServiceSpecificException e, String packageName, String activityClassName, @UserIdInt int userId)580 private static void handleServiceSpecificFromCarService(ServiceSpecificException e, 581 String packageName, String activityClassName, @UserIdInt int userId) 582 throws NameNotFoundException { 583 if (e.errorCode == ERROR_CODE_NO_PACKAGE) { 584 throw new NameNotFoundException( 585 "cannot find " + packageName + "/" + activityClassName + " for user id:" 586 + userId); 587 } 588 // don't know what this is 589 throw new IllegalStateException(e); 590 } 591 592 /** 593 * Callback interface to finish the blocking ui. 594 * 595 * @hide 596 */ 597 public interface BlockingUiCommandListener { 598 /** 599 * Called when the blocking ui needs to be finished 600 */ finishBlockingUi()601 void finishBlockingUi(); 602 } 603 604 /** 605 * Registers the {@link BlockingUiCommandListener} for the BlockingUi. 606 * 607 * <p>Note: A listener can only listen for one displayId. 608 * <p>Note: A listener cannot be registered twice. Registering the second time would result in a 609 * no-op. 610 * 611 * @param displayId {@link android.view.Display} for which the blocking ui is registered. 612 * @param callbackExecutor the executor to execute the callback with. 613 * @param listener {@link BlockingUiCommandListener} listener. 614 * @throws IllegalStateException if the listener is already registered. 615 * @hide 616 */ registerBlockingUiCommandListener(int displayId, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull BlockingUiCommandListener listener)617 public void registerBlockingUiCommandListener(int displayId, 618 @NonNull @CallbackExecutor Executor callbackExecutor, 619 @NonNull BlockingUiCommandListener listener) { 620 synchronized (mLock) { 621 if (mICarBlockingUiCommandListener.get(listener) != null) { 622 throw new IllegalStateException("BlockingUiListener already registered"); 623 } 624 CarBlockingUiCommandListenerImpl carBlockingUiListener = 625 new CarBlockingUiCommandListenerImpl(callbackExecutor, listener); 626 try { 627 mService.registerBlockingUiCommandListener(carBlockingUiListener, displayId); 628 mICarBlockingUiCommandListener.put(listener, carBlockingUiListener); 629 } catch (RemoteException e) { 630 handleRemoteExceptionFromCarService(e); 631 } 632 } 633 } 634 635 /** 636 * Unregisters the {@link BlockingUiCommandListener}. 637 * 638 * @hide 639 */ unregisterBlockingUiCommandListener(@onNull BlockingUiCommandListener listener)640 public void unregisterBlockingUiCommandListener(@NonNull BlockingUiCommandListener listener) { 641 synchronized (mLock) { 642 try { 643 if (mICarBlockingUiCommandListener.get(listener) == null) { 644 Slog.e(TAG, "BlockingUiListener already unregistered"); 645 return; 646 } 647 mService.unregisterBlockingUiCommandListener( 648 mICarBlockingUiCommandListener.get(listener)); 649 } catch (RemoteException e) { 650 handleRemoteExceptionFromCarService(e); 651 } 652 mICarBlockingUiCommandListener.remove(listener); 653 } 654 } 655 656 private class CarBlockingUiCommandListenerImpl extends ICarBlockingUiCommandListener.Stub { 657 private final Executor mExecutor; 658 private final BlockingUiCommandListener mListener; 659 CarBlockingUiCommandListenerImpl(Executor callbackExecutor, BlockingUiCommandListener listener)660 CarBlockingUiCommandListenerImpl(Executor callbackExecutor, 661 BlockingUiCommandListener listener) { 662 mExecutor = callbackExecutor; 663 mListener = listener; 664 } 665 finishBlockingUi()666 public void finishBlockingUi() throws RemoteException { 667 long identity = Binder.clearCallingIdentity(); 668 try { 669 synchronized (mLock) { 670 if (mICarBlockingUiCommandListener.get(mListener) == null) { 671 Slog.e(TAG, "BlockingUiListener already unregistered"); 672 return; 673 } 674 mExecutor.execute(mListener::finishBlockingUi); 675 } 676 } finally { 677 Binder.restoreCallingIdentity(identity); 678 } 679 } 680 } 681 } 682