blob: a7724a11eec2a0c32cf7f205b9e229d0ddfac2da [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
Jorim Jaggia2759b22019-01-24 13:21:40 +010019import static android.view.InsetsState.TYPE_IME;
20import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
21import static android.view.InsetsState.TYPE_TOP_BAR;
22import 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
Jorim Jaggif96c90a2018-09-26 16:55:15 +020027import android.annotation.NonNull;
28import android.annotation.Nullable;
Tarandeep Singh215929b2019-01-11 18:24:37 -080029import android.graphics.Point;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020030import android.graphics.Rect;
Jorim Jaggib6030952018-10-23 18:31:52 +020031import android.util.proto.ProtoOutputStream;
chaviw15ad49f2019-04-24 15:05:39 -070032import android.view.InsetsSource;
33import android.view.InsetsSourceControl;
Jorim Jaggie35c0592018-11-06 16:21:08 +010034import android.view.InsetsState;
Jorim Jaggib6030952018-10-23 18:31:52 +020035import android.view.SurfaceControl;
36import android.view.SurfaceControl.Transaction;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020037
38import com.android.internal.util.function.TriConsumer;
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +010039import com.android.internal.util.function.pooled.PooledLambda;
Jorim Jaggib6030952018-10-23 18:31:52 +020040import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
41
42import java.io.PrintWriter;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020043
44/**
45 * Controller for a specific inset source on the server. It's called provider as it provides the
46 * {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
47 */
48class InsetsSourceProvider {
49
Tarandeep Singh500a38f2019-09-26 13:36:40 -070050 protected final DisplayContent mDisplayContent;
51 protected final @NonNull InsetsSource mSource;
52 protected WindowState mWin;
53
Jorim Jaggif96c90a2018-09-26 16:55:15 +020054 private final Rect mTmpRect = new Rect();
Jorim Jaggib6030952018-10-23 18:31:52 +020055 private final InsetsStateController mStateController;
Jorim Jaggia12ea562019-01-07 17:47:47 +010056 private final InsetsSourceControl mFakeControl;
Jorim Jaggib6030952018-10-23 18:31:52 +020057 private @Nullable InsetsSourceControl mControl;
Jorim Jaggi28620472019-01-02 23:21:49 +010058 private @Nullable InsetsControlTarget mControlTarget;
Jorim Jaggia12ea562019-01-07 17:47:47 +010059 private @Nullable InsetsControlTarget mFakeControlTarget;
60
Jorim Jaggib6030952018-10-23 18:31:52 +020061 private @Nullable ControlAdapter mAdapter;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020062 private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider;
63
Jorim Jaggie35c0592018-11-06 16:21:08 +010064 /** The visibility override from the current controlling window. */
65 private boolean mClientVisible;
66
67 /**
68 * Whether the window is available and considered visible as in {@link WindowState#isVisible}.
69 */
70 private boolean mServerVisible;
71
Jorim Jaggia2759b22019-01-24 13:21:40 +010072 private final boolean mControllable;
Jorim Jaggie35c0592018-11-06 16:21:08 +010073
Jorim Jaggib6030952018-10-23 18:31:52 +020074 InsetsSourceProvider(InsetsSource source, InsetsStateController stateController,
75 DisplayContent displayContent) {
Jorim Jaggid89efeb2019-01-22 17:48:34 +010076 mClientVisible = InsetsState.getDefaultVisibility(source.getType());
Jorim Jaggif96c90a2018-09-26 16:55:15 +020077 mSource = source;
Jorim Jaggib6030952018-10-23 18:31:52 +020078 mDisplayContent = displayContent;
79 mStateController = stateController;
Jorim Jaggia12ea562019-01-07 17:47:47 +010080 mFakeControl = new InsetsSourceControl(source.getType(), null /* leash */,
81 new Point());
Jorim Jaggia2759b22019-01-24 13:21:40 +010082
83 final int type = source.getType();
84 if (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR) {
85 mControllable = sNewInsetsMode == NEW_INSETS_MODE_FULL;
86 } else if (type == TYPE_IME) {
87 mControllable = sNewInsetsMode >= NEW_INSETS_MODE_IME;
88 } else {
89 mControllable = false;
90 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +020091 }
92
93 InsetsSource getSource() {
94 return mSource;
95 }
96
97 /**
Jorim Jaggia2759b22019-01-24 13:21:40 +010098 * @return Whether the current flag configuration allows to control this source.
99 */
100 boolean isControllable() {
101 return mControllable;
102 }
103
104 /**
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200105 * Updates the window that currently backs this source.
106 *
107 * @param win The window that links to this source.
108 * @param frameProvider Based on display frame state and the window, calculates the resulting
109 * frame that should be reported to clients.
110 */
111 void setWindow(@Nullable WindowState win,
112 @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) {
113 if (mWin != null) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100114 if (mControllable) {
115 mWin.setControllableInsetProvider(null);
116 }
Tarandeep Singh5d54e722019-08-15 13:33:12 -0700117 // The window may be animating such that we can hand out the leash to the control
118 // target. Revoke the leash by cancelling the animation to correct the state.
119 // TODO: Ideally, we should wait for the animation to finish so previous window can
120 // animate-out as new one animates-in.
121 mWin.cancelAnimation();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200122 }
123 mWin = win;
124 mFrameProvider = frameProvider;
125 if (win == null) {
Jorim Jaggie35c0592018-11-06 16:21:08 +0100126 setServerVisible(false);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200127 mSource.setFrame(new Rect());
Jorim Jaggi956ca412019-01-07 14:49:14 +0100128 } else if (mControllable) {
129 mWin.setControllableInsetProvider(this);
Jorim Jaggi28620472019-01-02 23:21:49 +0100130 if (mControlTarget != null) {
131 updateControlForTarget(mControlTarget, true /* force */);
Jorim Jaggia2759b22019-01-24 13:21:40 +0100132 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200133 }
134 }
135
136 /**
Jorim Jaggi956ca412019-01-07 14:49:14 +0100137 * @return Whether there is a window which backs this source.
138 */
139 boolean hasWindow() {
140 return mWin != null;
141 }
142
143 /**
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200144 * Called when a layout pass has occurred.
145 */
146 void onPostLayout() {
147 if (mWin == null) {
148 return;
149 }
150
151 mTmpRect.set(mWin.getFrameLw());
152 if (mFrameProvider != null) {
153 mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect);
154 } else {
155 mTmpRect.inset(mWin.mGivenContentInsets);
156 }
157 mSource.setFrame(mTmpRect);
Tarandeep Singh215929b2019-01-11 18:24:37 -0800158 if (mControl != null) {
159 final Rect frame = mWin.getWindowFrames().mFrame;
160 if (mControl.setSurfacePosition(frame.left, frame.top)) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100161 mStateController.notifyControlChanged(mControlTarget);
Tarandeep Singh215929b2019-01-11 18:24:37 -0800162 }
163 }
chaviw15ad49f2019-04-24 15:05:39 -0700164 setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy()
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100165 && !mWin.mGivenInsetsPending);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200166 }
Jorim Jaggib6030952018-10-23 18:31:52 +0200167
Jorim Jaggia12ea562019-01-07 17:47:47 +0100168 /**
169 * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
170 */
171 void updateControlForFakeTarget(@Nullable InsetsControlTarget fakeTarget) {
172 if (fakeTarget == mFakeControlTarget) {
173 return;
174 }
175 mFakeControlTarget = fakeTarget;
176 }
177
Jorim Jaggi28620472019-01-02 23:21:49 +0100178 void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
Jorim Jaggia2759b22019-01-24 13:21:40 +0100179 if (mWin == null) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100180 mControlTarget = target;
Jorim Jaggia2759b22019-01-24 13:21:40 +0100181 return;
182 }
Jorim Jaggi28620472019-01-02 23:21:49 +0100183 if (target == mControlTarget && !force) {
Jorim Jaggib6030952018-10-23 18:31:52 +0200184 return;
185 }
186 if (target == null) {
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100187 // Cancelling the animation will invoke onAnimationCancelled, resetting all the fields.
188 mWin.cancelAnimation();
Jorim Jaggib6030952018-10-23 18:31:52 +0200189 return;
190 }
191 mAdapter = new ControlAdapter();
Jorim Jaggid89efeb2019-01-22 17:48:34 +0100192 setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
Jorim Jaggib6030952018-10-23 18:31:52 +0200193 mWin.startAnimation(mDisplayContent.getPendingTransaction(), mAdapter,
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100194 !mClientVisible /* hidden */);
Jorim Jaggi28620472019-01-02 23:21:49 +0100195 mControlTarget = target;
Tarandeep Singh215929b2019-01-11 18:24:37 -0800196 mControl = new InsetsSourceControl(mSource.getType(), mAdapter.mCapturedLeash,
197 new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
Jorim Jaggie35c0592018-11-06 16:21:08 +0100198 }
199
200 boolean onInsetsModified(WindowState caller, InsetsSource modifiedSource) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100201 if (mControlTarget != caller || modifiedSource.isVisible() == mClientVisible) {
Jorim Jaggie35c0592018-11-06 16:21:08 +0100202 return false;
203 }
204 setClientVisible(modifiedSource.isVisible());
205 return true;
206 }
207
208 private void setClientVisible(boolean clientVisible) {
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100209 if (mClientVisible == clientVisible) {
210 return;
211 }
Jorim Jaggie35c0592018-11-06 16:21:08 +0100212 mClientVisible = clientVisible;
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100213 mDisplayContent.mWmService.mH.sendMessage(PooledLambda.obtainMessage(
214 DisplayContent::layoutAndAssignWindowLayersIfNeeded, mDisplayContent));
Jorim Jaggie35c0592018-11-06 16:21:08 +0100215 updateVisibility();
216 }
217
218 private void setServerVisible(boolean serverVisible) {
219 mServerVisible = serverVisible;
220 updateVisibility();
221 }
222
223 private void updateVisibility() {
224 mSource.setVisible(mServerVisible && mClientVisible);
Jorim Jaggib6030952018-10-23 18:31:52 +0200225 }
226
Jorim Jaggia12ea562019-01-07 17:47:47 +0100227 InsetsSourceControl getControl(InsetsControlTarget target) {
228 if (target == mControlTarget) {
229 return mControl;
230 }
231 if (target == mFakeControlTarget) {
232 return mFakeControl;
233 }
234 return null;
Jorim Jaggib6030952018-10-23 18:31:52 +0200235 }
236
Jorim Jaggi956ca412019-01-07 14:49:14 +0100237 InsetsControlTarget getControlTarget() {
238 return mControlTarget;
239 }
240
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100241 boolean isClientVisible() {
Jorim Jaggia2759b22019-01-24 13:21:40 +0100242 return sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible;
Jorim Jaggib6030952018-10-23 18:31:52 +0200243 }
244
245 private class ControlAdapter implements AnimationAdapter {
246
247 private SurfaceControl mCapturedLeash;
248
249 @Override
250 public boolean getShowWallpaper() {
251 return false;
252 }
253
254 @Override
Jorim Jaggib6030952018-10-23 18:31:52 +0200255 public void startAnimation(SurfaceControl animationLeash, Transaction t,
256 OnAnimationFinishedCallback finishCallback) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100257 // TODO(b/118118435): We can remove the type check when implementing the transient bar
258 // animation.
259 if (mSource.getType() == TYPE_IME) {
260 // TODO: use 0 alpha and remove t.hide() once b/138459974 is fixed.
261 t.setAlpha(animationLeash, 1 /* alpha */);
262 t.hide(animationLeash);
263 }
Taran Singhfd0e5862019-10-10 15:15:16 +0200264
Jorim Jaggib6030952018-10-23 18:31:52 +0200265 mCapturedLeash = animationLeash;
Tarandeep Singh215929b2019-01-11 18:24:37 -0800266 final Rect frame = mWin.getWindowFrames().mFrame;
267 t.setPosition(mCapturedLeash, frame.left, frame.top);
Jorim Jaggib6030952018-10-23 18:31:52 +0200268 }
269
270 @Override
271 public void onAnimationCancelled(SurfaceControl animationLeash) {
272 if (mAdapter == this) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100273 mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this);
Jorim Jaggid89efeb2019-01-22 17:48:34 +0100274 setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
Jorim Jaggib6030952018-10-23 18:31:52 +0200275 mControl = null;
Jorim Jaggi28620472019-01-02 23:21:49 +0100276 mControlTarget = null;
Jorim Jaggib6030952018-10-23 18:31:52 +0200277 mAdapter = null;
278 }
279 }
280
281 @Override
282 public long getDurationHint() {
283 return 0;
284 }
285
286 @Override
287 public long getStatusBarTransitionsStartTime() {
288 return 0;
289 }
290
291 @Override
292 public void dump(PrintWriter pw, String prefix) {
293 }
294
295 @Override
296 public void writeToProto(ProtoOutputStream proto) {
297 }
Jorim Jaggia12ea562019-01-07 17:47:47 +0100298 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200299}