Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
      5  * except in compliance with the License. You may obtain a copy of the License at
      6  *
      7  *      http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the
     10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     11  * KIND, either express or implied. See the License for the specific language governing
     12  * permissions and limitations under the License.
     13  */
     14 
     15 package com.android.systemui.statusbar.phone;
     16 
     17 import static android.app.StatusBarManager.DISABLE_CLOCK;
     18 import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
     19 import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
     20 
     21 import android.annotation.Nullable;
     22 import android.app.Fragment;
     23 import android.app.StatusBarManager;
     24 import android.os.Bundle;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.view.ViewStub;
     29 import android.widget.LinearLayout;
     30 
     31 import com.android.systemui.Dependency;
     32 import com.android.systemui.Interpolators;
     33 import com.android.systemui.R;
     34 import com.android.systemui.SysUiServiceProvider;
     35 import com.android.systemui.statusbar.CommandQueue;
     36 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
     37 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
     38 import com.android.systemui.statusbar.policy.EncryptionHelper;
     39 import com.android.systemui.statusbar.policy.KeyguardMonitor;
     40 import com.android.systemui.statusbar.policy.NetworkController;
     41 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
     42 
     43 /**
     44  * Contains the collapsed status bar and handles hiding/showing based on disable flags
     45  * and keyguard state. Also manages lifecycle to make sure the views it contains are being
     46  * updated by the StatusBarIconController and DarkIconManager while it is attached.
     47  */
     48 public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks {
     49 
     50     public static final String TAG = "CollapsedStatusBarFragment";
     51     private static final String EXTRA_PANEL_STATE = "panel_state";
     52     public static final String STATUS_BAR_ICON_MANAGER_TAG = "status_bar_icon_manager";
     53     public static final int FADE_IN_DURATION = 320;
     54     public static final int FADE_IN_DELAY = 50;
     55     private PhoneStatusBarView mStatusBar;
     56     private KeyguardMonitor mKeyguardMonitor;
     57     private NetworkController mNetworkController;
     58     private LinearLayout mSystemIconArea;
     59     private View mClockView;
     60     private View mNotificationIconAreaInner;
     61     private int mDisabled1;
     62     private StatusBar mStatusBarComponent;
     63     private DarkIconManager mDarkIconManager;
     64     private View mOperatorNameFrame;
     65 
     66     private SignalCallback mSignalCallback = new SignalCallback() {
     67         @Override
     68         public void setIsAirplaneMode(NetworkController.IconState icon) {
     69             mStatusBarComponent.recomputeDisableFlags(true /* animate */);
     70         }
     71     };
     72 
     73     @Override
     74     public void onCreate(@Nullable Bundle savedInstanceState) {
     75         super.onCreate(savedInstanceState);
     76         mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
     77         mNetworkController = Dependency.get(NetworkController.class);
     78         mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
     79     }
     80 
     81     @Override
     82     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
     83             Bundle savedInstanceState) {
     84         return inflater.inflate(R.layout.status_bar, container, false);
     85     }
     86 
     87     @Override
     88     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
     89         super.onViewCreated(view, savedInstanceState);
     90         mStatusBar = (PhoneStatusBarView) view;
     91         if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
     92             mStatusBar.go(savedInstanceState.getInt(EXTRA_PANEL_STATE));
     93         }
     94         mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
     95         mDarkIconManager.setShouldLog(true);
     96         Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
     97         mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
     98         mClockView = mStatusBar.findViewById(R.id.clock);
     99         showSystemIconArea(false);
    100         showClock(false);
    101         initEmergencyCryptkeeperText();
    102         initOperatorName();
    103     }
    104 
    105     @Override
    106     public void onSaveInstanceState(Bundle outState) {
    107         super.onSaveInstanceState(outState);
    108         outState.putInt(EXTRA_PANEL_STATE, mStatusBar.getState());
    109     }
    110 
    111     @Override
    112     public void onResume() {
    113         super.onResume();
    114         SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
    115     }
    116 
    117     @Override
    118     public void onPause() {
    119         super.onPause();
    120         SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
    121     }
    122 
    123     @Override
    124     public void onDestroyView() {
    125         super.onDestroyView();
    126         Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
    127         if (mNetworkController.hasEmergencyCryptKeeperText()) {
    128             mNetworkController.removeCallback(mSignalCallback);
    129         }
    130     }
    131 
    132     public void initNotificationIconArea(NotificationIconAreaController
    133             notificationIconAreaController) {
    134         ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);
    135         mNotificationIconAreaInner =
    136                 notificationIconAreaController.getNotificationInnerAreaView();
    137         if (mNotificationIconAreaInner.getParent() != null) {
    138             ((ViewGroup) mNotificationIconAreaInner.getParent())
    139                     .removeView(mNotificationIconAreaInner);
    140         }
    141         notificationIconArea.addView(mNotificationIconAreaInner);
    142         // Default to showing until we know otherwise.
    143         showNotificationIconArea(false);
    144     }
    145 
    146     @Override
    147     public void disable(int state1, int state2, boolean animate) {
    148         state1 = adjustDisableFlags(state1);
    149         final int old1 = mDisabled1;
    150         final int diff1 = state1 ^ old1;
    151         mDisabled1 = state1;
    152         if ((diff1 & DISABLE_SYSTEM_INFO) != 0) {
    153             if ((state1 & DISABLE_SYSTEM_INFO) != 0) {
    154                 hideSystemIconArea(animate);
    155                 hideOperatorName(animate);
    156             } else {
    157                 showSystemIconArea(animate);
    158                 showOperatorName(animate);
    159             }
    160         }
    161         if ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0) {
    162             if ((state1 & DISABLE_NOTIFICATION_ICONS) != 0) {
    163                 hideNotificationIconArea(animate);
    164             } else {
    165                 showNotificationIconArea(animate);
    166             }
    167         }
    168         // The clock may have already been hidden, but we might want to shift its
    169         // visibility to GONE from INVISIBLE or vice versa
    170         if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) {
    171             if ((state1 & DISABLE_CLOCK) != 0) {
    172                 hideClock(animate);
    173             } else {
    174                 showClock(animate);
    175             }
    176         }
    177     }
    178 
    179     protected int adjustDisableFlags(int state) {
    180         if (!mStatusBarComponent.isLaunchTransitionFadingAway()
    181                 && !mKeyguardMonitor.isKeyguardFadingAway()
    182                 && shouldHideNotificationIcons()) {
    183             state |= DISABLE_NOTIFICATION_ICONS;
    184             state |= DISABLE_SYSTEM_INFO;
    185             state |= DISABLE_CLOCK;
    186         }
    187         if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
    188             if (mNetworkController.hasEmergencyCryptKeeperText()) {
    189                 state |= DISABLE_NOTIFICATION_ICONS;
    190             }
    191             if (!mNetworkController.isRadioOn()) {
    192                 state |= DISABLE_SYSTEM_INFO;
    193             }
    194         }
    195         return state;
    196     }
    197 
    198     private boolean shouldHideNotificationIcons() {
    199         if (!mStatusBar.isClosed() && mStatusBarComponent.hideStatusBarIconsWhenExpanded()) {
    200             return true;
    201         }
    202         if (mStatusBarComponent.hideStatusBarIconsForBouncer()) {
    203             return true;
    204         }
    205         return false;
    206     }
    207 
    208     public void hideSystemIconArea(boolean animate) {
    209         animateHide(mSystemIconArea, animate);
    210     }
    211 
    212     public void showSystemIconArea(boolean animate) {
    213         animateShow(mSystemIconArea, animate);
    214     }
    215 
    216     public void hideClock(boolean animate) {
    217         animateHiddenState(mClockView, clockHiddenMode(), animate);
    218     }
    219 
    220     public void showClock(boolean animate) {
    221         animateShow(mClockView, animate);
    222     }
    223 
    224     /**
    225      * If panel is expanded/expanding it usually means QS shade is opening, so
    226      * don't set the clock GONE otherwise it'll mess up the animation.
    227      */
    228     private int clockHiddenMode() {
    229         if (!mStatusBar.isClosed() && !mKeyguardMonitor.isShowing()) {
    230             return View.INVISIBLE;
    231         }
    232         return View.GONE;
    233     }
    234 
    235     public void hideNotificationIconArea(boolean animate) {
    236         animateHide(mNotificationIconAreaInner, animate);
    237     }
    238 
    239     public void showNotificationIconArea(boolean animate) {
    240         animateShow(mNotificationIconAreaInner, animate);
    241     }
    242 
    243     public void hideOperatorName(boolean animate) {
    244         if (mOperatorNameFrame != null) {
    245             animateHide(mOperatorNameFrame, animate);
    246         }
    247     }
    248 
    249     public void showOperatorName(boolean animate) {
    250         if (mOperatorNameFrame != null) {
    251             animateShow(mOperatorNameFrame, animate);
    252         }
    253     }
    254 
    255     /**
    256      * Animate a view to INVISIBLE or GONE
    257      */
    258     private void animateHiddenState(final View v, int state, boolean animate) {
    259         v.animate().cancel();
    260         if (!animate) {
    261             v.setAlpha(0f);
    262             v.setVisibility(state);
    263             return;
    264         }
    265 
    266         v.animate()
    267                 .alpha(0f)
    268                 .setDuration(160)
    269                 .setStartDelay(0)
    270                 .setInterpolator(Interpolators.ALPHA_OUT)
    271                 .withEndAction(() -> v.setVisibility(state));
    272     }
    273 
    274     /**
    275      * Hides a view.
    276      */
    277     private void animateHide(final View v, boolean animate) {
    278         animateHiddenState(v, View.INVISIBLE, animate);
    279     }
    280 
    281     /**
    282      * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
    283      */
    284     private void animateShow(View v, boolean animate) {
    285         v.animate().cancel();
    286         v.setVisibility(View.VISIBLE);
    287         if (!animate) {
    288             v.setAlpha(1f);
    289             return;
    290         }
    291         v.animate()
    292                 .alpha(1f)
    293                 .setDuration(FADE_IN_DURATION)
    294                 .setInterpolator(Interpolators.ALPHA_IN)
    295                 .setStartDelay(FADE_IN_DELAY)
    296 
    297                 // We need to clean up any pending end action from animateHide if we call
    298                 // both hide and show in the same frame before the animation actually gets started.
    299                 // cancel() doesn't really remove the end action.
    300                 .withEndAction(null);
    301 
    302         // Synchronize the motion with the Keyguard fading if necessary.
    303         if (mKeyguardMonitor.isKeyguardFadingAway()) {
    304             v.animate()
    305                     .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration())
    306                     .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
    307                     .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
    308                     .start();
    309         }
    310     }
    311 
    312     private void initEmergencyCryptkeeperText() {
    313         View emergencyViewStub = mStatusBar.findViewById(R.id.emergency_cryptkeeper_text);
    314         if (mNetworkController.hasEmergencyCryptKeeperText()) {
    315             if (emergencyViewStub != null) {
    316                 ((ViewStub) emergencyViewStub).inflate();
    317             }
    318             mNetworkController.addCallback(mSignalCallback);
    319         } else if (emergencyViewStub != null) {
    320             ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
    321             parent.removeView(emergencyViewStub);
    322         }
    323     }
    324 
    325     private void initOperatorName() {
    326         if (getResources().getBoolean(R.bool.config_showOperatorNameInStatusBar)) {
    327             ViewStub stub = mStatusBar.findViewById(R.id.operator_name);
    328             mOperatorNameFrame = stub.inflate();
    329         }
    330     }
    331 }
    332