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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.app.WindowConfiguration;
22 import android.content.ComponentName;
23 import android.content.Intent;
24 import android.content.pm.ActivityInfo;
25 import android.os.Process;
26 import android.os.UserHandle;
27 import android.util.ArraySet;
28 import android.util.Slog;
29 import android.window.DisplayWindowPolicyController;
30 
31 import java.io.PrintWriter;
32 import java.util.List;
33 
34 class DisplayWindowPolicyControllerHelper {
35     private static final String TAG = "DisplayWindowPolicyControllerHelper";
36 
37     private final DisplayContent mDisplayContent;
38 
39     /**
40      * The policy controller of the windows that can be displayed on the virtual display.
41      *
42      * @see DisplayWindowPolicyController
43      */
44     @Nullable
45     private DisplayWindowPolicyController mDisplayWindowPolicyController;
46 
47     /**
48      * The top non-finishing activity of this display.
49      */
50     private ActivityRecord mTopRunningActivity = null;
51 
52     /**
53      * All the uids of non-finishing activity on this display.
54      * @see DisplayWindowPolicyController#onRunningAppsChanged(ArraySet)
55      */
56     private ArraySet<Integer> mRunningUid = new ArraySet<>();
57 
DisplayWindowPolicyControllerHelper(DisplayContent displayContent)58     DisplayWindowPolicyControllerHelper(DisplayContent displayContent) {
59         mDisplayContent = displayContent;
60         mDisplayWindowPolicyController = mDisplayContent.mWmService.mDisplayManagerInternal
61                 .getDisplayWindowPolicyController(mDisplayContent.mDisplayId);
62     }
63 
64     /**
65      * Return {@code true} if there is DisplayWindowPolicyController.
66      */
hasController()67     public boolean hasController() {
68         return mDisplayWindowPolicyController != null;
69     }
70 
71     /**
72      * @see DisplayWindowPolicyController#canContainActivities
73      */
canContainActivities(@onNull List<ActivityInfo> activities, @WindowConfiguration.WindowingMode int windowingMode)74     public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
75             @WindowConfiguration.WindowingMode int windowingMode) {
76         if (mDisplayWindowPolicyController == null) {
77             for (int i = 0; i < activities.size(); ++i) {
78                 // Missing controller means that this display has no categories for activity launch
79                 // restriction.
80                 if (hasDisplayCategory(activities.get(i))) {
81                     return false;
82                 }
83             }
84             return true;
85         }
86         return mDisplayWindowPolicyController.canContainActivities(activities, windowingMode);
87     }
88 
89     /**
90      * @see DisplayWindowPolicyController#canActivityBeLaunched
91      */
canActivityBeLaunched(ActivityInfo activityInfo, Intent intent, @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId, boolean isNewTask)92     public boolean canActivityBeLaunched(ActivityInfo activityInfo,
93             Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
94             int launchingFromDisplayId, boolean isNewTask) {
95         if (mDisplayWindowPolicyController == null) {
96             // Missing controller means that this display has no categories for activity launch
97             // restriction.
98             return !hasDisplayCategory(activityInfo);
99         }
100         return mDisplayWindowPolicyController.canActivityBeLaunched(activityInfo, intent,
101             windowingMode, launchingFromDisplayId, isNewTask);
102     }
103 
hasDisplayCategory(ActivityInfo aInfo)104     private boolean hasDisplayCategory(ActivityInfo aInfo) {
105         if (aInfo.requiredDisplayCategory != null) {
106             Slog.d(TAG,
107                     String.format("Checking activity launch with requiredDisplayCategory='%s' on"
108                                     + " display %d, which doesn't have a matching category.",
109                             aInfo.requiredDisplayCategory, mDisplayContent.mDisplayId));
110             return true;
111         }
112         return false;
113     }
114 
115     /**
116      * @see DisplayWindowPolicyController#keepActivityOnWindowFlagsChanged(ActivityInfo, int, int)
117      */
keepActivityOnWindowFlagsChanged(ActivityInfo aInfo, int flagChanges, int privateFlagChanges, int flagValues, int privateFlagValues)118     boolean keepActivityOnWindowFlagsChanged(ActivityInfo aInfo, int flagChanges,
119             int privateFlagChanges, int flagValues, int privateFlagValues) {
120         if (mDisplayWindowPolicyController == null) {
121             return true;
122         }
123 
124         if (!mDisplayWindowPolicyController.isInterestedWindowFlags(
125                 flagChanges, privateFlagChanges)) {
126             return true;
127         }
128 
129         return mDisplayWindowPolicyController.keepActivityOnWindowFlagsChanged(
130                 aInfo, flagValues, privateFlagValues);
131     }
132 
133     /** Update the top activity and the uids of non-finishing activity */
onRunningActivityChanged()134     void onRunningActivityChanged() {
135         if (mDisplayWindowPolicyController == null) {
136             return;
137         }
138 
139         // Update top activity.
140         ActivityRecord topActivity = mDisplayContent.getTopActivity(false /* includeFinishing */,
141                 true /* includeOverlays */);
142         if (topActivity != mTopRunningActivity) {
143             mTopRunningActivity = topActivity;
144             if (topActivity == null) {
145                 mDisplayWindowPolicyController.onTopActivityChanged(null, Process.INVALID_UID,
146                         UserHandle.USER_NULL);
147             } else {
148                 mDisplayWindowPolicyController.onTopActivityChanged(
149                         topActivity.info.getComponentName(), topActivity.info.applicationInfo.uid,
150                         topActivity.mUserId);
151             }
152         }
153 
154         // Update running uid.
155         final boolean[] notifyChanged = {false};
156         ArraySet<Integer> runningUids = new ArraySet<>();
157         mDisplayContent.forAllActivities((r) -> {
158             if (!r.finishing) {
159                 notifyChanged[0] |= runningUids.add(r.getUid());
160             }
161         });
162 
163         // We need to compare the size because if it is the following case, we can't know the
164         // existence of 3 in the forAllActivities() loop.
165         // Old set: 1,2,3
166         // New set: 1,2
167         if (notifyChanged[0] || (mRunningUid.size() != runningUids.size())) {
168             mRunningUid = runningUids;
169             mDisplayWindowPolicyController.onRunningAppsChanged(runningUids);
170         }
171     }
172 
173     /**
174      * @see DisplayWindowPolicyController#isWindowingModeSupported(int)
175      */
isWindowingModeSupported( @indowConfiguration.WindowingMode int windowingMode)176     public final boolean isWindowingModeSupported(
177             @WindowConfiguration.WindowingMode int windowingMode) {
178         if (mDisplayWindowPolicyController == null) {
179             return true;
180         }
181         return mDisplayWindowPolicyController.isWindowingModeSupported(windowingMode);
182     }
183 
184     /**
185      * @see DisplayWindowPolicyController#canShowTasksInHostDeviceRecents()
186      */
canShowTasksInHostDeviceRecents()187     public final boolean canShowTasksInHostDeviceRecents() {
188         if (mDisplayWindowPolicyController == null) {
189             return true;
190         }
191         return mDisplayWindowPolicyController.canShowTasksInHostDeviceRecents();
192     }
193 
194     /**
195      * @see DisplayWindowPolicyController#isEnteringPipAllowed(int)
196      */
isEnteringPipAllowed(int uid)197     public final boolean isEnteringPipAllowed(int uid) {
198         if (mDisplayWindowPolicyController == null) {
199             return true;
200         }
201         return mDisplayWindowPolicyController.isEnteringPipAllowed(uid);
202     }
203 
204     /**
205      * @see DisplayWindowPolicyController#getCustomHomeComponent
206      */
207     @Nullable
getCustomHomeComponent()208     public ComponentName getCustomHomeComponent() {
209         if (mDisplayWindowPolicyController == null) {
210             return null;
211         }
212         return mDisplayWindowPolicyController.getCustomHomeComponent();
213     }
214 
dump(String prefix, PrintWriter pw)215     void dump(String prefix, PrintWriter pw) {
216         if (mDisplayWindowPolicyController != null) {
217             pw.println();
218             mDisplayWindowPolicyController.dump(prefix, pw);
219         }
220     }
221 }
222