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 17package com.android.server.policy; 18 19import android.app.StatusBarManager; 20import android.os.Handler; 21import android.os.RemoteException; 22import android.os.ServiceManager; 23import android.os.SystemClock; 24import android.util.Slog; 25import android.view.View; 26import android.view.WindowManager; 27import android.view.WindowManagerPolicy.WindowState; 28 29import com.android.internal.statusbar.IStatusBarService; 30 31import java.io.PrintWriter; 32 33/** 34 * Controls state/behavior specific to a system bar window. 35 */ 36public 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 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 76 public void setWindow(WindowState win) { 77 mWin = win; 78 } 79 80 public void setShowTransparent(boolean transparent) { 81 if (transparent != mShowTransparent) { 82 mShowTransparent = transparent; 83 mSetUnHideFlagWhenNextTransparent = transparent; 84 mNoAnimationOnNextShow = true; 85 } 86 } 87 88 public void showTransient() { 89 if (mWin != null) { 90 setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED); 91 } 92 } 93 94 public boolean isTransientShowing() { 95 return mTransientBarState == TRANSIENT_BAR_SHOWING; 96 } 97 98 public boolean isTransientShowRequested() { 99 return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED; 100 } 101 102 public boolean wasRecentlyTranslucent() { 103 return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS; 104 } 105 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 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 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 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 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 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 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 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 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 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 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 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