2 * Copyright (C) 2017 The Android Open Source Project
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
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 package com.android.systemui.statusbar.phone;
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;
21 import android.annotation.Nullable;
22 import android.app.Fragment;
23 import android.os.Bundle;
24 import android.os.Parcelable;
25 import android.util.SparseArray;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.view.ViewStub;
30 import android.widget.LinearLayout;
32 import com.android.systemui.Dependency;
33 import com.android.systemui.Interpolators;
34 import com.android.systemui.R;
35 import com.android.systemui.SysUiServiceProvider;
36 import com.android.systemui.plugins.statusbar.StatusBarStateController;
37 import com.android.systemui.statusbar.CommandQueue;
38 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
39 import com.android.systemui.statusbar.policy.EncryptionHelper;
40 import com.android.systemui.statusbar.policy.KeyguardMonitor;
41 import com.android.systemui.statusbar.policy.NetworkController;
42 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
45 * Contains the collapsed status bar and handles hiding/showing based on disable flags
46 * and keyguard state. Also manages lifecycle to make sure the views it contains are being
47 * updated by the StatusBarIconController and DarkIconManager while it is attached.
49 public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks,
50 StatusBarStateController.StateListener {
52 public static final String TAG = "CollapsedStatusBarFragment";
53 private static final String EXTRA_PANEL_STATE = "panel_state";
54 public static final String STATUS_BAR_ICON_MANAGER_TAG = "status_bar_icon_manager";
55 public static final int FADE_IN_DURATION = 320;
56 public static final int FADE_IN_DELAY = 50;
57 private PhoneStatusBarView mStatusBar;
58 private StatusBarStateController mStatusBarStateController;
59 private KeyguardMonitor mKeyguardMonitor;
60 private NetworkController mNetworkController;
61 private LinearLayout mSystemIconArea;
62 private View mClockView;
63 private View mNotificationIconAreaInner;
64 private View mCenteredIconArea;
65 private int mDisabled1;
66 private StatusBar mStatusBarComponent;
67 private DarkIconManager mDarkIconManager;
68 private View mOperatorNameFrame;
69 private CommandQueue mCommandQueue;
71 private SignalCallback mSignalCallback = new SignalCallback() {
73 public void setIsAirplaneMode(NetworkController.IconState icon) {
74 mCommandQueue.recomputeDisableFlags(getContext().getDisplayId(), true /* animate */);
79 public void onCreate(@Nullable Bundle savedInstanceState) {
80 super.onCreate(savedInstanceState);
81 mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
82 mNetworkController = Dependency.get(NetworkController.class);
83 mStatusBarStateController = Dependency.get(StatusBarStateController.class);
84 mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
85 mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
89 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
90 Bundle savedInstanceState) {
91 return inflater.inflate(R.layout.status_bar, container, false);
95 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
96 super.onViewCreated(view, savedInstanceState);
97 mStatusBar = (PhoneStatusBarView) view;
98 if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
99 mStatusBar.restoreHierarchyState(
100 savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
102 mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
103 mDarkIconManager.setShouldLog(true);
104 Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
105 mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
106 mClockView = mStatusBar.findViewById(R.id.clock);
107 showSystemIconArea(false);
109 initEmergencyCryptkeeperText();
114 public void onSaveInstanceState(Bundle outState) {
115 super.onSaveInstanceState(outState);
116 SparseArray<Parcelable> states = new SparseArray<>();
117 mStatusBar.saveHierarchyState(states);
118 outState.putSparseParcelableArray(EXTRA_PANEL_STATE, states);
122 public void onResume() {
124 mCommandQueue.addCallback(this);
125 mStatusBarStateController.addCallback(this);
129 public void onPause() {
131 mCommandQueue.removeCallback(this);
132 mStatusBarStateController.removeCallback(this);
136 public void onDestroyView() {
137 super.onDestroyView();
138 Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
139 if (mNetworkController.hasEmergencyCryptKeeperText()) {
140 mNetworkController.removeCallback(mSignalCallback);
144 public void initNotificationIconArea(NotificationIconAreaController
145 notificationIconAreaController) {
146 ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);
147 mNotificationIconAreaInner =
148 notificationIconAreaController.getNotificationInnerAreaView();
149 if (mNotificationIconAreaInner.getParent() != null) {
150 ((ViewGroup) mNotificationIconAreaInner.getParent())
151 .removeView(mNotificationIconAreaInner);
153 notificationIconArea.addView(mNotificationIconAreaInner);
155 ViewGroup statusBarCenteredIconArea = mStatusBar.findViewById(R.id.centered_icon_area);
156 mCenteredIconArea = notificationIconAreaController.getCenteredNotificationAreaView();
157 if (mCenteredIconArea.getParent() != null) {
158 ((ViewGroup) mCenteredIconArea.getParent())
159 .removeView(mCenteredIconArea);
161 statusBarCenteredIconArea.addView(mCenteredIconArea);
163 // Default to showing until we know otherwise.
164 showNotificationIconArea(false);
168 public void disable(int displayId, int state1, int state2, boolean animate) {
169 if (displayId != getContext().getDisplayId()) {
172 state1 = adjustDisableFlags(state1);
173 final int old1 = mDisabled1;
174 final int diff1 = state1 ^ old1;
176 if ((diff1 & DISABLE_SYSTEM_INFO) != 0) {
177 if ((state1 & DISABLE_SYSTEM_INFO) != 0) {
178 hideSystemIconArea(animate);
179 hideOperatorName(animate);
181 showSystemIconArea(animate);
182 showOperatorName(animate);
185 if ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0) {
186 if ((state1 & DISABLE_NOTIFICATION_ICONS) != 0) {
187 hideNotificationIconArea(animate);
189 showNotificationIconArea(animate);
192 // The clock may have already been hidden, but we might want to shift its
193 // visibility to GONE from INVISIBLE or vice versa
194 if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) {
195 if ((state1 & DISABLE_CLOCK) != 0) {
203 protected int adjustDisableFlags(int state) {
204 if (!mKeyguardMonitor.isLaunchTransitionFadingAway()
205 && !mKeyguardMonitor.isKeyguardFadingAway()
206 && shouldHideNotificationIcons()) {
207 state |= DISABLE_NOTIFICATION_ICONS;
208 state |= DISABLE_SYSTEM_INFO;
209 state |= DISABLE_CLOCK;
212 // In landscape, the heads up show but shouldHideNotificationIcons() return false
213 // because the visual icon is in notification icon area rather than heads up's space.
214 // whether the notification icon show or not, clock should hide when heads up show.
215 if (mStatusBarComponent.isHeadsUpShouldBeVisible()) {
216 state |= DISABLE_CLOCK;
219 if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
220 if (mNetworkController.hasEmergencyCryptKeeperText()) {
221 state |= DISABLE_NOTIFICATION_ICONS;
223 if (!mNetworkController.isRadioOn()) {
224 state |= DISABLE_SYSTEM_INFO;
228 // The shelf will be hidden when dozing with a custom clock, we must show notification
229 // icons in this occasion.
230 if (mStatusBarStateController.isDozing()
231 && mStatusBarComponent.getPanel().hasCustomClock()) {
232 state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO;
238 private boolean shouldHideNotificationIcons() {
239 if (!mStatusBar.isClosed() && mStatusBarComponent.hideStatusBarIconsWhenExpanded()) {
242 if (mStatusBarComponent.hideStatusBarIconsForBouncer()) {
248 public void hideSystemIconArea(boolean animate) {
249 animateHide(mSystemIconArea, animate);
252 public void showSystemIconArea(boolean animate) {
253 animateShow(mSystemIconArea, animate);
256 public void hideClock(boolean animate) {
257 animateHiddenState(mClockView, clockHiddenMode(), animate);
260 public void showClock(boolean animate) {
261 animateShow(mClockView, animate);
265 * If panel is expanded/expanding it usually means QS shade is opening, so
266 * don't set the clock GONE otherwise it'll mess up the animation.
268 private int clockHiddenMode() {
269 if (!mStatusBar.isClosed() && !mKeyguardMonitor.isShowing()
270 && !mStatusBarStateController.isDozing()) {
271 return View.INVISIBLE;
276 public void hideNotificationIconArea(boolean animate) {
277 animateHide(mNotificationIconAreaInner, animate);
278 animateHide(mCenteredIconArea, animate);
281 public void showNotificationIconArea(boolean animate) {
282 animateShow(mNotificationIconAreaInner, animate);
283 animateShow(mCenteredIconArea, animate);
286 public void hideOperatorName(boolean animate) {
287 if (mOperatorNameFrame != null) {
288 animateHide(mOperatorNameFrame, animate);
292 public void showOperatorName(boolean animate) {
293 if (mOperatorNameFrame != null) {
294 animateShow(mOperatorNameFrame, animate);
299 * Animate a view to INVISIBLE or GONE
301 private void animateHiddenState(final View v, int state, boolean animate) {
302 v.animate().cancel();
305 v.setVisibility(state);
313 .setInterpolator(Interpolators.ALPHA_OUT)
314 .withEndAction(() -> v.setVisibility(state));
320 private void animateHide(final View v, boolean animate) {
321 animateHiddenState(v, View.INVISIBLE, animate);
325 * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
327 private void animateShow(View v, boolean animate) {
328 v.animate().cancel();
329 v.setVisibility(View.VISIBLE);
336 .setDuration(FADE_IN_DURATION)
337 .setInterpolator(Interpolators.ALPHA_IN)
338 .setStartDelay(FADE_IN_DELAY)
340 // We need to clean up any pending end action from animateHide if we call
341 // both hide and show in the same frame before the animation actually gets started.
342 // cancel() doesn't really remove the end action.
343 .withEndAction(null);
345 // Synchronize the motion with the Keyguard fading if necessary.
346 if (mKeyguardMonitor.isKeyguardFadingAway()) {
348 .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration())
349 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
350 .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
355 private void initEmergencyCryptkeeperText() {
356 View emergencyViewStub = mStatusBar.findViewById(R.id.emergency_cryptkeeper_text);
357 if (mNetworkController.hasEmergencyCryptKeeperText()) {
358 if (emergencyViewStub != null) {
359 ((ViewStub) emergencyViewStub).inflate();
361 mNetworkController.addCallback(mSignalCallback);
362 } else if (emergencyViewStub != null) {
363 ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
364 parent.removeView(emergencyViewStub);
368 private void initOperatorName() {
369 if (getResources().getBoolean(R.bool.config_showOperatorNameInStatusBar)) {
370 ViewStub stub = mStatusBar.findViewById(R.id.operator_name);
371 mOperatorNameFrame = stub.inflate();
376 public void onStateChanged(int newState) {
381 public void onDozingChanged(boolean isDozing) {
382 disable(getContext().getDisplayId(), mDisabled1, mDisabled1, false /* animate */);