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.SystemClock; 22 import android.util.Slog; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.view.WindowManager; 26 import android.view.WindowManagerPolicy.WindowState; 27 28 import com.android.server.LocalServices; 29 import com.android.server.statusbar.StatusBarManagerInternal; 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 mTransparentFlag; 51 private final int mStatusBarManagerId; 52 private final int mTranslucentWmFlag; 53 protected final Handler mHandler; 54 private final Object mServiceAquireLock = new Object(); 55 protected StatusBarManagerInternal mStatusBarInternal; 56 57 protected WindowState mWin; 58 private int mState = StatusBarManager.WINDOW_STATE_SHOWING; 59 private int mTransientBarState; 60 private boolean mPendingShow; 61 private long mLastTranslucent; 62 private boolean mShowTransparent; 63 private boolean mSetUnHideFlagWhenNextTransparent; 64 private boolean mNoAnimationOnNextShow; 65 BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag, int statusBarManagerId, int translucentWmFlag, int transparentFlag)66 public BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag, 67 int statusBarManagerId, int translucentWmFlag, int transparentFlag) { 68 mTag = "BarController." + tag; 69 mTransientFlag = transientFlag; 70 mUnhideFlag = unhideFlag; 71 mTranslucentFlag = translucentFlag; 72 mStatusBarManagerId = statusBarManagerId; 73 mTranslucentWmFlag = translucentWmFlag; 74 mTransparentFlag = transparentFlag; 75 mHandler = new Handler(); 76 } 77 setWindow(WindowState win)78 public void setWindow(WindowState win) { 79 mWin = win; 80 } 81 setShowTransparent(boolean transparent)82 public void setShowTransparent(boolean transparent) { 83 if (transparent != mShowTransparent) { 84 mShowTransparent = transparent; 85 mSetUnHideFlagWhenNextTransparent = transparent; 86 mNoAnimationOnNextShow = true; 87 } 88 } 89 showTransient()90 public void showTransient() { 91 if (mWin != null) { 92 setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED); 93 } 94 } 95 isTransientShowing()96 public boolean isTransientShowing() { 97 return mTransientBarState == TRANSIENT_BAR_SHOWING; 98 } 99 isTransientShowRequested()100 public boolean isTransientShowRequested() { 101 return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED; 102 } 103 wasRecentlyTranslucent()104 public boolean wasRecentlyTranslucent() { 105 return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS; 106 } 107 adjustSystemUiVisibilityLw(int oldVis, int vis)108 public void adjustSystemUiVisibilityLw(int oldVis, int vis) { 109 if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING && 110 (vis & mTransientFlag) == 0) { 111 // sysui requests hide 112 setTransientBarState(TRANSIENT_BAR_HIDING); 113 setBarShowingLw(false); 114 } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) { 115 // sysui ready to unhide 116 setBarShowingLw(true); 117 } 118 } 119 applyTranslucentFlagLw(WindowState win, int vis, int oldVis)120 public int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) { 121 if (mWin != null) { 122 if (win != null && (win.getAttrs().privateFlags 123 & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) { 124 int fl = PolicyControl.getWindowFlags(win, null); 125 if ((fl & mTranslucentWmFlag) != 0) { 126 vis |= mTranslucentFlag; 127 } else { 128 vis &= ~mTranslucentFlag; 129 } 130 if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) { 131 vis |= mTransparentFlag; 132 } else { 133 vis &= ~mTransparentFlag; 134 } 135 } else { 136 vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag); 137 vis = (vis & ~mTransparentFlag) | (oldVis & mTransparentFlag); 138 } 139 } 140 return vis; 141 } 142 setBarShowingLw(final boolean show)143 public boolean setBarShowingLw(final boolean show) { 144 if (mWin == null) return false; 145 if (show && mTransientBarState == TRANSIENT_BAR_HIDING) { 146 mPendingShow = true; 147 return false; 148 } 149 final boolean wasVis = mWin.isVisibleLw(); 150 final boolean wasAnim = mWin.isAnimatingLw(); 151 final boolean change = show ? mWin.showLw(!mNoAnimationOnNextShow && !skipAnimation()) 152 : mWin.hideLw(!mNoAnimationOnNextShow && !skipAnimation()); 153 mNoAnimationOnNextShow = false; 154 final int state = computeStateLw(wasVis, wasAnim, mWin, change); 155 final boolean stateChanged = updateStateLw(state); 156 return change || stateChanged; 157 } 158 skipAnimation()159 protected boolean skipAnimation() { 160 return false; 161 } 162 computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change)163 private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) { 164 if (win.isDrawnLw()) { 165 final boolean vis = win.isVisibleLw(); 166 final boolean anim = win.isAnimatingLw(); 167 if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) { 168 return StatusBarManager.WINDOW_STATE_HIDDEN; 169 } else if (mState == StatusBarManager.WINDOW_STATE_HIDDEN && vis) { 170 return StatusBarManager.WINDOW_STATE_SHOWING; 171 } else if (change) { 172 if (wasVis && vis && !wasAnim && anim) { 173 return StatusBarManager.WINDOW_STATE_HIDING; 174 } else { 175 return StatusBarManager.WINDOW_STATE_SHOWING; 176 } 177 } 178 } 179 return mState; 180 } 181 updateStateLw(final int state)182 private boolean updateStateLw(final int state) { 183 if (state != mState) { 184 mState = state; 185 if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state)); 186 mHandler.post(new Runnable() { 187 @Override 188 public void run() { 189 StatusBarManagerInternal statusbar = getStatusBarInternal(); 190 if (statusbar != null) { 191 statusbar.setWindowState(mStatusBarManagerId, state); 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 |= mTransparentFlag; 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) & mTransparentFlag) != 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 getStatusBarInternal()277 protected StatusBarManagerInternal getStatusBarInternal() { 278 synchronized (mServiceAquireLock) { 279 if (mStatusBarInternal == null) { 280 mStatusBarInternal = LocalServices.getService(StatusBarManagerInternal.class); 281 } 282 return mStatusBarInternal; 283 } 284 } 285 transientBarStateToString(int state)286 private static String transientBarStateToString(int state) { 287 if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING"; 288 if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING"; 289 if (state == TRANSIENT_BAR_SHOW_REQUESTED) return "TRANSIENT_BAR_SHOW_REQUESTED"; 290 if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE"; 291 throw new IllegalArgumentException("Unknown state " + state); 292 } 293 dump(PrintWriter pw, String prefix)294 public void dump(PrintWriter pw, String prefix) { 295 if (mWin != null) { 296 pw.print(prefix); pw.println(mTag); 297 pw.print(prefix); pw.print(" "); pw.print("mState"); pw.print('='); 298 pw.println(StatusBarManager.windowStateToString(mState)); 299 pw.print(prefix); pw.print(" "); pw.print("mTransientBar"); pw.print('='); 300 pw.println(transientBarStateToString(mTransientBarState)); 301 } 302 } 303 } 304