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_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