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