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