• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.qs;
18 
19 import android.os.Bundle;
20 import android.view.View;
21 import android.view.View.OnClickListener;
22 
23 import androidx.annotation.NonNull;
24 
25 import com.android.internal.colorextraction.ColorExtractor;
26 import com.android.internal.logging.UiEventLogger;
27 import com.android.systemui.R;
28 import com.android.systemui.colorextraction.SysuiColorExtractor;
29 import com.android.systemui.demomode.DemoMode;
30 import com.android.systemui.demomode.DemoModeController;
31 import com.android.systemui.plugins.ActivityStarter;
32 import com.android.systemui.privacy.OngoingPrivacyChip;
33 import com.android.systemui.privacy.PrivacyChipEvent;
34 import com.android.systemui.privacy.PrivacyDialogController;
35 import com.android.systemui.privacy.PrivacyItem;
36 import com.android.systemui.privacy.PrivacyItemController;
37 import com.android.systemui.privacy.logging.PrivacyLogger;
38 import com.android.systemui.qs.carrier.QSCarrierGroupController;
39 import com.android.systemui.qs.dagger.QSScope;
40 import com.android.systemui.statusbar.FeatureFlags;
41 import com.android.systemui.statusbar.phone.StatusBarIconController;
42 import com.android.systemui.statusbar.phone.StatusIconContainer;
43 import com.android.systemui.statusbar.policy.Clock;
44 import com.android.systemui.util.ViewController;
45 
46 import java.util.List;
47 
48 import javax.inject.Inject;
49 
50 /**
51  * Controller for {@link QuickStatusBarHeader}.
52  */
53 @QSScope
54 class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader> {
55     private static final String TAG = "QuickStatusBarHeader";
56 
57     private final PrivacyItemController mPrivacyItemController;
58     private final ActivityStarter mActivityStarter;
59     private final UiEventLogger mUiEventLogger;
60     private final QSCarrierGroupController mQSCarrierGroupController;
61     private final QuickQSPanelController mHeaderQsPanelController;
62     private final OngoingPrivacyChip mPrivacyChip;
63     private final Clock mClockView;
64     private final StatusBarIconController mStatusBarIconController;
65     private final DemoModeController mDemoModeController;
66     private final StatusIconContainer mIconContainer;
67     private final StatusBarIconController.TintedIconManager mIconManager;
68     private final DemoMode mDemoModeReceiver;
69     private final PrivacyLogger mPrivacyLogger;
70     private final PrivacyDialogController mPrivacyDialogController;
71     private final QSExpansionPathInterpolator mQSExpansionPathInterpolator;
72     private final FeatureFlags mFeatureFlags;
73 
74     private boolean mListening;
75     private boolean mMicCameraIndicatorsEnabled;
76     private boolean mLocationIndicatorsEnabled;
77     private boolean mPrivacyChipLogged;
78     private final String mCameraSlot;
79     private final String mMicSlot;
80     private final String mLocationSlot;
81 
82     private SysuiColorExtractor mColorExtractor;
83     private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
84 
85     private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
86         @Override
87         public void onPrivacyItemsChanged(@NonNull List<PrivacyItem> privacyItems) {
88             mPrivacyChip.setPrivacyList(privacyItems);
89             setChipVisibility(!privacyItems.isEmpty());
90         }
91 
92         @Override
93         public void onFlagMicCameraChanged(boolean flag) {
94             if (mMicCameraIndicatorsEnabled != flag) {
95                 mMicCameraIndicatorsEnabled = flag;
96                 update();
97             }
98         }
99 
100         @Override
101         public void onFlagLocationChanged(boolean flag) {
102             if (mLocationIndicatorsEnabled != flag) {
103                 mLocationIndicatorsEnabled = flag;
104                 update();
105             }
106         }
107 
108         private void update() {
109             updatePrivacyIconSlots();
110             setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
111         }
112     };
113 
114     private View.OnClickListener mOnClickListener = new OnClickListener() {
115         @Override
116         public void onClick(View v) {
117             if (v == mPrivacyChip) {
118                 // If the privacy chip is visible, it means there were some indicators
119                 mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK);
120                 mPrivacyDialogController.showDialog(getContext());
121             }
122         }
123     };
124 
125     @Inject
QuickStatusBarHeaderController(QuickStatusBarHeader view, PrivacyItemController privacyItemController, ActivityStarter activityStarter, UiEventLogger uiEventLogger, StatusBarIconController statusBarIconController, DemoModeController demoModeController, QuickQSPanelController quickQSPanelController, QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder, PrivacyLogger privacyLogger, SysuiColorExtractor colorExtractor, PrivacyDialogController privacyDialogController, QSExpansionPathInterpolator qsExpansionPathInterpolator, FeatureFlags featureFlags)126     QuickStatusBarHeaderController(QuickStatusBarHeader view,
127             PrivacyItemController privacyItemController,
128             ActivityStarter activityStarter, UiEventLogger uiEventLogger,
129             StatusBarIconController statusBarIconController,
130             DemoModeController demoModeController,
131             QuickQSPanelController quickQSPanelController,
132             QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder,
133             PrivacyLogger privacyLogger,
134             SysuiColorExtractor colorExtractor,
135             PrivacyDialogController privacyDialogController,
136             QSExpansionPathInterpolator qsExpansionPathInterpolator,
137             FeatureFlags featureFlags) {
138         super(view);
139         mPrivacyItemController = privacyItemController;
140         mActivityStarter = activityStarter;
141         mUiEventLogger = uiEventLogger;
142         mStatusBarIconController = statusBarIconController;
143         mDemoModeController = demoModeController;
144         mHeaderQsPanelController = quickQSPanelController;
145         mPrivacyLogger = privacyLogger;
146         mPrivacyDialogController = privacyDialogController;
147         mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
148         mFeatureFlags = featureFlags;
149 
150         mQSCarrierGroupController = qsCarrierGroupControllerBuilder
151                 .setQSCarrierGroup(mView.findViewById(R.id.carrier_group))
152                 .build();
153 
154         mPrivacyChip = mView.findViewById(R.id.privacy_chip);
155         mClockView = mView.findViewById(R.id.clock);
156         mIconContainer = mView.findViewById(R.id.statusIcons);
157 
158         mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, featureFlags);
159         mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
160         mColorExtractor = colorExtractor;
161         mOnColorsChangedListener = (extractor, which) -> {
162             final boolean lightTheme = mColorExtractor.getNeutralColors().supportsDarkText();
163             mClockView.onColorsChanged(lightTheme);
164         };
165         mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
166 
167         mCameraSlot = getResources().getString(com.android.internal.R.string.status_bar_camera);
168         mMicSlot = getResources().getString(com.android.internal.R.string.status_bar_microphone);
169         mLocationSlot = getResources().getString(com.android.internal.R.string.status_bar_location);
170     }
171 
172     @Override
onViewAttached()173     protected void onViewAttached() {
174         mPrivacyChip.setOnClickListener(mOnClickListener);
175 
176         mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
177         mLocationIndicatorsEnabled = mPrivacyItemController.getLocationAvailable();
178 
179         // Ignore privacy icons because they show in the space above QQS
180         updatePrivacyIconSlots();
181         mIconContainer.addIgnoredSlot(
182                 getResources().getString(com.android.internal.R.string.status_bar_managed_profile));
183         mIconContainer.setShouldRestrictIcons(false);
184         mStatusBarIconController.addIconGroup(mIconManager);
185 
186         setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
187 
188         mView.setIsSingleCarrier(mQSCarrierGroupController.isSingleCarrier());
189         mQSCarrierGroupController
190                 .setOnSingleCarrierChangedListener(mView::setIsSingleCarrier);
191 
192         List<String> rssiIgnoredSlots;
193 
194         if (mFeatureFlags.isCombinedStatusBarSignalIconsEnabled()) {
195             rssiIgnoredSlots = List.of(
196                     getResources().getString(com.android.internal.R.string.status_bar_no_calling),
197                     getResources().getString(com.android.internal.R.string.status_bar_call_strength)
198             );
199         } else {
200             rssiIgnoredSlots = List.of(
201                     getResources().getString(com.android.internal.R.string.status_bar_mobile)
202             );
203         }
204 
205         mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots);
206 
207         mDemoModeController.addCallback(mDemoModeReceiver);
208     }
209 
210     @Override
onViewDetached()211     protected void onViewDetached() {
212         mColorExtractor.removeOnColorsChangedListener(mOnColorsChangedListener);
213         mPrivacyChip.setOnClickListener(null);
214         mStatusBarIconController.removeIconGroup(mIconManager);
215         mQSCarrierGroupController.setOnSingleCarrierChangedListener(null);
216         mDemoModeController.removeCallback(mDemoModeReceiver);
217         setListening(false);
218     }
219 
setListening(boolean listening)220     public void setListening(boolean listening) {
221         mQSCarrierGroupController.setListening(listening);
222 
223         if (listening == mListening) {
224             return;
225         }
226         mListening = listening;
227 
228         mHeaderQsPanelController.setListening(listening);
229         if (mHeaderQsPanelController.isListening()) {
230             mHeaderQsPanelController.refreshAllTiles();
231         }
232 
233         if (mHeaderQsPanelController.switchTileLayout(false)) {
234             mView.updateResources();
235         }
236 
237         if (listening) {
238             // Get the most up to date info
239             mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
240             mLocationIndicatorsEnabled = mPrivacyItemController.getLocationAvailable();
241             mPrivacyItemController.addCallback(mPICCallback);
242         } else {
243             mPrivacyItemController.removeCallback(mPICCallback);
244             mPrivacyChipLogged = false;
245         }
246     }
247 
setChipVisibility(boolean chipVisible)248     private void setChipVisibility(boolean chipVisible) {
249         if (chipVisible && getChipEnabled()) {
250             mPrivacyLogger.logChipVisible(true);
251             // Makes sure that the chip is logged as viewed at most once each time QS is opened
252             // mListening makes sure that the callback didn't return after the user closed QS
253             if (!mPrivacyChipLogged && mListening) {
254                 mPrivacyChipLogged = true;
255                 mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_VIEW);
256             }
257         } else {
258             mPrivacyLogger.logChipVisible(false);
259         }
260         mView.setChipVisibility(chipVisible);
261     }
262 
updatePrivacyIconSlots()263     private void updatePrivacyIconSlots() {
264         if (getChipEnabled()) {
265             if (mMicCameraIndicatorsEnabled) {
266                 mIconContainer.addIgnoredSlot(mCameraSlot);
267                 mIconContainer.addIgnoredSlot(mMicSlot);
268             } else {
269                 mIconContainer.removeIgnoredSlot(mCameraSlot);
270                 mIconContainer.removeIgnoredSlot(mMicSlot);
271             }
272             if (mLocationIndicatorsEnabled) {
273                 mIconContainer.addIgnoredSlot(mLocationSlot);
274             } else {
275                 mIconContainer.removeIgnoredSlot(mLocationSlot);
276             }
277         } else {
278             mIconContainer.removeIgnoredSlot(mCameraSlot);
279             mIconContainer.removeIgnoredSlot(mMicSlot);
280             mIconContainer.removeIgnoredSlot(mLocationSlot);
281         }
282     }
283 
getChipEnabled()284     private boolean getChipEnabled() {
285         return mMicCameraIndicatorsEnabled || mLocationIndicatorsEnabled;
286     }
287 
setContentMargins(int marginStart, int marginEnd)288     public void setContentMargins(int marginStart, int marginEnd) {
289         mHeaderQsPanelController.setContentMargins(marginStart, marginEnd);
290     }
291 
292     private static class ClockDemoModeReceiver implements DemoMode {
293         private Clock mClockView;
294 
295         @Override
demoCommands()296         public List<String> demoCommands() {
297             return List.of(COMMAND_CLOCK);
298         }
299 
ClockDemoModeReceiver(Clock clockView)300         ClockDemoModeReceiver(Clock clockView) {
301             mClockView = clockView;
302         }
303 
304         @Override
dispatchDemoCommand(String command, Bundle args)305         public void dispatchDemoCommand(String command, Bundle args) {
306             mClockView.dispatchDemoCommand(command, args);
307         }
308 
309         @Override
onDemoModeStarted()310         public void onDemoModeStarted() {
311             mClockView.onDemoModeStarted();
312         }
313 
314         @Override
onDemoModeFinished()315         public void onDemoModeFinished() {
316             mClockView.onDemoModeFinished();
317         }
318     }
319 }
320