• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.NonNull;
20 import android.annotation.Nullable;
21 import android.app.ActivityManager;
22 import android.car.builtin.util.Slogf;
23 import android.car.builtin.view.ViewHelper;
24 import android.content.Context;
25 import android.graphics.Rect;
26 import android.os.Binder;
27 import android.view.SurfaceControl;
28 
29 import com.android.internal.annotations.GuardedBy;
30 
31 import java.util.concurrent.Executor;
32 
33 /**
34  * A {@link RemoteCarDefaultRootTaskView} can act as a default app container. A default app
35  * container is the container where all apps open by default.
36  *
37  * Please use this with caution. If this task view is used inside an activity, that activity might
38  * always remain running as all the other activities will start appearing inside this launch root
39  * instead of appearing in the full screen.
40  *
41  * @hide
42  */
43 public final class RemoteCarDefaultRootTaskView extends RemoteCarTaskView {
44     private static final String TAG = RemoteCarDefaultRootTaskView.class.getSimpleName();
45 
46     private final Executor mCallbackExecutor;
47     private final RemoteCarDefaultRootTaskViewCallback mCallback;
48     private final CarTaskViewController mCarTaskViewController;
49     private final RemoteCarDefaultRootTaskViewConfig mConfig;
50     private final Rect mTmpRect = new Rect();
51     private final Object mLock = new Object();
52     @GuardedBy("mLock")
53     private final RootTaskStackManager mRootTaskStackManager = new RootTaskStackManager();
54 
55     @GuardedBy("mLock")
56     private ActivityManager.RunningTaskInfo mRootTask;
57 
58     final ICarTaskViewClient mICarTaskViewClient = new ICarTaskViewClient.Stub() {
59         @Override
60         public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
61             synchronized (mLock) {
62                 if (mRootTask == null) {
63                     mRootTask = taskInfo;
64                     // If onTaskAppeared() is called, it implicitly means that super.isInitialized()
65                     // is true, as the root task is created only after initialization.
66                     long identity = Binder.clearCallingIdentity();
67                     try {
68                         mCallbackExecutor.execute(() -> {
69                             // Check for isReleased() because the car task view might have
70                             // already been released but this code path is executed later because
71                             // the executor was busy.
72                             if (isReleased()) {
73                                 Slogf.w(TAG, "car task view has already been released");
74                                 return;
75                             }
76                             mCallback.onTaskViewInitialized();
77                         });
78                     } finally {
79                         Binder.restoreCallingIdentity(identity);
80                     }
81 
82                     if (taskInfo.taskDescription != null) {
83                         ViewHelper.seResizeBackgroundColor(
84                                 RemoteCarDefaultRootTaskView.this,
85                                 taskInfo.taskDescription.getBackgroundColor());
86                     }
87                     updateWindowBounds();
88                 }
89                 mRootTaskStackManager.taskAppeared(taskInfo, leash);
90             }
91 
92             long identity = Binder.clearCallingIdentity();
93             try {
94                 mCallbackExecutor.execute(() -> {
95                     if (isReleased()) {
96                         Slogf.w(TAG, "car task view has already been released");
97                         return;
98                     }
99                     mCallback.onTaskAppeared(taskInfo);
100                 });
101             } finally {
102                 Binder.restoreCallingIdentity(identity);
103             }
104         }
105 
106         @Override
107         public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
108             synchronized (mLock) {
109                 if (mRootTask == null) {
110                     return;
111                 }
112                 if (mRootTask.taskId == taskInfo.taskId && taskInfo.taskDescription != null) {
113                     ViewHelper.seResizeBackgroundColor(
114                             RemoteCarDefaultRootTaskView.this,
115                             taskInfo.taskDescription.getBackgroundColor());
116                 }
117                 mRootTaskStackManager.taskInfoChanged(taskInfo);
118             }
119             long identity = Binder.clearCallingIdentity();
120             try {
121                 mCallbackExecutor.execute(() -> {
122                     if (isReleased()) {
123                         Slogf.w(TAG, "car task view has already been released");
124                         return;
125                     }
126                     mCallback.onTaskInfoChanged(taskInfo);
127                 });
128             } finally {
129                 Binder.restoreCallingIdentity(identity);
130             }
131         }
132 
133         @Override
134         public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
135             synchronized (mLock) {
136                 if (mRootTask == null) {
137                     return;
138                 }
139                 if (mRootTask.taskId == taskInfo.taskId) {
140                     mRootTask = null;
141                 }
142                 mRootTaskStackManager.taskVanished(taskInfo);
143             }
144             long identity = Binder.clearCallingIdentity();
145             try {
146                 mCallbackExecutor.execute(() -> {
147                     if (isReleased()) {
148                         Slogf.w(TAG, "car task view has already been released");
149                         return;
150                     }
151                     mCallback.onTaskVanished(taskInfo);
152                 });
153             } finally {
154                 Binder.restoreCallingIdentity(identity);
155             }
156         }
157 
158         @Override
159         public void setResizeBackgroundColor(SurfaceControl.Transaction t, int color) {
160             ViewHelper.seResizeBackgroundColor(RemoteCarDefaultRootTaskView.this, color);
161         }
162 
163         @Override
164         public Rect getCurrentBoundsOnScreen() {
165             ViewHelper.getBoundsOnScreen(RemoteCarDefaultRootTaskView.this, mTmpRect);
166             return mTmpRect;
167         }
168     };
169 
RemoteCarDefaultRootTaskView( @onNull Context context, RemoteCarDefaultRootTaskViewConfig config, @NonNull Executor callbackExecutor, @NonNull RemoteCarDefaultRootTaskViewCallback callback, CarTaskViewController carTaskViewController)170     RemoteCarDefaultRootTaskView(
171             @NonNull Context context,
172             RemoteCarDefaultRootTaskViewConfig config,
173             @NonNull Executor callbackExecutor,
174             @NonNull RemoteCarDefaultRootTaskViewCallback callback,
175             CarTaskViewController carTaskViewController) {
176         super(context);
177         mConfig = config;
178         mCallbackExecutor = callbackExecutor;
179         mCallback = callback;
180         mCarTaskViewController = carTaskViewController;
181 
182         mCallbackExecutor.execute(() -> mCallback.onTaskViewCreated(this));
183     }
184 
185     /**
186      * Returns the task info of the top task running in the root task embedded in this task view.
187      *
188      * @return task info object of the top task.
189      */
190     @Nullable
getTopTaskInfo()191     public ActivityManager.RunningTaskInfo getTopTaskInfo() {
192         synchronized (mLock) {
193             return mRootTaskStackManager.getTopTask();
194         }
195     }
196 
197     @Override
onInitialized()198     void onInitialized() {
199         // A signal when the surface and host-side are ready. This task view initialization
200         // completes after root task has been created and set as launch root.
201         createLaunchRootTask(mConfig.getDisplayId(), mConfig.embedsHomeTask(),
202                 mConfig.embedsRecentsTask(), mConfig.embedsAssistantTask());
203     }
204 
205     @Override
isInitialized()206     public boolean isInitialized() {
207         synchronized (mLock) {
208             return super.isInitialized() && mRootTask != null;
209         }
210     }
211 
212     @Override
onReleased()213     void onReleased() {
214         mCallbackExecutor.execute(() -> mCallback.onTaskViewReleased());
215         mCarTaskViewController.onRemoteCarTaskViewReleased(this);
216     }
217 
218     @Nullable
219     @Override
getTaskInfo()220     public ActivityManager.RunningTaskInfo getTaskInfo() {
221         synchronized (mLock) {
222             return mRootTask;
223         }
224     }
225 
getConfig()226     RemoteCarDefaultRootTaskViewConfig getConfig() {
227         return mConfig;
228     }
229 
230     @Override
toString()231     public String toString() {
232         return toString(/* withBounds= */ false);
233     }
234 
toString(boolean withBounds)235     String toString(boolean withBounds) {
236         if (withBounds) {
237             ViewHelper.getBoundsOnScreen(this, mTmpRect);
238         }
239         return TAG + " {\n"
240                 + "  config=" + mConfig + "\n"
241                 + "  rootTaskId=" + (getTaskInfo() == null ? "null" : getTaskInfo().taskId) + "\n"
242                 + (withBounds ? ("  boundsOnScreen=" + mTmpRect) : "")
243                 + "}\n";
244 
245     }
246 }
247