• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.wm.shell.fullscreen;
18 
19 import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
20 import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
21 
22 import android.app.ActivityManager;
23 import android.app.ActivityManager.RunningTaskInfo;
24 import android.graphics.Point;
25 import android.util.SparseArray;
26 import android.view.SurfaceControl;
27 
28 import androidx.annotation.NonNull;
29 
30 import com.android.internal.protolog.ProtoLog;
31 import com.android.wm.shell.ShellTaskOrganizer;
32 import com.android.wm.shell.common.SyncTransactionQueue;
33 import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
34 import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider;
35 import com.android.wm.shell.protolog.ShellProtoLogGroup;
36 import com.android.wm.shell.recents.RecentTasksController;
37 import com.android.wm.shell.sysui.ShellInit;
38 import com.android.wm.shell.transition.Transitions;
39 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
40 
41 import java.io.PrintWriter;
42 import java.util.Optional;
43 
44 /**
45   * Organizes tasks presented in {@link android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN}.
46  * @param <T> the type of window decoration instance
47   */
48 public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
49     private static final String TAG = "FullscreenTaskListener";
50 
51     private final ShellTaskOrganizer mShellTaskOrganizer;
52 
53     private final SparseArray<State> mTasks = new SparseArray<>();
54 
55     private static class State {
56         RunningTaskInfo mTaskInfo;
57         SurfaceControl mLeash;
58     }
59     private final SyncTransactionQueue mSyncQueue;
60     private final Optional<RecentTasksController> mRecentTasksOptional;
61     private final Optional<WindowDecorViewModel> mWindowDecorViewModelOptional;
62     private final Optional<DesktopWallpaperActivityTokenProvider>
63             mDesktopWallpaperActivityTokenProviderOptional;
64 
65     /**
66      * This constructor is used by downstream products.
67      */
FullscreenTaskListener(SyncTransactionQueue syncQueue)68     public FullscreenTaskListener(SyncTransactionQueue syncQueue) {
69         this(null /* shellInit */, null /* shellTaskOrganizer */, syncQueue, Optional.empty(),
70                 Optional.empty(), Optional.empty());
71     }
72 
FullscreenTaskListener(ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Optional<RecentTasksController> recentTasksOptional, Optional<WindowDecorViewModel> windowDecorViewModelOptional, Optional<DesktopWallpaperActivityTokenProvider> desktopWallpaperActivityTokenProviderOptional)73     public FullscreenTaskListener(ShellInit shellInit,
74             ShellTaskOrganizer shellTaskOrganizer,
75             SyncTransactionQueue syncQueue,
76             Optional<RecentTasksController> recentTasksOptional,
77             Optional<WindowDecorViewModel> windowDecorViewModelOptional,
78             Optional<DesktopWallpaperActivityTokenProvider>
79                     desktopWallpaperActivityTokenProviderOptional) {
80         mShellTaskOrganizer = shellTaskOrganizer;
81         mSyncQueue = syncQueue;
82         mRecentTasksOptional = recentTasksOptional;
83         mWindowDecorViewModelOptional = windowDecorViewModelOptional;
84         mDesktopWallpaperActivityTokenProviderOptional =
85                 desktopWallpaperActivityTokenProviderOptional;
86         // Note: Some derivative FullscreenTaskListener implementations do not use ShellInit
87         if (shellInit != null) {
88             shellInit.addInitCallback(this::onInit, this);
89         }
90     }
91 
onInit()92     private void onInit() {
93         mShellTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_FULLSCREEN);
94     }
95 
96     @Override
onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash)97     public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
98         if (mTasks.get(taskInfo.taskId) != null) {
99             throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId);
100         }
101         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
102                 taskInfo.taskId);
103         final Point positionInParent = taskInfo.positionInParent;
104         final State state = new State();
105         state.mLeash = leash;
106         state.mTaskInfo = taskInfo;
107         mTasks.put(taskInfo.taskId, state);
108 
109         if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
110         updateRecentsForVisibleFullscreenTask(taskInfo);
111         boolean createdWindowDecor = false;
112         if (mWindowDecorViewModelOptional.isPresent()) {
113             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
114             createdWindowDecor = mWindowDecorViewModelOptional.get()
115                     .onTaskOpening(taskInfo, leash, t, t);
116             t.apply();
117         }
118         if (!createdWindowDecor) {
119             mSyncQueue.runInSync(t -> {
120                 if (!leash.isValid()) {
121                     // Task vanished before sync completion
122                     return;
123                 }
124                 // Reset several properties back to fullscreen (PiP, for example, leaves all these
125                 // properties in a bad state).
126                 t.setWindowCrop(leash, null);
127                 t.setPosition(leash, positionInParent.x, positionInParent.y);
128                 t.setAlpha(leash, 1f);
129                 t.setMatrix(leash, 1, 0, 0, 1);
130                 if (taskInfo.isVisible) {
131                     t.show(leash);
132                 }
133             });
134         }
135     }
136 
137     @Override
onTaskInfoChanged(RunningTaskInfo taskInfo)138     public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
139         final State state = mTasks.get(taskInfo.taskId);
140         final Point oldPositionInParent = state.mTaskInfo.positionInParent;
141         boolean oldVisible = state.mTaskInfo.isVisible;
142 
143         if (mWindowDecorViewModelOptional.isPresent()) {
144             mWindowDecorViewModelOptional.get().onTaskInfoChanged(taskInfo);
145         }
146         state.mTaskInfo = taskInfo;
147         if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
148         updateRecentsForVisibleFullscreenTask(taskInfo);
149 
150         final Point positionInParent = state.mTaskInfo.positionInParent;
151         boolean positionInParentChanged = !oldPositionInParent.equals(positionInParent);
152         boolean becameVisible = !oldVisible && state.mTaskInfo.isVisible;
153 
154         if (becameVisible || positionInParentChanged) {
155             mSyncQueue.runInSync(t -> {
156                 if (!state.mLeash.isValid()) {
157                     // Task vanished before sync completion
158                     return;
159                 }
160                 if (becameVisible) {
161                     t.show(state.mLeash);
162                 }
163                 t.setPosition(state.mLeash, positionInParent.x, positionInParent.y);
164             });
165         }
166     }
167 
168     @Override
onTaskVanished(ActivityManager.RunningTaskInfo taskInfo)169     public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
170         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
171                 taskInfo.taskId);
172         mTasks.remove(taskInfo.taskId);
173         mWindowDecorViewModelOptional.ifPresent(v -> v.onTaskVanished(taskInfo));
174         mDesktopWallpaperActivityTokenProviderOptional.ifPresent(
175                 provider -> {
176                     if (DesktopWallpaperActivity.isWallpaperTask(taskInfo)) {
177                         provider.removeToken(taskInfo.getToken());
178                     }
179                 });
180         if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
181         if (mWindowDecorViewModelOptional.isPresent()) {
182             mWindowDecorViewModelOptional.get().destroyWindowDecoration(taskInfo);
183         }
184     }
185 
updateRecentsForVisibleFullscreenTask(RunningTaskInfo taskInfo)186     private void updateRecentsForVisibleFullscreenTask(RunningTaskInfo taskInfo) {
187         mRecentTasksOptional.ifPresent(recentTasks -> {
188             if (taskInfo.isVisible) {
189                 // Remove any persisted splits if either tasks are now made fullscreen and visible
190                 recentTasks.removeSplitPair(taskInfo.taskId);
191             }
192         });
193     }
194 
195     @Override
attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b)196     public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
197         b.setParent(findTaskSurface(taskId));
198     }
199 
200     @Override
reparentChildSurfaceToTask(int taskId, SurfaceControl sc, SurfaceControl.Transaction t)201     public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
202             SurfaceControl.Transaction t) {
203         t.reparent(sc, findTaskSurface(taskId));
204     }
205 
findTaskSurface(int taskId)206     private SurfaceControl findTaskSurface(int taskId) {
207         if (!mTasks.contains(taskId)) {
208             throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
209         }
210         return mTasks.get(taskId).mLeash;
211     }
212 
213     @Override
dump(@onNull PrintWriter pw, String prefix)214     public void dump(@NonNull PrintWriter pw, String prefix) {
215         final String innerPrefix = prefix + "  ";
216         pw.println(prefix + this);
217         pw.println(innerPrefix + mTasks.size() + " Tasks");
218     }
219 
220     @Override
toString()221     public String toString() {
222         return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN);
223     }
224 }
225