blob: 2bb58ddc5b387a0bb515e3838d6ca11af55fff5b [file] [log] [blame]
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001/*
2 * Copyright (C) 2018 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
Tiger Huang332793b2019-10-29 23:21:27 +080019import static android.view.InsetsState.ITYPE_IME;
20import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
21import static android.view.InsetsState.ITYPE_STATUS_BAR;
Jorim Jaggia2759b22019-01-24 13:21:40 +010022import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
23import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
Jorim Jaggi73f3e8a2019-01-14 13:06:23 +010024import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
Jorim Jaggia2759b22019-01-24 13:21:40 +010025import static android.view.ViewRootImpl.sNewInsetsMode;
Jorim Jaggi73f3e8a2019-01-14 13:06:23 +010026
Tiger Huang3f38f262019-12-18 21:08:40 +080027import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED;
28
Jorim Jaggif96c90a2018-09-26 16:55:15 +020029import android.annotation.NonNull;
30import android.annotation.Nullable;
Tarandeep Singh215929b2019-01-11 18:24:37 -080031import android.graphics.Point;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020032import android.graphics.Rect;
Jorim Jaggib6030952018-10-23 18:31:52 +020033import android.util.proto.ProtoOutputStream;
chaviw15ad49f2019-04-24 15:05:39 -070034import android.view.InsetsSource;
35import android.view.InsetsSourceControl;
Jorim Jaggie35c0592018-11-06 16:21:08 +010036import android.view.InsetsState;
Jorim Jaggib6030952018-10-23 18:31:52 +020037import android.view.SurfaceControl;
38import android.view.SurfaceControl.Transaction;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020039
40import com.android.internal.util.function.TriConsumer;
Jorim Jaggib6030952018-10-23 18:31:52 +020041import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
42
43import java.io.PrintWriter;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020044
45/**
46 * Controller for a specific inset source on the server. It's called provider as it provides the
47 * {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
48 */
49class InsetsSourceProvider {
50
Tarandeep Singh500a38f2019-09-26 13:36:40 -070051 protected final DisplayContent mDisplayContent;
52 protected final @NonNull InsetsSource mSource;
53 protected WindowState mWin;
54
Jorim Jaggif96c90a2018-09-26 16:55:15 +020055 private final Rect mTmpRect = new Rect();
Jorim Jaggib6030952018-10-23 18:31:52 +020056 private final InsetsStateController mStateController;
Jorim Jaggia12ea562019-01-07 17:47:47 +010057 private final InsetsSourceControl mFakeControl;
Jorim Jaggib6030952018-10-23 18:31:52 +020058 private @Nullable InsetsSourceControl mControl;
Jorim Jaggi28620472019-01-02 23:21:49 +010059 private @Nullable InsetsControlTarget mControlTarget;
Jorim Jaggia12ea562019-01-07 17:47:47 +010060 private @Nullable InsetsControlTarget mFakeControlTarget;
61
Jorim Jaggib6030952018-10-23 18:31:52 +020062 private @Nullable ControlAdapter mAdapter;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020063 private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider;
64
Jorim Jaggie35c0592018-11-06 16:21:08 +010065 /** The visibility override from the current controlling window. */
66 private boolean mClientVisible;
67
68 /**
69 * Whether the window is available and considered visible as in {@link WindowState#isVisible}.
70 */
71 private boolean mServerVisible;
72
Tiger Huang969c6082019-12-24 20:08:57 +080073 private boolean mSeamlessRotating;
74 private long mFinishSeamlessRotateFrameNumber = -1;
75
Jorim Jaggia2759b22019-01-24 13:21:40 +010076 private final boolean mControllable;
Jorim Jaggie35c0592018-11-06 16:21:08 +010077
Jorim Jaggib6030952018-10-23 18:31:52 +020078 InsetsSourceProvider(InsetsSource source, InsetsStateController stateController,
79 DisplayContent displayContent) {
Jorim Jaggid89efeb2019-01-22 17:48:34 +010080 mClientVisible = InsetsState.getDefaultVisibility(source.getType());
Jorim Jaggif96c90a2018-09-26 16:55:15 +020081 mSource = source;
Jorim Jaggib6030952018-10-23 18:31:52 +020082 mDisplayContent = displayContent;
83 mStateController = stateController;
Jorim Jaggia12ea562019-01-07 17:47:47 +010084 mFakeControl = new InsetsSourceControl(source.getType(), null /* leash */,
85 new Point());
Jorim Jaggia2759b22019-01-24 13:21:40 +010086
87 final int type = source.getType();
Tiger Huang332793b2019-10-29 23:21:27 +080088 if (type == ITYPE_STATUS_BAR || type == ITYPE_NAVIGATION_BAR) {
Jorim Jaggia2759b22019-01-24 13:21:40 +010089 mControllable = sNewInsetsMode == NEW_INSETS_MODE_FULL;
Tiger Huang332793b2019-10-29 23:21:27 +080090 } else if (type == ITYPE_IME) {
Jorim Jaggia2759b22019-01-24 13:21:40 +010091 mControllable = sNewInsetsMode >= NEW_INSETS_MODE_IME;
92 } else {
93 mControllable = false;
94 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +020095 }
96
97 InsetsSource getSource() {
98 return mSource;
99 }
100
101 /**
Jorim Jaggia2759b22019-01-24 13:21:40 +0100102 * @return Whether the current flag configuration allows to control this source.
103 */
104 boolean isControllable() {
105 return mControllable;
106 }
107
108 /**
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200109 * Updates the window that currently backs this source.
110 *
111 * @param win The window that links to this source.
112 * @param frameProvider Based on display frame state and the window, calculates the resulting
113 * frame that should be reported to clients.
114 */
115 void setWindow(@Nullable WindowState win,
116 @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) {
117 if (mWin != null) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100118 if (mControllable) {
119 mWin.setControllableInsetProvider(null);
120 }
Tarandeep Singh5d54e722019-08-15 13:33:12 -0700121 // The window may be animating such that we can hand out the leash to the control
122 // target. Revoke the leash by cancelling the animation to correct the state.
123 // TODO: Ideally, we should wait for the animation to finish so previous window can
124 // animate-out as new one animates-in.
125 mWin.cancelAnimation();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200126 }
127 mWin = win;
128 mFrameProvider = frameProvider;
129 if (win == null) {
Jorim Jaggie35c0592018-11-06 16:21:08 +0100130 setServerVisible(false);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200131 mSource.setFrame(new Rect());
Jorim Jaggi4e04eb22020-01-09 16:42:14 +0100132 mSource.setVisibleFrame(null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100133 } else if (mControllable) {
134 mWin.setControllableInsetProvider(this);
Jorim Jaggi28620472019-01-02 23:21:49 +0100135 if (mControlTarget != null) {
136 updateControlForTarget(mControlTarget, true /* force */);
Jorim Jaggia2759b22019-01-24 13:21:40 +0100137 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200138 }
139 }
140
141 /**
Jorim Jaggi956ca412019-01-07 14:49:14 +0100142 * @return Whether there is a window which backs this source.
143 */
144 boolean hasWindow() {
145 return mWin != null;
146 }
147
148 /**
Tiger Huang4a7835f2019-11-06 00:07:56 +0800149 * The source frame can affect the layout of other windows, so this should be called once the
150 * window gets laid out.
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200151 */
Tiger Huang4a7835f2019-11-06 00:07:56 +0800152 void updateSourceFrame() {
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200153 if (mWin == null) {
154 return;
155 }
156
157 mTmpRect.set(mWin.getFrameLw());
158 if (mFrameProvider != null) {
159 mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect);
160 } else {
161 mTmpRect.inset(mWin.mGivenContentInsets);
162 }
163 mSource.setFrame(mTmpRect);
Jorim Jaggi4e04eb22020-01-09 16:42:14 +0100164
165 if (mWin.mGivenVisibleInsets.left != 0 || mWin.mGivenVisibleInsets.top != 0
166 || mWin.mGivenVisibleInsets.right != 0 || mWin.mGivenVisibleInsets.bottom != 0) {
167 mTmpRect.set(mWin.getFrameLw());
168 mTmpRect.inset(mWin.mGivenVisibleInsets);
169 mSource.setVisibleFrame(mTmpRect);
170 } else {
171 mSource.setVisibleFrame(null);
172 }
Tiger Huang4a7835f2019-11-06 00:07:56 +0800173 }
174
175 /**
176 * Called when a layout pass has occurred.
177 */
178 void onPostLayout() {
179 if (mWin == null) {
180 return;
181 }
182
183 updateSourceFrame();
Tarandeep Singh215929b2019-01-11 18:24:37 -0800184 if (mControl != null) {
185 final Rect frame = mWin.getWindowFrames().mFrame;
Tiger Huang969c6082019-12-24 20:08:57 +0800186 if (mControl.setSurfacePosition(frame.left, frame.top) && mControlTarget != null) {
187 // The leash has been stale, we need to create a new one for the client.
188 updateControlForTarget(mControlTarget, true /* force */);
Jorim Jaggi28620472019-01-02 23:21:49 +0100189 mStateController.notifyControlChanged(mControlTarget);
Tarandeep Singh215929b2019-01-11 18:24:37 -0800190 }
191 }
chaviw15ad49f2019-04-24 15:05:39 -0700192 setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy()
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100193 && !mWin.mGivenInsetsPending);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200194 }
Jorim Jaggib6030952018-10-23 18:31:52 +0200195
Jorim Jaggia12ea562019-01-07 17:47:47 +0100196 /**
197 * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
198 */
199 void updateControlForFakeTarget(@Nullable InsetsControlTarget fakeTarget) {
200 if (fakeTarget == mFakeControlTarget) {
201 return;
202 }
203 mFakeControlTarget = fakeTarget;
204 }
205
Jorim Jaggi28620472019-01-02 23:21:49 +0100206 void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
Tiger Huang969c6082019-12-24 20:08:57 +0800207 if (mSeamlessRotating) {
208 // We are un-rotating the window against the display rotation. We don't want the target
209 // to control the window for now.
210 return;
211 }
Jorim Jaggia2759b22019-01-24 13:21:40 +0100212 if (mWin == null) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100213 mControlTarget = target;
Jorim Jaggia2759b22019-01-24 13:21:40 +0100214 return;
215 }
Jorim Jaggi28620472019-01-02 23:21:49 +0100216 if (target == mControlTarget && !force) {
Jorim Jaggib6030952018-10-23 18:31:52 +0200217 return;
218 }
219 if (target == null) {
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100220 // Cancelling the animation will invoke onAnimationCancelled, resetting all the fields.
221 mWin.cancelAnimation();
Jorim Jaggib6030952018-10-23 18:31:52 +0200222 return;
223 }
224 mAdapter = new ControlAdapter();
Jorim Jaggid89efeb2019-01-22 17:48:34 +0100225 setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
Tiger Huang969c6082019-12-24 20:08:57 +0800226 final Transaction t = mDisplayContent.getPendingTransaction();
227 mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */);
228 final SurfaceControl leash = mAdapter.mCapturedLeash;
229 final long frameNumber = mFinishSeamlessRotateFrameNumber;
230 mFinishSeamlessRotateFrameNumber = -1;
231 if (frameNumber >= 0 && mWin.mHasSurface && leash != null) {
232 // We just finished the seamless rotation. We don't want to change the position or the
233 // window crop of the surface controls (including the leash) until the client finishes
234 // drawing the new frame of the new orientation. Although we cannot defer the reparent
235 // operation, it is fine, because reparent won't cause any visual effect.
Robert Carr2e20bcd2020-01-22 13:32:38 -0800236 final SurfaceControl barrier = mWin.getDeferTransactionBarrier();
Tiger Huang969c6082019-12-24 20:08:57 +0800237 t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
238 t.deferTransactionUntil(leash, barrier, frameNumber);
239 }
Jorim Jaggi28620472019-01-02 23:21:49 +0100240 mControlTarget = target;
Tiger Huang969c6082019-12-24 20:08:57 +0800241 mControl = new InsetsSourceControl(mSource.getType(), leash,
Tarandeep Singh215929b2019-01-11 18:24:37 -0800242 new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
Jorim Jaggie35c0592018-11-06 16:21:08 +0100243 }
244
Tiger Huang969c6082019-12-24 20:08:57 +0800245 void startSeamlessRotation() {
246 if (!mSeamlessRotating) {
247 mSeamlessRotating = true;
248
249 // This will revoke the leash and clear the control target.
250 mWin.cancelAnimation();
251 }
252 }
253
254 void finishSeamlessRotation(boolean timeout) {
255 if (mSeamlessRotating) {
256 mSeamlessRotating = false;
257 mFinishSeamlessRotateFrameNumber = timeout ? -1 : mWin.getFrameNumber();
258 }
259 }
260
Evan Rosky8d782e02019-10-14 15:43:53 -0700261 boolean onInsetsModified(InsetsControlTarget caller, InsetsSource modifiedSource) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100262 if (mControlTarget != caller || modifiedSource.isVisible() == mClientVisible) {
Jorim Jaggie35c0592018-11-06 16:21:08 +0100263 return false;
264 }
265 setClientVisible(modifiedSource.isVisible());
266 return true;
267 }
268
269 private void setClientVisible(boolean clientVisible) {
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100270 if (mClientVisible == clientVisible) {
271 return;
272 }
Jorim Jaggie35c0592018-11-06 16:21:08 +0100273 mClientVisible = clientVisible;
Tiger Huang3f38f262019-12-18 21:08:40 +0800274 mDisplayContent.mWmService.mH.obtainMessage(
275 LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED, mDisplayContent).sendToTarget();
Jorim Jaggie35c0592018-11-06 16:21:08 +0100276 updateVisibility();
277 }
278
279 private void setServerVisible(boolean serverVisible) {
280 mServerVisible = serverVisible;
281 updateVisibility();
282 }
283
284 private void updateVisibility() {
285 mSource.setVisible(mServerVisible && mClientVisible);
Jorim Jaggib6030952018-10-23 18:31:52 +0200286 }
287
Jorim Jaggia12ea562019-01-07 17:47:47 +0100288 InsetsSourceControl getControl(InsetsControlTarget target) {
289 if (target == mControlTarget) {
290 return mControl;
291 }
292 if (target == mFakeControlTarget) {
293 return mFakeControl;
294 }
295 return null;
Jorim Jaggib6030952018-10-23 18:31:52 +0200296 }
297
Jorim Jaggi956ca412019-01-07 14:49:14 +0100298 InsetsControlTarget getControlTarget() {
299 return mControlTarget;
300 }
301
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100302 boolean isClientVisible() {
Jorim Jaggia2759b22019-01-24 13:21:40 +0100303 return sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible;
Jorim Jaggib6030952018-10-23 18:31:52 +0200304 }
305
306 private class ControlAdapter implements AnimationAdapter {
307
308 private SurfaceControl mCapturedLeash;
309
310 @Override
311 public boolean getShowWallpaper() {
312 return false;
313 }
314
315 @Override
Jorim Jaggib6030952018-10-23 18:31:52 +0200316 public void startAnimation(SurfaceControl animationLeash, Transaction t,
317 OnAnimationFinishedCallback finishCallback) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100318 // TODO(b/118118435): We can remove the type check when implementing the transient bar
319 // animation.
Tiger Huang332793b2019-10-29 23:21:27 +0800320 if (mSource.getType() == ITYPE_IME) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100321 // TODO: use 0 alpha and remove t.hide() once b/138459974 is fixed.
322 t.setAlpha(animationLeash, 1 /* alpha */);
323 t.hide(animationLeash);
324 }
Taran Singhfd0e5862019-10-10 15:15:16 +0200325
Jorim Jaggib6030952018-10-23 18:31:52 +0200326 mCapturedLeash = animationLeash;
Tarandeep Singh215929b2019-01-11 18:24:37 -0800327 final Rect frame = mWin.getWindowFrames().mFrame;
328 t.setPosition(mCapturedLeash, frame.left, frame.top);
Jorim Jaggib6030952018-10-23 18:31:52 +0200329 }
330
331 @Override
332 public void onAnimationCancelled(SurfaceControl animationLeash) {
333 if (mAdapter == this) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100334 mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this);
Jorim Jaggid89efeb2019-01-22 17:48:34 +0100335 setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
Jorim Jaggib6030952018-10-23 18:31:52 +0200336 mControl = null;
Jorim Jaggi28620472019-01-02 23:21:49 +0100337 mControlTarget = null;
Jorim Jaggib6030952018-10-23 18:31:52 +0200338 mAdapter = null;
339 }
340 }
341
342 @Override
343 public long getDurationHint() {
344 return 0;
345 }
346
347 @Override
348 public long getStatusBarTransitionsStartTime() {
349 return 0;
350 }
351
352 @Override
353 public void dump(PrintWriter pw, String prefix) {
354 }
355
356 @Override
Jeffrey Huangcb782852019-12-05 11:28:11 -0800357 public void dumpDebug(ProtoOutputStream proto) {
Jorim Jaggib6030952018-10-23 18:31:52 +0200358 }
Jorim Jaggia12ea562019-01-07 17:47:47 +0100359 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200360}