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