• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.app;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.RequiresPermission;
22 import android.annotation.SystemApi;
23 import android.annotation.TestApi;
24 import android.app.Activity;
25 import android.app.ActivityManager;
26 import android.car.Car;
27 import android.car.CarManagerBase;
28 import android.car.annotation.AddedInOrBefore;
29 import android.car.annotation.ApiRequirements;
30 import android.car.user.CarUserManager;
31 import android.content.ActivityNotFoundException;
32 import android.content.ComponentName;
33 import android.os.Binder;
34 import android.os.IBinder;
35 import android.os.RemoteException;
36 import android.os.ServiceSpecificException;
37 import android.util.Log;
38 
39 import com.android.internal.annotations.VisibleForTesting;
40 
41 import java.lang.annotation.ElementType;
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.RetentionPolicy;
44 import java.lang.annotation.Target;
45 import java.util.Collections;
46 import java.util.List;
47 
48 /**
49  * API to manage {@link android.app.Activity} in Car.
50  *
51  * @hide
52  */
53 @SystemApi
54 @TestApi
55 public final class CarActivityManager extends CarManagerBase {
56     private static final String TAG = CarUserManager.class.getSimpleName();
57 
58     /** Indicates that the operation was successful. */
59     @AddedInOrBefore(majorVersion = 33)
60     public static final int RESULT_SUCCESS = 0;
61     /** Indicates that the operation was failed with the unknown reason. */
62     @AddedInOrBefore(majorVersion = 33)
63     public static final int RESULT_FAILURE = -1;
64     /**
65      * Indicates that the operation was failed because the requester isn't the current user or
66      * the system user
67      */
68     @AddedInOrBefore(majorVersion = 33)
69     public static final int RESULT_INVALID_USER = -2;
70 
71     /** @hide */
72     @Retention(RetentionPolicy.SOURCE)
73     @IntDef(prefix = "RESULT_", value = {
74             RESULT_SUCCESS,
75             RESULT_FAILURE,
76             RESULT_INVALID_USER,
77     })
78     @Target({ElementType.TYPE_USE})
79     public @interface ResultTypeEnum {}
80 
81     /**
82      * Internal error code for throwing {@link ActivityNotFoundException} from service.
83      * @hide
84      */
85     @AddedInOrBefore(majorVersion = 33)
86     public static final int ERROR_CODE_ACTIVITY_NOT_FOUND = -101;
87 
88     private final ICarActivityService mService;
89     private IBinder mTaskMonitorToken;
90 
91     /**
92      * @hide
93      */
CarActivityManager(@onNull Car car, @NonNull IBinder service)94     public CarActivityManager(@NonNull Car car, @NonNull IBinder service) {
95         this(car, ICarActivityService.Stub.asInterface(service));
96     }
97 
98     /**
99      * @hide
100      */
101     @VisibleForTesting
CarActivityManager(@onNull Car car, @NonNull ICarActivityService service)102     public CarActivityManager(@NonNull Car car, @NonNull ICarActivityService service) {
103         super(car);
104 
105         mService = service;
106     }
107 
108     /**
109      * Designates the given {@code activity} to be launched in {@code TaskDisplayArea} of
110      * {@code featureId} in the display of {@code displayId}.
111      * <p>Note: this will not affect the existing {@link Activity}.
112      * Note: You can map assign {@code Activity} to one {@code TaskDisplayArea} only. If
113      * you assign it to the multiple {@code TaskDisplayArea}s, then the last one wins.
114      * Note: The requester should be the current user or the system user, if not, the operation will
115      * be failed with {@code RESULT_INVALID_USER}.
116      *
117      * @param activity {@link Activity} to designate
118      * @param displayId {@code Display} where {@code TaskDisplayArea} is located in
119      * @param featureId {@code TaskDisplayArea} where {@link Activity} is launched in, if it is
120      *         {@code DisplayAreaOrganizer.FEATURE_UNDEFINED}, then it'll remove the existing one.
121      * @return {@code ResultTypeEnum}. {@code RESULT_SUCCESS} if the operation is successful,
122      *         otherwise, {@code RESULT_XXX} depending on the type of the error.
123      * @throws {@link IllegalArgumentException} if {@code displayId} or {@code featureId} is
124      *         invalid. {@link ActivityNotFoundException} if {@code activity} is not found
125      *         when it tries to remove.
126      */
127     @RequiresPermission(Car.PERMISSION_CONTROL_CAR_APP_LAUNCH)
128     @ResultTypeEnum
129     @AddedInOrBefore(majorVersion = 33)
setPersistentActivity( @onNull ComponentName activity, int displayId, int featureId)130     public int setPersistentActivity(
131             @NonNull ComponentName activity, int displayId, int featureId) {
132         try {
133             return mService.setPersistentActivity(activity, displayId, featureId);
134         } catch (IllegalArgumentException | IllegalStateException | SecurityException e) {
135             throw e;
136         } catch (ServiceSpecificException e) {
137             return handleServiceSpecificFromCarService(e);
138         } catch (RemoteException | RuntimeException e) {
139             return handleExceptionFromCarService(e, RESULT_FAILURE);
140         }
141     }
142 
143     /** @hide */
144     @Override
145     @AddedInOrBefore(majorVersion = 33)
onCarDisconnected()146     protected void onCarDisconnected() {
147         mTaskMonitorToken = null;
148     }
149 
handleServiceSpecificFromCarService(ServiceSpecificException e)150     private int handleServiceSpecificFromCarService(ServiceSpecificException e)
151             throws ActivityNotFoundException {
152         if (e.errorCode == ERROR_CODE_ACTIVITY_NOT_FOUND) {
153             throw new ActivityNotFoundException(e.getMessage());
154         }
155         // don't know what this is
156         throw new IllegalStateException(e);
157     }
158 
159     /**
160      * Registers the caller as TaskMonitor, which can provide Task lifecycle events to CarService.
161      * The caller should provide a binder token, which is used to check if the given TaskMonitor is
162      * live and the reported events are from the legitimate TaskMonitor.
163      * @hide
164      */
165     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
166     @AddedInOrBefore(majorVersion = 33)
registerTaskMonitor()167     public boolean registerTaskMonitor() {
168         IBinder token = new Binder();
169         try {
170             mService.registerTaskMonitor(token);
171             mTaskMonitorToken = token;
172             return true;
173         } catch (RemoteException e) {
174             handleRemoteExceptionFromCarService(e);
175         }
176         return false;
177     }
178 
179     /**
180      * Reports that a Task is created.
181      * @hide
182      */
183     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
184     @AddedInOrBefore(majorVersion = 33)
onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo)185     public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
186         if (!hasValidToken()) return;
187         try {
188             mService.onTaskAppeared(mTaskMonitorToken, taskInfo);
189         } catch (RemoteException e) {
190             handleRemoteExceptionFromCarService(e);
191         }
192     }
193 
194     /**
195      * Reports that a Task is vanished.
196      * @hide
197      */
198     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
199     @AddedInOrBefore(majorVersion = 33)
onTaskVanished(ActivityManager.RunningTaskInfo taskInfo)200     public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
201         if (!hasValidToken()) return;
202         try {
203             mService.onTaskVanished(mTaskMonitorToken, taskInfo);
204         } catch (RemoteException e) {
205             handleRemoteExceptionFromCarService(e);
206         }
207     }
208 
209     /**
210      * Reports that some Task's states are changed.
211      * @hide
212      */
213     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
214     @AddedInOrBefore(majorVersion = 33)
onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo)215     public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
216         if (!hasValidToken()) return;
217         try {
218             mService.onTaskInfoChanged(mTaskMonitorToken, taskInfo);
219         } catch (RemoteException e) {
220             handleRemoteExceptionFromCarService(e);
221         }
222     }
223 
224     /**
225      * Unregisters the caller from TaskMonitor.
226      * @hide
227      */
228     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
229     @AddedInOrBefore(majorVersion = 33)
unregisterTaskMonitor()230     public void unregisterTaskMonitor() {
231         if (!hasValidToken()) return;
232         try {
233             mService.unregisterTaskMonitor(mTaskMonitorToken);
234             mTaskMonitorToken = null;
235         } catch (RemoteException e) {
236             handleRemoteExceptionFromCarService(e);
237         }
238     }
239 
240     /**
241      * Returns all the visible tasks. The order is not guaranteed.
242      * @hide
243      */
244     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
245     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
246              minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
247     @NonNull
getVisibleTasks()248     public List<ActivityManager.RunningTaskInfo> getVisibleTasks() {
249         try {
250             return mService.getVisibleTasks();
251         } catch (RemoteException e) {
252             handleRemoteExceptionFromCarService(e);
253         }
254         return Collections.emptyList();
255     }
256 
hasValidToken()257     private boolean hasValidToken() {
258         boolean valid = mTaskMonitorToken != null;
259         if (!valid) {
260             Log.w(TAG, "Has invalid token, skip the operation: "
261                     + new Throwable().getStackTrace()[1].getMethodName());
262         }
263         return valid;
264     }
265 }
266