blob: d50bcc4c23acdb69080ab4b12b0b71b1f2aa1dc3 [file] [log] [blame]
Jorim Jaggi28620472019-01-02 23:21:49 +01001/*
2 * Copyright (C) 2019 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 Jaggi956ca412019-01-07 14:49:14 +010019import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
20import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
Jorim Jaggi28620472019-01-02 23:21:49 +010021import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Tiger Huang332793b2019-10-29 23:21:27 +080023import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
24import static android.view.InsetsState.ITYPE_STATUS_BAR;
Jorim Jaggi28620472019-01-02 23:21:49 +010025import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
26import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
27import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
28
29import android.annotation.Nullable;
Jorim Jaggi956ca412019-01-07 14:49:14 +010030import android.app.StatusBarManager;
31import android.util.IntArray;
32import android.view.InsetsState;
Tiger Huang332793b2019-10-29 23:21:27 +080033import android.view.InsetsState.InternalInsetsType;
Jorim Jaggi956ca412019-01-07 14:49:14 +010034import android.view.ViewRootImpl;
Jorim Jaggi28620472019-01-02 23:21:49 +010035
36/**
37 * Policy that implements who gets control over the windows generating insets.
38 */
39class InsetsPolicy {
40
41 private final InsetsStateController mStateController;
42 private final DisplayContent mDisplayContent;
43 private final DisplayPolicy mPolicy;
Jorim Jaggi956ca412019-01-07 14:49:14 +010044 private final TransientControlTarget mTransientControlTarget = new TransientControlTarget();
45 private final IntArray mShowingTransientTypes = new IntArray();
46
47 private WindowState mFocusedWin;
48 private BarWindow mTopBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
49 private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
Jorim Jaggi28620472019-01-02 23:21:49 +010050
51 InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
52 mStateController = stateController;
53 mDisplayContent = displayContent;
54 mPolicy = displayContent.getDisplayPolicy();
55 }
56
57 /** Updates the target which can control system bars. */
58 void updateBarControlTarget(@Nullable WindowState focusedWin) {
Jorim Jaggi956ca412019-01-07 14:49:14 +010059 mFocusedWin = focusedWin;
Jorim Jaggi28620472019-01-02 23:21:49 +010060 mStateController.onBarControlTargetChanged(getTopControlTarget(focusedWin),
Jorim Jaggi956ca412019-01-07 14:49:14 +010061 getFakeTopControlTarget(focusedWin),
62 getNavControlTarget(focusedWin),
63 getFakeNavControlTarget(focusedWin));
64 if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) {
65 return;
66 }
67 mTopBar.setVisible(focusedWin == null
68 || focusedWin != getTopControlTarget(focusedWin)
Tiger Huang332793b2019-10-29 23:21:27 +080069 || focusedWin.getClientInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
Jorim Jaggi956ca412019-01-07 14:49:14 +010070 mNavBar.setVisible(focusedWin == null
71 || focusedWin != getNavControlTarget(focusedWin)
Tiger Huang332793b2019-10-29 23:21:27 +080072 || focusedWin.getClientInsetsState().getSource(ITYPE_NAVIGATION_BAR).isVisible());
Jorim Jaggi956ca412019-01-07 14:49:14 +010073 }
74
Tiger Huang332793b2019-10-29 23:21:27 +080075 boolean isHidden(@InternalInsetsType int type) {
Jorim Jaggi956ca412019-01-07 14:49:14 +010076 final InsetsSourceProvider provider = mStateController.peekSourceProvider(type);
77 return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
78 }
79
80 void showTransient(IntArray types) {
81 boolean changed = false;
82 for (int i = types.size() - 1; i >= 0; i--) {
83 final int type = types.get(i);
84 if (mShowingTransientTypes.indexOf(type) != -1) {
85 continue;
86 }
87 if (!isHidden(type)) {
88 continue;
89 }
90 mShowingTransientTypes.add(type);
91 changed = true;
92 }
93 if (changed) {
94 updateBarControlTarget(mFocusedWin);
95 mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(),
96 mShowingTransientTypes.toArray());
97 mStateController.notifyInsetsChanged();
98 // TODO(b/118118435): Animation
99 }
100 }
101
102 void hideTransient() {
103 if (mShowingTransientTypes.size() == 0) {
104 return;
105 }
106
107 // TODO(b/118118435): Animation
108 mShowingTransientTypes.clear();
109 updateBarControlTarget(mFocusedWin);
110 mStateController.notifyInsetsChanged();
111 }
112
113 /**
114 * @see InsetsStateController#getInsetsForDispatch
115 */
116 InsetsState getInsetsForDispatch(WindowState target) {
117 InsetsState state = mStateController.getInsetsForDispatch(target);
118 if (mShowingTransientTypes.size() == 0) {
119 return state;
120 }
121 for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
122 state.setSourceVisible(mShowingTransientTypes.get(i), false);
123 }
124 return state;
125 }
126
127 void onInsetsModified(WindowState windowState, InsetsState state) {
128 mStateController.onInsetsModified(windowState, state);
129 checkAbortTransient(windowState, state);
130 if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) {
131 return;
132 }
133 if (windowState == getTopControlTarget(mFocusedWin)) {
Tiger Huang332793b2019-10-29 23:21:27 +0800134 mTopBar.setVisible(state.getSource(ITYPE_STATUS_BAR).isVisible());
Jorim Jaggi956ca412019-01-07 14:49:14 +0100135 }
136 if (windowState == getNavControlTarget(mFocusedWin)) {
Tiger Huang332793b2019-10-29 23:21:27 +0800137 mNavBar.setVisible(state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
Jorim Jaggi956ca412019-01-07 14:49:14 +0100138 }
139 }
140
141 /**
142 * Called when a window modified the insets state. If the window set a insets source to visible
143 * while it is shown transiently, we need to abort the transient state.
144 *
145 * @param windowState who changed the insets state.
146 * @param state the modified insets state.
147 */
148 private void checkAbortTransient(WindowState windowState, InsetsState state) {
149 if (mShowingTransientTypes.size() != 0) {
150 IntArray abortTypes = new IntArray();
151 for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
152 final int type = mShowingTransientTypes.get(i);
153 if (mStateController.isFakeTarget(type, windowState)
154 && state.getSource(type).isVisible()) {
155 mShowingTransientTypes.remove(i);
156 abortTypes.add(type);
157 }
158 }
159 if (abortTypes.size() > 0) {
160 mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(),
161 abortTypes.toArray());
162 updateBarControlTarget(mFocusedWin);
163 }
164 }
165 }
166
167 private @Nullable InsetsControlTarget getFakeTopControlTarget(@Nullable WindowState focused) {
Tiger Huang332793b2019-10-29 23:21:27 +0800168 if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100169 return focused;
170 }
171 return null;
172 }
173
174 private @Nullable InsetsControlTarget getFakeNavControlTarget(@Nullable WindowState focused) {
Tiger Huang332793b2019-10-29 23:21:27 +0800175 if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100176 return focused;
177 }
178 return null;
Jorim Jaggi28620472019-01-02 23:21:49 +0100179 }
180
181 private @Nullable InsetsControlTarget getTopControlTarget(@Nullable WindowState focusedWin) {
Tiger Huang332793b2019-10-29 23:21:27 +0800182 if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100183 return mTransientControlTarget;
184 }
Jorim Jaggi28620472019-01-02 23:21:49 +0100185 if (areSystemBarsForciblyVisible() || isStatusBarForciblyVisible()) {
186 return null;
187 }
188 return focusedWin;
189 }
190
191 private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) {
Tiger Huang332793b2019-10-29 23:21:27 +0800192 if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100193 return mTransientControlTarget;
194 }
Jorim Jaggi28620472019-01-02 23:21:49 +0100195 if (areSystemBarsForciblyVisible() || isNavBarForciblyVisible()) {
196 return null;
197 }
198 return focusedWin;
199 }
200
201 private boolean isStatusBarForciblyVisible() {
202 final WindowState statusBar = mPolicy.getStatusBar();
203 if (statusBar == null) {
204 return false;
205 }
206 final int privateFlags = statusBar.mAttrs.privateFlags;
207
Jorim Jaggi956ca412019-01-07 14:49:14 +0100208 // TODO(b/118118435): Pretend to the app that it's still able to control it?
Jorim Jaggi28620472019-01-02 23:21:49 +0100209 if ((privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
210 return true;
211 }
212 if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
213 return true;
214 }
215 return false;
216 }
217
218 private boolean isNavBarForciblyVisible() {
219 final WindowState statusBar = mPolicy.getStatusBar();
220 if (statusBar == null) {
221 return false;
222 }
223 if ((statusBar.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0) {
224 return true;
225 }
226 return false;
227 }
228
229 private boolean areSystemBarsForciblyVisible() {
230 final boolean isDockedStackVisible =
231 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
232 final boolean isFreeformStackVisible =
233 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
234 final boolean isResizing = mDisplayContent.getDockedDividerController().isResizing();
235
236 // We need to force system bars when the docked stack is visible, when the freeform stack
237 // is visible but also when we are resizing for the transitions when docked stack
238 // visibility changes.
239 return isDockedStackVisible || isFreeformStackVisible || isResizing;
240 }
241
Jorim Jaggi956ca412019-01-07 14:49:14 +0100242 private class BarWindow {
243
244 private final int mId;
245 private @StatusBarManager.WindowVisibleState int mState =
246 StatusBarManager.WINDOW_STATE_SHOWING;
247
248 BarWindow(int id) {
249 mId = id;
250 }
251
252 private void setVisible(boolean visible) {
253 final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN;
254 if (mState != state) {
255 mState = state;
256 mPolicy.getStatusBarManagerInternal().setWindowState(
257 mDisplayContent.getDisplayId(), mId, state);
258 }
259 }
260 }
261
262 // TODO(b/118118435): Implement animations for it (with SurfaceAnimator)
263 private class TransientControlTarget implements InsetsControlTarget {
264
265 @Override
266 public void notifyInsetsControlChanged() {
267 }
268 }
Jorim Jaggi28620472019-01-02 23:21:49 +0100269}