• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.server.policy;
18 
19 import android.app.StatusBarManager;
20 import android.os.Handler;
21 import android.os.RemoteException;
22 import android.os.ServiceManager;
23 import android.os.SystemClock;
24 import android.util.Slog;
25 import android.view.View;
26 import android.view.WindowManager;
27 import android.view.WindowManagerPolicy.WindowState;
28 
29 import com.android.internal.statusbar.IStatusBarService;
30 
31 import java.io.PrintWriter;
32 
33 /**
34  * Controls state/behavior specific to a system bar window.
35  */
36 public class BarController {
37     private static final boolean DEBUG = false;
38 
39     private static final int TRANSIENT_BAR_NONE = 0;
40     private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1;
41     private static final int TRANSIENT_BAR_SHOWING = 2;
42     private static final int TRANSIENT_BAR_HIDING = 3;
43 
44     private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
45 
46     protected final String mTag;
47     private final int mTransientFlag;
48     private final int mUnhideFlag;
49     private final int mTranslucentFlag;
50     private final int mStatusBarManagerId;
51     private final int mTranslucentWmFlag;
52     protected final Handler mHandler;
53     private final Object mServiceAquireLock = new Object();
54     protected IStatusBarService mStatusBarService;
55 
56     private WindowState mWin;
57     private int mState = StatusBarManager.WINDOW_STATE_SHOWING;
58     private int mTransientBarState;
59     private boolean mPendingShow;
60     private long mLastTranslucent;
61     private boolean mShowTransparent;
62     private boolean mSetUnHideFlagWhenNextTransparent;
63     private boolean mNoAnimationOnNextShow;
64 
BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag, int statusBarManagerId, int translucentWmFlag)65     public BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag,
66             int statusBarManagerId, int translucentWmFlag) {
67         mTag = "BarController." + tag;
68         mTransientFlag = transientFlag;
69         mUnhideFlag = unhideFlag;
70         mTranslucentFlag = translucentFlag;
71         mStatusBarManagerId = statusBarManagerId;
72         mTranslucentWmFlag = translucentWmFlag;
73         mHandler = new Handler();
74     }
75 
setWindow(WindowState win)76     public void setWindow(WindowState win) {
77         mWin = win;
78     }
79 
setShowTransparent(boolean transparent)80     public void setShowTransparent(boolean transparent) {
81         if (transparent != mShowTransparent) {
82             mShowTransparent = transparent;
83             mSetUnHideFlagWhenNextTransparent = transparent;
84             mNoAnimationOnNextShow = true;
85         }
86     }
87 
showTransient()88     public void showTransient() {
89         if (mWin != null) {
90             setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
91         }
92     }
93 
isTransientShowing()94     public boolean isTransientShowing() {
95         return mTransientBarState == TRANSIENT_BAR_SHOWING;
96     }
97 
isTransientShowRequested()98     public boolean isTransientShowRequested() {
99         return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED;
100     }
101 
wasRecentlyTranslucent()102     public boolean wasRecentlyTranslucent() {
103         return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS;
104     }
105 
adjustSystemUiVisibilityLw(int oldVis, int vis)106     public void adjustSystemUiVisibilityLw(int oldVis, int vis) {
107         if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
108                 (vis & mTransientFlag) == 0) {
109             // sysui requests hide
110             setTransientBarState(TRANSIENT_BAR_HIDING);
111             setBarShowingLw(false);
112         } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) {
113             // sysui ready to unhide
114             setBarShowingLw(true);
115         }
116     }
117 
applyTranslucentFlagLw(WindowState win, int vis, int oldVis)118     public int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) {
119         if (mWin != null) {
120             if (win != null && (win.getAttrs().privateFlags
121                     & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
122                 int fl = PolicyControl.getWindowFlags(win, null);
123                 if ((fl & mTranslucentWmFlag) != 0) {
124                     vis |= mTranslucentFlag;
125                 } else {
126                     vis &= ~mTranslucentFlag;
127                 }
128                 if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
129                     vis |= View.SYSTEM_UI_TRANSPARENT;
130                 } else {
131                     vis &= ~View.SYSTEM_UI_TRANSPARENT;
132                 }
133             } else {
134                 vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag);
135                 vis = (vis & ~View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT);
136             }
137         }
138         return vis;
139     }
140 
setBarShowingLw(final boolean show)141     public boolean setBarShowingLw(final boolean show) {
142         if (mWin == null) return false;
143         if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
144             mPendingShow = true;
145             return false;
146         }
147         final boolean wasVis = mWin.isVisibleLw();
148         final boolean wasAnim = mWin.isAnimatingLw();
149         final boolean change = show ? mWin.showLw(!mNoAnimationOnNextShow)
150                 : mWin.hideLw(!mNoAnimationOnNextShow);
151         mNoAnimationOnNextShow = false;
152         final int state = computeStateLw(wasVis, wasAnim, mWin, change);
153         final boolean stateChanged = updateStateLw(state);
154         return change || stateChanged;
155     }
156 
computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change)157     private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
158         if (win.isDrawnLw()) {
159             final boolean vis = win.isVisibleLw();
160             final boolean anim = win.isAnimatingLw();
161             if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
162                 return StatusBarManager.WINDOW_STATE_HIDDEN;
163             } else if (mState == StatusBarManager.WINDOW_STATE_HIDDEN && vis) {
164                 return StatusBarManager.WINDOW_STATE_SHOWING;
165             } else if (change) {
166                 if (wasVis && vis && !wasAnim && anim) {
167                     return StatusBarManager.WINDOW_STATE_HIDING;
168                 } else {
169                     return StatusBarManager.WINDOW_STATE_SHOWING;
170                 }
171             }
172         }
173         return mState;
174     }
175 
updateStateLw(final int state)176     private boolean updateStateLw(final int state) {
177         if (state != mState) {
178             mState = state;
179             if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
180             mHandler.post(new Runnable() {
181                 @Override
182                 public void run() {
183                     try {
184                         IStatusBarService statusbar = getStatusBarService();
185                         if (statusbar != null) {
186                             statusbar.setWindowState(mStatusBarManagerId, state);
187                         }
188                     } catch (RemoteException e) {
189                         if (DEBUG) Slog.w(mTag, "Error posting window state", e);
190                         // re-acquire status bar service next time it is needed.
191                         mStatusBarService = null;
192                     }
193                 }
194             });
195             return true;
196         }
197         return false;
198     }
199 
checkHiddenLw()200     public boolean checkHiddenLw() {
201         if (mWin != null && mWin.isDrawnLw()) {
202             if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
203                 updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
204             }
205             if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
206                 // Finished animating out, clean up and reset style
207                 setTransientBarState(TRANSIENT_BAR_NONE);
208                 if (mPendingShow) {
209                     setBarShowingLw(true);
210                     mPendingShow = false;
211                 }
212                 return true;
213             }
214         }
215         return false;
216     }
217 
checkShowTransientBarLw()218     public boolean checkShowTransientBarLw() {
219         if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
220             if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
221             return false;
222         } else if (mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED) {
223             if (DEBUG) Slog.d(mTag, "Not showing transient bar, already requested");
224             return false;
225         } else if (mWin == null) {
226             if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
227             return false;
228         } else if (mWin.isDisplayedLw()) {
229             if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
230             return false;
231         } else {
232             return true;
233         }
234     }
235 
updateVisibilityLw(boolean transientAllowed, int oldVis, int vis)236     public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
237         if (mWin == null) return vis;
238         if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
239             if (transientAllowed) {
240                 vis |= mTransientFlag;
241                 if ((oldVis & mTransientFlag) == 0) {
242                     vis |= mUnhideFlag;  // tell sysui we're ready to unhide
243                 }
244                 setTransientBarState(TRANSIENT_BAR_SHOWING);  // request accepted
245             } else {
246                 setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
247             }
248         }
249         if (mShowTransparent) {
250             vis |= View.SYSTEM_UI_TRANSPARENT;
251             if (mSetUnHideFlagWhenNextTransparent) {
252                 vis |= mUnhideFlag;
253                 mSetUnHideFlagWhenNextTransparent = false;
254             }
255         }
256         if (mTransientBarState != TRANSIENT_BAR_NONE) {
257             vis |= mTransientFlag;  // ignore clear requests until transition completes
258             vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
259         }
260         if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 ||
261                 ((vis | oldVis) & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
262             mLastTranslucent = SystemClock.uptimeMillis();
263         }
264         return vis;
265     }
266 
setTransientBarState(int state)267     private void setTransientBarState(int state) {
268         if (mWin != null && state != mTransientBarState) {
269             if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) {
270                 mLastTranslucent = SystemClock.uptimeMillis();
271             }
272             mTransientBarState = state;
273             if (DEBUG) Slog.d(mTag, "mTransientBarState: " + transientBarStateToString(state));
274         }
275     }
276 
getStatusBarService()277     protected IStatusBarService getStatusBarService() {
278         synchronized (mServiceAquireLock) {
279             if (mStatusBarService == null) {
280                 mStatusBarService = IStatusBarService.Stub.asInterface(
281                         ServiceManager.getService("statusbar"));
282             }
283             return mStatusBarService;
284         }
285     }
286 
transientBarStateToString(int state)287     private static String transientBarStateToString(int state) {
288         if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
289         if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
290         if (state == TRANSIENT_BAR_SHOW_REQUESTED) return "TRANSIENT_BAR_SHOW_REQUESTED";
291         if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
292         throw new IllegalArgumentException("Unknown state " + state);
293     }
294 
dump(PrintWriter pw, String prefix)295     public void dump(PrintWriter pw, String prefix) {
296         if (mWin != null) {
297             pw.print(prefix); pw.println(mTag);
298             pw.print(prefix); pw.print("  "); pw.print("mState"); pw.print('=');
299             pw.println(StatusBarManager.windowStateToString(mState));
300             pw.print(prefix); pw.print("  "); pw.print("mTransientBar"); pw.print('=');
301             pw.println(transientBarStateToString(mTransientBarState));
302         }
303     }
304 }
305