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      * &#60;meta-data android:name="android.car.targetCarVersion" android:value="33"/&#62;
178      * </code>
179      *
180      * <p>Or:
181      *
182      * <code>
183      * &#60;meta-data android:name="android.car.targetCarVersion" android:value="33:0"/&#62;
184      * </code>
185      *
186      * <p>And for {@link android.os.Build.VERSION_CODES#TIRAMISU Android 13} first update:
187      *
188      * <code>
189      * &#60;meta-data android:name="android.car.targetCarVersion" android:value="33:1"/&#62;
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