blob: 3e698da13097aab4641a2cfec65e78b13cebf8b5 [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 Jaggia12ea562019-01-07 17:47:47 +010022import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
23import static android.view.ViewRootImpl.sNewInsetsMode;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020024
Jorim Jaggib6030952018-10-23 18:31:52 +020025import android.annotation.NonNull;
26import android.annotation.Nullable;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020027import android.util.ArrayMap;
Jorim Jaggib6030952018-10-23 18:31:52 +020028import android.util.ArraySet;
29import android.util.SparseArray;
Jorim Jaggie35c0592018-11-06 16:21:08 +010030import android.view.InsetsSource;
Jorim Jaggib6030952018-10-23 18:31:52 +020031import android.view.InsetsSourceControl;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020032import android.view.InsetsState;
Tiger Huang332793b2019-10-29 23:21:27 +080033import android.view.InsetsState.InternalInsetsType;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020034
35import java.io.PrintWriter;
Jorim Jaggib6030952018-10-23 18:31:52 +020036import java.util.ArrayList;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020037import java.util.function.Consumer;
38
39/**
40 * Manages global window inset state in the system represented by {@link InsetsState}.
41 */
42class InsetsStateController {
43
44 private final InsetsState mLastState = new InsetsState();
45 private final InsetsState mState = new InsetsState();
46 private final DisplayContent mDisplayContent;
Jorim Jaggib6030952018-10-23 18:31:52 +020047
Jorim Jaggi28620472019-01-02 23:21:49 +010048 private final ArrayMap<Integer, InsetsSourceProvider> mProviders = new ArrayMap<>();
49 private final ArrayMap<InsetsControlTarget, ArrayList<Integer>> mControlTargetTypeMap =
50 new ArrayMap<>();
51 private final SparseArray<InsetsControlTarget> mTypeControlTargetMap = new SparseArray<>();
Jorim Jaggia12ea562019-01-07 17:47:47 +010052
53 /** @see #onControlFakeTargetChanged */
54 private final SparseArray<InsetsControlTarget> mTypeFakeControlTargetMap = new SparseArray<>();
55
Jorim Jaggi28620472019-01-02 23:21:49 +010056 private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
Jorim Jaggif96c90a2018-09-26 16:55:15 +020057
58 private final Consumer<WindowState> mDispatchInsetsChanged = w -> {
59 if (w.isVisible()) {
60 w.notifyInsetsChanged();
61 }
62 };
63
64 InsetsStateController(DisplayContent displayContent) {
65 mDisplayContent = displayContent;
66 }
67
68 /**
69 * When dispatching window state to the client, we'll need to exclude the source that represents
70 * the window that is being dispatched.
71 *
72 * @param target The client we dispatch the state to.
73 * @return The state stripped of the necessary information.
74 */
75 InsetsState getInsetsForDispatch(WindowState target) {
Jorim Jaggi956ca412019-01-07 14:49:14 +010076 final InsetsSourceProvider provider = target.getControllableInsetProvider();
Jorim Jaggif96c90a2018-09-26 16:55:15 +020077 if (provider == null) {
78 return mState;
79 }
80
81 final InsetsState state = new InsetsState();
82 state.set(mState);
83 final int type = provider.getSource().getType();
84 state.removeSource(type);
85
86 // Navigation bar doesn't get influenced by anything else
Tiger Huang332793b2019-10-29 23:21:27 +080087 if (type == ITYPE_NAVIGATION_BAR) {
88 state.removeSource(ITYPE_IME);
89 state.removeSource(ITYPE_STATUS_BAR);
Jorim Jaggif96c90a2018-09-26 16:55:15 +020090 }
Jorim Jaggi9b4f4202020-01-28 17:05:06 +010091
92 // IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
93 if (type == ITYPE_IME) {
94 for (int i = mProviders.size() - 1; i >= 0; i--) {
95 InsetsSourceProvider otherProvider = mProviders.valueAt(i);
96 if (otherProvider.overridesImeFrame()) {
97 InsetsSource override =
98 new InsetsSource(state.getSource(otherProvider.getSource().getType()));
99 override.setFrame(otherProvider.getImeOverrideFrame());
100 state.addSource(override);
101 }
102 }
103 }
104
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200105 return state;
106 }
107
Evan Rosky8d782e02019-10-14 15:43:53 -0700108 InsetsState getRawInsetsState() {
109 return mState;
110 }
111
Jorim Jaggi28620472019-01-02 23:21:49 +0100112 @Nullable InsetsSourceControl[] getControlsForDispatch(InsetsControlTarget target) {
113 ArrayList<Integer> controlled = mControlTargetTypeMap.get(target);
Jorim Jaggib6030952018-10-23 18:31:52 +0200114 if (controlled == null) {
115 return null;
116 }
117 final int size = controlled.size();
118 final InsetsSourceControl[] result = new InsetsSourceControl[size];
119 for (int i = 0; i < size; i++) {
Jorim Jaggia12ea562019-01-07 17:47:47 +0100120 result[i] = mProviders.get(controlled.get(i)).getControl(target);
Jorim Jaggib6030952018-10-23 18:31:52 +0200121 }
122 return result;
123 }
124
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200125 /**
126 * @return The provider of a specific type.
127 */
Tiger Huang332793b2019-10-29 23:21:27 +0800128 InsetsSourceProvider getSourceProvider(@InternalInsetsType int type) {
129 if (type == ITYPE_IME) {
Tarandeep Singh500a38f2019-09-26 13:36:40 -0700130 return mProviders.computeIfAbsent(type,
131 key -> new ImeInsetsSourceProvider(
132 mState.getSource(key), this, mDisplayContent));
133 } else {
134 return mProviders.computeIfAbsent(type,
135 key -> new InsetsSourceProvider(mState.getSource(key), this, mDisplayContent));
136 }
137 }
138
139 ImeInsetsSourceProvider getImeSourceProvider() {
Tiger Huang332793b2019-10-29 23:21:27 +0800140 return (ImeInsetsSourceProvider) getSourceProvider(ITYPE_IME);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200141 }
142
143 /**
Jorim Jaggi956ca412019-01-07 14:49:14 +0100144 * @return The provider of a specific type or null if we don't have it.
145 */
Tiger Huang332793b2019-10-29 23:21:27 +0800146 @Nullable InsetsSourceProvider peekSourceProvider(@InternalInsetsType int type) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100147 return mProviders.get(type);
148 }
149
150 /**
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200151 * Called when a layout pass has occurred.
152 */
153 void onPostLayout() {
Tarandeep Singha6f35612019-01-11 19:50:46 -0800154 mState.setDisplayFrame(mDisplayContent.getBounds());
Jorim Jaggi28620472019-01-02 23:21:49 +0100155 for (int i = mProviders.size() - 1; i >= 0; i--) {
156 mProviders.valueAt(i).onPostLayout();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200157 }
158 if (!mLastState.equals(mState)) {
159 mLastState.set(mState, true /* copySources */);
160 notifyInsetsChanged();
161 }
Tarandeep Singh500a38f2019-09-26 13:36:40 -0700162 getImeSourceProvider().onPostInsetsDispatched();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200163 }
164
Evan Rosky8d782e02019-10-14 15:43:53 -0700165 void onInsetsModified(InsetsControlTarget windowState, InsetsState state) {
Jorim Jaggie35c0592018-11-06 16:21:08 +0100166 boolean changed = false;
167 for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
168 final InsetsSource source = state.sourceAt(i);
Jorim Jaggi28620472019-01-02 23:21:49 +0100169 final InsetsSourceProvider provider = mProviders.get(source.getType());
Jorim Jaggie35c0592018-11-06 16:21:08 +0100170 if (provider == null) {
171 continue;
172 }
173 changed |= provider.onInsetsModified(windowState, source);
174 }
175 if (changed) {
176 notifyInsetsChanged();
177 }
178 }
179
Tiger Huang332793b2019-10-29 23:21:27 +0800180 boolean isFakeTarget(@InternalInsetsType int type, InsetsControlTarget target) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100181 return mTypeFakeControlTargetMap.get(type) == target;
182 }
183
Jorim Jaggi28620472019-01-02 23:21:49 +0100184 void onImeTargetChanged(@Nullable InsetsControlTarget imeTarget) {
Tiger Huang332793b2019-10-29 23:21:27 +0800185 onControlChanged(ITYPE_IME, imeTarget);
Jorim Jaggib6030952018-10-23 18:31:52 +0200186 notifyPendingInsetsControlChanged();
187 }
188
189 /**
Jorim Jaggi28620472019-01-02 23:21:49 +0100190 * Called when the focused window that is able to control the system bars changes.
Jorim Jaggib6030952018-10-23 18:31:52 +0200191 *
Jorim Jaggi28620472019-01-02 23:21:49 +0100192 * @param topControlling The target that is now able to control the top bar appearance
193 * and visibility.
194 * @param navControlling The target that is now able to control the nav bar appearance
195 * and visibility.
Jorim Jaggib6030952018-10-23 18:31:52 +0200196 */
Jorim Jaggi28620472019-01-02 23:21:49 +0100197 void onBarControlTargetChanged(@Nullable InsetsControlTarget topControlling,
Jorim Jaggi956ca412019-01-07 14:49:14 +0100198 @Nullable InsetsControlTarget fakeTopControlling,
199 @Nullable InsetsControlTarget navControlling,
200 @Nullable InsetsControlTarget fakeNavControlling) {
Tiger Huang332793b2019-10-29 23:21:27 +0800201 onControlChanged(ITYPE_STATUS_BAR, topControlling);
202 onControlChanged(ITYPE_NAVIGATION_BAR, navControlling);
203 onControlFakeTargetChanged(ITYPE_STATUS_BAR, fakeTopControlling);
204 onControlFakeTargetChanged(ITYPE_NAVIGATION_BAR, fakeNavControlling);
Jorim Jaggib6030952018-10-23 18:31:52 +0200205 notifyPendingInsetsControlChanged();
206 }
207
Jorim Jaggi28620472019-01-02 23:21:49 +0100208 void notifyControlRevoked(@NonNull InsetsControlTarget previousControlTarget,
Jorim Jaggib6030952018-10-23 18:31:52 +0200209 InsetsSourceProvider provider) {
Jorim Jaggia12ea562019-01-07 17:47:47 +0100210 removeFromControlMaps(previousControlTarget, provider.getSource().getType(),
211 false /* fake */);
Jorim Jaggib6030952018-10-23 18:31:52 +0200212 }
213
Tiger Huang332793b2019-10-29 23:21:27 +0800214 private void onControlChanged(@InternalInsetsType int type,
Jorim Jaggi28620472019-01-02 23:21:49 +0100215 @Nullable InsetsControlTarget target) {
216 final InsetsControlTarget previous = mTypeControlTargetMap.get(type);
217 if (target == previous) {
Jorim Jaggib6030952018-10-23 18:31:52 +0200218 return;
219 }
Tiger Huang969c6082019-12-24 20:08:57 +0800220 final InsetsSourceProvider provider = mProviders.get(type);
Jorim Jaggi28620472019-01-02 23:21:49 +0100221 if (provider == null) {
Jorim Jaggib6030952018-10-23 18:31:52 +0200222 return;
223 }
Jorim Jaggi28620472019-01-02 23:21:49 +0100224 if (!provider.isControllable()) {
Jorim Jaggia2759b22019-01-24 13:21:40 +0100225 return;
226 }
Jorim Jaggi28620472019-01-02 23:21:49 +0100227 provider.updateControlForTarget(target, false /* force */);
Tiger Huang969c6082019-12-24 20:08:57 +0800228 target = provider.getControlTarget();
Jorim Jaggib6030952018-10-23 18:31:52 +0200229 if (previous != null) {
Jorim Jaggia12ea562019-01-07 17:47:47 +0100230 removeFromControlMaps(previous, type, false /* fake */);
Jorim Jaggib6030952018-10-23 18:31:52 +0200231 mPendingControlChanged.add(previous);
232 }
Jorim Jaggi28620472019-01-02 23:21:49 +0100233 if (target != null) {
Jorim Jaggia12ea562019-01-07 17:47:47 +0100234 addToControlMaps(target, type, false /* fake */);
Jorim Jaggi28620472019-01-02 23:21:49 +0100235 mPendingControlChanged.add(target);
Jorim Jaggib6030952018-10-23 18:31:52 +0200236 }
237 }
238
Jorim Jaggia12ea562019-01-07 17:47:47 +0100239 /**
240 * The fake target saved here will be used to pretend to the app that it's still under control
241 * of the bars while it's not really, but we still need to find out the apps intentions around
242 * showing/hiding. For example, when the transient bars are showing, and the fake target
243 * requests to show system bars, the transient state will be aborted.
244 */
Tiger Huang332793b2019-10-29 23:21:27 +0800245 void onControlFakeTargetChanged(@InternalInsetsType int type,
Jorim Jaggia12ea562019-01-07 17:47:47 +0100246 @Nullable InsetsControlTarget fakeTarget) {
247 if (sNewInsetsMode != NEW_INSETS_MODE_FULL) {
248 return;
249 }
250 final InsetsControlTarget previous = mTypeFakeControlTargetMap.get(type);
251 if (fakeTarget == previous) {
252 return;
253 }
254 final InsetsSourceProvider provider = mProviders.get(type);
255 if (provider == null) {
256 return;
257 }
258 provider.updateControlForFakeTarget(fakeTarget);
259 if (previous != null) {
260 removeFromControlMaps(previous, type, true /* fake */);
261 mPendingControlChanged.add(previous);
262 }
263 if (fakeTarget != null) {
264 addToControlMaps(fakeTarget, type, true /* fake */);
265 mPendingControlChanged.add(fakeTarget);
266 }
267 }
268
Jorim Jaggi28620472019-01-02 23:21:49 +0100269 private void removeFromControlMaps(@NonNull InsetsControlTarget target,
Tiger Huang332793b2019-10-29 23:21:27 +0800270 @InternalInsetsType int type, boolean fake) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100271 final ArrayList<Integer> array = mControlTargetTypeMap.get(target);
Jorim Jaggib6030952018-10-23 18:31:52 +0200272 if (array == null) {
273 return;
274 }
275 array.remove((Integer) type);
276 if (array.isEmpty()) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100277 mControlTargetTypeMap.remove(target);
Jorim Jaggib6030952018-10-23 18:31:52 +0200278 }
Jorim Jaggia12ea562019-01-07 17:47:47 +0100279 if (fake) {
280 mTypeFakeControlTargetMap.remove(type);
281 } else {
282 mTypeControlTargetMap.remove(type);
283 }
Jorim Jaggib6030952018-10-23 18:31:52 +0200284 }
285
Jorim Jaggi28620472019-01-02 23:21:49 +0100286 private void addToControlMaps(@NonNull InsetsControlTarget target,
Tiger Huang332793b2019-10-29 23:21:27 +0800287 @InternalInsetsType int type, boolean fake) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100288 final ArrayList<Integer> array = mControlTargetTypeMap.computeIfAbsent(target,
Jorim Jaggib6030952018-10-23 18:31:52 +0200289 key -> new ArrayList<>());
290 array.add(type);
Jorim Jaggia12ea562019-01-07 17:47:47 +0100291 if (fake) {
292 mTypeFakeControlTargetMap.put(type, target);
293 } else {
294 mTypeControlTargetMap.put(type, target);
295 }
Jorim Jaggib6030952018-10-23 18:31:52 +0200296 }
297
Jorim Jaggi28620472019-01-02 23:21:49 +0100298 void notifyControlChanged(InsetsControlTarget target) {
Tarandeep Singh215929b2019-01-11 18:24:37 -0800299 mPendingControlChanged.add(target);
300 notifyPendingInsetsControlChanged();
301 }
302
Jorim Jaggib6030952018-10-23 18:31:52 +0200303 private void notifyPendingInsetsControlChanged() {
Jorim Jaggif86eb492019-01-09 17:37:08 +0100304 if (mPendingControlChanged.isEmpty()) {
305 return;
306 }
Jorim Jaggib6030952018-10-23 18:31:52 +0200307 mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
308 for (int i = mPendingControlChanged.size() - 1; i >= 0; i--) {
Jorim Jaggi28620472019-01-02 23:21:49 +0100309 final InsetsControlTarget controlTarget = mPendingControlChanged.valueAt(i);
310 controlTarget.notifyInsetsControlChanged();
Jorim Jaggib6030952018-10-23 18:31:52 +0200311 }
312 mPendingControlChanged.clear();
313 });
314 }
315
Jorim Jaggi956ca412019-01-07 14:49:14 +0100316 void notifyInsetsChanged() {
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200317 mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */);
Evan Rosky8d782e02019-10-14 15:43:53 -0700318 if (mDisplayContent.mRemoteInsetsControlTarget != null) {
319 mDisplayContent.mRemoteInsetsControlTarget.notifyInsetsChanged();
320 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200321 }
322
323 void dump(String prefix, PrintWriter pw) {
324 pw.println(prefix + "WindowInsetsStateController");
325 mState.dump(prefix + " ", pw);
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100326 pw.println(prefix + " " + "Control map:");
Jorim Jaggi28620472019-01-02 23:21:49 +0100327 for (int i = mTypeControlTargetMap.size() - 1; i >= 0; i--) {
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100328 pw.print(prefix + " ");
Jorim Jaggi28620472019-01-02 23:21:49 +0100329 pw.println(InsetsState.typeToString(mTypeControlTargetMap.keyAt(i)) + " -> "
330 + mTypeControlTargetMap.valueAt(i));
Jorim Jaggicfd6f3b2018-11-07 15:30:18 +0100331 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200332 }
333}