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 com.android.systemui.statusbar.phone.StatusBar.reinflateSignalCluster;
18 
19 import android.annotation.Nullable;
20 import android.app.Fragment;
21 import android.app.StatusBarManager;
22 import android.os.Bundle;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.view.ViewStub;
27 import android.widget.LinearLayout;
28 
29 import com.android.systemui.Dependency;
30 import com.android.systemui.Interpolators;
31 import com.android.systemui.R;
32 import com.android.systemui.SysUiServiceProvider;
33 import com.android.systemui.statusbar.CommandQueue;
34 import com.android.systemui.statusbar.SignalClusterView;
35 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
36 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
37 import com.android.systemui.statusbar.policy.EncryptionHelper;
38 import com.android.systemui.statusbar.policy.KeyguardMonitor;
39 import com.android.systemui.statusbar.policy.NetworkController;
40 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
41 
42 /**
43  * Contains the collapsed status bar and handles hiding/showing based on disable flags
44  * and keyguard state. Also manages lifecycle to make sure the views it contains are being
45  * updated by the StatusBarIconController and DarkIconManager while it is attached.
46  */
47 public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks {
48 
49     public static final String TAG = "CollapsedStatusBarFragment";
50     private static final String EXTRA_PANEL_STATE = "panel_state";
51     private PhoneStatusBarView mStatusBar;
52     private KeyguardMonitor mKeyguardMonitor;
53     private NetworkController mNetworkController;
54     private LinearLayout mSystemIconArea;
55     private View mNotificationIconAreaInner;
56     private int mDisabled1;
57     private StatusBar mStatusBarComponent;
58     private DarkIconManager mDarkIconManager;
59     private SignalClusterView mSignalClusterView;
60 
61     private SignalCallback mSignalCallback = new SignalCallback() {
62         @Override
63         public void setIsAirplaneMode(NetworkController.IconState icon) {
64             mStatusBarComponent.recomputeDisableFlags(true /* animate */);
65         }
66     };
67 
68     @Override
onCreate(@ullable Bundle savedInstanceState)69     public void onCreate(@Nullable Bundle savedInstanceState) {
70         super.onCreate(savedInstanceState);
71         mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
72         mNetworkController = Dependency.get(NetworkController.class);
73         mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
74     }
75 
76     @Override
onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState)77     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
78             Bundle savedInstanceState) {
79         return inflater.inflate(R.layout.status_bar, container, false);
80     }
81 
82     @Override
onViewCreated(View view, @Nullable Bundle savedInstanceState)83     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
84         super.onViewCreated(view, savedInstanceState);
85         mStatusBar = (PhoneStatusBarView) view;
86         if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
87             mStatusBar.go(savedInstanceState.getInt(EXTRA_PANEL_STATE));
88         }
89         mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
90         Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
91         mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
92         mSignalClusterView = mStatusBar.findViewById(R.id.signal_cluster);
93         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mSignalClusterView);
94         // Default to showing until we know otherwise.
95         showSystemIconArea(false);
96         initEmergencyCryptkeeperText();
97     }
98 
99     @Override
onSaveInstanceState(Bundle outState)100     public void onSaveInstanceState(Bundle outState) {
101         super.onSaveInstanceState(outState);
102         outState.putInt(EXTRA_PANEL_STATE, mStatusBar.getState());
103     }
104 
105     @Override
onResume()106     public void onResume() {
107         super.onResume();
108         SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
109     }
110 
111     @Override
onPause()112     public void onPause() {
113         super.onPause();
114         SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
115     }
116 
117     @Override
onDestroyView()118     public void onDestroyView() {
119         super.onDestroyView();
120         Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mSignalClusterView);
121         Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
122         if (mNetworkController.hasEmergencyCryptKeeperText()) {
123             mNetworkController.removeCallback(mSignalCallback);
124         }
125     }
126 
initNotificationIconArea(NotificationIconAreaController notificationIconAreaController)127     public void initNotificationIconArea(NotificationIconAreaController
128             notificationIconAreaController) {
129         ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);
130         mNotificationIconAreaInner =
131                 notificationIconAreaController.getNotificationInnerAreaView();
132         if (mNotificationIconAreaInner.getParent() != null) {
133             ((ViewGroup) mNotificationIconAreaInner.getParent())
134                     .removeView(mNotificationIconAreaInner);
135         }
136         notificationIconArea.addView(mNotificationIconAreaInner);
137         // Default to showing until we know otherwise.
138         showNotificationIconArea(false);
139     }
140 
141     @Override
disable(int state1, int state2, boolean animate)142     public void disable(int state1, int state2, boolean animate) {
143         state1 = adjustDisableFlags(state1);
144         final int old1 = mDisabled1;
145         final int diff1 = state1 ^ old1;
146         mDisabled1 = state1;
147         if ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
148             if ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
149                 hideSystemIconArea(animate);
150             } else {
151                 showSystemIconArea(animate);
152             }
153         }
154         if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
155             if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
156                 hideNotificationIconArea(animate);
157             } else {
158                 showNotificationIconArea(animate);
159             }
160         }
161     }
162 
adjustDisableFlags(int state)163     protected int adjustDisableFlags(int state) {
164         if (!mStatusBarComponent.isLaunchTransitionFadingAway()
165                 && !mKeyguardMonitor.isKeyguardFadingAway()
166                 && shouldHideNotificationIcons()) {
167             state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
168             state |= StatusBarManager.DISABLE_SYSTEM_INFO;
169         }
170         if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
171             if (mNetworkController.hasEmergencyCryptKeeperText()) {
172                 state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
173             }
174             if (!mNetworkController.isRadioOn()) {
175                 state |= StatusBarManager.DISABLE_SYSTEM_INFO;
176             }
177         }
178         return state;
179     }
180 
shouldHideNotificationIcons()181     private boolean shouldHideNotificationIcons() {
182         return !mStatusBar.isClosed() && mStatusBarComponent.hideStatusBarIconsWhenExpanded();
183     }
184 
hideSystemIconArea(boolean animate)185     public void hideSystemIconArea(boolean animate) {
186         animateHide(mSystemIconArea, animate);
187     }
188 
showSystemIconArea(boolean animate)189     public void showSystemIconArea(boolean animate) {
190         animateShow(mSystemIconArea, animate);
191     }
192 
hideNotificationIconArea(boolean animate)193     public void hideNotificationIconArea(boolean animate) {
194         animateHide(mNotificationIconAreaInner, animate);
195     }
196 
showNotificationIconArea(boolean animate)197     public void showNotificationIconArea(boolean animate) {
198         animateShow(mNotificationIconAreaInner, animate);
199     }
200 
201     /**
202      * Hides a view.
203      */
animateHide(final View v, boolean animate)204     private void animateHide(final View v, boolean animate) {
205         v.animate().cancel();
206         if (!animate) {
207             v.setAlpha(0f);
208             v.setVisibility(View.INVISIBLE);
209             return;
210         }
211         v.animate()
212                 .alpha(0f)
213                 .setDuration(160)
214                 .setStartDelay(0)
215                 .setInterpolator(Interpolators.ALPHA_OUT)
216                 .withEndAction(() -> v.setVisibility(View.INVISIBLE));
217     }
218 
219     /**
220      * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
221      */
animateShow(View v, boolean animate)222     private void animateShow(View v, boolean animate) {
223         v.animate().cancel();
224         v.setVisibility(View.VISIBLE);
225         if (!animate) {
226             v.setAlpha(1f);
227             return;
228         }
229         v.animate()
230                 .alpha(1f)
231                 .setDuration(320)
232                 .setInterpolator(Interpolators.ALPHA_IN)
233                 .setStartDelay(50)
234 
235                 // We need to clean up any pending end action from animateHide if we call
236                 // both hide and show in the same frame before the animation actually gets started.
237                 // cancel() doesn't really remove the end action.
238                 .withEndAction(null);
239 
240         // Synchronize the motion with the Keyguard fading if necessary.
241         if (mKeyguardMonitor.isKeyguardFadingAway()) {
242             v.animate()
243                     .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration())
244                     .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
245                     .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
246                     .start();
247         }
248     }
249 
initEmergencyCryptkeeperText()250     private void initEmergencyCryptkeeperText() {
251         View emergencyViewStub = mStatusBar.findViewById(R.id.emergency_cryptkeeper_text);
252         if (mNetworkController.hasEmergencyCryptKeeperText()) {
253             if (emergencyViewStub != null) {
254                 ((ViewStub) emergencyViewStub).inflate();
255             }
256             mNetworkController.addCallback(mSignalCallback);
257         } else if (emergencyViewStub != null) {
258             ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
259             parent.removeView(emergencyViewStub);
260         }
261     }
262 }
263