blob: ba23258770753e4bc45efc7af8dd74be52c4067c [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
Wale Ogunwale68278562017-09-23 17:13:55 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
Wale Ogunwaleb62139d2017-09-20 15:37:35 -070020import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Winson Chung655332c2016-10-31 13:14:28 -070021import static android.util.TypedValue.COMPLEX_UNIT_DIP;
22
Yi Jin6c6e9ca2018-03-20 16:53:35 -070023import static com.android.server.wm.PinnedStackControllerProto.DEFAULT_BOUNDS;
24import static com.android.server.wm.PinnedStackControllerProto.MOVEMENT_BOUNDS;
Evan Rosky35630df2018-10-31 10:22:08 -070025import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
26import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Winson Chung655332c2016-10-31 13:14:28 -070027
Winson Chunga29eb982016-12-14 12:01:27 -080028import android.app.RemoteAction;
29import android.content.pm.ParceledListSlice;
Winson Chung655332c2016-10-31 13:14:28 -070030import android.content.res.Resources;
31import android.graphics.Point;
32import android.graphics.Rect;
33import android.os.Handler;
34import android.os.IBinder;
35import android.os.RemoteException;
36import android.util.DisplayMetrics;
37import android.util.Log;
38import android.util.Size;
39import android.util.Slog;
40import android.util.TypedValue;
Steven Timotiusaf03df62017-07-18 16:56:43 -070041import android.util.proto.ProtoOutputStream;
Winson Chung14fefc22016-11-02 10:02:29 -070042import android.view.DisplayInfo;
Winson Chung655332c2016-10-31 13:14:28 -070043import android.view.Gravity;
44import android.view.IPinnedStackController;
45import android.view.IPinnedStackListener;
46
Winson Chung655332c2016-10-31 13:14:28 -070047import com.android.internal.policy.PipSnapAlgorithm;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070048import com.android.server.UiThread;
Winson Chung655332c2016-10-31 13:14:28 -070049
50import java.io.PrintWriter;
Winson Chunge55c0192017-08-24 14:50:48 -070051import java.lang.ref.WeakReference;
Winson Chunga29eb982016-12-14 12:01:27 -080052import java.util.ArrayList;
53import java.util.List;
Winson Chung655332c2016-10-31 13:14:28 -070054
55/**
Winson Chung2a82fe52017-02-02 14:43:34 -080056 * Holds the common state of the pinned stack between the system and SystemUI. If SystemUI ever
57 * needs to be restarted, it will be notified with the last known state.
58 *
59 * Changes to the pinned stack also flow through this controller, and generally, the system only
60 * changes the pinned stack bounds through this controller in two ways:
61 *
62 * 1) When first entering PiP: the controller returns the valid bounds given, taking aspect ratio
63 * and IME state into account.
64 * 2) When rotating the device: the controller calculates the new bounds in the new orientation,
65 * taking the minimized and IME state into account. In this case, we currently ignore the
66 * SystemUI adjustments (ie. expanded for menu, interaction, etc).
67 *
68 * Other changes in the system, including adjustment of IME, configuration change, and more are
69 * handled by SystemUI (similar to the docked stack divider).
Winson Chung655332c2016-10-31 13:14:28 -070070 */
71class PinnedStackController {
72
73 private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;
74
Winson Chunge55c0192017-08-24 14:50:48 -070075 public static final float INVALID_SNAP_FRACTION = -1f;
Winson Chung655332c2016-10-31 13:14:28 -070076 private final WindowManagerService mService;
77 private final DisplayContent mDisplayContent;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070078 private final Handler mHandler = UiThread.getHandler();
Winson Chung655332c2016-10-31 13:14:28 -070079
80 private IPinnedStackListener mPinnedStackListener;
81 private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
82 new PinnedStackListenerDeathHandler();
83
84 private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
85 private final PipSnapAlgorithm mSnapAlgorithm;
Winson Chung655332c2016-10-31 13:14:28 -070086
87 // States that affect how the PIP can be manipulated
Winson Chungfa7053782016-11-08 15:45:10 -080088 private boolean mIsMinimized;
Winson Chung655332c2016-10-31 13:14:28 -070089 private boolean mIsImeShowing;
90 private int mImeHeight;
Tracy Zhou43513082018-03-08 21:58:36 -080091 private boolean mIsShelfShowing;
92 private int mShelfHeight;
Winson Chung655332c2016-10-31 13:14:28 -070093
Winson Chung2a82fe52017-02-02 14:43:34 -080094 // The set of actions and aspect-ratio for the that are currently allowed on the PiP activity
Winson Chunga29eb982016-12-14 12:01:27 -080095 private ArrayList<RemoteAction> mActions = new ArrayList<>();
Winson Chung2a82fe52017-02-02 14:43:34 -080096 private float mAspectRatio = -1f;
Winson Chunga29eb982016-12-14 12:01:27 -080097
Winson Chung14fefc22016-11-02 10:02:29 -070098 // Used to calculate stack bounds across rotations
99 private final DisplayInfo mDisplayInfo = new DisplayInfo();
Winson Chung114aeea2017-01-09 16:08:07 -0800100 private final Rect mStableInsets = new Rect();
Winson Chung14fefc22016-11-02 10:02:29 -0700101
Winson Chung655332c2016-10-31 13:14:28 -0700102 // The size and position information that describes where the pinned stack will go by default.
Winson Chunga71febe2017-05-22 11:14:22 -0700103 private int mDefaultMinSize;
Winson Chung655332c2016-10-31 13:14:28 -0700104 private int mDefaultStackGravity;
Mady Mellora7f69742017-02-03 11:00:20 -0800105 private float mDefaultAspectRatio;
Winson Chung655332c2016-10-31 13:14:28 -0700106 private Point mScreenEdgeInsets;
Winson Chunga71febe2017-05-22 11:14:22 -0700107 private int mCurrentMinSize;
Winson Chunge55c0192017-08-24 14:50:48 -0700108 private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
109 private WeakReference<AppWindowToken> mLastPipActivity = null;
Winson Chung655332c2016-10-31 13:14:28 -0700110
Winson Chung2a82fe52017-02-02 14:43:34 -0800111 // The aspect ratio bounds of the PIP.
112 private float mMinAspectRatio;
113 private float mMaxAspectRatio;
114
Winson Chung655332c2016-10-31 13:14:28 -0700115 // Temp vars for calculation
116 private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
117 private final Rect mTmpInsets = new Rect();
Jorim Jaggiad5d2842016-11-01 18:22:53 -0700118 private final Rect mTmpRect = new Rect();
Winson Chung34a07f42017-03-10 18:06:25 -0800119 private final Rect mTmpAnimatingBoundsRect = new Rect();
Winson Chungf1f72f62017-02-14 17:15:48 -0800120 private final Point mTmpDisplaySize = new Point();
Winson Chung655332c2016-10-31 13:14:28 -0700121
Winson Chunge55c0192017-08-24 14:50:48 -0700122
Winson Chung655332c2016-10-31 13:14:28 -0700123 /**
124 * The callback object passed to listeners for them to notify the controller of state changes.
125 */
126 private class PinnedStackControllerCallback extends IPinnedStackController.Stub {
127
128 @Override
Winson Chungfa7053782016-11-08 15:45:10 -0800129 public void setIsMinimized(final boolean isMinimized) {
130 mHandler.post(() -> {
131 mIsMinimized = isMinimized;
Mady Mellor3b10dcd2017-01-23 10:08:35 -0800132 mSnapAlgorithm.setMinimized(isMinimized);
Winson Chungfa7053782016-11-08 15:45:10 -0800133 });
134 }
Winson Chungef4dc812017-04-11 13:31:44 -0700135
136 @Override
Winson Chunga71febe2017-05-22 11:14:22 -0700137 public void setMinEdgeSize(int minEdgeSize) {
138 mHandler.post(() -> {
139 mCurrentMinSize = Math.max(mDefaultMinSize, minEdgeSize);
140 });
141 }
142
143 @Override
Winson Chungef4dc812017-04-11 13:31:44 -0700144 public int getDisplayRotation() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700145 synchronized (mService.mGlobalLock) {
Winson Chungef4dc812017-04-11 13:31:44 -0700146 return mDisplayInfo.rotation;
147 }
148 }
Winson Chung655332c2016-10-31 13:14:28 -0700149 }
150
151 /**
152 * Handler for the case where the listener dies.
153 */
154 private class PinnedStackListenerDeathHandler implements IBinder.DeathRecipient {
155
156 @Override
157 public void binderDied() {
158 // Clean up the state if the listener dies
Winson Chung397967f2017-11-01 16:21:35 -0700159 if (mPinnedStackListener != null) {
160 mPinnedStackListener.asBinder().unlinkToDeath(mPinnedStackListenerDeathHandler, 0);
161 }
Winson Chung655332c2016-10-31 13:14:28 -0700162 mPinnedStackListener = null;
163 }
164 }
165
166 PinnedStackController(WindowManagerService service, DisplayContent displayContent) {
167 mService = service;
168 mDisplayContent = displayContent;
169 mSnapAlgorithm = new PipSnapAlgorithm(service.mContext);
Winson Chung14fefc22016-11-02 10:02:29 -0700170 mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
Winson Chung655332c2016-10-31 13:14:28 -0700171 reloadResources();
Winson Chung401f78e2017-06-16 10:52:40 -0700172 // Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
173 // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
174 // triggers a configuration change and the resources to be reloaded.
175 mAspectRatio = mDefaultAspectRatio;
Winson Chung655332c2016-10-31 13:14:28 -0700176 }
177
178 void onConfigurationChanged() {
179 reloadResources();
180 }
181
182 /**
183 * Reloads all the resources for the current configuration.
184 */
Wale Ogunwale027f4752017-05-12 10:37:16 -0700185 private void reloadResources() {
Winson Chung655332c2016-10-31 13:14:28 -0700186 final Resources res = mService.mContext.getResources();
Winson Chunga71febe2017-05-22 11:14:22 -0700187 mDefaultMinSize = res.getDimensionPixelSize(
Mady Mellora7f69742017-02-03 11:00:20 -0800188 com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
Winson Chunga71febe2017-05-22 11:14:22 -0700189 mCurrentMinSize = mDefaultMinSize;
Mady Mellora7f69742017-02-03 11:00:20 -0800190 mDefaultAspectRatio = res.getFloat(
191 com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
Wale Ogunwale027f4752017-05-12 10:37:16 -0700192 final String screenEdgeInsetsDpString = res.getString(
193 com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
194 final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
195 ? Size.parseSize(screenEdgeInsetsDpString)
196 : null;
Winson Chung655332c2016-10-31 13:14:28 -0700197 mDefaultStackGravity = res.getInteger(
198 com.android.internal.R.integer.config_defaultPictureInPictureGravity);
199 mDisplayContent.getDisplay().getRealMetrics(mTmpMetrics);
Wale Ogunwale027f4752017-05-12 10:37:16 -0700200 mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
201 : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), mTmpMetrics),
202 dpToPx(screenEdgeInsetsDp.getHeight(), mTmpMetrics));
Winson Chung2a82fe52017-02-02 14:43:34 -0800203 mMinAspectRatio = res.getFloat(
204 com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
205 mMaxAspectRatio = res.getFloat(
206 com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
Winson Chung655332c2016-10-31 13:14:28 -0700207 }
208
209 /**
210 * Registers a pinned stack listener.
211 */
212 void registerPinnedStackListener(IPinnedStackListener listener) {
213 try {
214 listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
215 listener.onListenerRegistered(mCallbacks);
216 mPinnedStackListener = listener;
Winson Chung2a82fe52017-02-02 14:43:34 -0800217 notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
Tracy Zhou43513082018-03-08 21:58:36 -0800218 notifyShelfVisibilityChanged(mIsShelfShowing, mShelfHeight);
Winson Chung2a82fe52017-02-02 14:43:34 -0800219 // The movement bounds notification needs to be sent before the minimized state, since
220 // SystemUI may use the bounds to retore the minimized position
Tracy Zhou43513082018-03-08 21:58:36 -0800221 notifyMovementBoundsChanged(false /* fromImeAdjustment */,
222 false /* fromShelfAdjustment */);
Winson Chunga29eb982016-12-14 12:01:27 -0800223 notifyActionsChanged(mActions);
Winson Chung2a82fe52017-02-02 14:43:34 -0800224 notifyMinimizeChanged(mIsMinimized);
Winson Chung655332c2016-10-31 13:14:28 -0700225 } catch (RemoteException e) {
226 Log.e(TAG, "Failed to register pinned stack listener", e);
227 }
228 }
229
230 /**
Winson Chung2a82fe52017-02-02 14:43:34 -0800231 * @return whether the given {@param aspectRatio} is valid.
232 */
233 public boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
Winson Chungbd041962017-03-06 15:07:25 -0800234 return Float.compare(mMinAspectRatio, aspectRatio) <= 0 &&
235 Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
Winson Chung2a82fe52017-02-02 14:43:34 -0800236 }
237
238 /**
Winson Chung84a38342016-11-08 16:15:10 -0800239 * Returns the current bounds (or the default bounds if there are no current bounds) with the
240 * specified aspect ratio.
241 */
Winson Chunga71febe2017-05-22 11:14:22 -0700242 Rect transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
243 boolean useCurrentMinEdgeSize) {
Mady Mellora7f69742017-02-03 11:00:20 -0800244 // Save the snap fraction, calculate the aspect ratio based on screen size
Winson Chung84a38342016-11-08 16:15:10 -0800245 final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
246 getMovementBounds(stackBounds));
Winson Chunga71febe2017-05-22 11:14:22 -0700247
248 final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize;
249 final Size size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize,
250 mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
Mady Mellora7f69742017-02-03 11:00:20 -0800251 final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
252 final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
253 stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
Winson Chung84a38342016-11-08 16:15:10 -0800254 mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
Winson Chungf1f72f62017-02-14 17:15:48 -0800255 if (mIsMinimized) {
256 applyMinimizedOffset(stackBounds, getMovementBounds(stackBounds));
257 }
Winson Chung84a38342016-11-08 16:15:10 -0800258 return stackBounds;
259 }
260
261 /**
Winson Chunge55c0192017-08-24 14:50:48 -0700262 * Saves the current snap fraction for re-entry of the current activity into PiP.
263 */
264 void saveReentrySnapFraction(final AppWindowToken token, final Rect stackBounds) {
265 mReentrySnapFraction = getSnapFraction(stackBounds);
266 mLastPipActivity = new WeakReference<>(token);
267 }
268
269 /**
270 * Resets the last saved snap fraction so that the default bounds will be returned.
271 */
272 void resetReentrySnapFraction(AppWindowToken token) {
273 if (mLastPipActivity != null && mLastPipActivity.get() == token) {
274 mReentrySnapFraction = INVALID_SNAP_FRACTION;
275 mLastPipActivity = null;
276 }
277 }
278
279 /**
Winson Chung655332c2016-10-31 13:14:28 -0700280 * @return the default bounds to show the PIP when there is no active PIP.
281 */
Winson Chunge55c0192017-08-24 14:50:48 -0700282 Rect getDefaultOrLastSavedBounds() {
283 return getDefaultBounds(mReentrySnapFraction);
284 }
285
286 /**
287 * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it
288 * will apply the default bounds to the provided snap fraction.
289 */
290 Rect getDefaultBounds(float snapFraction) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700291 synchronized (mService.mGlobalLock) {
Winson Chungef4dc812017-04-11 13:31:44 -0700292 final Rect insetBounds = new Rect();
293 getInsetBounds(insetBounds);
Winson Chung655332c2016-10-31 13:14:28 -0700294
Winson Chungef4dc812017-04-11 13:31:44 -0700295 final Rect defaultBounds = new Rect();
Winson Chunga71febe2017-05-22 11:14:22 -0700296 final Size size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
297 mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
Winson Chunge55c0192017-08-24 14:50:48 -0700298 if (snapFraction != INVALID_SNAP_FRACTION) {
299 defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
300 final Rect movementBounds = getMovementBounds(defaultBounds);
301 mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
302 } else {
303 Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
Tracy Zhou43513082018-03-08 21:58:36 -0800304 0, Math.max(mIsImeShowing ? mImeHeight : 0,
305 mIsShelfShowing ? mShelfHeight : 0),
306 defaultBounds);
Winson Chunge55c0192017-08-24 14:50:48 -0700307 }
Winson Chungef4dc812017-04-11 13:31:44 -0700308 return defaultBounds;
309 }
Winson Chung655332c2016-10-31 13:14:28 -0700310 }
311
312 /**
Winson Chung32c566f2017-04-11 18:31:21 -0700313 * In the case where the display rotation is changed but there is no stack, we can't depend on
314 * onTaskStackBoundsChanged() to be called. But we still should update our known display info
315 * with the new state so that we can update SystemUI.
316 */
Evan Rosky39b6f232018-10-30 18:35:41 -0700317 synchronized void onDisplayInfoChanged(DisplayInfo displayInfo) {
318 mDisplayInfo.copyFrom(displayInfo);
Tracy Zhou43513082018-03-08 21:58:36 -0800319 notifyMovementBoundsChanged(false /* fromImeAdjustment */, false /* fromShelfAdjustment */);
Winson Chung32c566f2017-04-11 18:31:21 -0700320 }
321
322 /**
Winson Chung47f2bf62017-02-16 18:58:12 -0800323 * Updates the display info, calculating and returning the new stack and movement bounds in the
324 * new orientation of the device if necessary.
Winson Chung655332c2016-10-31 13:14:28 -0700325 */
Winson Chung19953ca2017-04-11 11:19:23 -0700326 boolean onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700327 synchronized (mService.mGlobalLock) {
Winson Chungef4dc812017-04-11 13:31:44 -0700328 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
329 if (mDisplayInfo.equals(displayInfo)) {
330 // We are already in the right orientation, ignore
331 outBounds.setEmpty();
332 return false;
333 } else if (targetBounds.isEmpty()) {
334 // The stack is null, we are just initializing the stack, so just store the display
335 // info and ignore
336 mDisplayInfo.copyFrom(displayInfo);
337 outBounds.setEmpty();
338 return false;
339 }
340
341 mTmpRect.set(targetBounds);
342 final Rect postChangeStackBounds = mTmpRect;
343
344 // Calculate the snap fraction of the current stack along the old movement bounds
Winson Chunge55c0192017-08-24 14:50:48 -0700345 final float snapFraction = getSnapFraction(postChangeStackBounds);
Winson Chung19953ca2017-04-11 11:19:23 -0700346 mDisplayInfo.copyFrom(displayInfo);
Winson Chungef4dc812017-04-11 13:31:44 -0700347
348 // Calculate the stack bounds in the new orientation to the same same fraction along the
349 // rotated movement bounds.
350 final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
Tracy Zhou43513082018-03-08 21:58:36 -0800351 false /* adjustForIme */, false /* adjustForShelf */);
Winson Chungef4dc812017-04-11 13:31:44 -0700352 mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
353 snapFraction);
354 if (mIsMinimized) {
355 applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
356 }
357
Tracy Zhou43513082018-03-08 21:58:36 -0800358 notifyMovementBoundsChanged(false /* fromImeAdjustment */,
359 false /* fromShelfAdjustment */);
Winson Chungef4dc812017-04-11 13:31:44 -0700360
361 outBounds.set(postChangeStackBounds);
362 return true;
Winson Chung14fefc22016-11-02 10:02:29 -0700363 }
Winson Chung655332c2016-10-31 13:14:28 -0700364 }
365
366 /**
367 * Sets the Ime state and height.
368 */
369 void setAdjustedForIme(boolean adjustedForIme, int imeHeight) {
Winson Chung2a35e6d2018-01-13 14:27:50 -0800370 // Due to the order of callbacks from the system, we may receive an ime height even when
371 // {@param adjustedForIme} is false, and also a zero height when {@param adjustedForIme}
372 // is true. Instead, ensure that the ime state changes with the height and if the ime is
373 // showing, then the height is non-zero.
374 final boolean imeShowing = adjustedForIme && imeHeight > 0;
375 imeHeight = imeShowing ? imeHeight : 0;
376 if (imeShowing == mIsImeShowing && imeHeight == mImeHeight) {
Winson Chung655332c2016-10-31 13:14:28 -0700377 return;
378 }
379
Winson Chung2a35e6d2018-01-13 14:27:50 -0800380 mIsImeShowing = imeShowing;
Winson Chung655332c2016-10-31 13:14:28 -0700381 mImeHeight = imeHeight;
Winson Chung2a35e6d2018-01-13 14:27:50 -0800382 notifyImeVisibilityChanged(imeShowing, imeHeight);
Tracy Zhou43513082018-03-08 21:58:36 -0800383 notifyMovementBoundsChanged(true /* fromImeAdjustment */, false /* fromShelfAdjustment */);
384 }
385
386 /**
387 * Sets the shelf state and height.
388 */
389 void setAdjustedForShelf(boolean adjustedForShelf, int shelfHeight) {
390 final boolean shelfShowing = adjustedForShelf && shelfHeight > 0;
391 if (shelfShowing == mIsShelfShowing && shelfHeight == mShelfHeight) {
392 return;
393 }
394
395 mIsShelfShowing = shelfShowing;
396 mShelfHeight = shelfHeight;
397 notifyShelfVisibilityChanged(shelfShowing, shelfHeight);
398 notifyMovementBoundsChanged(false /* fromImeAdjustment */, true /* fromShelfAdjustment */);
Winson Chung2a82fe52017-02-02 14:43:34 -0800399 }
400
401 /**
402 * Sets the current aspect ratio.
403 */
404 void setAspectRatio(float aspectRatio) {
405 if (Float.compare(mAspectRatio, aspectRatio) != 0) {
406 mAspectRatio = aspectRatio;
Tracy Zhou43513082018-03-08 21:58:36 -0800407 notifyMovementBoundsChanged(false /* fromImeAdjustment */,
408 false /* fromShelfAdjustment */);
Winson Chung655332c2016-10-31 13:14:28 -0700409 }
410 }
411
412 /**
Winson Chungc95ff842017-03-21 10:20:20 -0700413 * @return the current aspect ratio.
414 */
415 float getAspectRatio() {
416 return mAspectRatio;
417 }
418
419 /**
Winson Chunga29eb982016-12-14 12:01:27 -0800420 * Sets the current set of actions.
421 */
422 void setActions(List<RemoteAction> actions) {
423 mActions.clear();
Winson Chungc2baac02017-01-11 13:34:47 -0800424 if (actions != null) {
425 mActions.addAll(actions);
426 }
Winson Chunga29eb982016-12-14 12:01:27 -0800427 notifyActionsChanged(mActions);
428 }
429
430 /**
Winson Chung2a82fe52017-02-02 14:43:34 -0800431 * Notifies listeners that the PIP needs to be adjusted for the IME.
Winson Chung655332c2016-10-31 13:14:28 -0700432 */
Winson Chung2a82fe52017-02-02 14:43:34 -0800433 private void notifyImeVisibilityChanged(boolean imeVisible, int imeHeight) {
Winson Chung655332c2016-10-31 13:14:28 -0700434 if (mPinnedStackListener != null) {
435 try {
Winson Chung2a82fe52017-02-02 14:43:34 -0800436 mPinnedStackListener.onImeVisibilityChanged(imeVisible, imeHeight);
Winson Chung655332c2016-10-31 13:14:28 -0700437 } catch (RemoteException e) {
438 Slog.e(TAG_WM, "Error delivering bounds changed event.", e);
439 }
440 }
441 }
442
Tracy Zhou43513082018-03-08 21:58:36 -0800443 private void notifyShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
444 if (mPinnedStackListener != null) {
445 try {
446 mPinnedStackListener.onShelfVisibilityChanged(shelfVisible, shelfHeight);
447 } catch (RemoteException e) {
448 Slog.e(TAG_WM, "Error delivering bounds changed event.", e);
449 }
450 }
451 }
452
Winson Chung655332c2016-10-31 13:14:28 -0700453 /**
Winson Chunga29eb982016-12-14 12:01:27 -0800454 * Notifies listeners that the PIP minimized state has changed.
455 */
456 private void notifyMinimizeChanged(boolean isMinimized) {
457 if (mPinnedStackListener != null) {
458 try {
459 mPinnedStackListener.onMinimizedStateChanged(isMinimized);
460 } catch (RemoteException e) {
461 Slog.e(TAG_WM, "Error delivering minimize changed event.", e);
462 }
463 }
464 }
465
466 /**
Winson Chunga29eb982016-12-14 12:01:27 -0800467 * Notifies listeners that the PIP actions have changed.
468 */
469 private void notifyActionsChanged(List<RemoteAction> actions) {
470 if (mPinnedStackListener != null) {
471 try {
472 mPinnedStackListener.onActionsChanged(new ParceledListSlice(actions));
473 } catch (RemoteException e) {
474 Slog.e(TAG_WM, "Error delivering actions changed event.", e);
475 }
476 }
477 }
478
479 /**
Winson Chung2a82fe52017-02-02 14:43:34 -0800480 * Notifies listeners that the PIP movement bounds have changed.
481 */
Tracy Zhou43513082018-03-08 21:58:36 -0800482 private void notifyMovementBoundsChanged(boolean fromImeAdjustment,
483 boolean fromShelfAdjustment) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700484 synchronized (mService.mGlobalLock) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700485 if (mPinnedStackListener == null) {
486 return;
487 }
488 try {
489 final Rect insetBounds = new Rect();
490 getInsetBounds(insetBounds);
Winson Chunge55c0192017-08-24 14:50:48 -0700491 final Rect normalBounds = getDefaultBounds(INVALID_SNAP_FRACTION);
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700492 if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
493 transformBoundsToAspectRatio(normalBounds, mAspectRatio,
494 false /* useCurrentMinEdgeSize */);
Winson Chung2a82fe52017-02-02 14:43:34 -0800495 }
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700496 final Rect animatingBounds = mTmpAnimatingBoundsRect;
Wale Ogunwale61911492017-10-11 08:50:50 -0700497 final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700498 if (pinnedStack != null) {
499 pinnedStack.getAnimationOrCurrentBounds(animatingBounds);
500 } else {
501 animatingBounds.set(normalBounds);
502 }
503 mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds,
Tracy Zhou43513082018-03-08 21:58:36 -0800504 animatingBounds, fromImeAdjustment, fromShelfAdjustment,
505 mDisplayInfo.rotation);
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700506 } catch (RemoteException e) {
507 Slog.e(TAG_WM, "Error delivering actions changed event.", e);
Winson Chung2a82fe52017-02-02 14:43:34 -0800508 }
509 }
510 }
511
512 /**
Winson Chung655332c2016-10-31 13:14:28 -0700513 * @return the bounds on the screen that the PIP can be visible in.
514 */
Winson Chung14fefc22016-11-02 10:02:29 -0700515 private void getInsetBounds(Rect outRect) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700516 synchronized (mService.mGlobalLock) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800517 mDisplayContent.getDisplayPolicy().getStableInsetsLw(mDisplayInfo.rotation,
518 mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
519 mDisplayInfo.displayCutout, mTmpInsets);
Winson Chungef4dc812017-04-11 13:31:44 -0700520 outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y,
521 mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x,
522 mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y);
523 }
Winson Chung655332c2016-10-31 13:14:28 -0700524 }
525
526 /**
Winson Chung55893332017-02-17 17:13:10 -0800527 * @return the movement bounds for the given {@param stackBounds} and the current state of the
528 * controller.
529 */
530 private Rect getMovementBounds(Rect stackBounds) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700531 synchronized (mService.mGlobalLock) {
Tracy Zhou43513082018-03-08 21:58:36 -0800532 return getMovementBounds(stackBounds, true /* adjustForIme */,
533 true /* adjustForShelf */);
Winson Chungef4dc812017-04-11 13:31:44 -0700534 }
Winson Chung55893332017-02-17 17:13:10 -0800535 }
536
537 /**
538 * @return the movement bounds for the given {@param stackBounds} and the current state of the
539 * controller.
540 */
Tracy Zhou43513082018-03-08 21:58:36 -0800541 private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme, boolean adjustForShelf) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700542 synchronized (mService.mGlobalLock) {
Winson Chungef4dc812017-04-11 13:31:44 -0700543 final Rect movementBounds = new Rect();
544 getInsetBounds(movementBounds);
Winson Chung55893332017-02-17 17:13:10 -0800545
Winson Chungef4dc812017-04-11 13:31:44 -0700546 // Apply the movement bounds adjustments based on the current state
547 mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
Tracy Zhou43513082018-03-08 21:58:36 -0800548 Math.max((adjustForIme && mIsImeShowing) ? mImeHeight : 0,
549 (adjustForShelf && mIsShelfShowing) ? mShelfHeight : 0));
Winson Chungef4dc812017-04-11 13:31:44 -0700550 return movementBounds;
551 }
Winson Chung55893332017-02-17 17:13:10 -0800552 }
553
554 /**
Winson Chungf1f72f62017-02-14 17:15:48 -0800555 * Applies the minimized offsets to the given stack bounds.
556 */
557 private void applyMinimizedOffset(Rect stackBounds, Rect movementBounds) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700558 synchronized (mService.mGlobalLock) {
Winson Chungef4dc812017-04-11 13:31:44 -0700559 mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
560 mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets);
561 mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize,
562 mStableInsets);
563 }
Winson Chungf1f72f62017-02-14 17:15:48 -0800564 }
565
566 /**
Winson Chunge55c0192017-08-24 14:50:48 -0700567 * @return the default snap fraction to apply instead of the default gravity when calculating
568 * the default stack bounds when first entering PiP.
569 */
570 private float getSnapFraction(Rect stackBounds) {
571 return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
572 }
573
574 /**
Winson Chung655332c2016-10-31 13:14:28 -0700575 * @return the pixels for a given dp value.
576 */
577 private int dpToPx(float dpValue, DisplayMetrics dm) {
578 return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
579 }
580
581 void dump(String prefix, PrintWriter pw) {
582 pw.println(prefix + "PinnedStackController");
Winson Chunge55c0192017-08-24 14:50:48 -0700583 pw.print(prefix + " defaultBounds=");
584 getDefaultBounds(INVALID_SNAP_FRACTION).printShortString(pw);
Jorim Jaggiad5d2842016-11-01 18:22:53 -0700585 pw.println();
Winson Chung95b7b622018-10-05 15:00:01 -0700586 pw.println(prefix + " mDefaultMinSize=" + mDefaultMinSize);
587 pw.println(prefix + " mDefaultStackGravity=" + mDefaultStackGravity);
588 pw.println(prefix + " mDefaultAspectRatio=" + mDefaultAspectRatio);
Wale Ogunwale68278562017-09-23 17:13:55 -0700589 mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
Jorim Jaggiad5d2842016-11-01 18:22:53 -0700590 pw.print(prefix + " movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
591 pw.println();
Winson Chung655332c2016-10-31 13:14:28 -0700592 pw.println(prefix + " mIsImeShowing=" + mIsImeShowing);
Tracy Zhou43513082018-03-08 21:58:36 -0800593 pw.println(prefix + " mImeHeight=" + mImeHeight);
594 pw.println(prefix + " mIsShelfShowing=" + mIsShelfShowing);
595 pw.println(prefix + " mShelfHeight=" + mShelfHeight);
Winson Chung8efa1652018-06-06 09:34:23 -0700596 pw.println(prefix + " mReentrySnapFraction=" + mReentrySnapFraction);
Winson Chungfa7053782016-11-08 15:45:10 -0800597 pw.println(prefix + " mIsMinimized=" + mIsMinimized);
Winson Chung95b7b622018-10-05 15:00:01 -0700598 pw.println(prefix + " mAspectRatio=" + mAspectRatio);
599 pw.println(prefix + " mMinAspectRatio=" + mMinAspectRatio);
600 pw.println(prefix + " mMaxAspectRatio=" + mMaxAspectRatio);
Winson Chunga29eb982016-12-14 12:01:27 -0800601 if (mActions.isEmpty()) {
602 pw.println(prefix + " mActions=[]");
603 } else {
604 pw.println(prefix + " mActions=[");
605 for (int i = 0; i < mActions.size(); i++) {
606 RemoteAction action = mActions.get(i);
607 pw.print(prefix + " Action[" + i + "]: ");
608 action.dump("", pw);
609 }
610 pw.println(prefix + " ]");
611 }
Winson Chung95b7b622018-10-05 15:00:01 -0700612 pw.println(prefix + " mDisplayInfo=" + mDisplayInfo);
Winson Chung655332c2016-10-31 13:14:28 -0700613 }
Steven Timotiusaf03df62017-07-18 16:56:43 -0700614
615 void writeToProto(ProtoOutputStream proto, long fieldId) {
616 final long token = proto.start(fieldId);
Winson Chunge55c0192017-08-24 14:50:48 -0700617 getDefaultBounds(INVALID_SNAP_FRACTION).writeToProto(proto, DEFAULT_BOUNDS);
Wale Ogunwale68278562017-09-23 17:13:55 -0700618 mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
Steven Timotiusaf03df62017-07-18 16:56:43 -0700619 getMovementBounds(mTmpRect).writeToProto(proto, MOVEMENT_BOUNDS);
620 proto.end(token);
621 }
Winson Chung655332c2016-10-31 13:14:28 -0700622}