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