StatusBarWindowManager.java revision 1c0ca508b9d6184beba2050e6ab3a44ac5be137a
1/*
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
19import android.content.Context;
20import android.content.pm.ActivityInfo;
21import android.content.res.Resources;
22import android.graphics.PixelFormat;
23import android.os.SystemProperties;
24import android.view.Gravity;
25import android.view.View;
26import android.view.ViewGroup;
27import android.view.Window;
28import android.view.WindowManager;
29
30import com.android.keyguard.R;
31import com.android.systemui.keyguard.KeyguardViewMediator;
32import com.android.systemui.statusbar.BaseStatusBar;
33import com.android.systemui.statusbar.StatusBarState;
34
35import java.io.FileDescriptor;
36import java.io.PrintWriter;
37import java.lang.reflect.Field;
38
39/**
40 * Encapsulates all logic for the status bar window state management.
41 */
42public class StatusBarWindowManager {
43
44    private final Context mContext;
45    private final WindowManager mWindowManager;
46    private View mStatusBarView;
47    private WindowManager.LayoutParams mLp;
48    private WindowManager.LayoutParams mLpChanged;
49    private int mBarHeight;
50    private final boolean mKeyguardScreenRotation;
51    private final float mScreenBrightnessDoze;
52    private final State mCurrentState = new State();
53
54    public StatusBarWindowManager(Context context) {
55        mContext = context;
56        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
57        mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
58        mScreenBrightnessDoze = mContext.getResources().getInteger(
59                com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
60    }
61
62    private boolean shouldEnableKeyguardScreenRotation() {
63        Resources res = mContext.getResources();
64        return SystemProperties.getBoolean("lockscreen.rot_override", false)
65                || res.getBoolean(R.bool.config_enableLockScreenRotation);
66    }
67
68    /**
69     * Adds the status bar view to the window manager.
70     *
71     * @param statusBarView The view to add.
72     * @param barHeight The height of the status bar in collapsed state.
73     */
74    public void add(View statusBarView, int barHeight) {
75
76        // Now that the status bar window encompasses the sliding panel and its
77        // translucent backdrop, the entire thing is made TRANSLUCENT and is
78        // hardware-accelerated.
79        mLp = new WindowManager.LayoutParams(
80                ViewGroup.LayoutParams.MATCH_PARENT,
81                barHeight,
82                WindowManager.LayoutParams.TYPE_STATUS_BAR,
83                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
84                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
85                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
86                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
87                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
88                PixelFormat.TRANSLUCENT);
89        mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
90        mLp.gravity = Gravity.TOP;
91        mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
92        mLp.setTitle("StatusBar");
93        mLp.packageName = mContext.getPackageName();
94        mStatusBarView = statusBarView;
95        mBarHeight = barHeight;
96        mWindowManager.addView(mStatusBarView, mLp);
97        mLpChanged = new WindowManager.LayoutParams();
98        mLpChanged.copyFrom(mLp);
99    }
100
101    private void applyKeyguardFlags(State state) {
102        if (state.keyguardShowing) {
103            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
104            mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
105        } else {
106            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
107            mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
108        }
109    }
110
111    private void adjustScreenOrientation(State state) {
112        if (state.isKeyguardShowingAndNotOccluded()) {
113            if (mKeyguardScreenRotation) {
114                mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
115            } else {
116                mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
117            }
118        } else {
119            mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
120        }
121    }
122
123    private void applyFocusableFlag(State state) {
124        boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
125        if (state.keyguardShowing && state.keyguardNeedsInput && state.bouncerShowing
126                || BaseStatusBar.ENABLE_REMOTE_INPUT && state.remoteInputActive) {
127            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
128            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
129        } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
130            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
131            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
132        } else {
133            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
134            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
135        }
136    }
137
138    private void applyHeight(State state) {
139        boolean expanded = isExpanded(state);
140        if (expanded) {
141            mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
142        } else {
143            mLpChanged.height = mBarHeight;
144        }
145    }
146
147    private boolean isExpanded(State state) {
148        return !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
149                || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
150                || state.headsUpShowing);
151    }
152
153    private void applyFitsSystemWindows(State state) {
154        mStatusBarView.setFitsSystemWindows(!state.isKeyguardShowingAndNotOccluded());
155    }
156
157    private void applyUserActivityTimeout(State state) {
158        if (state.isKeyguardShowingAndNotOccluded()
159                && state.statusBarState == StatusBarState.KEYGUARD
160                && !state.qsExpanded) {
161            mLpChanged.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
162        } else {
163            mLpChanged.userActivityTimeout = -1;
164        }
165    }
166
167    private void applyInputFeatures(State state) {
168        if (state.isKeyguardShowingAndNotOccluded()
169                && state.statusBarState == StatusBarState.KEYGUARD
170                && !state.qsExpanded) {
171            mLpChanged.inputFeatures |=
172                    WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
173        } else {
174            mLpChanged.inputFeatures &=
175                    ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
176        }
177    }
178
179    private void apply(State state) {
180        applyKeyguardFlags(state);
181        applyForceStatusBarVisibleFlag(state);
182        applyFocusableFlag(state);
183        adjustScreenOrientation(state);
184        applyHeight(state);
185        applyUserActivityTimeout(state);
186        applyInputFeatures(state);
187        applyFitsSystemWindows(state);
188        applyModalFlag(state);
189        applyBrightness(state);
190        if (mLp.copyFrom(mLpChanged) != 0) {
191            mWindowManager.updateViewLayout(mStatusBarView, mLp);
192        }
193    }
194
195    private void applyForceStatusBarVisibleFlag(State state) {
196        if (state.forceStatusBarVisible) {
197            mLpChanged.privateFlags |= WindowManager
198                    .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
199        } else {
200            mLpChanged.privateFlags &= ~WindowManager
201                    .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
202        }
203    }
204
205    private void applyModalFlag(State state) {
206        if (state.headsUpShowing) {
207            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
208        } else {
209            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
210        }
211    }
212
213    private void applyBrightness(State state) {
214        if (state.forceDozeBrightness) {
215            mLpChanged.screenBrightness = mScreenBrightnessDoze;
216        } else {
217            mLpChanged.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
218        }
219    }
220
221    public void setKeyguardShowing(boolean showing) {
222        mCurrentState.keyguardShowing = showing;
223        apply(mCurrentState);
224    }
225
226    public void setKeyguardOccluded(boolean occluded) {
227        mCurrentState.keyguardOccluded = occluded;
228        apply(mCurrentState);
229    }
230
231    public void setKeyguardNeedsInput(boolean needsInput) {
232        mCurrentState.keyguardNeedsInput = needsInput;
233        apply(mCurrentState);
234    }
235
236    public void setPanelVisible(boolean visible) {
237        mCurrentState.panelVisible = visible;
238        mCurrentState.statusBarFocusable = visible;
239        apply(mCurrentState);
240    }
241
242    public void setStatusBarFocusable(boolean focusable) {
243        mCurrentState.statusBarFocusable = focusable;
244        apply(mCurrentState);
245    }
246
247    public void setBouncerShowing(boolean showing) {
248        mCurrentState.bouncerShowing = showing;
249        apply(mCurrentState);
250    }
251
252    public void setKeyguardFadingAway(boolean keyguardFadingAway) {
253        mCurrentState.keyguardFadingAway = keyguardFadingAway;
254        apply(mCurrentState);
255    }
256
257    public void setQsExpanded(boolean expanded) {
258        mCurrentState.qsExpanded = expanded;
259        apply(mCurrentState);
260    }
261
262    public void setHeadsUpShowing(boolean showing) {
263        mCurrentState.headsUpShowing = showing;
264        apply(mCurrentState);
265    }
266
267    /**
268     * @param state The {@link StatusBarState} of the status bar.
269     */
270    public void setStatusBarState(int state) {
271        mCurrentState.statusBarState = state;
272        apply(mCurrentState);
273    }
274
275    public void setForceStatusBarVisible(boolean forceStatusBarVisible) {
276        mCurrentState.forceStatusBarVisible = forceStatusBarVisible;
277        apply(mCurrentState);
278    }
279
280    /**
281     * Force the window to be collapsed, even if it should theoretically be expanded.
282     * Used for when a heads-up comes in but we still need to wait for the touchable regions to
283     * be computed.
284     */
285    public void setForceWindowCollapsed(boolean force) {
286        mCurrentState.forceCollapsed = force;
287        apply(mCurrentState);
288    }
289
290    public void setPanelExpanded(boolean isExpanded) {
291        mCurrentState.panelExpanded = isExpanded;
292        apply(mCurrentState);
293    }
294
295    public void setRemoteInputActive(boolean remoteInputActive) {
296        mCurrentState.remoteInputActive = remoteInputActive;
297        apply(mCurrentState);
298    }
299
300    /**
301     * Set whether the screen brightness is forced to the value we use for doze mode by the status
302     * bar window.
303     */
304    public void setForceDozeBrightness(boolean forceDozeBrightness) {
305        mCurrentState.forceDozeBrightness = forceDozeBrightness;
306        apply(mCurrentState);
307    }
308
309    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
310        pw.println("StatusBarWindowManager state:");
311        pw.println(mCurrentState);
312    }
313
314    private static class State {
315        boolean keyguardShowing;
316        boolean keyguardOccluded;
317        boolean keyguardNeedsInput;
318        boolean panelVisible;
319        boolean panelExpanded;
320        boolean statusBarFocusable;
321        boolean bouncerShowing;
322        boolean keyguardFadingAway;
323        boolean qsExpanded;
324        boolean headsUpShowing;
325        boolean forceStatusBarVisible;
326        boolean forceCollapsed;
327        boolean forceDozeBrightness;
328
329        /**
330         * The {@link BaseStatusBar} state from the status bar.
331         */
332        int statusBarState;
333
334        boolean remoteInputActive;
335
336        private boolean isKeyguardShowingAndNotOccluded() {
337            return keyguardShowing && !keyguardOccluded;
338        }
339
340        @Override
341        public String toString() {
342            StringBuilder result = new StringBuilder();
343            String newLine = "\n";
344            result.append("Window State {");
345            result.append(newLine);
346
347            Field[] fields = this.getClass().getDeclaredFields();
348
349            // Print field names paired with their values
350            for (Field field : fields) {
351                result.append("  ");
352                try {
353                    result.append(field.getName());
354                    result.append(": ");
355                    //requires access to private field:
356                    result.append(field.get(this));
357                } catch (IllegalAccessException ex) {
358                }
359                result.append(newLine);
360            }
361            result.append("}");
362
363            return result.toString();
364        }
365    }
366}
367