blob: 66dbfd5f2a842c308a218aeea607d9083f793a80 [file] [log] [blame]
Winson Chung655332c2016-10-31 13:14:28 -07001/*
2 * Copyright (C) 2016 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
17package com.android.server.wm;
18
Evan Rosky35630df2018-10-31 10:22:08 -070019import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
20import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Winson Chung655332c2016-10-31 13:14:28 -070021
Winson Chunga29eb982016-12-14 12:01:27 -080022import android.app.RemoteAction;
Hongwei Wang43a752b2019-09-17 20:20:30 +000023import android.content.ComponentName;
Winson Chunga29eb982016-12-14 12:01:27 -080024import android.content.pm.ParceledListSlice;
Winson Chung655332c2016-10-31 13:14:28 -070025import android.content.res.Resources;
Winson Chung655332c2016-10-31 13:14:28 -070026import android.graphics.Rect;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.RemoteException;
30import android.util.DisplayMetrics;
31import android.util.Log;
Winson Chung655332c2016-10-31 13:14:28 -070032import android.util.Slog;
Winson Chung14fefc22016-11-02 10:02:29 -070033import android.view.DisplayInfo;
Winson Chung655332c2016-10-31 13:14:28 -070034import android.view.IPinnedStackController;
35import android.view.IPinnedStackListener;
36
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070037import com.android.server.UiThread;
Winson Chung655332c2016-10-31 13:14:28 -070038
39import java.io.PrintWriter;
Winson Chunga29eb982016-12-14 12:01:27 -080040import java.util.ArrayList;
41import java.util.List;
Winson Chung655332c2016-10-31 13:14:28 -070042
43/**
Winson Chung2a82fe52017-02-02 14:43:34 -080044 * Holds the common state of the pinned stack between the system and SystemUI. If SystemUI ever
45 * needs to be restarted, it will be notified with the last known state.
46 *
47 * Changes to the pinned stack also flow through this controller, and generally, the system only
48 * changes the pinned stack bounds through this controller in two ways:
49 *
50 * 1) When first entering PiP: the controller returns the valid bounds given, taking aspect ratio
51 * and IME state into account.
52 * 2) When rotating the device: the controller calculates the new bounds in the new orientation,
Hongwei Wang85cf41f2020-01-15 15:14:47 -080053 * taking the IME state into account. In this case, we currently ignore the
Winson Chung2a82fe52017-02-02 14:43:34 -080054 * SystemUI adjustments (ie. expanded for menu, interaction, etc).
55 *
56 * Other changes in the system, including adjustment of IME, configuration change, and more are
57 * handled by SystemUI (similar to the docked stack divider).
Winson Chung655332c2016-10-31 13:14:28 -070058 */
59class PinnedStackController {
60
61 private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;
62
63 private final WindowManagerService mService;
64 private final DisplayContent mDisplayContent;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070065 private final Handler mHandler = UiThread.getHandler();
Winson Chung655332c2016-10-31 13:14:28 -070066
67 private IPinnedStackListener mPinnedStackListener;
68 private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
69 new PinnedStackListenerDeathHandler();
70
71 private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
Winson Chung655332c2016-10-31 13:14:28 -070072
Winson Chung655332c2016-10-31 13:14:28 -070073 private boolean mIsImeShowing;
74 private int mImeHeight;
Winson Chung655332c2016-10-31 13:14:28 -070075
Winson Chung2a82fe52017-02-02 14:43:34 -080076 // The set of actions and aspect-ratio for the that are currently allowed on the PiP activity
Winson Chunga29eb982016-12-14 12:01:27 -080077 private ArrayList<RemoteAction> mActions = new ArrayList<>();
Winson Chung2a82fe52017-02-02 14:43:34 -080078 private float mAspectRatio = -1f;
Winson Chunga29eb982016-12-14 12:01:27 -080079
Winson Chung14fefc22016-11-02 10:02:29 -070080 // Used to calculate stack bounds across rotations
81 private final DisplayInfo mDisplayInfo = new DisplayInfo();
82
Winson Chung2a82fe52017-02-02 14:43:34 -080083 // The aspect ratio bounds of the PIP.
84 private float mMinAspectRatio;
85 private float mMaxAspectRatio;
86
Winson Chung655332c2016-10-31 13:14:28 -070087 // Temp vars for calculation
88 private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
Winson Chung655332c2016-10-31 13:14:28 -070089
90 /**
91 * The callback object passed to listeners for them to notify the controller of state changes.
92 */
93 private class PinnedStackControllerCallback extends IPinnedStackController.Stub {
Winson Chungef4dc812017-04-11 13:31:44 -070094 @Override
Hongwei Wang77598952019-09-17 16:42:37 +000095 public int getDisplayRotation() {
Hongwei Wange3ff1392019-08-06 14:24:43 -070096 synchronized (mService.mGlobalLock) {
Hongwei Wang77598952019-09-17 16:42:37 +000097 return mDisplayInfo.rotation;
Hongwei Wange3ff1392019-08-06 14:24:43 -070098 }
99 }
Winson Chung655332c2016-10-31 13:14:28 -0700100 }
101
102 /**
103 * Handler for the case where the listener dies.
104 */
105 private class PinnedStackListenerDeathHandler implements IBinder.DeathRecipient {
106
107 @Override
108 public void binderDied() {
109 // Clean up the state if the listener dies
Winson Chung397967f2017-11-01 16:21:35 -0700110 if (mPinnedStackListener != null) {
111 mPinnedStackListener.asBinder().unlinkToDeath(mPinnedStackListenerDeathHandler, 0);
112 }
Winson Chung655332c2016-10-31 13:14:28 -0700113 mPinnedStackListener = null;
114 }
115 }
116
117 PinnedStackController(WindowManagerService service, DisplayContent displayContent) {
118 mService = service;
119 mDisplayContent = displayContent;
Winson Chung14fefc22016-11-02 10:02:29 -0700120 mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
Winson Chung655332c2016-10-31 13:14:28 -0700121 reloadResources();
122 }
123
124 void onConfigurationChanged() {
125 reloadResources();
126 }
127
128 /**
129 * Reloads all the resources for the current configuration.
130 */
Wale Ogunwale027f4752017-05-12 10:37:16 -0700131 private void reloadResources() {
Winson Chung655332c2016-10-31 13:14:28 -0700132 final Resources res = mService.mContext.getResources();
Winson Chung655332c2016-10-31 13:14:28 -0700133 mDisplayContent.getDisplay().getRealMetrics(mTmpMetrics);
Winson Chung2a82fe52017-02-02 14:43:34 -0800134 mMinAspectRatio = res.getFloat(
135 com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
136 mMaxAspectRatio = res.getFloat(
137 com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
Winson Chung655332c2016-10-31 13:14:28 -0700138 }
139
140 /**
141 * Registers a pinned stack listener.
142 */
143 void registerPinnedStackListener(IPinnedStackListener listener) {
144 try {
145 listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
146 listener.onListenerRegistered(mCallbacks);
147 mPinnedStackListener = listener;
Hongwei Wang43a752b2019-09-17 20:20:30 +0000148 notifyDisplayInfoChanged(mDisplayInfo);
Winson Chung2a82fe52017-02-02 14:43:34 -0800149 notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800150 notifyMovementBoundsChanged(false /* fromImeAdjustment */);
Winson Chunga29eb982016-12-14 12:01:27 -0800151 notifyActionsChanged(mActions);
Winson Chung655332c2016-10-31 13:14:28 -0700152 } catch (RemoteException e) {
153 Log.e(TAG, "Failed to register pinned stack listener", e);
154 }
155 }
156
157 /**
Winson Chung2a82fe52017-02-02 14:43:34 -0800158 * @return whether the given {@param aspectRatio} is valid.
159 */
160 public boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
Winson Chungbd041962017-03-06 15:07:25 -0800161 return Float.compare(mMinAspectRatio, aspectRatio) <= 0 &&
162 Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
Winson Chung2a82fe52017-02-02 14:43:34 -0800163 }
164
165 /**
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700166 * Activity is hidden (either stopped or removed), resets the last saved snap fraction
167 * so that the default bounds will be returned for the next session.
Winson Chunge55c0192017-08-24 14:50:48 -0700168 */
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700169 void onActivityHidden(ComponentName componentName) {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000170 if (mPinnedStackListener == null) return;
171 try {
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700172 mPinnedStackListener.onActivityHidden(componentName);
Hongwei Wang43a752b2019-09-17 20:20:30 +0000173 } catch (RemoteException e) {
174 Slog.e(TAG_WM, "Error delivering reset reentry fraction event.", e);
Winson Chunge55c0192017-08-24 14:50:48 -0700175 }
176 }
177
Hongwei Wang43a752b2019-09-17 20:20:30 +0000178 private void setDisplayInfo(DisplayInfo displayInfo) {
179 mDisplayInfo.copyFrom(displayInfo);
180 notifyDisplayInfoChanged(mDisplayInfo);
181 }
182
Winson Chung655332c2016-10-31 13:14:28 -0700183 /**
Winson Chung32c566f2017-04-11 18:31:21 -0700184 * In the case where the display rotation is changed but there is no stack, we can't depend on
185 * onTaskStackBoundsChanged() to be called. But we still should update our known display info
186 * with the new state so that we can update SystemUI.
187 */
Hongwei Wange79f26a2019-11-05 14:38:33 -0800188 void onDisplayInfoChanged(DisplayInfo displayInfo) {
189 synchronized (mService.mGlobalLock) {
190 setDisplayInfo(displayInfo);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800191 notifyMovementBoundsChanged(false /* fromImeAdjustment */);
Hongwei Wange79f26a2019-11-05 14:38:33 -0800192 }
Winson Chung32c566f2017-04-11 18:31:21 -0700193 }
194
195 /**
Winson Chung655332c2016-10-31 13:14:28 -0700196 * Sets the Ime state and height.
197 */
198 void setAdjustedForIme(boolean adjustedForIme, int imeHeight) {
Winson Chung2a35e6d2018-01-13 14:27:50 -0800199 // Due to the order of callbacks from the system, we may receive an ime height even when
200 // {@param adjustedForIme} is false, and also a zero height when {@param adjustedForIme}
201 // is true. Instead, ensure that the ime state changes with the height and if the ime is
202 // showing, then the height is non-zero.
203 final boolean imeShowing = adjustedForIme && imeHeight > 0;
204 imeHeight = imeShowing ? imeHeight : 0;
205 if (imeShowing == mIsImeShowing && imeHeight == mImeHeight) {
Winson Chung655332c2016-10-31 13:14:28 -0700206 return;
207 }
208
Winson Chung2a35e6d2018-01-13 14:27:50 -0800209 mIsImeShowing = imeShowing;
Winson Chung655332c2016-10-31 13:14:28 -0700210 mImeHeight = imeHeight;
Winson Chung2a35e6d2018-01-13 14:27:50 -0800211 notifyImeVisibilityChanged(imeShowing, imeHeight);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800212 notifyMovementBoundsChanged(true /* fromImeAdjustment */);
Tracy Zhou43513082018-03-08 21:58:36 -0800213 }
214
215 /**
Winson Chung2a82fe52017-02-02 14:43:34 -0800216 * Sets the current aspect ratio.
217 */
218 void setAspectRatio(float aspectRatio) {
219 if (Float.compare(mAspectRatio, aspectRatio) != 0) {
220 mAspectRatio = aspectRatio;
Hongwei Wang43a752b2019-09-17 20:20:30 +0000221 notifyAspectRatioChanged(aspectRatio);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800222 notifyMovementBoundsChanged(false /* fromImeAdjustment */);
Winson Chung655332c2016-10-31 13:14:28 -0700223 }
224 }
225
226 /**
Winson Chungc95ff842017-03-21 10:20:20 -0700227 * @return the current aspect ratio.
228 */
229 float getAspectRatio() {
230 return mAspectRatio;
231 }
232
233 /**
Winson Chunga29eb982016-12-14 12:01:27 -0800234 * Sets the current set of actions.
235 */
236 void setActions(List<RemoteAction> actions) {
237 mActions.clear();
Winson Chungc2baac02017-01-11 13:34:47 -0800238 if (actions != null) {
239 mActions.addAll(actions);
240 }
Winson Chunga29eb982016-12-14 12:01:27 -0800241 notifyActionsChanged(mActions);
242 }
243
244 /**
Winson Chung2a82fe52017-02-02 14:43:34 -0800245 * Notifies listeners that the PIP needs to be adjusted for the IME.
Winson Chung655332c2016-10-31 13:14:28 -0700246 */
Winson Chung2a82fe52017-02-02 14:43:34 -0800247 private void notifyImeVisibilityChanged(boolean imeVisible, int imeHeight) {
Winson Chung655332c2016-10-31 13:14:28 -0700248 if (mPinnedStackListener != null) {
249 try {
Winson Chung2a82fe52017-02-02 14:43:34 -0800250 mPinnedStackListener.onImeVisibilityChanged(imeVisible, imeHeight);
Winson Chung655332c2016-10-31 13:14:28 -0700251 } catch (RemoteException e) {
252 Slog.e(TAG_WM, "Error delivering bounds changed event.", e);
253 }
254 }
255 }
256
Hongwei Wang43a752b2019-09-17 20:20:30 +0000257 private void notifyAspectRatioChanged(float aspectRatio) {
258 if (mPinnedStackListener == null) return;
259 try {
260 mPinnedStackListener.onAspectRatioChanged(aspectRatio);
261 } catch (RemoteException e) {
262 Slog.e(TAG_WM, "Error delivering aspect ratio changed event.", e);
263 }
264 }
265
Winson Chung655332c2016-10-31 13:14:28 -0700266 /**
Winson Chunga29eb982016-12-14 12:01:27 -0800267 * Notifies listeners that the PIP actions have changed.
268 */
269 private void notifyActionsChanged(List<RemoteAction> actions) {
270 if (mPinnedStackListener != null) {
271 try {
272 mPinnedStackListener.onActionsChanged(new ParceledListSlice(actions));
273 } catch (RemoteException e) {
274 Slog.e(TAG_WM, "Error delivering actions changed event.", e);
275 }
276 }
277 }
278
279 /**
Winson Chung2a82fe52017-02-02 14:43:34 -0800280 * Notifies listeners that the PIP movement bounds have changed.
281 */
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800282 private void notifyMovementBoundsChanged(boolean fromImeAdjustment) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700283 synchronized (mService.mGlobalLock) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700284 if (mPinnedStackListener == null) {
285 return;
286 }
287 try {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000288 final Rect animatingBounds = new Rect();
Wale Ogunwale734b8962020-01-21 12:17:42 -0800289 final ActivityStack pinnedStack = mDisplayContent.getRootPinnedTask();
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700290 if (pinnedStack != null) {
291 pinnedStack.getAnimationOrCurrentBounds(animatingBounds);
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700292 }
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800293 mPinnedStackListener.onMovementBoundsChanged(animatingBounds, fromImeAdjustment);
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700294 } catch (RemoteException e) {
295 Slog.e(TAG_WM, "Error delivering actions changed event.", e);
Winson Chung2a82fe52017-02-02 14:43:34 -0800296 }
297 }
298 }
299
300 /**
Hongwei Wang43a752b2019-09-17 20:20:30 +0000301 * Notifies listeners that the PIP animation is about to happen.
302 */
303 private void notifyDisplayInfoChanged(DisplayInfo displayInfo) {
304 if (mPinnedStackListener == null) return;
305 try {
306 mPinnedStackListener.onDisplayInfoChanged(displayInfo);
307 } catch (RemoteException e) {
308 Slog.e(TAG_WM, "Error delivering DisplayInfo changed event.", e);
309 }
310 }
311
Winson Chung655332c2016-10-31 13:14:28 -0700312 void dump(String prefix, PrintWriter pw) {
313 pw.println(prefix + "PinnedStackController");
Winson Chung655332c2016-10-31 13:14:28 -0700314 pw.println(prefix + " mIsImeShowing=" + mIsImeShowing);
Tracy Zhou43513082018-03-08 21:58:36 -0800315 pw.println(prefix + " mImeHeight=" + mImeHeight);
Winson Chung95b7b622018-10-05 15:00:01 -0700316 pw.println(prefix + " mAspectRatio=" + mAspectRatio);
317 pw.println(prefix + " mMinAspectRatio=" + mMinAspectRatio);
318 pw.println(prefix + " mMaxAspectRatio=" + mMaxAspectRatio);
Winson Chunga29eb982016-12-14 12:01:27 -0800319 if (mActions.isEmpty()) {
320 pw.println(prefix + " mActions=[]");
321 } else {
322 pw.println(prefix + " mActions=[");
323 for (int i = 0; i < mActions.size(); i++) {
324 RemoteAction action = mActions.get(i);
325 pw.print(prefix + " Action[" + i + "]: ");
326 action.dump("", pw);
327 }
328 pw.println(prefix + " ]");
329 }
Winson Chung95b7b622018-10-05 15:00:01 -0700330 pw.println(prefix + " mDisplayInfo=" + mDisplayInfo);
Winson Chung655332c2016-10-31 13:14:28 -0700331 }
Winson Chung655332c2016-10-31 13:14:28 -0700332}