• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 com.android.car.carlauncher;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
23 import static android.view.Display.DEFAULT_DISPLAY;
24 
25 import static com.android.car.carlauncher.TaskViewManager.DBG;
26 
27 import android.app.Activity;
28 import android.app.ActivityManager;
29 import android.util.Log;
30 import android.view.SurfaceControl;
31 import android.window.WindowContainerTransaction;
32 
33 import com.android.wm.shell.ShellTaskOrganizer;
34 import com.android.wm.shell.common.SyncTransactionQueue;
35 
36 import java.util.concurrent.Executor;
37 
38 /**
39  * A {@link CarTaskView} that can act as a default app container. A default app container is the
40  * container where all apps open by default.
41  */
42 final class LaunchRootCarTaskView extends CarTaskView {
43     private static final String TAG = LaunchRootCarTaskView.class.getSimpleName();
44 
45     private final Executor mCallbackExecutor;
46     private final LaunchRootCarTaskViewCallbacks mCallbacks;
47     private final ShellTaskOrganizer mShellTaskOrganizer;
48     private final SyncTransactionQueue mSyncQueue;
49     private final ShellTaskOrganizer.TaskListener mRootTaskListener;
50 
51     private ActivityManager.RunningTaskInfo mLaunchRootTask;
52 
53     private final ShellTaskOrganizer.TaskListener mRootTaskListenerWrapper =
54             new ShellTaskOrganizer.TaskListener() {
55                 @Override
56                 public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo,
57                         SurfaceControl leash) {
58                     // The first call to onTaskAppeared() is always for the root-task.
59                     if (mLaunchRootTask == null && !taskInfo.hasParentTask()) {
60                         setRootTaskAsLaunchRoot(taskInfo);
61                         LaunchRootCarTaskView.this.onTaskAppeared(taskInfo, leash);
62                         mCallbackExecutor.execute(() -> mCallbacks.onTaskViewReady());
63                         return;
64                     }
65 
66                     if (DBG) {
67                         Log.d(TAG, "onTaskAppeared " + taskInfo.taskId + " - "
68                                 + taskInfo.baseActivity);
69                     }
70 
71 
72                     mRootTaskListener.onTaskAppeared(taskInfo, leash);
73                 }
74 
75                 @Override
76                 public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
77                     if (mLaunchRootTask != null
78                             && mLaunchRootTask.taskId == taskInfo.taskId) {
79                         LaunchRootCarTaskView.this.onTaskInfoChanged(taskInfo);
80                         if (DBG) {
81                             Log.d(TAG, "got onTaskInfoChanged for the launch root task. Not "
82                                     + "forwarding this to root task listener");
83                         }
84                         return;
85                     }
86                     if (DBG) {
87                         Log.d(TAG, "onTaskInfoChanged " + taskInfo.taskId + " - "
88                                 + taskInfo.baseActivity);
89                     }
90 
91                     mRootTaskListener.onTaskInfoChanged(taskInfo);
92                 }
93 
94                 @Override
95                 public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
96                     if (DBG) {
97                         Log.d(TAG, "onTaskVanished " + taskInfo.taskId + " - "
98                                 + taskInfo.baseActivity);
99                     }
100                     if (mLaunchRootTask != null
101                             && mLaunchRootTask.taskId == taskInfo.taskId) {
102                         LaunchRootCarTaskView.this.onTaskVanished(taskInfo);
103                         if (DBG) {
104                             Log.d(TAG, "got onTaskVanished for the launch root task. Not "
105                                     + "forwarding this to root task listener");
106                         }
107                         return;
108                     }
109 
110                     mRootTaskListener.onTaskVanished(taskInfo);
111                 }
112 
113                 @Override
114                 public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
115                     mRootTaskListener.onBackPressedOnTaskRoot(taskInfo);
116                 }
117             };
118 
LaunchRootCarTaskView(Activity context, ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue, Executor callbackExecutor, LaunchRootCarTaskViewCallbacks callbacks, ShellTaskOrganizer.TaskListener rootTaskListener)119     public LaunchRootCarTaskView(Activity context,
120             ShellTaskOrganizer organizer,
121             SyncTransactionQueue syncQueue,
122             Executor callbackExecutor,
123             LaunchRootCarTaskViewCallbacks callbacks,
124             ShellTaskOrganizer.TaskListener rootTaskListener) {
125         super(context, organizer, syncQueue);
126         mCallbacks = callbacks;
127         mCallbackExecutor = callbackExecutor;
128         mShellTaskOrganizer = organizer;
129         mSyncQueue = syncQueue;
130         mRootTaskListener = rootTaskListener;
131 
132         mCallbackExecutor.execute(() -> mCallbacks.onTaskViewCreated(this));
133     }
134 
135     @Override
onCarTaskViewInitialized()136     protected void onCarTaskViewInitialized() {
137         super.onCarTaskViewInitialized();
138         mShellTaskOrganizer.getExecutor().execute(() -> {
139             // Should run on shell's executor
140             mShellTaskOrganizer.createRootTask(DEFAULT_DISPLAY,
141                     WINDOWING_MODE_MULTI_WINDOW,
142                     mRootTaskListenerWrapper);
143         });
144     }
145 
146     @Override
notifyReleased()147     protected void notifyReleased() {
148         super.notifyReleased();
149         clearLaunchRootTask();
150     }
151 
clearLaunchRootTask()152     private void clearLaunchRootTask() {
153         if (mLaunchRootTask == null) {
154             Log.w(TAG, "Unable to clear launch root task because it is not created.");
155             return;
156         }
157         WindowContainerTransaction wct = new WindowContainerTransaction();
158         wct.setLaunchRoot(mLaunchRootTask.token, null, null);
159         mSyncQueue.queue(wct);
160         // Should run on shell's executor
161         mShellTaskOrganizer.deleteRootTask(mLaunchRootTask.token);
162         mLaunchRootTask = null;
163     }
164 
setRootTaskAsLaunchRoot(ActivityManager.RunningTaskInfo taskInfo)165     private void setRootTaskAsLaunchRoot(ActivityManager.RunningTaskInfo taskInfo) {
166         mLaunchRootTask = taskInfo;
167         WindowContainerTransaction wct = new WindowContainerTransaction();
168         wct.setLaunchRoot(taskInfo.token,
169                         new int[]{WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED},
170                         new int[]{ACTIVITY_TYPE_STANDARD})
171                 .reorder(taskInfo.token, true);
172         mSyncQueue.queue(wct);
173     }
174 }
175