blob: d3ae5cf35b0cc9c5fc8f9e4bec69184bade9a117 [file] [log] [blame]
Jorim Jaggi5cf17872014-03-26 18:31:48 +01001/*
2 * Copyright (C) 2014 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.systemui.statusbar.phone;
18
Adrian Roos7b54b072018-03-08 12:52:22 +010019import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
20
Eliot Courtneye77edea2017-11-15 14:25:21 +090021import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
22
Sudheer Shankadc589ac2016-11-10 15:30:17 -080023import android.app.ActivityManager;
Jorim Jaggif6782ee2016-07-22 11:40:00 +020024import android.app.IActivityManager;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010025import android.content.Context;
26import android.content.pm.ActivityInfo;
27import android.content.res.Resources;
28import android.graphics.PixelFormat;
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -080029import android.os.Binder;
Jorim Jaggif6782ee2016-07-22 11:40:00 +020030import android.os.RemoteException;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010031import android.os.SystemProperties;
Lucas Dupine25c4872019-07-29 13:51:35 -070032import android.os.Trace;
Jorim Jaggif6782ee2016-07-22 11:40:00 +020033import android.util.Log;
Lucas Dupine25c4872019-07-29 13:51:35 -070034import android.view.Display;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010035import android.view.Gravity;
36import android.view.View;
37import android.view.ViewGroup;
38import android.view.WindowManager;
Jorim Jaggif12ec0f2017-08-23 16:14:10 +020039import android.view.WindowManager.LayoutParams;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010040
Lucas Dupina3e36272018-08-21 13:22:33 -070041import com.android.internal.annotations.VisibleForTesting;
Jason Monk1fd3fc32018-08-14 17:20:09 -040042import com.android.systemui.Dependency;
Jason Monk421a9412017-02-06 09:15:21 -080043import com.android.systemui.Dumpable;
Sunny Goyal87fccf02019-08-13 17:39:10 -070044import com.android.systemui.R;
Jason Monke59dc402018-08-16 12:05:01 -040045import com.android.systemui.colorextraction.SysuiColorExtractor;
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +010046import com.android.systemui.keyguard.KeyguardViewMediator;
Beverly8fdb5332019-02-04 14:29:49 -050047import com.android.systemui.plugins.statusbar.StatusBarStateController;
48import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
Jason Monke59dc402018-08-16 12:05:01 -040049import com.android.systemui.statusbar.RemoteInputController.Callback;
Jorim Jaggiecbab362014-04-23 16:13:15 +020050import com.android.systemui.statusbar.StatusBarState;
Beverly8fdb5332019-02-04 14:29:49 -050051import com.android.systemui.statusbar.SysuiStatusBarStateController;
Jason Monke59dc402018-08-16 12:05:01 -040052import com.android.systemui.statusbar.policy.ConfigurationController;
53import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010054
Winson Chungdc0eca62019-06-13 22:37:31 -070055import com.google.android.collect.Lists;
Beverly8adbd1e2019-07-25 14:27:17 -040056
Selim Cinek7025f262015-07-13 16:22:48 -070057import java.io.FileDescriptor;
58import java.io.PrintWriter;
Winson Chungdc0eca62019-06-13 22:37:31 -070059import java.lang.ref.WeakReference;
Selim Cinek6a1bd2b2015-06-02 16:02:41 +020060import java.lang.reflect.Field;
Winson Chungdc0eca62019-06-13 22:37:31 -070061import java.util.ArrayList;
Lucas Dupine25c4872019-07-29 13:51:35 -070062import java.util.Arrays;
Beverly8adbd1e2019-07-25 14:27:17 -040063
Jason Monk196d6392018-12-20 13:25:34 -050064import javax.inject.Inject;
65import javax.inject.Singleton;
66
Jorim Jaggi5cf17872014-03-26 18:31:48 +010067/**
68 * Encapsulates all logic for the status bar window state management.
69 */
Jason Monk196d6392018-12-20 13:25:34 -050070@Singleton
Jason Monke59dc402018-08-16 12:05:01 -040071public class StatusBarWindowController implements Callback, Dumpable, ConfigurationListener {
Jorim Jaggi5cf17872014-03-26 18:31:48 +010072
Lucas Dupin1a8588d2018-08-21 12:18:47 -070073 private static final String TAG = "StatusBarWindowController";
Jorim Jaggif6782ee2016-07-22 11:40:00 +020074
Jorim Jaggi5cf17872014-03-26 18:31:48 +010075 private final Context mContext;
76 private final WindowManager mWindowManager;
Jorim Jaggif6782ee2016-07-22 11:40:00 +020077 private final IActivityManager mActivityManager;
Lucas Dupin7517b5d2017-08-22 12:51:25 -070078 private final DozeParameters mDozeParameters;
Steve Elliottff2c0d92019-07-30 15:09:54 -040079 private final LayoutParams mLpChanged;
Lucas Dupin42ebe542019-01-22 09:45:09 -080080 private final boolean mKeyguardScreenRotation;
Lucas Dupine90fead2019-06-12 16:22:41 -070081 private final long mLockScreenDisplayTimeout;
Lucas Dupine25c4872019-07-29 13:51:35 -070082 private final Display.Mode mKeyguardDisplayMode;
83 private final KeyguardBypassController mKeyguardBypassController;
Mady Mellord1c78b262018-11-06 18:04:40 -080084 private ViewGroup mStatusBarView;
Steve Elliottff2c0d92019-07-30 15:09:54 -040085 private LayoutParams mLp;
Jorim Jaggif6782ee2016-07-22 11:40:00 +020086 private boolean mHasTopUi;
87 private boolean mHasTopUiChanged;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010088 private int mBarHeight;
Adrian Roos3e23eb52017-07-07 15:58:57 +020089 private float mScreenBrightnessDoze;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010090 private final State mCurrentState = new State();
Jason Monk421a9412017-02-06 09:15:21 -080091 private OtherwisedCollapsedListener mListener;
Beverly4ec838b2019-05-29 11:34:45 -040092 private ForcePluginOpenListener mForcePluginOpenListener;
Winson Chungdc0eca62019-06-13 22:37:31 -070093 private final ArrayList<WeakReference<StatusBarWindowCallback>>
94 mCallbacks = Lists.newArrayList();
Jorim Jaggi5cf17872014-03-26 18:31:48 +010095
Jason Monke59dc402018-08-16 12:05:01 -040096 private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
Jason Monk1fd3fc32018-08-14 17:20:09 -040097
Jason Monk196d6392018-12-20 13:25:34 -050098 @Inject
Lucas Dupine25c4872019-07-29 13:51:35 -070099 public StatusBarWindowController(Context context,
100 StatusBarStateController statusBarStateController,
101 ConfigurationController configurationController,
102 KeyguardBypassController keyguardBypassController) {
Lucas Dupina3e36272018-08-21 13:22:33 -0700103 this(context, context.getSystemService(WindowManager.class), ActivityManager.getService(),
Lucas Dupine25c4872019-07-29 13:51:35 -0700104 DozeParameters.getInstance(context), statusBarStateController,
105 configurationController, keyguardBypassController);
Lucas Dupina3e36272018-08-21 13:22:33 -0700106 }
107
108 @VisibleForTesting
Mady Mellorebdbbb92018-11-15 14:36:48 -0800109 public StatusBarWindowController(Context context, WindowManager windowManager,
Lucas Dupine25c4872019-07-29 13:51:35 -0700110 IActivityManager activityManager, DozeParameters dozeParameters,
111 StatusBarStateController statusBarStateController,
112 ConfigurationController configurationController,
113 KeyguardBypassController keyguardBypassController) {
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100114 mContext = context;
Lucas Dupina3e36272018-08-21 13:22:33 -0700115 mWindowManager = windowManager;
116 mActivityManager = activityManager;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100117 mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
Lucas Dupina3e36272018-08-21 13:22:33 -0700118 mDozeParameters = dozeParameters;
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700119 mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
Steve Elliottff2c0d92019-07-30 15:09:54 -0400120 mLpChanged = new LayoutParams();
Lucas Dupine25c4872019-07-29 13:51:35 -0700121 mKeyguardBypassController = keyguardBypassController;
Lucas Dupine90fead2019-06-12 16:22:41 -0700122 mLockScreenDisplayTimeout = context.getResources()
123 .getInteger(R.integer.config_lockScreenDisplayTimeout);
Lucas Dupine25c4872019-07-29 13:51:35 -0700124 ((SysuiStatusBarStateController) statusBarStateController)
Beverly8fdb5332019-02-04 14:29:49 -0500125 .addCallback(mStateListener,
126 SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
Lucas Dupine25c4872019-07-29 13:51:35 -0700127 configurationController.addCallback(this);
128
129 Display.Mode[] supportedModes = context.getDisplay().getSupportedModes();
130 Display.Mode currentMode = context.getDisplay().getMode();
131 // Running on the highest frame rate available can be expensive.
132 // Let's specify a preferred refresh rate, and allow higher FPS only when we
133 // know that we're not falsing (because we unlocked.)
134 int keyguardRefreshRate = context.getResources()
135 .getInteger(R.integer.config_keyguardRefreshRate);
136 // Find supported display mode with the same resolution and requested refresh rate.
137 mKeyguardDisplayMode = Arrays.stream(supportedModes).filter(mode ->
138 (int) mode.getRefreshRate() == keyguardRefreshRate
139 && mode.getPhysicalWidth() == currentMode.getPhysicalWidth()
140 && mode.getPhysicalHeight() == currentMode.getPhysicalHeight())
141 .findFirst().orElse(null);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100142 }
143
Winson Chungdc0eca62019-06-13 22:37:31 -0700144 /**
145 * Register to receive notifications about status bar window state changes.
146 */
147 public void registerCallback(StatusBarWindowCallback callback) {
148 // Prevent adding duplicate callbacks
149 for (int i = 0; i < mCallbacks.size(); i++) {
150 if (mCallbacks.get(i).get() == callback) {
151 return;
152 }
153 }
154 mCallbacks.add(new WeakReference<StatusBarWindowCallback>(callback));
155 }
156
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100157 private boolean shouldEnableKeyguardScreenRotation() {
158 Resources res = mContext.getResources();
159 return SystemProperties.getBoolean("lockscreen.rot_override", false)
160 || res.getBoolean(R.bool.config_enableLockScreenRotation);
161 }
162
163 /**
164 * Adds the status bar view to the window manager.
165 *
166 * @param statusBarView The view to add.
167 * @param barHeight The height of the status bar in collapsed state.
168 */
Mady Mellord1c78b262018-11-06 18:04:40 -0800169 public void add(ViewGroup statusBarView, int barHeight) {
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100170
171 // Now that the status bar window encompasses the sliding panel and its
172 // translucent backdrop, the entire thing is made TRANSLUCENT and is
173 // hardware-accelerated.
Steve Elliottff2c0d92019-07-30 15:09:54 -0400174 mLp = new LayoutParams(
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100175 ViewGroup.LayoutParams.MATCH_PARENT,
176 barHeight,
Steve Elliottff2c0d92019-07-30 15:09:54 -0400177 LayoutParams.TYPE_STATUS_BAR,
178 LayoutParams.FLAG_NOT_FOCUSABLE
179 | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
180 | LayoutParams.FLAG_SPLIT_TOUCH
181 | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
182 | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100183 PixelFormat.TRANSLUCENT);
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800184 mLp.token = new Binder();
Jorim Jaggi76aaef52014-05-08 19:16:49 +0200185 mLp.gravity = Gravity.TOP;
Steve Elliottff2c0d92019-07-30 15:09:54 -0400186 mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100187 mLp.setTitle("StatusBar");
188 mLp.packageName = mContext.getPackageName();
Adrian Roos7b54b072018-03-08 12:52:22 +0100189 mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100190 mStatusBarView = statusBarView;
191 mBarHeight = barHeight;
192 mWindowManager.addView(mStatusBarView, mLp);
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100193 mLpChanged.copyFrom(mLp);
Lucas Dupinfdbfc542018-09-17 15:56:09 -0700194 onThemeChanged();
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100195 }
196
Mady Mellord1c78b262018-11-06 18:04:40 -0800197 public ViewGroup getStatusBarView() {
Mady Mellorc3d6f7d2018-11-07 09:36:56 -0800198 return mStatusBarView;
199 }
200
Adrian Roos3e23eb52017-07-07 15:58:57 +0200201 public void setDozeScreenBrightness(int value) {
202 mScreenBrightnessDoze = value / 255f;
203 }
204
Jason Monke59dc402018-08-16 12:05:01 -0400205 private void setKeyguardDark(boolean dark) {
Lucas Dupin987f1932017-05-13 21:02:52 -0700206 int vis = mStatusBarView.getSystemUiVisibility();
207 if (dark) {
208 vis = vis | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
209 vis = vis | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
210 } else {
211 vis = vis & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
212 vis = vis & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
213 }
214 mStatusBarView.setSystemUiVisibility(vis);
215 }
216
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100217 private void applyKeyguardFlags(State state) {
218 if (state.keyguardShowing) {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400219 mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_KEYGUARD;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100220 } else {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400221 mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_KEYGUARD;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100222 }
Adrian Roosd5c2db62016-03-08 16:11:31 -0800223
Lucas Dupin16cfe452018-02-08 13:14:50 -0800224 final boolean scrimsOccludingWallpaper =
Lyn Hanbde48202019-05-29 19:18:29 -0700225 state.scrimsVisibility == ScrimController.OPAQUE;
Lucas Dupin47a65c72018-02-15 14:16:18 -0800226 final boolean keyguardOrAod = state.keyguardShowing
227 || (state.dozing && mDozeParameters.getAlwaysOn());
Selim Cinekdbf172e2018-08-08 18:31:45 +0000228 if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400229 mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER;
Adrian Roosd5c2db62016-03-08 16:11:31 -0800230 } else {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400231 mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER;
Adrian Roosd5c2db62016-03-08 16:11:31 -0800232 }
Lucas Dupina3e36272018-08-21 13:22:33 -0700233
234 if (state.dozing) {
Philip P. Moltmann66ce2382018-10-09 13:46:11 -0700235 mLpChanged.privateFlags |= LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
Lucas Dupina3e36272018-08-21 13:22:33 -0700236 } else {
Philip P. Moltmann66ce2382018-10-09 13:46:11 -0700237 mLpChanged.privateFlags &= ~LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
Lucas Dupina3e36272018-08-21 13:22:33 -0700238 }
Lucas Dupine25c4872019-07-29 13:51:35 -0700239
240 if (mKeyguardDisplayMode != null) {
241 boolean bypassOnKeyguard = mKeyguardBypassController.getBypassEnabled()
242 && state.statusBarState == StatusBarState.KEYGUARD && !state.keyguardFadingAway
243 && !state.keyguardGoingAway;
244 if (state.dozing || bypassOnKeyguard) {
245 mLpChanged.preferredDisplayModeId = mKeyguardDisplayMode.getModeId();
246 } else {
247 mLpChanged.preferredDisplayModeId = 0;
248 }
249 Trace.setCounter("display_mode_id", mLpChanged.preferredDisplayModeId);
250 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100251 }
252
253 private void adjustScreenOrientation(State state) {
Adrian Roos82069442017-06-28 19:37:24 +0200254 if (state.isKeyguardShowingAndNotOccluded() || state.dozing) {
Jorim Jaggica36cf72014-04-17 20:36:15 +0200255 if (mKeyguardScreenRotation) {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100256 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
Jorim Jaggica36cf72014-04-17 20:36:15 +0200257 } else {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100258 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
Jorim Jaggica36cf72014-04-17 20:36:15 +0200259 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100260 } else {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100261 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100262 }
263 }
264
265 private void applyFocusableFlag(State state) {
Selim Cinek4a21a7f2015-05-19 11:00:38 -0700266 boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
Jorim Jaggibb336692016-11-15 15:24:26 -0800267 if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput)
Issei Suzukiac9fcb72019-02-04 17:45:57 +0100268 || ENABLE_REMOTE_INPUT && state.remoteInputActive
269 || state.bubbleExpanded) {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400270 mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
271 mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
Matt Caseya0966b52019-05-15 18:49:37 -0400272 } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400273 mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
274 mLpChanged.flags |= LayoutParams.FLAG_ALT_FOCUSABLE_IM;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100275 } else {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400276 mLpChanged.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
277 mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100278 }
Adrian Roosdc5b4532016-01-06 20:49:41 +0100279
Steve Elliottff2c0d92019-07-30 15:09:54 -0400280 mLpChanged.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100281 }
282
Tiger Huanga90dea42018-08-03 17:20:17 +0800283 private void applyForceShowNavigationFlag(State state) {
284 if (state.panelExpanded || state.bouncerShowing
Tiger Huang34046012018-06-29 15:26:52 +0800285 || ENABLE_REMOTE_INPUT && state.remoteInputActive) {
Tiger Huanga90dea42018-08-03 17:20:17 +0800286 mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
Tiger Huang34046012018-06-29 15:26:52 +0800287 } else {
Tiger Huanga90dea42018-08-03 17:20:17 +0800288 mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
Tiger Huang34046012018-06-29 15:26:52 +0800289 }
290 }
291
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100292 private void applyHeight(State state) {
Selim Cinek6a1bd2b2015-06-02 16:02:41 +0200293 boolean expanded = isExpanded(state);
Jason Monk421a9412017-02-06 09:15:21 -0800294 if (state.forcePluginOpen) {
Lucas Dupin42ebe542019-01-22 09:45:09 -0800295 if (mListener != null) {
296 mListener.setWouldOtherwiseCollapse(expanded);
297 }
Jason Monk421a9412017-02-06 09:15:21 -0800298 expanded = true;
299 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100300 if (expanded) {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100301 mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100302 } else {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100303 mLpChanged.height = mBarHeight;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100304 }
305 }
306
Selim Cinek6a1bd2b2015-06-02 16:02:41 +0200307 private boolean isExpanded(State state) {
308 return !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
309 || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
Matt Caseya0966b52019-05-15 18:49:37 -0400310 || state.headsUpShowing || state.bubblesShowing
Lyn Hanbde48202019-05-29 19:18:29 -0700311 || state.scrimsVisibility != ScrimController.TRANSPARENT);
Selim Cinek6a1bd2b2015-06-02 16:02:41 +0200312 }
313
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200314 private void applyFitsSystemWindows(State state) {
Adrian Roosa5d6cd02016-07-27 15:12:40 -0700315 boolean fitsSystemWindows = !state.isKeyguardShowingAndNotOccluded();
Lucas Dupin42ebe542019-01-22 09:45:09 -0800316 if (mStatusBarView != null && mStatusBarView.getFitsSystemWindows() != fitsSystemWindows) {
Adrian Roosa5d6cd02016-07-27 15:12:40 -0700317 mStatusBarView.setFitsSystemWindows(fitsSystemWindows);
318 mStatusBarView.requestApplyInsets();
319 }
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200320 }
321
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100322 private void applyUserActivityTimeout(State state) {
Jorim Jaggiecbab362014-04-23 16:13:15 +0200323 if (state.isKeyguardShowingAndNotOccluded()
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200324 && state.statusBarState == StatusBarState.KEYGUARD
325 && !state.qsExpanded) {
Lucas Dupine90fead2019-06-12 16:22:41 -0700326 mLpChanged.userActivityTimeout = state.bouncerShowing
327 ? KeyguardViewMediator.AWAKE_INTERVAL_BOUNCER_MS : mLockScreenDisplayTimeout;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100328 } else {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100329 mLpChanged.userActivityTimeout = -1;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100330 }
331 }
332
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200333 private void applyInputFeatures(State state) {
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200334 if (state.isKeyguardShowingAndNotOccluded()
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200335 && state.statusBarState == StatusBarState.KEYGUARD
Vadim Tryshev6069c402016-03-09 14:24:29 -0800336 && !state.qsExpanded && !state.forceUserActivity) {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100337 mLpChanged.inputFeatures |=
Steve Elliottff2c0d92019-07-30 15:09:54 -0400338 LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200339 } else {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100340 mLpChanged.inputFeatures &=
Steve Elliottff2c0d92019-07-30 15:09:54 -0400341 ~LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200342 }
343 }
344
Peiyong Lin75045382019-03-04 19:22:33 -0800345 private void applyStatusBarColorSpaceAgnosticFlag(State state) {
346 if (!isExpanded(state)) {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400347 mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
Peiyong Lin75045382019-03-04 19:22:33 -0800348 } else {
349 mLpChanged.privateFlags &=
Steve Elliottff2c0d92019-07-30 15:09:54 -0400350 ~LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
Peiyong Lin75045382019-03-04 19:22:33 -0800351 }
352 }
353
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100354 private void apply(State state) {
355 applyKeyguardFlags(state);
Selim Cinek4a4a2bddc2015-05-07 12:50:19 -0700356 applyForceStatusBarVisibleFlag(state);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100357 applyFocusableFlag(state);
Tiger Huanga90dea42018-08-03 17:20:17 +0800358 applyForceShowNavigationFlag(state);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100359 adjustScreenOrientation(state);
360 applyHeight(state);
361 applyUserActivityTimeout(state);
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200362 applyInputFeatures(state);
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200363 applyFitsSystemWindows(state);
Selim Cineka59ecc32015-04-07 10:51:49 -0700364 applyModalFlag(state);
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700365 applyBrightness(state);
Jorim Jaggif6782ee2016-07-22 11:40:00 +0200366 applyHasTopUi(state);
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700367 applyNotTouchable(state);
Peiyong Lin75045382019-03-04 19:22:33 -0800368 applyStatusBarColorSpaceAgnosticFlag(state);
Lucas Dupin42ebe542019-01-22 09:45:09 -0800369 if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100370 mWindowManager.updateViewLayout(mStatusBarView, mLp);
371 }
Jorim Jaggif6782ee2016-07-22 11:40:00 +0200372 if (mHasTopUi != mHasTopUiChanged) {
373 try {
374 mActivityManager.setHasTopUi(mHasTopUiChanged);
375 } catch (RemoteException e) {
376 Log.e(TAG, "Failed to call setHasTopUi", e);
377 }
378 mHasTopUi = mHasTopUiChanged;
379 }
Winson Chungdc0eca62019-06-13 22:37:31 -0700380 notifyStateChangedCallbacks();
Winson Chung7bbeb452019-06-04 10:25:50 -0700381 }
382
Winson Chungdc0eca62019-06-13 22:37:31 -0700383 public void notifyStateChangedCallbacks() {
384 for (int i = 0; i < mCallbacks.size(); i++) {
385 StatusBarWindowCallback cb = mCallbacks.get(i).get();
386 if (cb != null) {
387 cb.onStateChanged(mCurrentState.keyguardShowing,
388 mCurrentState.keyguardOccluded,
389 mCurrentState.bouncerShowing);
390 }
391 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100392 }
393
Selim Cinek4a4a2bddc2015-05-07 12:50:19 -0700394 private void applyForceStatusBarVisibleFlag(State state) {
Beverly8adbd1e2019-07-25 14:27:17 -0400395 if (state.forceStatusBarVisible || state.forcePluginOpen) {
Selim Cinek4a4a2bddc2015-05-07 12:50:19 -0700396 mLpChanged.privateFlags |= WindowManager
397 .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
398 } else {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400399 mLpChanged.privateFlags
400 &= ~LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
Selim Cinek4a4a2bddc2015-05-07 12:50:19 -0700401 }
402 }
403
Selim Cineka59ecc32015-04-07 10:51:49 -0700404 private void applyModalFlag(State state) {
405 if (state.headsUpShowing) {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400406 mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCH_MODAL;
Selim Cineka59ecc32015-04-07 10:51:49 -0700407 } else {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400408 mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCH_MODAL;
Selim Cineka59ecc32015-04-07 10:51:49 -0700409 }
410 }
411
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700412 private void applyBrightness(State state) {
413 if (state.forceDozeBrightness) {
414 mLpChanged.screenBrightness = mScreenBrightnessDoze;
415 } else {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400416 mLpChanged.screenBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700417 }
418 }
419
Jorim Jaggif6782ee2016-07-22 11:40:00 +0200420 private void applyHasTopUi(State state) {
Steve Elliottff2c0d92019-07-30 15:09:54 -0400421 mHasTopUiChanged = state.forceHasTopUi || isExpanded(state);
Jorim Jaggif6782ee2016-07-22 11:40:00 +0200422 }
423
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700424 private void applyNotTouchable(State state) {
425 if (state.notTouchable) {
426 mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
427 } else {
428 mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCHABLE;
429 }
430 }
431
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100432 public void setKeyguardShowing(boolean showing) {
433 mCurrentState.keyguardShowing = showing;
434 apply(mCurrentState);
435 }
436
437 public void setKeyguardOccluded(boolean occluded) {
438 mCurrentState.keyguardOccluded = occluded;
439 apply(mCurrentState);
440 }
441
442 public void setKeyguardNeedsInput(boolean needsInput) {
443 mCurrentState.keyguardNeedsInput = needsInput;
444 apply(mCurrentState);
445 }
446
Selim Cinek4a21a7f2015-05-19 11:00:38 -0700447 public void setPanelVisible(boolean visible) {
448 mCurrentState.panelVisible = visible;
449 mCurrentState.statusBarFocusable = visible;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100450 apply(mCurrentState);
451 }
452
453 public void setStatusBarFocusable(boolean focusable) {
454 mCurrentState.statusBarFocusable = focusable;
455 apply(mCurrentState);
456 }
457
Jorim Jaggi5fd4d052014-05-13 22:50:20 +0200458 public void setBouncerShowing(boolean showing) {
459 mCurrentState.bouncerShowing = showing;
460 apply(mCurrentState);
461 }
462
Adrian Roosd5c2db62016-03-08 16:11:31 -0800463 public void setBackdropShowing(boolean showing) {
464 mCurrentState.backdropShowing = showing;
465 apply(mCurrentState);
466 }
467
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200468 public void setKeyguardFadingAway(boolean keyguardFadingAway) {
469 mCurrentState.keyguardFadingAway = keyguardFadingAway;
470 apply(mCurrentState);
471 }
472
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200473 public void setQsExpanded(boolean expanded) {
474 mCurrentState.qsExpanded = expanded;
475 apply(mCurrentState);
476 }
477
Vadim Tryshev6069c402016-03-09 14:24:29 -0800478 public void setForceUserActivity(boolean forceUserActivity) {
479 mCurrentState.forceUserActivity = forceUserActivity;
480 apply(mCurrentState);
481 }
482
Lucas Dupin82aa1632017-12-13 00:13:57 -0800483 public void setScrimsVisibility(int scrimsVisibility) {
484 mCurrentState.scrimsVisibility = scrimsVisibility;
Adrian Roosa5c63222017-07-27 16:33:39 +0200485 apply(mCurrentState);
486 }
487
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700488 public void setHeadsUpShowing(boolean showing) {
489 mCurrentState.headsUpShowing = showing;
490 apply(mCurrentState);
491 }
492
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700493 public void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) {
494 mCurrentState.wallpaperSupportsAmbientMode = supportsAmbientMode;
495 apply(mCurrentState);
496 }
497
Jorim Jaggiecbab362014-04-23 16:13:15 +0200498 /**
Jason Monk1fd3fc32018-08-14 17:20:09 -0400499 * @param state The {@link StatusBarStateController} of the status bar.
Jorim Jaggiecbab362014-04-23 16:13:15 +0200500 */
Jason Monk1fd3fc32018-08-14 17:20:09 -0400501 private void setStatusBarState(int state) {
Jorim Jaggiecbab362014-04-23 16:13:15 +0200502 mCurrentState.statusBarState = state;
503 apply(mCurrentState);
504 }
505
Selim Cinek4a4a2bddc2015-05-07 12:50:19 -0700506 public void setForceStatusBarVisible(boolean forceStatusBarVisible) {
507 mCurrentState.forceStatusBarVisible = forceStatusBarVisible;
508 apply(mCurrentState);
509 }
510
Selim Cinek737bff32015-05-08 16:08:35 -0700511 /**
512 * Force the window to be collapsed, even if it should theoretically be expanded.
513 * Used for when a heads-up comes in but we still need to wait for the touchable regions to
514 * be computed.
515 */
516 public void setForceWindowCollapsed(boolean force) {
517 mCurrentState.forceCollapsed = force;
518 apply(mCurrentState);
519 }
520
Selim Cinek4a21a7f2015-05-19 11:00:38 -0700521 public void setPanelExpanded(boolean isExpanded) {
522 mCurrentState.panelExpanded = isExpanded;
523 apply(mCurrentState);
524 }
525
Adrian Roosd28ccd72016-01-06 15:23:14 +0100526 @Override
527 public void onRemoteInputActive(boolean remoteInputActive) {
Adrian Roos1c0ca502015-10-07 12:20:42 -0700528 mCurrentState.remoteInputActive = remoteInputActive;
529 apply(mCurrentState);
530 }
531
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700532 /**
533 * Set whether the screen brightness is forced to the value we use for doze mode by the status
534 * bar window.
535 */
536 public void setForceDozeBrightness(boolean forceDozeBrightness) {
537 mCurrentState.forceDozeBrightness = forceDozeBrightness;
538 apply(mCurrentState);
539 }
540
Adrian Roos67cca742017-04-13 16:52:51 -0700541 public void setDozing(boolean dozing) {
542 mCurrentState.dozing = dozing;
543 apply(mCurrentState);
544 }
545
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700546 public void setBarHeight(int barHeight) {
547 mBarHeight = barHeight;
548 apply(mCurrentState);
549 }
550
Jason Monk421a9412017-02-06 09:15:21 -0800551 public void setForcePluginOpen(boolean forcePluginOpen) {
552 mCurrentState.forcePluginOpen = forcePluginOpen;
553 apply(mCurrentState);
Beverly4ec838b2019-05-29 11:34:45 -0400554 if (mForcePluginOpenListener != null) {
555 mForcePluginOpenListener.onChange(forcePluginOpen);
556 }
557 }
558
559 /**
560 * The forcePluginOpen state for the status bar.
561 */
562 public boolean getForcePluginOpen() {
563 return mCurrentState.forcePluginOpen;
Jason Monk421a9412017-02-06 09:15:21 -0800564 }
565
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700566 public void setNotTouchable(boolean notTouchable) {
567 mCurrentState.notTouchable = notTouchable;
568 apply(mCurrentState);
569 }
570
Mady Mellord1c78b262018-11-06 18:04:40 -0800571 /**
572 * Sets whether there are bubbles showing on the screen.
573 */
574 public void setBubblesShowing(boolean bubblesShowing) {
575 mCurrentState.bubblesShowing = bubblesShowing;
576 apply(mCurrentState);
577 }
578
579 /**
580 * The bubbles showing state for the status bar.
581 */
582 public boolean getBubblesShowing() {
583 return mCurrentState.bubblesShowing;
584 }
585
Issei Suzukiac9fcb72019-02-04 17:45:57 +0100586 /**
587 * Sets if there is a bubble being expanded on the screen.
588 */
589 public void setBubbleExpanded(boolean bubbleExpanded) {
590 mCurrentState.bubbleExpanded = bubbleExpanded;
591 apply(mCurrentState);
592 }
593
594 /**
Mady Mellor390bff42019-04-05 15:09:01 -0700595 * Whether the bubble is shown in expanded state for the status bar.
Issei Suzukiac9fcb72019-02-04 17:45:57 +0100596 */
597 public boolean getBubbleExpanded() {
598 return mCurrentState.bubbleExpanded;
599 }
600
Mady Mellor390bff42019-04-05 15:09:01 -0700601 /**
602 * Whether the status bar panel is expanded or not.
603 */
604 public boolean getPanelExpanded() {
605 return mCurrentState.panelExpanded;
606 }
607
Jason Monk421a9412017-02-06 09:15:21 -0800608 public void setStateListener(OtherwisedCollapsedListener listener) {
609 mListener = listener;
610 }
611
Beverly4ec838b2019-05-29 11:34:45 -0400612 public void setForcePluginOpenListener(ForcePluginOpenListener listener) {
613 mForcePluginOpenListener = listener;
614 }
615
Selim Cinek7025f262015-07-13 16:22:48 -0700616 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Lucas Dupine25c4872019-07-29 13:51:35 -0700617 pw.println("StatusBarWindowController:");
618 pw.println(" mKeyguardDisplayMode=" + mKeyguardDisplayMode);
Selim Cinek7025f262015-07-13 16:22:48 -0700619 pw.println(mCurrentState);
Selim Cinek6a1bd2b2015-06-02 16:02:41 +0200620 }
621
Adrian Roosd5c2db62016-03-08 16:11:31 -0800622 public boolean isShowingWallpaper() {
623 return !mCurrentState.backdropShowing;
624 }
625
Jason Monke59dc402018-08-16 12:05:01 -0400626 @Override
627 public void onThemeChanged() {
Lucas Dupinfdbfc542018-09-17 15:56:09 -0700628 if (mStatusBarView == null) {
629 return;
630 }
631
Lucas Dupin89233c42019-06-10 18:00:22 -0700632 final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
Jason Monke59dc402018-08-16 12:05:01 -0400633 // Make sure we have the correct navbar/statusbar colors.
634 setKeyguardDark(useDarkText);
635 }
636
Lucas Dupine25c4872019-07-29 13:51:35 -0700637 /**
638 * When keyguard will be dismissed but didn't start animation yet.
639 */
640 public void setKeyguardGoingAway(boolean goingAway) {
641 mCurrentState.keyguardGoingAway = goingAway;
642 apply(mCurrentState);
643 }
644
Steve Elliottff2c0d92019-07-30 15:09:54 -0400645 public boolean getForceHasTopUi() {
646 return mCurrentState.forceHasTopUi;
647 }
648
649 public void setForceHasTopUi(boolean forceHasTopUi) {
650 mCurrentState.forceHasTopUi = forceHasTopUi;
651 apply(mCurrentState);
652 }
653
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100654 private static class State {
655 boolean keyguardShowing;
656 boolean keyguardOccluded;
657 boolean keyguardNeedsInput;
Selim Cinek4a21a7f2015-05-19 11:00:38 -0700658 boolean panelVisible;
659 boolean panelExpanded;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100660 boolean statusBarFocusable;
Jorim Jaggi5fd4d052014-05-13 22:50:20 +0200661 boolean bouncerShowing;
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200662 boolean keyguardFadingAway;
Lucas Dupine25c4872019-07-29 13:51:35 -0700663 boolean keyguardGoingAway;
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200664 boolean qsExpanded;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700665 boolean headsUpShowing;
Selim Cinek4a4a2bddc2015-05-07 12:50:19 -0700666 boolean forceStatusBarVisible;
Selim Cinek737bff32015-05-08 16:08:35 -0700667 boolean forceCollapsed;
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700668 boolean forceDozeBrightness;
Vadim Tryshev6069c402016-03-09 14:24:29 -0800669 boolean forceUserActivity;
Adrian Roosd5c2db62016-03-08 16:11:31 -0800670 boolean backdropShowing;
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700671 boolean wallpaperSupportsAmbientMode;
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700672 boolean notTouchable;
Mady Mellord1c78b262018-11-06 18:04:40 -0800673 boolean bubblesShowing;
Issei Suzukiac9fcb72019-02-04 17:45:57 +0100674 boolean bubbleExpanded;
Steve Elliottff2c0d92019-07-30 15:09:54 -0400675 boolean forceHasTopUi;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100676
Jorim Jaggiecbab362014-04-23 16:13:15 +0200677 /**
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500678 * The {@link StatusBar} state from the status bar.
Jorim Jaggiecbab362014-04-23 16:13:15 +0200679 */
680 int statusBarState;
681
Adrian Roos1c0ca502015-10-07 12:20:42 -0700682 boolean remoteInputActive;
Jason Monk421a9412017-02-06 09:15:21 -0800683 boolean forcePluginOpen;
Adrian Roos67cca742017-04-13 16:52:51 -0700684 boolean dozing;
Lucas Dupin82aa1632017-12-13 00:13:57 -0800685 int scrimsVisibility;
Adrian Roos1c0ca502015-10-07 12:20:42 -0700686
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100687 private boolean isKeyguardShowingAndNotOccluded() {
688 return keyguardShowing && !keyguardOccluded;
689 }
Selim Cinek6a1bd2b2015-06-02 16:02:41 +0200690
691 @Override
692 public String toString() {
693 StringBuilder result = new StringBuilder();
694 String newLine = "\n";
695 result.append("Window State {");
696 result.append(newLine);
697
698 Field[] fields = this.getClass().getDeclaredFields();
699
700 // Print field names paired with their values
701 for (Field field : fields) {
702 result.append(" ");
703 try {
704 result.append(field.getName());
705 result.append(": ");
706 //requires access to private field:
707 result.append(field.get(this));
708 } catch (IllegalAccessException ex) {
709 }
710 result.append(newLine);
711 }
712 result.append("}");
713
714 return result.toString();
715 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100716 }
Jason Monk421a9412017-02-06 09:15:21 -0800717
Evan Laird878c8532018-10-15 15:54:29 -0400718 private final StateListener mStateListener = new StateListener() {
719 @Override
720 public void onStateChanged(int newState) {
721 setStatusBarState(newState);
722 }
723
724 @Override
725 public void onDozingChanged(boolean isDozing) {
726 setDozing(isDozing);
727 }
728 };
729
Jason Monk421a9412017-02-06 09:15:21 -0800730 /**
731 * Custom listener to pipe data back to plugins about whether or not the status bar would be
732 * collapsed if not for the plugin.
733 * TODO: Find cleaner way to do this.
734 */
735 public interface OtherwisedCollapsedListener {
736 void setWouldOtherwiseCollapse(boolean otherwiseCollapse);
737 }
Beverly4ec838b2019-05-29 11:34:45 -0400738
739 /**
740 * Listener to indicate forcePluginOpen has changed
741 */
742 public interface ForcePluginOpenListener {
743 /**
744 * Called when mState.forcePluginOpen is changed
745 */
746 void onChange(boolean forceOpen);
747 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100748}