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