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.server.wm;
18 
19 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
20 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
21 import static android.view.WindowManager.TRANSIT_CLOSE;
22 import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM;
23 import static android.view.WindowManager.TRANSIT_OPEN;
24 import static android.view.WindowManager.TRANSIT_TO_BACK;
25 import static android.view.WindowManager.TRANSIT_TO_FRONT;
26 
27 import android.os.Trace;
28 import android.view.WindowManager;
29 
30 import java.io.PrintWriter;
31 import java.util.ArrayList;
32 
33 /**
34  * Integrates common functionality from TaskSnapshotController and ActivitySnapshotController.
35  */
36 class SnapshotController {
37     private final SnapshotPersistQueue mSnapshotPersistQueue;
38     final TaskSnapshotController mTaskSnapshotController;
39     final ActivitySnapshotController mActivitySnapshotController;
40 
SnapshotController(WindowManagerService wms)41     SnapshotController(WindowManagerService wms) {
42         mSnapshotPersistQueue = new SnapshotPersistQueue();
43         mTaskSnapshotController = new TaskSnapshotController(wms, mSnapshotPersistQueue);
44         mActivitySnapshotController = new ActivitySnapshotController(wms, mSnapshotPersistQueue);
45     }
46 
systemReady()47     void systemReady() {
48         mSnapshotPersistQueue.systemReady();
49     }
50 
setPause(boolean paused)51     void setPause(boolean paused) {
52         mSnapshotPersistQueue.setPaused(paused);
53     }
54 
onAppRemoved(ActivityRecord activity)55     void onAppRemoved(ActivityRecord activity) {
56         mTaskSnapshotController.onAppRemoved(activity);
57         mActivitySnapshotController.onAppRemoved(activity);
58     }
59 
onAppDied(ActivityRecord activity)60     void onAppDied(ActivityRecord activity) {
61         mTaskSnapshotController.onAppDied(activity);
62         mActivitySnapshotController.onAppDied(activity);
63     }
64 
notifyAppVisibilityChanged(ActivityRecord appWindowToken, boolean visible)65     void notifyAppVisibilityChanged(ActivityRecord appWindowToken, boolean visible) {
66         mActivitySnapshotController.notifyAppVisibilityChanged(appWindowToken, visible);
67     }
68 
69     // For legacy transition, which won't support activity snapshot
onTransitionStarting(DisplayContent displayContent)70     void onTransitionStarting(DisplayContent displayContent) {
71         mTaskSnapshotController.handleClosingApps(displayContent.mClosingApps);
72     }
73 
74     // For shell transition, record snapshots before transaction start.
onTransactionReady(@indowManager.TransitionType int type, ArrayList<Transition.ChangeInfo> changeInfos)75     void onTransactionReady(@WindowManager.TransitionType int type,
76             ArrayList<Transition.ChangeInfo> changeInfos) {
77         final boolean isTransitionOpen = isTransitionOpen(type);
78         final boolean isTransitionClose = isTransitionClose(type);
79         if (!isTransitionOpen && !isTransitionClose && type < TRANSIT_FIRST_CUSTOM) {
80             return;
81         }
82         for (int i = changeInfos.size() - 1; i >= 0; --i) {
83             Transition.ChangeInfo info = changeInfos.get(i);
84             // Intentionally skip record snapshot for changes originated from PiP.
85             if (info.mWindowingMode == WINDOWING_MODE_PINNED) continue;
86             if (info.mContainer.asTask() != null && !info.mContainer.isVisibleRequested()) {
87                 mTaskSnapshotController.recordSnapshot(info.mContainer.asTask(),
88                         false /* allowSnapshotHome */);
89             }
90             // Won't need to capture activity snapshot in close transition.
91             if (isTransitionClose) {
92                 continue;
93             }
94             if (info.mContainer.asActivityRecord() != null
95                     || info.mContainer.asTaskFragment() != null) {
96                 final TaskFragment tf = info.mContainer.asTaskFragment();
97                 final ActivityRecord ar = tf != null ? tf.getTopMostActivity()
98                         : info.mContainer.asActivityRecord();
99                 final boolean taskVis = ar != null && ar.getTask().isVisibleRequested();
100                 if (ar != null && !ar.isVisibleRequested() && taskVis) {
101                     mActivitySnapshotController.recordSnapshot(ar);
102                 }
103             }
104         }
105     }
106 
onTransitionFinish(@indowManager.TransitionType int type, ArrayList<Transition.ChangeInfo> changeInfos)107     void onTransitionFinish(@WindowManager.TransitionType int type,
108             ArrayList<Transition.ChangeInfo> changeInfos) {
109         final boolean isTransitionOpen = isTransitionOpen(type);
110         final boolean isTransitionClose = isTransitionClose(type);
111         if (!isTransitionOpen && !isTransitionClose && type < TRANSIT_FIRST_CUSTOM
112                 || (changeInfos.isEmpty())) {
113             return;
114         }
115         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "SnapshotController_analysis");
116         mActivitySnapshotController.beginSnapshotProcess();
117         final ArrayList<WindowContainer> windows = new ArrayList<>();
118         for (int i = changeInfos.size() - 1; i >= 0; --i) {
119             final WindowContainer wc = changeInfos.get(i).mContainer;
120             if (wc.asTask() == null && wc.asTaskFragment() == null
121                     && wc.asActivityRecord() == null) {
122                 continue;
123             }
124             windows.add(wc);
125         }
126         mActivitySnapshotController.handleTransitionFinish(windows);
127         mActivitySnapshotController.endSnapshotProcess();
128         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
129     }
130 
isTransitionOpen(int type)131     private static boolean isTransitionOpen(int type) {
132         return type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT;
133     }
isTransitionClose(int type)134     private static boolean isTransitionClose(int type) {
135         return type == TRANSIT_CLOSE || type == TRANSIT_TO_BACK;
136     }
137 
dump(PrintWriter pw, String prefix)138     void dump(PrintWriter pw, String prefix) {
139         mTaskSnapshotController.dump(pw, prefix);
140         mActivitySnapshotController.dump(pw, prefix);
141     }
142 }
143