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 onCreate(@ullable Bundle savedInstanceState)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 onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState)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 onViewCreated(View view, @Nullable Bundle savedInstanceState)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 onSaveInstanceState(Bundle outState)106 public void onSaveInstanceState(Bundle outState) { 107 super.onSaveInstanceState(outState); 108 outState.putInt(EXTRA_PANEL_STATE, mStatusBar.getState()); 109 } 110 111 @Override onResume()112 public void onResume() { 113 super.onResume(); 114 SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this); 115 } 116 117 @Override onPause()118 public void onPause() { 119 super.onPause(); 120 SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this); 121 } 122 123 @Override onDestroyView()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 initNotificationIconArea(NotificationIconAreaController notificationIconAreaController)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 disable(int state1, int state2, boolean animate)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 adjustDisableFlags(int state)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 shouldHideNotificationIcons()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 hideSystemIconArea(boolean animate)208 public void hideSystemIconArea(boolean animate) { 209 animateHide(mSystemIconArea, animate); 210 } 211 showSystemIconArea(boolean animate)212 public void showSystemIconArea(boolean animate) { 213 animateShow(mSystemIconArea, animate); 214 } 215 hideClock(boolean animate)216 public void hideClock(boolean animate) { 217 animateHiddenState(mClockView, clockHiddenMode(), animate); 218 } 219 showClock(boolean animate)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 */ clockHiddenMode()228 private int clockHiddenMode() { 229 if (!mStatusBar.isClosed() && !mKeyguardMonitor.isShowing()) { 230 return View.INVISIBLE; 231 } 232 return View.GONE; 233 } 234 hideNotificationIconArea(boolean animate)235 public void hideNotificationIconArea(boolean animate) { 236 animateHide(mNotificationIconAreaInner, animate); 237 } 238 showNotificationIconArea(boolean animate)239 public void showNotificationIconArea(boolean animate) { 240 animateShow(mNotificationIconAreaInner, animate); 241 } 242 hideOperatorName(boolean animate)243 public void hideOperatorName(boolean animate) { 244 if (mOperatorNameFrame != null) { 245 animateHide(mOperatorNameFrame, animate); 246 } 247 } 248 showOperatorName(boolean animate)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 */ animateHiddenState(final View v, int state, boolean animate)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 */ animateHide(final View v, boolean animate)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 */ animateShow(View v, boolean animate)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 initEmergencyCryptkeeperText()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 initOperatorName()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