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