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.app.Activity; 23 import android.car.Car; 24 import android.car.CarManagerBase; 25 import android.car.user.CarUserManager; 26 import android.content.ActivityNotFoundException; 27 import android.content.ComponentName; 28 import android.os.IBinder; 29 import android.os.RemoteException; 30 import android.os.ServiceSpecificException; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 34 import java.lang.annotation.ElementType; 35 import java.lang.annotation.Retention; 36 import java.lang.annotation.RetentionPolicy; 37 import java.lang.annotation.Target; 38 39 /** 40 * API to manage {@link android.app.Activity} in Car. 41 * 42 * @hide 43 */ 44 public final class CarActivityManager extends CarManagerBase { 45 private static final String TAG = CarUserManager.class.getSimpleName(); 46 47 /** Indicates that the operation was successful. */ 48 public static final int RESULT_SUCCESS = 0; 49 /** Indicates that the operation was failed with the unknown reason. */ 50 public static final int RESULT_FAILURE = -1; 51 /** 52 * Indicates that the operation was failed because the requester isn't the current user or 53 * the system user 54 */ 55 public static final int RESULT_INVALID_USER = -2; 56 57 /** @hide */ 58 @Retention(RetentionPolicy.SOURCE) 59 @IntDef(prefix = "RESULT_", value = { 60 RESULT_SUCCESS, 61 RESULT_FAILURE, 62 RESULT_INVALID_USER, 63 }) 64 @Target({ElementType.TYPE_USE}) 65 public @interface ResultTypeEnum {} 66 67 /** 68 * Internal error code for throwing {@link ActivityNotFoundException} from service. 69 * @hide 70 */ 71 public static final int ERROR_CODE_ACTIVITY_NOT_FOUND = -101; 72 73 private final ICarActivityService mService; 74 75 /** 76 * @hide 77 */ CarActivityManager(@onNull Car car, @NonNull IBinder service)78 public CarActivityManager(@NonNull Car car, @NonNull IBinder service) { 79 this(car, ICarActivityService.Stub.asInterface(service)); 80 } 81 82 /** 83 * @hide 84 */ 85 @VisibleForTesting CarActivityManager(@onNull Car car, @NonNull ICarActivityService service)86 public CarActivityManager(@NonNull Car car, @NonNull ICarActivityService service) { 87 super(car); 88 89 mService = service; 90 } 91 92 /** 93 * Designates the given {@code activity} to be launched in {@code TaskDisplayArea} of 94 * {@code featureId} in the display of {@code displayId}. 95 * <p>Note: this will not affect the existing {@link Activity}. 96 * Note: You can map assign {@code Activity} to one {@code TaskDisplayArea} only. If 97 * you assign it to the multiple {@code TaskDisplayArea}s, then the last one wins. 98 * Note: The requester should be the current user or the system user, if not, the operation will 99 * be failed with {@code RESULT_INVALID_USER}. 100 * 101 * @param activity {@link Activity} to designate 102 * @param displayId {@code Display} where {@code TaskDisplayArea} is located in 103 * @param featureId {@code TaskDisplayArea} where {@link Activity} is launched in, if it is 104 * {@code DisplayAreaOrganizer.FEATURE_UNDEFINED}, then it'll remove the existing one. 105 * @return {@code ResultTypeEnum}. {@code RESULT_SUCCESS} if the operation is successful, 106 * otherwise, {@code RESULT_XXX} depending on the type of the error. 107 * @throws {@link IllegalArgumentException} if {@code displayId} or {@code featureId} is 108 * invalid. {@link ActivityNotFoundException} if {@code activity} is not found 109 * when it tries to remove. 110 */ 111 @RequiresPermission(Car.PERMISSION_CONTROL_CAR_APP_LAUNCH) 112 @ResultTypeEnum setPersistentActivity( @onNull ComponentName activity, int displayId, int featureId)113 public int setPersistentActivity( 114 @NonNull ComponentName activity, int displayId, int featureId) { 115 try { 116 return mService.setPersistentActivity(activity, displayId, featureId); 117 } catch (IllegalArgumentException | IllegalStateException | SecurityException e) { 118 throw e; 119 } catch (ServiceSpecificException e) { 120 return handleServiceSpecificFromCarService(e); 121 } catch (RemoteException | RuntimeException e) { 122 return handleExceptionFromCarService(e, RESULT_FAILURE); 123 } 124 } 125 126 /** @hide */ 127 @Override onCarDisconnected()128 protected void onCarDisconnected() { 129 // nothing to do 130 } 131 handleServiceSpecificFromCarService(ServiceSpecificException e)132 private int handleServiceSpecificFromCarService(ServiceSpecificException e) 133 throws ActivityNotFoundException { 134 if (e.errorCode == ERROR_CODE_ACTIVITY_NOT_FOUND) { 135 throw new ActivityNotFoundException(e.getMessage()); 136 } 137 // don't know what this is 138 throw new IllegalStateException(e); 139 } 140 } 141