1 /* 2 * Copyright (C) 2020 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 static com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED; 20 21 import android.content.ClipData; 22 import android.content.ClipboardManager; 23 import android.content.Intent; 24 import android.graphics.drawable.Drawable; 25 import android.os.UserManager; 26 import android.text.TextUtils; 27 import android.view.View; 28 import android.widget.TextView; 29 import android.widget.Toast; 30 31 import com.android.internal.jank.InteractionJankMonitor; 32 import com.android.internal.logging.MetricsLogger; 33 import com.android.internal.logging.UiEventLogger; 34 import com.android.internal.logging.nano.MetricsProto; 35 import com.android.keyguard.KeyguardUpdateMonitor; 36 import com.android.systemui.R; 37 import com.android.systemui.animation.ActivityLaunchAnimator; 38 import com.android.systemui.globalactions.GlobalActionsDialogLite; 39 import com.android.systemui.plugins.ActivityStarter; 40 import com.android.systemui.plugins.FalsingManager; 41 import com.android.systemui.qs.dagger.QSScope; 42 import com.android.systemui.settings.UserTracker; 43 import com.android.systemui.statusbar.phone.MultiUserSwitchController; 44 import com.android.systemui.statusbar.phone.SettingsButton; 45 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 46 import com.android.systemui.statusbar.policy.UserInfoController; 47 import com.android.systemui.tuner.TunerService; 48 import com.android.systemui.util.ViewController; 49 50 import javax.inject.Inject; 51 import javax.inject.Named; 52 53 /** 54 * Controller for {@link QSFooterView}. 55 */ 56 @QSScope 57 public class QSFooterViewController extends ViewController<QSFooterView> implements QSFooter { 58 59 private final UserManager mUserManager; 60 private final UserInfoController mUserInfoController; 61 private final ActivityStarter mActivityStarter; 62 private final DeviceProvisionedController mDeviceProvisionedController; 63 private final UserTracker mUserTracker; 64 private final QSPanelController mQsPanelController; 65 private final QuickQSPanelController mQuickQSPanelController; 66 private final TunerService mTunerService; 67 private final MetricsLogger mMetricsLogger; 68 private final FalsingManager mFalsingManager; 69 private final MultiUserSwitchController mMultiUserSwitchController; 70 private final SettingsButton mSettingsButton; 71 private final View mSettingsButtonContainer; 72 private final TextView mBuildText; 73 private final View mEdit; 74 private final PageIndicator mPageIndicator; 75 private final View mPowerMenuLite; 76 private final boolean mShowPMLiteButton; 77 private final GlobalActionsDialogLite mGlobalActionsDialog; 78 private final UiEventLogger mUiEventLogger; 79 80 private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener = 81 new UserInfoController.OnUserInfoChangedListener() { 82 @Override 83 public void onUserInfoChanged(String name, Drawable picture, String userAccount) { 84 boolean isGuestUser = mUserManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser()); 85 mView.onUserInfoChanged(picture, isGuestUser); 86 } 87 }; 88 89 private final View.OnClickListener mSettingsOnClickListener = new View.OnClickListener() { 90 @Override 91 public void onClick(View v) { 92 // Don't do anything until views are unhidden. Don't do anything if the tap looks 93 // suspicious. 94 if (!mExpanded || mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { 95 return; 96 } 97 98 if (v == mSettingsButton) { 99 if (!mDeviceProvisionedController.isCurrentUserSetup()) { 100 // If user isn't setup just unlock the device and dump them back at SUW. 101 mActivityStarter.postQSRunnableDismissingKeyguard(() -> { 102 }); 103 return; 104 } 105 mMetricsLogger.action( 106 mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH 107 : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH); 108 if (mSettingsButton.isTunerClick()) { 109 mActivityStarter.postQSRunnableDismissingKeyguard(() -> { 110 if (isTunerEnabled()) { 111 mTunerService.showResetRequest( 112 () -> { 113 // Relaunch settings so that the tuner disappears. 114 startSettingsActivity(); 115 }); 116 } else { 117 Toast.makeText(getContext(), R.string.tuner_toast, 118 Toast.LENGTH_LONG).show(); 119 mTunerService.setTunerEnabled(true); 120 } 121 startSettingsActivity(); 122 123 }); 124 } else { 125 startSettingsActivity(); 126 } 127 } else if (v == mPowerMenuLite) { 128 mUiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS); 129 mGlobalActionsDialog.showOrHideDialog(false, true); 130 } 131 } 132 }; 133 134 private boolean mListening; 135 private boolean mExpanded; 136 137 @Inject QSFooterViewController(QSFooterView view, UserManager userManager, UserInfoController userInfoController, ActivityStarter activityStarter, DeviceProvisionedController deviceProvisionedController, UserTracker userTracker, QSPanelController qsPanelController, MultiUserSwitchController multiUserSwitchController, QuickQSPanelController quickQSPanelController, TunerService tunerService, MetricsLogger metricsLogger, FalsingManager falsingManager, @Named(PM_LITE_ENABLED) boolean showPMLiteButton, GlobalActionsDialogLite globalActionsDialog, UiEventLogger uiEventLogger)138 QSFooterViewController(QSFooterView view, UserManager userManager, 139 UserInfoController userInfoController, ActivityStarter activityStarter, 140 DeviceProvisionedController deviceProvisionedController, UserTracker userTracker, 141 QSPanelController qsPanelController, 142 MultiUserSwitchController multiUserSwitchController, 143 QuickQSPanelController quickQSPanelController, 144 TunerService tunerService, MetricsLogger metricsLogger, FalsingManager falsingManager, 145 @Named(PM_LITE_ENABLED) boolean showPMLiteButton, 146 GlobalActionsDialogLite globalActionsDialog, UiEventLogger uiEventLogger) { 147 super(view); 148 mUserManager = userManager; 149 mUserInfoController = userInfoController; 150 mActivityStarter = activityStarter; 151 mDeviceProvisionedController = deviceProvisionedController; 152 mUserTracker = userTracker; 153 mQsPanelController = qsPanelController; 154 mQuickQSPanelController = quickQSPanelController; 155 mTunerService = tunerService; 156 mMetricsLogger = metricsLogger; 157 mFalsingManager = falsingManager; 158 mMultiUserSwitchController = multiUserSwitchController; 159 160 mSettingsButton = mView.findViewById(R.id.settings_button); 161 mSettingsButtonContainer = mView.findViewById(R.id.settings_button_container); 162 mBuildText = mView.findViewById(R.id.build); 163 mEdit = mView.findViewById(android.R.id.edit); 164 mPageIndicator = mView.findViewById(R.id.footer_page_indicator); 165 mPowerMenuLite = mView.findViewById(R.id.pm_lite); 166 mShowPMLiteButton = showPMLiteButton; 167 mGlobalActionsDialog = globalActionsDialog; 168 mUiEventLogger = uiEventLogger; 169 } 170 171 @Override onInit()172 protected void onInit() { 173 super.onInit(); 174 mMultiUserSwitchController.init(); 175 } 176 177 @Override onViewAttached()178 protected void onViewAttached() { 179 if (mShowPMLiteButton) { 180 mPowerMenuLite.setVisibility(View.VISIBLE); 181 mPowerMenuLite.setOnClickListener(mSettingsOnClickListener); 182 } else { 183 mPowerMenuLite.setVisibility(View.GONE); 184 } 185 mView.addOnLayoutChangeListener( 186 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> 187 mView.updateAnimator( 188 right - left, mQuickQSPanelController.getNumQuickTiles())); 189 mSettingsButton.setOnClickListener(mSettingsOnClickListener); 190 mBuildText.setOnLongClickListener(view -> { 191 CharSequence buildText = mBuildText.getText(); 192 if (!TextUtils.isEmpty(buildText)) { 193 ClipboardManager service = 194 mUserTracker.getUserContext().getSystemService(ClipboardManager.class); 195 String label = getResources().getString(R.string.build_number_clip_data_label); 196 service.setPrimaryClip(ClipData.newPlainText(label, buildText)); 197 Toast.makeText(getContext(), R.string.build_number_copy_toast, Toast.LENGTH_SHORT) 198 .show(); 199 return true; 200 } 201 return false; 202 }); 203 204 mEdit.setOnClickListener(view -> { 205 if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { 206 return; 207 } 208 mActivityStarter.postQSRunnableDismissingKeyguard(() -> 209 mQsPanelController.showEdit(view)); 210 }); 211 212 mQsPanelController.setFooterPageIndicator(mPageIndicator); 213 mView.updateEverything(isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled()); 214 } 215 216 @Override onViewDetached()217 protected void onViewDetached() { 218 setListening(false); 219 } 220 221 @Override setVisibility(int visibility)222 public void setVisibility(int visibility) { 223 mView.setVisibility(visibility); 224 } 225 226 @Override setExpanded(boolean expanded)227 public void setExpanded(boolean expanded) { 228 mExpanded = expanded; 229 mView.setExpanded( 230 expanded, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled()); 231 } 232 233 @Override getHeight()234 public int getHeight() { 235 return mView.getHeight(); 236 } 237 238 @Override setExpansion(float expansion)239 public void setExpansion(float expansion) { 240 mView.setExpansion(expansion); 241 } 242 243 @Override setListening(boolean listening)244 public void setListening(boolean listening) { 245 if (mListening == listening) { 246 return; 247 } 248 249 mListening = listening; 250 if (mListening) { 251 mUserInfoController.addCallback(mOnUserInfoChangedListener); 252 } else { 253 mUserInfoController.removeCallback(mOnUserInfoChangedListener); 254 } 255 } 256 257 @Override setKeyguardShowing(boolean keyguardShowing)258 public void setKeyguardShowing(boolean keyguardShowing) { 259 mView.setKeyguardShowing(); 260 } 261 262 /** */ 263 @Override setExpandClickListener(View.OnClickListener onClickListener)264 public void setExpandClickListener(View.OnClickListener onClickListener) { 265 mView.setExpandClickListener(onClickListener); 266 } 267 268 @Override disable(int state1, int state2, boolean animate)269 public void disable(int state1, int state2, boolean animate) { 270 mView.disable(state2, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled()); 271 } 272 startSettingsActivity()273 private void startSettingsActivity() { 274 ActivityLaunchAnimator.Controller animationController = 275 mSettingsButtonContainer != null ? ActivityLaunchAnimator.Controller.fromView( 276 mSettingsButtonContainer, 277 InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON) : null; 278 mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS), 279 true /* dismissShade */, animationController); 280 } 281 isTunerEnabled()282 private boolean isTunerEnabled() { 283 return mTunerService.isTunerEnabled(); 284 } 285 } 286