• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.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;
31 
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;
43 
44 /**
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.
48  */
49 public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks,
50         StatusBarStateController.StateListener {
51 
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;
70 
71     private SignalCallback mSignalCallback = new SignalCallback() {
72         @Override
73         public void setIsAirplaneMode(NetworkController.IconState icon) {
74             mCommandQueue.recomputeDisableFlags(getContext().getDisplayId(), true /* animate */);
75         }
76     };
77 
78     @Override
onCreate(@ullable Bundle savedInstanceState)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);
86     }
87 
88     @Override
onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState)89     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
90             Bundle savedInstanceState) {
91         return inflater.inflate(R.layout.status_bar, container, false);
92     }
93 
94     @Override
onViewCreated(View view, @Nullable Bundle savedInstanceState)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));
101         }
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);
108         showClock(false);
109         initEmergencyCryptkeeperText();
110         initOperatorName();
111     }
112 
113     @Override
onSaveInstanceState(Bundle outState)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);
119     }
120 
121     @Override
onResume()122     public void onResume() {
123         super.onResume();
124         mCommandQueue.addCallback(this);
125         mStatusBarStateController.addCallback(this);
126     }
127 
128     @Override
onPause()129     public void onPause() {
130         super.onPause();
131         mCommandQueue.removeCallback(this);
132         mStatusBarStateController.removeCallback(this);
133     }
134 
135     @Override
onDestroyView()136     public void onDestroyView() {
137         super.onDestroyView();
138         Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
139         if (mNetworkController.hasEmergencyCryptKeeperText()) {
140             mNetworkController.removeCallback(mSignalCallback);
141         }
142     }
143 
initNotificationIconArea(NotificationIconAreaController notificationIconAreaController)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);
152         }
153         notificationIconArea.addView(mNotificationIconAreaInner);
154 
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);
160         }
161         statusBarCenteredIconArea.addView(mCenteredIconArea);
162 
163         // Default to showing until we know otherwise.
164         showNotificationIconArea(false);
165     }
166 
167     @Override
disable(int displayId, int state1, int state2, boolean animate)168     public void disable(int displayId, int state1, int state2, boolean animate) {
169         if (displayId != getContext().getDisplayId()) {
170             return;
171         }
172         state1 = adjustDisableFlags(state1);
173         final int old1 = mDisabled1;
174         final int diff1 = state1 ^ old1;
175         mDisabled1 = state1;
176         if ((diff1 & DISABLE_SYSTEM_INFO) != 0) {
177             if ((state1 & DISABLE_SYSTEM_INFO) != 0) {
178                 hideSystemIconArea(animate);
179                 hideOperatorName(animate);
180             } else {
181                 showSystemIconArea(animate);
182                 showOperatorName(animate);
183             }
184         }
185         if ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0) {
186             if ((state1 & DISABLE_NOTIFICATION_ICONS) != 0) {
187                 hideNotificationIconArea(animate);
188             } else {
189                 showNotificationIconArea(animate);
190             }
191         }
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) {
196                 hideClock(animate);
197             } else {
198                 showClock(animate);
199             }
200         }
201     }
202 
adjustDisableFlags(int state)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;
210         }
211 
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;
217         }
218 
219         if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
220             if (mNetworkController.hasEmergencyCryptKeeperText()) {
221                 state |= DISABLE_NOTIFICATION_ICONS;
222             }
223             if (!mNetworkController.isRadioOn()) {
224                 state |= DISABLE_SYSTEM_INFO;
225             }
226         }
227 
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;
233         }
234 
235         return state;
236     }
237 
shouldHideNotificationIcons()238     private boolean shouldHideNotificationIcons() {
239         if (!mStatusBar.isClosed() && mStatusBarComponent.hideStatusBarIconsWhenExpanded()) {
240             return true;
241         }
242         if (mStatusBarComponent.hideStatusBarIconsForBouncer()) {
243             return true;
244         }
245         return false;
246     }
247 
hideSystemIconArea(boolean animate)248     public void hideSystemIconArea(boolean animate) {
249         animateHide(mSystemIconArea, animate);
250     }
251 
showSystemIconArea(boolean animate)252     public void showSystemIconArea(boolean animate) {
253         animateShow(mSystemIconArea, animate);
254     }
255 
hideClock(boolean animate)256     public void hideClock(boolean animate) {
257         animateHiddenState(mClockView, clockHiddenMode(), animate);
258     }
259 
showClock(boolean animate)260     public void showClock(boolean animate) {
261         animateShow(mClockView, animate);
262     }
263 
264     /**
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.
267      */
clockHiddenMode()268     private int clockHiddenMode() {
269         if (!mStatusBar.isClosed() && !mKeyguardMonitor.isShowing()
270                 && !mStatusBarStateController.isDozing()) {
271             return View.INVISIBLE;
272         }
273         return View.GONE;
274     }
275 
hideNotificationIconArea(boolean animate)276     public void hideNotificationIconArea(boolean animate) {
277         animateHide(mNotificationIconAreaInner, animate);
278         animateHide(mCenteredIconArea, animate);
279     }
280 
showNotificationIconArea(boolean animate)281     public void showNotificationIconArea(boolean animate) {
282         animateShow(mNotificationIconAreaInner, animate);
283         animateShow(mCenteredIconArea, animate);
284     }
285 
hideOperatorName(boolean animate)286     public void hideOperatorName(boolean animate) {
287         if (mOperatorNameFrame != null) {
288             animateHide(mOperatorNameFrame, animate);
289         }
290     }
291 
showOperatorName(boolean animate)292     public void showOperatorName(boolean animate) {
293         if (mOperatorNameFrame != null) {
294             animateShow(mOperatorNameFrame, animate);
295         }
296     }
297 
298     /**
299      * Animate a view to INVISIBLE or GONE
300      */
animateHiddenState(final View v, int state, boolean animate)301     private void animateHiddenState(final View v, int state, boolean animate) {
302         v.animate().cancel();
303         if (!animate) {
304             v.setAlpha(0f);
305             v.setVisibility(state);
306             return;
307         }
308 
309         v.animate()
310                 .alpha(0f)
311                 .setDuration(160)
312                 .setStartDelay(0)
313                 .setInterpolator(Interpolators.ALPHA_OUT)
314                 .withEndAction(() -> v.setVisibility(state));
315     }
316 
317     /**
318      * Hides a view.
319      */
animateHide(final View v, boolean animate)320     private void animateHide(final View v, boolean animate) {
321         animateHiddenState(v, View.INVISIBLE, animate);
322     }
323 
324     /**
325      * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
326      */
animateShow(View v, boolean animate)327     private void animateShow(View v, boolean animate) {
328         v.animate().cancel();
329         v.setVisibility(View.VISIBLE);
330         if (!animate) {
331             v.setAlpha(1f);
332             return;
333         }
334         v.animate()
335                 .alpha(1f)
336                 .setDuration(FADE_IN_DURATION)
337                 .setInterpolator(Interpolators.ALPHA_IN)
338                 .setStartDelay(FADE_IN_DELAY)
339 
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);
344 
345         // Synchronize the motion with the Keyguard fading if necessary.
346         if (mKeyguardMonitor.isKeyguardFadingAway()) {
347             v.animate()
348                     .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration())
349                     .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
350                     .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
351                     .start();
352         }
353     }
354 
initEmergencyCryptkeeperText()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();
360             }
361             mNetworkController.addCallback(mSignalCallback);
362         } else if (emergencyViewStub != null) {
363             ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
364             parent.removeView(emergencyViewStub);
365         }
366     }
367 
initOperatorName()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();
372         }
373     }
374 
375     @Override
onStateChanged(int newState)376     public void onStateChanged(int newState) {
377 
378     }
379 
380     @Override
onDozingChanged(boolean isDozing)381     public void onDozingChanged(boolean isDozing) {
382         disable(getContext().getDisplayId(), mDisabled1, mDisabled1, false /* animate */);
383     }
384 }
385