blob: 9bb253b3d890f65a269c5139e19a81c6465d2641 [file] [log] [blame]
Jason Monk361915c2017-03-21 20:33:59 -04001/*
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
15package com.android.systemui.globalactions;
16
Adrian Roosedfab3b2018-03-08 18:39:20 +010017import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
Adrian Roos2f05bb32018-02-19 16:42:27 +010018import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
19
Chad Brubakerf4075fe2018-01-03 13:23:22 -080020import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
21import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
Chad Brubaker4f28f0d2017-09-07 14:28:13 -070022import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
23
Dave Mankoffc88a2d72020-01-10 15:59:31 -050024import android.annotation.Nullable;
Jason Monk361915c2017-03-21 20:33:59 -040025import android.app.ActivityManager;
26import android.app.Dialog;
Dave Mankoffc88a2d72020-01-10 15:59:31 -050027import android.app.IActivityManager;
Steve Elliott4c868852019-03-14 16:25:41 -040028import android.app.PendingIntent;
Steve Elliott53f12ae2019-05-13 17:14:15 -040029import android.app.StatusBarManager;
Lucas Dupinc1cc7592017-05-22 15:56:16 -070030import android.app.WallpaperManager;
Alex Chau04458852017-11-27 18:21:23 +000031import android.app.admin.DevicePolicyManager;
Pavel Grafov059021b2018-05-02 13:44:46 +010032import android.app.trust.TrustManager;
Jason Monk361915c2017-03-21 20:33:59 -040033import android.content.BroadcastReceiver;
Matt Pietal61266442020-03-17 12:53:44 -040034import android.content.ComponentName;
Dave Mankoffc88a2d72020-01-10 15:59:31 -050035import android.content.ContentResolver;
Jason Monk361915c2017-03-21 20:33:59 -040036import android.content.Context;
37import android.content.DialogInterface;
38import android.content.Intent;
39import android.content.IntentFilter;
Matt Pietal61266442020-03-17 12:53:44 -040040import android.content.SharedPreferences;
Jason Monk361915c2017-03-21 20:33:59 -040041import android.content.pm.UserInfo;
Lucas Dupincb6726f2020-04-07 19:32:38 -070042import android.content.res.ColorStateList;
Dave Mankoffc88a2d72020-01-10 15:59:31 -050043import android.content.res.Resources;
Jason Monk361915c2017-03-21 20:33:59 -040044import android.database.ContentObserver;
Matt Pietale0661b62020-01-29 14:35:31 -050045import android.graphics.Color;
Jason Monk361915c2017-03-21 20:33:59 -040046import android.graphics.drawable.Drawable;
47import android.media.AudioManager;
48import android.net.ConnectivityManager;
Steve Elliott53f12ae2019-05-13 17:14:15 -040049import android.os.Binder;
Jason Monk361915c2017-03-21 20:33:59 -040050import android.os.Handler;
Steve Elliott53f12ae2019-05-13 17:14:15 -040051import android.os.IBinder;
Jason Monk361915c2017-03-21 20:33:59 -040052import android.os.Message;
53import android.os.RemoteException;
Jason Monk361915c2017-03-21 20:33:59 -040054import android.os.SystemProperties;
55import android.os.UserHandle;
56import android.os.UserManager;
57import android.os.Vibrator;
58import android.provider.Settings;
Jason Monk361915c2017-03-21 20:33:59 -040059import android.service.dreams.IDreamManager;
Inseob Kim5e82f732019-11-08 15:08:38 +090060import android.sysprop.TelephonyProperties;
Fan Zhangf9914762019-11-01 15:58:38 -070061import android.telecom.TelecomManager;
Jason Monk361915c2017-03-21 20:33:59 -040062import android.telephony.PhoneStateListener;
63import android.telephony.ServiceState;
64import android.telephony.TelephonyManager;
Jason Monk361915c2017-03-21 20:33:59 -040065import android.util.ArraySet;
yuanjiahsu88363e92018-09-06 19:23:52 +080066import android.util.FeatureFlagUtils;
Jason Monk361915c2017-03-21 20:33:59 -040067import android.util.Log;
Lucas Dupin448786c2017-07-24 17:44:25 -070068import android.view.ContextThemeWrapper;
Dave Mankoff8df818e2020-02-12 14:22:26 -050069import android.view.IWindowManager;
Jason Monk361915c2017-03-21 20:33:59 -040070import android.view.LayoutInflater;
71import android.view.View;
72import android.view.ViewGroup;
Lucas Dupinc1cc7592017-05-22 15:56:16 -070073import android.view.Window;
Lucas Dupin26571e92020-04-08 14:55:10 -070074import android.view.WindowInsets;
Jason Monk361915c2017-03-21 20:33:59 -040075import android.view.WindowManager;
Jason Monk361915c2017-03-21 20:33:59 -040076import android.view.accessibility.AccessibilityEvent;
Aran Inkcf038272020-03-31 17:48:37 -040077import android.widget.BaseAdapter;
Steve Elliott9b87a442019-03-05 10:24:16 -050078import android.widget.FrameLayout;
Jason Monk361915c2017-03-21 20:33:59 -040079import android.widget.ImageView;
80import android.widget.ImageView.ScaleType;
Aran Inkcf038272020-03-31 17:48:37 -040081import android.widget.ListPopupWindow;
82import android.widget.ListView;
Jason Monk361915c2017-03-21 20:33:59 -040083import android.widget.TextView;
84
Fabian Kozynskib6a20372020-04-01 09:36:43 -040085import androidx.annotation.NonNull;
86import androidx.lifecycle.Lifecycle;
87import androidx.lifecycle.LifecycleOwner;
88import androidx.lifecycle.LifecycleRegistry;
89
Charles He9851a8d2017-10-10 17:31:30 +010090import com.android.internal.R;
Chris Wren65a70c92020-04-02 10:43:46 -040091import com.android.internal.annotations.VisibleForTesting;
Charles He9851a8d2017-10-10 17:31:30 +010092import com.android.internal.colorextraction.ColorExtractor;
93import com.android.internal.colorextraction.ColorExtractor.GradientColors;
Lucas Dupin2bd3af62019-03-25 17:44:28 -070094import com.android.internal.colorextraction.drawable.ScrimDrawable;
Charles He9851a8d2017-10-10 17:31:30 +010095import com.android.internal.logging.MetricsLogger;
Chris Wren65a70c92020-04-02 10:43:46 -040096import com.android.internal.logging.UiEvent;
97import com.android.internal.logging.UiEventLogger;
Charles He9851a8d2017-10-10 17:31:30 +010098import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Steve Elliott53f12ae2019-05-13 17:14:15 -040099import com.android.internal.statusbar.IStatusBarService;
Charles He9851a8d2017-10-10 17:31:30 +0100100import com.android.internal.util.EmergencyAffordanceManager;
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400101import com.android.internal.util.ScreenRecordHelper;
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500102import com.android.internal.util.ScreenshotHelper;
Steve Elliott48f75db2019-05-03 15:03:38 -0400103import com.android.internal.view.RotationPolicy;
Charles He9851a8d2017-10-10 17:31:30 +0100104import com.android.internal.widget.LockPatternUtils;
Charles He9851a8d2017-10-10 17:31:30 +0100105import com.android.systemui.Interpolators;
Aaron Heuckrothf708d472019-01-10 16:54:51 -0500106import com.android.systemui.MultiListLayout;
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500107import com.android.systemui.MultiListLayout.MultiListAdapter;
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -0400108import com.android.systemui.broadcast.BroadcastDispatcher;
Charles He9851a8d2017-10-10 17:31:30 +0100109import com.android.systemui.colorextraction.SysuiColorExtractor;
Matt Pietal61266442020-03-17 12:53:44 -0400110import com.android.systemui.controls.ControlsServiceInfo;
111import com.android.systemui.controls.controller.ControlsController;
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500112import com.android.systemui.controls.management.ControlsListingController;
Matt Pietal22231792020-01-23 09:51:09 -0500113import com.android.systemui.controls.ui.ControlsUiController;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500114import com.android.systemui.dagger.qualifiers.Background;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500115import com.android.systemui.dagger.qualifiers.Main;
Steve Elliott4c868852019-03-14 16:25:41 -0400116import com.android.systemui.plugins.ActivityStarter;
Charles He9851a8d2017-10-10 17:31:30 +0100117import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
Steve Elliott9b87a442019-03-05 10:24:16 -0500118import com.android.systemui.plugins.GlobalActionsPanelPlugin;
Lucas Dupin99f5fba2020-03-12 12:59:18 -0700119import com.android.systemui.statusbar.BlurUtils;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -0800120import com.android.systemui.statusbar.NotificationShadeDepthController;
Matt Pietal22231792020-01-23 09:51:09 -0500121import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
Lucas Dupin43d01242020-02-03 11:58:33 -0800122import com.android.systemui.statusbar.phone.ScrimController;
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700123import com.android.systemui.statusbar.policy.ConfigurationController;
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400124import com.android.systemui.statusbar.policy.KeyguardStateController;
Shaotang Li5c422632018-07-04 14:18:40 +0800125import com.android.systemui.util.EmergencyDialerConstants;
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400126import com.android.systemui.util.RingerModeTracker;
Aaron Heuckroth75e249f2019-02-01 15:59:57 -0500127import com.android.systemui.util.leak.RotationUtils;
Julia Reynolds42411922017-11-08 11:19:09 -0500128import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator;
Lucas Dupinc1cc7592017-05-22 15:56:16 -0700129
Jason Monk361915c2017-03-21 20:33:59 -0400130import java.util.ArrayList;
131import java.util.List;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500132import java.util.concurrent.Executor;
Jason Monk361915c2017-03-21 20:33:59 -0400133
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500134import javax.inject.Inject;
135
Jason Monk361915c2017-03-21 20:33:59 -0400136/**
Sean Pont9d4fb032020-03-04 18:54:32 -0800137 * Helper to show the global actions dialog. Each item is an {@link Action} that may show depending
138 * on whether the keyguard is showing, and whether the device is provisioned.
Jason Monk361915c2017-03-21 20:33:59 -0400139 */
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500140public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
Sean Pont9d4fb032020-03-04 18:54:32 -0800141 DialogInterface.OnShowListener,
142 ConfigurationController.ConfigurationListener,
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400143 GlobalActionsPanelPlugin.Callbacks,
144 LifecycleOwner {
Jason Monk361915c2017-03-21 20:33:59 -0400145
Sean Pont9d4fb032020-03-04 18:54:32 -0800146 public static final String SYSTEM_DIALOG_REASON_KEY = "reason";
147 public static final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
148 public static final String SYSTEM_DIALOG_REASON_DREAM = "dream";
Jason Monk361915c2017-03-21 20:33:59 -0400149
150 private static final String TAG = "GlobalActionsDialog";
151
152 private static final boolean SHOW_SILENT_TOGGLE = true;
153
154 /* Valid settings for global actions keys.
155 * see config.xml config_globalActionList */
Aran Inkcf038272020-03-31 17:48:37 -0400156 @VisibleForTesting
157 protected static final String GLOBAL_ACTION_KEY_POWER = "power";
158 protected static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
159 protected static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
160 protected static final String GLOBAL_ACTION_KEY_SILENT = "silent";
161 protected static final String GLOBAL_ACTION_KEY_USERS = "users";
162 protected static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
163 protected static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
164 protected static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
165 protected static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
166 protected static final String GLOBAL_ACTION_KEY_RESTART = "restart";
167 protected static final String GLOBAL_ACTION_KEY_LOGOUT = "logout";
168 protected static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
169 protected static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
Jason Monk361915c2017-03-21 20:33:59 -0400170
Matt Pietal61266442020-03-17 12:53:44 -0400171 private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "ControlsSeedingCompleted";
172 private static final String PREFS_CONTROLS_FILE = "controls_prefs";
173
Jason Monk361915c2017-03-21 20:33:59 -0400174 private final Context mContext;
175 private final GlobalActionsManager mWindowManagerFuncs;
176 private final AudioManager mAudioManager;
177 private final IDreamManager mDreamManager;
Alex Chau04458852017-11-27 18:21:23 +0000178 private final DevicePolicyManager mDevicePolicyManager;
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800179 private final LockPatternUtils mLockPatternUtils;
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500180 private final KeyguardStateController mKeyguardStateController;
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000181 private final BroadcastDispatcher mBroadcastDispatcher;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500182 private final ContentResolver mContentResolver;
183 private final Resources mResources;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500184 private final ConfigurationController mConfigurationController;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500185 private final UserManager mUserManager;
186 private final TrustManager mTrustManager;
187 private final IActivityManager mIActivityManager;
188 private final TelecomManager mTelecomManager;
189 private final MetricsLogger mMetricsLogger;
Chris Wren65a70c92020-04-02 10:43:46 -0400190 private final UiEventLogger mUiEventLogger;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -0800191 private final NotificationShadeDepthController mDepthController;
Lucas Dupin99f5fba2020-03-12 12:59:18 -0700192 private final BlurUtils mBlurUtils;
Jason Monk361915c2017-03-21 20:33:59 -0400193
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400194 // Used for RingerModeTracker
195 private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
196
Aran Inkcf038272020-03-31 17:48:37 -0400197 @VisibleForTesting
198 protected ArrayList<Action> mItems;
199 @VisibleForTesting
200 protected ArrayList<Action> mOverflowItems;
201
Jason Monk361915c2017-03-21 20:33:59 -0400202 private ActionsDialog mDialog;
203
204 private Action mSilentModeAction;
205 private ToggleAction mAirplaneModeOn;
206
207 private MyAdapter mAdapter;
Aran Inkcf038272020-03-31 17:48:37 -0400208 private MyOverflowAdapter mOverflowAdapter;
Jason Monk361915c2017-03-21 20:33:59 -0400209
210 private boolean mKeyguardShowing = false;
211 private boolean mDeviceProvisioned = false;
Lucas Dupincb6726f2020-04-07 19:32:38 -0700212 private ToggleState mAirplaneState = ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -0400213 private boolean mIsWaitingForEcmExit = false;
214 private boolean mHasTelephony;
215 private boolean mHasVibrator;
216 private final boolean mShowSilentToggle;
217 private final EmergencyAffordanceManager mEmergencyAffordanceManager;
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500218 private final ScreenshotHelper mScreenshotHelper;
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400219 private final ScreenRecordHelper mScreenRecordHelper;
Steve Elliotta3f5207922019-03-18 13:37:22 -0400220 private final ActivityStarter mActivityStarter;
Lucas Dupin991415e2019-11-25 17:48:58 -0800221 private final SysuiColorExtractor mSysuiColorExtractor;
222 private final IStatusBarService mStatusBarService;
223 private final NotificationShadeWindowController mNotificationShadeWindowController;
Steve Elliotta3f5207922019-03-18 13:37:22 -0400224 private GlobalActionsPanelPlugin mPanelPlugin;
Matt Pietal22231792020-01-23 09:51:09 -0500225 private ControlsUiController mControlsUiController;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500226 private final IWindowManager mIWindowManager;
227 private final Executor mBackgroundExecutor;
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500228 private final ControlsListingController mControlsListingController;
Matt Pietalcd757c82020-04-08 10:20:48 -0400229 private List<ControlsServiceInfo> mControlsServiceInfos = new ArrayList<>();
230 private ControlsController mControlsController;
231 private SharedPreferences mControlsPreferences;
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400232 private final RingerModeTracker mRingerModeTracker;
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400233 private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
Steve Elliott9b87a442019-03-05 10:24:16 -0500234
Chris Wren65a70c92020-04-02 10:43:46 -0400235 @VisibleForTesting
236 public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum {
237 @UiEvent(doc = "The global actions / power menu surface became visible on the screen.")
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400238 GA_POWER_MENU_OPEN(337),
239
240 @UiEvent(doc = "The global actions bugreport button was pressed.")
241 GA_BUGREPORT_PRESS(344),
242
243 @UiEvent(doc = "The global actions bugreport button was long pressed.")
244 GA_BUGREPORT_LONG_PRESS(345),
245
246 @UiEvent(doc = "The global actions emergency button was pressed.")
247 GA_EMERGENCY_DIALER_PRESS(346),
248
249 @UiEvent(doc = "The global actions screenshot button was pressed.")
250 GA_SCREENSHOT_PRESS(347),
251
252 @UiEvent(doc = "The global actions screenshot button was long pressed.")
253 GA_SCREENSHOT_LONG_PRESS(348);
Chris Wren65a70c92020-04-02 10:43:46 -0400254
255 private final int mId;
256
257 GlobalActionsEvent(int id) {
258 mId = id;
259 }
260
261 @Override
262 public int getId() {
263 return mId;
264 }
265 }
266
Jason Monk361915c2017-03-21 20:33:59 -0400267 /**
268 * @param context everything needs a context :(
269 */
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500270 @Inject
271 public GlobalActionsDialog(Context context, GlobalActionsManager windowManagerFuncs,
272 AudioManager audioManager, IDreamManager iDreamManager,
273 DevicePolicyManager devicePolicyManager, LockPatternUtils lockPatternUtils,
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500274 BroadcastDispatcher broadcastDispatcher,
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500275 ConnectivityManager connectivityManager, TelephonyManager telephonyManager,
276 ContentResolver contentResolver, @Nullable Vibrator vibrator, @Main Resources resources,
277 ConfigurationController configurationController, ActivityStarter activityStarter,
278 KeyguardStateController keyguardStateController, UserManager userManager,
279 TrustManager trustManager, IActivityManager iActivityManager,
Dave Mankoff3c6aaab2020-01-10 17:50:34 -0500280 @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -0800281 NotificationShadeDepthController depthController, SysuiColorExtractor colorExtractor,
Lucas Dupin99f5fba2020-03-12 12:59:18 -0700282 IStatusBarService statusBarService, BlurUtils blurUtils,
Matt Pietal22231792020-01-23 09:51:09 -0500283 NotificationShadeWindowController notificationShadeWindowController,
Dave Mankoff8df818e2020-02-12 14:22:26 -0500284 ControlsUiController controlsUiController, IWindowManager iWindowManager,
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500285 @Background Executor backgroundExecutor,
Matt Pietal61266442020-03-17 12:53:44 -0400286 ControlsListingController controlsListingController,
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400287 ControlsController controlsController, UiEventLogger uiEventLogger,
288 RingerModeTracker ringerModeTracker) {
Lucas Dupin448786c2017-07-24 17:44:25 -0700289 mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
Jason Monk361915c2017-03-21 20:33:59 -0400290 mWindowManagerFuncs = windowManagerFuncs;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500291 mAudioManager = audioManager;
292 mDreamManager = iDreamManager;
293 mDevicePolicyManager = devicePolicyManager;
294 mLockPatternUtils = lockPatternUtils;
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500295 mKeyguardStateController = keyguardStateController;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500296 mBroadcastDispatcher = broadcastDispatcher;
297 mContentResolver = contentResolver;
298 mResources = resources;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500299 mConfigurationController = configurationController;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500300 mUserManager = userManager;
301 mTrustManager = trustManager;
302 mIActivityManager = iActivityManager;
303 mTelecomManager = telecomManager;
304 mMetricsLogger = metricsLogger;
Chris Wren65a70c92020-04-02 10:43:46 -0400305 mUiEventLogger = uiEventLogger;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -0800306 mDepthController = depthController;
Lucas Dupin991415e2019-11-25 17:48:58 -0800307 mSysuiColorExtractor = colorExtractor;
308 mStatusBarService = statusBarService;
309 mNotificationShadeWindowController = notificationShadeWindowController;
Matt Pietal22231792020-01-23 09:51:09 -0500310 mControlsUiController = controlsUiController;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500311 mIWindowManager = iWindowManager;
312 mBackgroundExecutor = backgroundExecutor;
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500313 mControlsListingController = controlsListingController;
Lucas Dupin99f5fba2020-03-12 12:59:18 -0700314 mBlurUtils = blurUtils;
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400315 mRingerModeTracker = ringerModeTracker;
Matt Pietalcd757c82020-04-08 10:20:48 -0400316 mControlsController = controlsController;
Jason Monk361915c2017-03-21 20:33:59 -0400317
318 // receive broadcasts
319 IntentFilter filter = new IntentFilter();
320 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
321 filter.addAction(Intent.ACTION_SCREEN_OFF);
Jayachandran C142eae02019-12-13 19:29:20 -0800322 filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000323 mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
Jason Monk361915c2017-03-21 20:33:59 -0400324
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500325 mHasTelephony = connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
Jason Monk361915c2017-03-21 20:33:59 -0400326
327 // get notified of phone state changes
Jason Monk361915c2017-03-21 20:33:59 -0400328 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500329 contentResolver.registerContentObserver(
Jason Monk361915c2017-03-21 20:33:59 -0400330 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
331 mAirplaneModeObserver);
Jason Monk361915c2017-03-21 20:33:59 -0400332 mHasVibrator = vibrator != null && vibrator.hasVibrator();
333
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500334 mShowSilentToggle = SHOW_SILENT_TOGGLE && !resources.getBoolean(
Jason Monk361915c2017-03-21 20:33:59 -0400335 R.bool.config_useFixedVolume);
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400336 if (mShowSilentToggle) {
337 mRingerModeTracker.getRingerMode().observe(this, ringer ->
338 mHandler.sendEmptyMessage(MESSAGE_REFRESH)
339 );
340 }
Jason Monk361915c2017-03-21 20:33:59 -0400341
342 mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500343 mScreenshotHelper = new ScreenshotHelper(context);
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400344 mScreenRecordHelper = new ScreenRecordHelper(context);
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700345
Dave Mankoff8df818e2020-02-12 14:22:26 -0500346 mConfigurationController.addCallback(this);
Steve Elliott9b87a442019-03-05 10:24:16 -0500347
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500348 mActivityStarter = activityStarter;
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400349 keyguardStateController.addCallback(new KeyguardStateController.Callback() {
350 @Override
351 public void onUnlockedChanged() {
352 if (mDialog != null && mDialog.mPanelController != null) {
Sean Pont9d4fb032020-03-04 18:54:32 -0800353 boolean unlocked = keyguardStateController.isUnlocked()
354 || keyguardStateController.canDismissLockScreen();
355 mDialog.mPanelController.onDeviceLockStateChanged(unlocked);
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400356 }
357 }
358 });
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500359
Matt Pietal61266442020-03-17 12:53:44 -0400360 mControlsListingController.addCallback(list -> {
Matt Pietalcd757c82020-04-08 10:20:48 -0400361 mControlsServiceInfos = list;
Matt Pietal61266442020-03-17 12:53:44 -0400362 });
Matt Pietalcd757c82020-04-08 10:20:48 -0400363
364 // Need to be user-specific with the context to make sure we read the correct prefs
365 Context userContext = context.createContextAsUser(
366 new UserHandle(mUserManager.getUserHandle()), 0);
367 mControlsPreferences = userContext.getSharedPreferences(PREFS_CONTROLS_FILE,
368 Context.MODE_PRIVATE);
369
Jason Monk361915c2017-03-21 20:33:59 -0400370 }
371
Matt Pietalcd757c82020-04-08 10:20:48 -0400372 private void seedFavorites() {
373 if (mControlsServiceInfos.isEmpty()
374 || mControlsController.getFavorites().size() > 0
375 || mControlsPreferences.getBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, false)) {
376 return;
377 }
Matt Pietal61266442020-03-17 12:53:44 -0400378
Matt Pietalcd757c82020-04-08 10:20:48 -0400379 /*
380 * See if any service providers match the preferred component. If they do,
381 * and there are no current favorites, and we haven't successfully loaded favorites to
382 * date, query the preferred component for a limited number of suggested controls.
383 */
384 String preferredControlsPackage = mContext.getResources()
385 .getString(com.android.systemui.R.string.config_controlsPreferredPackage);
Matt Pietal61266442020-03-17 12:53:44 -0400386
Matt Pietalcd757c82020-04-08 10:20:48 -0400387 ComponentName preferredComponent = null;
388 for (ControlsServiceInfo info : mControlsServiceInfos) {
389 if (info.componentName.getPackageName().equals(preferredControlsPackage)) {
390 preferredComponent = info.componentName;
391 break;
392 }
393 }
394
395 if (preferredComponent == null) {
396 Log.i(TAG, "Controls seeding: No preferred component has been set, will not seed");
397 mControlsPreferences.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, true).apply();
Matt Pietal69dfb642020-04-16 13:34:46 -0400398 return;
Matt Pietalcd757c82020-04-08 10:20:48 -0400399 }
400
401 mControlsController.seedFavoritesForComponent(
402 preferredComponent,
403 (accepted) -> {
404 Log.i(TAG, "Controls seeded: " + accepted);
405 mControlsPreferences.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED,
406 accepted).apply();
407 });
408 }
Matt Pietal61266442020-03-17 12:53:44 -0400409
Jason Monk361915c2017-03-21 20:33:59 -0400410 /**
411 * Show the global actions dialog (creating if necessary)
Jason Monk16fbd9d2017-04-27 14:28:49 -0400412 *
Jason Monk361915c2017-03-21 20:33:59 -0400413 * @param keyguardShowing True if keyguard is showing
414 */
Steve Elliotta3f5207922019-03-18 13:37:22 -0400415 public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned,
416 GlobalActionsPanelPlugin panelPlugin) {
Jason Monk361915c2017-03-21 20:33:59 -0400417 mKeyguardShowing = keyguardShowing;
418 mDeviceProvisioned = isDeviceProvisioned;
Steve Elliotta3f5207922019-03-18 13:37:22 -0400419 mPanelPlugin = panelPlugin;
Jason Monk361915c2017-03-21 20:33:59 -0400420 if (mDialog != null) {
421 mDialog.dismiss();
422 mDialog = null;
423 // Show delayed, so that the dismiss of the previous dialog completes
424 mHandler.sendEmptyMessage(MESSAGE_SHOW);
425 } else {
426 handleShow();
427 }
428 }
429
Charles He9851a8d2017-10-10 17:31:30 +0100430 /**
431 * Dismiss the global actions dialog, if it's currently shown
432 */
433 public void dismissDialog() {
434 mHandler.removeMessages(MESSAGE_DISMISS);
435 mHandler.sendEmptyMessage(MESSAGE_DISMISS);
436 }
437
Jason Monk361915c2017-03-21 20:33:59 -0400438 private void awakenIfNecessary() {
439 if (mDreamManager != null) {
440 try {
441 if (mDreamManager.isDreaming()) {
442 mDreamManager.awaken();
443 }
444 } catch (RemoteException e) {
445 // we tried
446 }
447 }
448 }
449
450 private void handleShow() {
451 awakenIfNecessary();
452 mDialog = createDialog();
453 prepareDialog();
Matt Pietalcd757c82020-04-08 10:20:48 -0400454 seedFavorites();
Jason Monk361915c2017-03-21 20:33:59 -0400455
456 // If we only have 1 item and it's a simple press action, just do this action.
457 if (mAdapter.getCount() == 1
458 && mAdapter.getItem(0) instanceof SinglePressAction
459 && !(mAdapter.getItem(0) instanceof LongPressAction)) {
460 ((SinglePressAction) mAdapter.getItem(0)).onPress();
461 } else {
462 WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
463 attrs.setTitle("ActionsDialog");
Adrian Roos2f05bb32018-02-19 16:42:27 +0100464 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
Jason Monk361915c2017-03-21 20:33:59 -0400465 mDialog.getWindow().setAttributes(attrs);
466 mDialog.show();
467 mWindowManagerFuncs.onGlobalActionsShown();
Jason Monk361915c2017-03-21 20:33:59 -0400468 }
469 }
470
Aran Inkcf038272020-03-31 17:48:37 -0400471 @VisibleForTesting
472 protected boolean shouldShowAction(Action action) {
473 if (mKeyguardShowing && !action.showDuringKeyguard()) {
474 return false;
475 }
476 if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
477 return false;
478 }
479 return true;
480 }
481
Jason Monk361915c2017-03-21 20:33:59 -0400482 /**
Aran Inkcf038272020-03-31 17:48:37 -0400483 * Returns the maximum number of power menu items to show based on which GlobalActions
484 * layout is being used.
Jason Monk361915c2017-03-21 20:33:59 -0400485 */
Aran Inkcf038272020-03-31 17:48:37 -0400486 @VisibleForTesting
487 protected int getMaxShownPowerItems() {
488 if (shouldShowControls()) {
489 return mResources.getInteger(com.android.systemui.R.integer.power_menu_max_columns);
490 } else {
491 return Integer.MAX_VALUE;
492 }
493 }
494
495 /**
496 * Add a power menu action item for to either the main or overflow items lists, depending on
497 * whether controls are enabled and whether the max number of shown items has been reached.
498 */
499 private void addActionItem(Action action) {
500 if (mItems != null && shouldShowAction(action)) {
501 if (mItems.size() < getMaxShownPowerItems()) {
502 mItems.add(action);
503 } else if (mOverflowItems != null) {
504 mOverflowItems.add(action);
505 }
506 }
507 }
508
509 @VisibleForTesting
510 protected String[] getDefaultActions() {
511 return mResources.getStringArray(R.array.config_globalActionsList);
512 }
513
514 @VisibleForTesting
515 protected void createActionItems() {
Jason Monk361915c2017-03-21 20:33:59 -0400516 // Simple toggle style if there's no vibrator, otherwise use a tri-state
517 if (!mHasVibrator) {
518 mSilentModeAction = new SilentModeToggleAction();
519 } else {
Lucas Dupin40ec6b782018-06-05 19:07:16 -0700520 mSilentModeAction = new SilentModeTriStateAction(mAudioManager, mHandler);
Jason Monk361915c2017-03-21 20:33:59 -0400521 }
Aran Ink780d4502020-02-14 10:39:58 -0500522 mAirplaneModeOn = new AirplaneModeAction();
Jason Monk361915c2017-03-21 20:33:59 -0400523 onAirplaneModeChanged();
524
525 mItems = new ArrayList<Action>();
Aran Inkcf038272020-03-31 17:48:37 -0400526 mOverflowItems = new ArrayList<Action>();
527 String[] defaultActions = getDefaultActions();
528
529 // make sure emergency affordance action is first, if needed
530 if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
531 addActionItem(new EmergencyAffordanceAction());
532 }
Jason Monk361915c2017-03-21 20:33:59 -0400533
534 ArraySet<String> addedKeys = new ArraySet<String>();
535 for (int i = 0; i < defaultActions.length; i++) {
536 String actionKey = defaultActions[i];
537 if (addedKeys.contains(actionKey)) {
538 // If we already have added this, don't add it again.
539 continue;
540 }
541 if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400542 addActionItem(new PowerAction());
Jason Monk361915c2017-03-21 20:33:59 -0400543 } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400544 addActionItem(mAirplaneModeOn);
Jason Monk361915c2017-03-21 20:33:59 -0400545 } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500546 if (Settings.Global.getInt(mContentResolver,
Jason Monk361915c2017-03-21 20:33:59 -0400547 Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
Aran Inkcf038272020-03-31 17:48:37 -0400548 addActionItem(new BugReportAction());
Jason Monk361915c2017-03-21 20:33:59 -0400549 }
550 } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
551 if (mShowSilentToggle) {
Aran Inkcf038272020-03-31 17:48:37 -0400552 addActionItem(mSilentModeAction);
Jason Monk361915c2017-03-21 20:33:59 -0400553 }
554 } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
555 if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
Aran Inkcf038272020-03-31 17:48:37 -0400556 addUsersToMenu();
Jason Monk361915c2017-03-21 20:33:59 -0400557 }
558 } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400559 addActionItem(getSettingsAction());
Jason Monk361915c2017-03-21 20:33:59 -0400560 } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500561 if (Settings.Secure.getIntForUser(mContentResolver,
Sean Pont9d4fb032020-03-04 18:54:32 -0800562 Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, getCurrentUser().id) != 0
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800563 && shouldDisplayLockdown()) {
Aran Inkcf038272020-03-31 17:48:37 -0400564 addActionItem(getLockdownAction());
Chad Brubaker4f28f0d2017-09-07 14:28:13 -0700565 }
Jason Monk361915c2017-03-21 20:33:59 -0400566 } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400567 addActionItem(getVoiceAssistAction());
Jason Monk361915c2017-03-21 20:33:59 -0400568 } else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400569 addActionItem(getAssistAction());
Jason Monk361915c2017-03-21 20:33:59 -0400570 } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400571 addActionItem(new RestartAction());
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500572 } else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400573 addActionItem(new ScreenshotAction());
Alex Chau04458852017-11-27 18:21:23 +0000574 } else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) {
Alex Chaud7958272017-12-08 11:30:52 +0000575 if (mDevicePolicyManager.isLogoutEnabled()
Alex Chau04458852017-11-27 18:21:23 +0000576 && getCurrentUser().id != UserHandle.USER_SYSTEM) {
Aran Inkcf038272020-03-31 17:48:37 -0400577 addActionItem(new LogoutAction());
Alex Chau04458852017-11-27 18:21:23 +0000578 }
Wesley.CW Wanga9de7922018-07-06 15:26:21 +0800579 } else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400580 if (!mEmergencyAffordanceManager.needsEmergencyAffordance()) {
Aran Inkcf038272020-03-31 17:48:37 -0400581 addActionItem(new EmergencyDialerAction());
Wesley.CW Wanga9de7922018-07-06 15:26:21 +0800582 }
Jason Monk361915c2017-03-21 20:33:59 -0400583 } else {
584 Log.e(TAG, "Invalid global action key " + actionKey);
585 }
586 // Add here so we don't add more than one.
587 addedKeys.add(actionKey);
588 }
Aran Inkcf038272020-03-31 17:48:37 -0400589 }
Jason Monk361915c2017-03-21 20:33:59 -0400590
Aran Inkcf038272020-03-31 17:48:37 -0400591 /**
592 * Create the global actions dialog.
593 *
594 * @return A new dialog.
595 */
596 private ActionsDialog createDialog() {
597 createActionItems();
Jason Monk361915c2017-03-21 20:33:59 -0400598
599 mAdapter = new MyAdapter();
Aran Inkcf038272020-03-31 17:48:37 -0400600 mOverflowAdapter = new MyOverflowAdapter();
Jason Monk361915c2017-03-21 20:33:59 -0400601
Lucas Dupin3a8531e2020-04-06 17:18:09 -0700602 mDepthController.setShowingHomeControls(shouldShowControls());
Aran Inkcf038272020-03-31 17:48:37 -0400603 ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mOverflowAdapter,
604 getWalletPanelViewController(), mDepthController, mSysuiColorExtractor,
605 mStatusBarService, mNotificationShadeWindowController,
Lucas Dupin99f5fba2020-03-12 12:59:18 -0700606 shouldShowControls() ? mControlsUiController : null, mBlurUtils);
Jason Monk361915c2017-03-21 20:33:59 -0400607 dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
Lucas Dupinc1cc7592017-05-22 15:56:16 -0700608 dialog.setKeyguardShowing(mKeyguardShowing);
Jason Monk361915c2017-03-21 20:33:59 -0400609
610 dialog.setOnDismissListener(this);
Shaotang Li786da902018-08-02 11:18:00 +0800611 dialog.setOnShowListener(this);
Jason Monk361915c2017-03-21 20:33:59 -0400612
613 return dialog;
614 }
615
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800616 private boolean shouldDisplayLockdown() {
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800617 // Lockdown is meaningless without a place to go.
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500618 if (!mKeyguardStateController.isMethodSecure()) {
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800619 return false;
620 }
621
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500622 int userId = getCurrentUser().id;
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800623 // Only show the lockdown button if the device isn't locked down (for whatever reason).
624 int state = mLockPatternUtils.getStrongAuthForUser(userId);
625 return (state == STRONG_AUTH_NOT_REQUIRED
626 || state == SOME_AUTH_REQUIRED_AFTER_USER_REQUEST);
627 }
628
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700629 @Override
630 public void onUiModeChanged() {
631 mContext.getTheme().applyStyle(mContext.getThemeResId(), true);
Lucas Dupina4e12ba2019-04-18 11:56:28 -0700632 if (mDialog != null && mDialog.isShowing()) {
Aaron Heuckroth4ef3a542019-04-01 14:17:23 -0400633 mDialog.refreshDialog();
634 }
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700635 }
636
637 public void destroy() {
Dave Mankoff8df818e2020-02-12 14:22:26 -0500638 mConfigurationController.removeCallback(this);
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700639 }
640
Sean Pont9d4fb032020-03-04 18:54:32 -0800641 @Nullable
642 private GlobalActionsPanelPlugin.PanelViewController getWalletPanelViewController() {
643 if (mPanelPlugin == null) {
644 return null;
645 }
646 return mPanelPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked());
647 }
648
649 /**
650 * Implements {@link GlobalActionsPanelPlugin.Callbacks#dismissGlobalActionsMenu()}, which is
651 * called when the quick access wallet requests dismissal.
652 */
653 @Override
654 public void dismissGlobalActionsMenu() {
655 dismissDialog();
656 }
657
658 /**
659 * Implements {@link GlobalActionsPanelPlugin.Callbacks#dismissGlobalActionsMenu()}, which is
660 * called when the quick access wallet requests that an intent be started (with lock screen
661 * shown first if needed).
662 */
663 @Override
664 public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
665 mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
666 }
667
Jason Monk361915c2017-03-21 20:33:59 -0400668 private final class PowerAction extends SinglePressAction implements LongPressAction {
669 private PowerAction() {
670 super(R.drawable.ic_lock_power_off,
Jason Monk16fbd9d2017-04-27 14:28:49 -0400671 R.string.global_action_power_off);
Jason Monk361915c2017-03-21 20:33:59 -0400672 }
673
674 @Override
675 public boolean onLongPress() {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500676 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
Jason Monk361915c2017-03-21 20:33:59 -0400677 mWindowManagerFuncs.reboot(true);
678 return true;
679 }
680 return false;
681 }
682
683 @Override
684 public boolean showDuringKeyguard() {
685 return true;
686 }
687
688 @Override
689 public boolean showBeforeProvisioning() {
690 return true;
691 }
692
693 @Override
694 public void onPress() {
695 // shutdown by making sure radio and power are handled accordingly.
696 mWindowManagerFuncs.shutdown();
697 }
698 }
699
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400700 private abstract class EmergencyAction extends SinglePressAction {
701 EmergencyAction(int iconResId, int messageResId) {
702 super(iconResId, messageResId);
703 }
704
705 @Override
706 public boolean shouldBeSeparated() {
Lucas Dupincb6726f2020-04-07 19:32:38 -0700707 return !shouldShowControls();
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400708 }
709
710 @Override
711 public View create(
712 Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
713 View v = super.create(context, convertView, parent, inflater);
714 int textColor;
Lucas Dupincb6726f2020-04-07 19:32:38 -0700715 if (shouldShowControls()) {
716 v.setBackgroundTintList(ColorStateList.valueOf(v.getResources().getColor(
717 com.android.systemui.R.color.global_actions_emergency_background)));
718 textColor = v.getResources().getColor(
719 com.android.systemui.R.color.global_actions_emergency_text);
720 } else if (shouldBeSeparated()) {
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400721 textColor = v.getResources().getColor(
722 com.android.systemui.R.color.global_actions_alert_text);
723 } else {
724 textColor = v.getResources().getColor(
725 com.android.systemui.R.color.global_actions_text);
726 }
727 TextView messageView = v.findViewById(R.id.message);
728 messageView.setTextColor(textColor);
Aaron Heuckroth3f2d8b52019-04-05 13:27:51 -0400729 messageView.setSelected(true); // necessary for marquee to work
Lucas Dupincb6726f2020-04-07 19:32:38 -0700730 ImageView icon = v.findViewById(R.id.icon);
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400731 icon.getDrawable().setTint(textColor);
732 return v;
733 }
734
735 @Override
736 public boolean showDuringKeyguard() {
737 return true;
738 }
739
740 @Override
741 public boolean showBeforeProvisioning() {
742 return true;
743 }
744 }
745
746 private class EmergencyAffordanceAction extends EmergencyAction {
747 EmergencyAffordanceAction() {
748 super(R.drawable.emergency_icon,
749 R.string.global_action_emergency);
750 }
751
752 @Override
753 public void onPress() {
754 mEmergencyAffordanceManager.performEmergencyCall();
755 }
756 }
757
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400758 @VisibleForTesting
759 class EmergencyDialerAction extends EmergencyAction {
Wesley.CW Wanga9de7922018-07-06 15:26:21 +0800760 private EmergencyDialerAction() {
Aran Ink50195262019-05-30 10:55:37 -0400761 super(com.android.systemui.R.drawable.ic_emergency_star,
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800762 R.string.global_action_emergency);
Wesley.CW Wang8d072762018-05-28 16:39:27 +0800763 }
764
765 @Override
766 public void onPress() {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500767 mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_DIALER_FROM_POWER_MENU);
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400768 mUiEventLogger.log(GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS);
Dave Mankoff3c6aaab2020-01-10 17:50:34 -0500769 if (mTelecomManager != null) {
770 Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent(
771 null /* number */);
772 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
773 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
774 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
775 intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
776 EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU);
777 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
778 }
Wesley.CW Wang8d072762018-05-28 16:39:27 +0800779 }
Wesley.CW Wang8d072762018-05-28 16:39:27 +0800780 }
781
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400782 @VisibleForTesting
783 EmergencyDialerAction makeEmergencyDialerActionForTesting() {
784 return new EmergencyDialerAction();
785 }
786
Jason Monk361915c2017-03-21 20:33:59 -0400787 private final class RestartAction extends SinglePressAction implements LongPressAction {
788 private RestartAction() {
789 super(R.drawable.ic_restart, R.string.global_action_restart);
790 }
791
792 @Override
793 public boolean onLongPress() {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500794 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
Jason Monk361915c2017-03-21 20:33:59 -0400795 mWindowManagerFuncs.reboot(true);
796 return true;
797 }
798 return false;
799 }
800
801 @Override
802 public boolean showDuringKeyguard() {
803 return true;
804 }
805
806 @Override
807 public boolean showBeforeProvisioning() {
808 return true;
809 }
810
811 @Override
812 public void onPress() {
813 mWindowManagerFuncs.reboot(false);
814 }
815 }
816
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400817 @VisibleForTesting
818 class ScreenshotAction extends SinglePressAction implements LongPressAction {
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500819 public ScreenshotAction() {
820 super(R.drawable.ic_screenshot, R.string.global_action_screenshot);
821 }
822
823 @Override
824 public void onPress() {
825 // Add a little delay before executing, to give the
826 // dialog a chance to go away before it takes a
827 // screenshot.
828 // TODO: instead, omit global action dialog layer
829 mHandler.postDelayed(new Runnable() {
830 @Override
831 public void run() {
James O'Learyfa5bb7a2019-09-05 13:43:29 -0400832 mScreenshotHelper.takeScreenshot(1, true, true, mHandler, null);
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500833 mMetricsLogger.action(MetricsEvent.ACTION_SCREENSHOT_POWER_MENU);
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400834 mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_PRESS);
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500835 }
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400836 }, mDialogPressDelay);
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500837 }
838
839 @Override
840 public boolean showDuringKeyguard() {
841 return true;
842 }
843
844 @Override
845 public boolean showBeforeProvisioning() {
846 return false;
847 }
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400848
849 @Override
850 public boolean onLongPress() {
851 if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS)) {
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400852 mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS);
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400853 mScreenRecordHelper.launchRecordPrompt();
854 } else {
855 onPress();
856 }
857 return true;
858 }
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500859 }
860
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400861 @VisibleForTesting
862 ScreenshotAction makeScreenshotActionForTesting() {
863 return new ScreenshotAction();
864 }
865
866 @VisibleForTesting
867 class BugReportAction extends SinglePressAction implements LongPressAction {
Jason Monk361915c2017-03-21 20:33:59 -0400868
869 public BugReportAction() {
870 super(R.drawable.ic_lock_bugreport, R.string.bugreport_title);
871 }
872
873 @Override
874 public void onPress() {
875 // don't actually trigger the bugreport if we are running stability
876 // tests via monkey
877 if (ActivityManager.isUserAMonkey()) {
878 return;
879 }
880 // Add a little delay before executing, to give the
881 // dialog a chance to go away before it takes a
882 // screenshot.
883 mHandler.postDelayed(new Runnable() {
884 @Override
885 public void run() {
886 try {
887 // Take an "interactive" bugreport.
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500888 mMetricsLogger.action(
Jason Monk361915c2017-03-21 20:33:59 -0400889 MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400890 mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_PRESS);
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500891 if (!mIActivityManager.launchBugReportHandlerApp()) {
Paul Changc40f5782019-11-04 18:55:31 +0800892 Log.w(TAG, "Bugreport handler could not be launched");
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500893 mIActivityManager.requestInteractiveBugReport();
Paul Changc40f5782019-11-04 18:55:31 +0800894 }
Jason Monk361915c2017-03-21 20:33:59 -0400895 } catch (RemoteException e) {
896 }
897 }
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400898 }, mDialogPressDelay);
Jason Monk361915c2017-03-21 20:33:59 -0400899 }
900
901 @Override
902 public boolean onLongPress() {
903 // don't actually trigger the bugreport if we are running stability
904 // tests via monkey
905 if (ActivityManager.isUserAMonkey()) {
906 return false;
907 }
908 try {
909 // Take a "full" bugreport.
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500910 mMetricsLogger.action(MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400911 mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS);
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500912 mIActivityManager.requestFullBugReport();
Jason Monk361915c2017-03-21 20:33:59 -0400913 } catch (RemoteException e) {
914 }
915 return false;
916 }
917
918 public boolean showDuringKeyguard() {
919 return true;
920 }
921
922 @Override
923 public boolean showBeforeProvisioning() {
924 return false;
925 }
Jason Monk361915c2017-03-21 20:33:59 -0400926 }
927
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400928 @VisibleForTesting
929 BugReportAction makeBugReportActionForTesting() {
930 return new BugReportAction();
931 }
932
Alex Chau04458852017-11-27 18:21:23 +0000933 private final class LogoutAction extends SinglePressAction {
934 private LogoutAction() {
935 super(R.drawable.ic_logout, R.string.global_action_logout);
936 }
937
938 @Override
939 public boolean showDuringKeyguard() {
940 return true;
941 }
942
943 @Override
944 public boolean showBeforeProvisioning() {
945 return false;
946 }
947
948 @Override
949 public void onPress() {
950 // Add a little delay before executing, to give the dialog a chance to go away before
951 // switching user
952 mHandler.postDelayed(() -> {
953 try {
Alex Chauedb6a012018-01-26 12:52:43 +0000954 int currentUserId = getCurrentUser().id;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500955 mIActivityManager.switchUser(UserHandle.USER_SYSTEM);
956 mIActivityManager.stopUser(currentUserId, true /*force*/, null);
Alex Chau04458852017-11-27 18:21:23 +0000957 } catch (RemoteException re) {
958 Log.e(TAG, "Couldn't logout user " + re);
959 }
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400960 }, mDialogPressDelay);
Alex Chau04458852017-11-27 18:21:23 +0000961 }
962 }
963
Jason Monk361915c2017-03-21 20:33:59 -0400964 private Action getSettingsAction() {
965 return new SinglePressAction(R.drawable.ic_settings,
966 R.string.global_action_settings) {
967
968 @Override
969 public void onPress() {
970 Intent intent = new Intent(Settings.ACTION_SETTINGS);
971 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
972 mContext.startActivity(intent);
973 }
974
975 @Override
976 public boolean showDuringKeyguard() {
977 return true;
978 }
979
980 @Override
981 public boolean showBeforeProvisioning() {
982 return true;
983 }
984 };
985 }
986
Jason Monk361915c2017-03-21 20:33:59 -0400987 private Action getAssistAction() {
988 return new SinglePressAction(R.drawable.ic_action_assist_focused,
989 R.string.global_action_assist) {
990 @Override
991 public void onPress() {
992 Intent intent = new Intent(Intent.ACTION_ASSIST);
993 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
994 mContext.startActivity(intent);
995 }
996
997 @Override
998 public boolean showDuringKeyguard() {
999 return true;
1000 }
1001
1002 @Override
1003 public boolean showBeforeProvisioning() {
1004 return true;
1005 }
1006 };
1007 }
1008
1009 private Action getVoiceAssistAction() {
1010 return new SinglePressAction(R.drawable.ic_voice_search,
1011 R.string.global_action_voice_assist) {
1012 @Override
1013 public void onPress() {
1014 Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
1015 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1016 mContext.startActivity(intent);
1017 }
1018
1019 @Override
1020 public boolean showDuringKeyguard() {
1021 return true;
1022 }
1023
1024 @Override
1025 public boolean showBeforeProvisioning() {
1026 return true;
1027 }
1028 };
1029 }
1030
1031 private Action getLockdownAction() {
Alison Cichowlas21125432018-05-16 15:40:45 -04001032 return new SinglePressAction(R.drawable.ic_lock_lockdown,
Jason Monk361915c2017-03-21 20:33:59 -04001033 R.string.global_action_lockdown) {
1034
1035 @Override
1036 public void onPress() {
Dave Mankoff8df818e2020-02-12 14:22:26 -05001037 mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
1038 UserHandle.USER_ALL);
Jason Monk361915c2017-03-21 20:33:59 -04001039 try {
Dave Mankoff8df818e2020-02-12 14:22:26 -05001040 mIWindowManager.lockNow(null);
Pavel Grafov059021b2018-05-02 13:44:46 +01001041 // Lock profiles (if any) on the background thread.
Dave Mankoff8df818e2020-02-12 14:22:26 -05001042 mBackgroundExecutor.execute(() -> lockProfiles());
Jason Monk361915c2017-03-21 20:33:59 -04001043 } catch (RemoteException e) {
1044 Log.e(TAG, "Error while trying to lock device.", e);
1045 }
1046 }
1047
1048 @Override
1049 public boolean showDuringKeyguard() {
1050 return true;
1051 }
1052
1053 @Override
1054 public boolean showBeforeProvisioning() {
1055 return false;
1056 }
1057 };
1058 }
1059
Pavel Grafov059021b2018-05-02 13:44:46 +01001060 private void lockProfiles() {
Pavel Grafov059021b2018-05-02 13:44:46 +01001061 final int currentUserId = getCurrentUser().id;
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001062 final int[] profileIds = mUserManager.getEnabledProfileIds(currentUserId);
Pavel Grafov059021b2018-05-02 13:44:46 +01001063 for (final int id : profileIds) {
1064 if (id != currentUserId) {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001065 mTrustManager.setDeviceLockedForUser(id, true);
Pavel Grafov059021b2018-05-02 13:44:46 +01001066 }
1067 }
1068 }
1069
Jason Monk361915c2017-03-21 20:33:59 -04001070 private UserInfo getCurrentUser() {
1071 try {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001072 return mIActivityManager.getCurrentUser();
Jason Monk361915c2017-03-21 20:33:59 -04001073 } catch (RemoteException re) {
1074 return null;
1075 }
1076 }
1077
1078 private boolean isCurrentUserOwner() {
1079 UserInfo currentUser = getCurrentUser();
1080 return currentUser == null || currentUser.isPrimary();
1081 }
1082
Aran Inkcf038272020-03-31 17:48:37 -04001083 private void addUsersToMenu() {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001084 if (mUserManager.isUserSwitcherEnabled()) {
1085 List<UserInfo> users = mUserManager.getUsers();
Jason Monk361915c2017-03-21 20:33:59 -04001086 UserInfo currentUser = getCurrentUser();
1087 for (final UserInfo user : users) {
1088 if (user.supportsSwitchToByUser()) {
1089 boolean isCurrentUser = currentUser == null
1090 ? user.id == 0 : (currentUser.id == user.id);
1091 Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
1092 : null;
1093 SinglePressAction switchToUser = new SinglePressAction(
1094 R.drawable.ic_menu_cc, icon,
1095 (user.name != null ? user.name : "Primary")
Jason Monk16fbd9d2017-04-27 14:28:49 -04001096 + (isCurrentUser ? " \u2714" : "")) {
Jason Monk361915c2017-03-21 20:33:59 -04001097 public void onPress() {
1098 try {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001099 mIActivityManager.switchUser(user.id);
Jason Monk361915c2017-03-21 20:33:59 -04001100 } catch (RemoteException re) {
1101 Log.e(TAG, "Couldn't switch user " + re);
1102 }
1103 }
1104
1105 public boolean showDuringKeyguard() {
1106 return true;
1107 }
1108
1109 public boolean showBeforeProvisioning() {
1110 return false;
1111 }
1112 };
Aran Inkcf038272020-03-31 17:48:37 -04001113 addActionItem(switchToUser);
Jason Monk361915c2017-03-21 20:33:59 -04001114 }
1115 }
1116 }
1117 }
1118
1119 private void prepareDialog() {
1120 refreshSilentMode();
1121 mAirplaneModeOn.updateState(mAirplaneState);
1122 mAdapter.notifyDataSetChanged();
Fabian Kozynskib6a20372020-04-01 09:36:43 -04001123 mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
Jason Monk361915c2017-03-21 20:33:59 -04001124 }
1125
1126 private void refreshSilentMode() {
1127 if (!mHasVibrator) {
Fabian Kozynskib6a20372020-04-01 09:36:43 -04001128 Integer value = mRingerModeTracker.getRingerMode().getValue();
1129 final boolean silentModeOn = value != null && value != AudioManager.RINGER_MODE_NORMAL;
Jason Monk16fbd9d2017-04-27 14:28:49 -04001130 ((ToggleAction) mSilentModeAction).updateState(
Lucas Dupincb6726f2020-04-07 19:32:38 -07001131 silentModeOn ? ToggleState.On : ToggleState.Off);
Jason Monk361915c2017-03-21 20:33:59 -04001132 }
1133 }
1134
Sean Pont9d4fb032020-03-04 18:54:32 -08001135 /**
1136 * {@inheritDoc}
1137 */
Jason Monk361915c2017-03-21 20:33:59 -04001138 public void onDismiss(DialogInterface dialog) {
Steve Elliottc3147e22019-11-20 19:34:57 -05001139 if (mDialog == dialog) {
1140 mDialog = null;
1141 }
Jason Monk361915c2017-03-21 20:33:59 -04001142 mWindowManagerFuncs.onGlobalActionsHidden();
Fabian Kozynskib6a20372020-04-01 09:36:43 -04001143 mLifecycle.setCurrentState(Lifecycle.State.DESTROYED);
Jason Monk361915c2017-03-21 20:33:59 -04001144 }
1145
Sean Pont9d4fb032020-03-04 18:54:32 -08001146 /**
1147 * {@inheritDoc}
1148 */
Shaotang Li786da902018-08-02 11:18:00 +08001149 public void onShow(DialogInterface dialog) {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001150 mMetricsLogger.visible(MetricsEvent.POWER_MENU);
Chris Wren65a70c92020-04-02 10:43:46 -04001151 mUiEventLogger.log(GlobalActionsEvent.GA_POWER_MENU_OPEN);
Shaotang Li786da902018-08-02 11:18:00 +08001152 }
1153
Lucas Dupincb6726f2020-04-07 19:32:38 -07001154 private int getActionLayoutId() {
1155 if (shouldShowControls()) {
1156 return com.android.systemui.R.layout.global_actions_grid_item_v2;
1157 }
1158 return com.android.systemui.R.layout.global_actions_grid_item;
1159 }
1160
Jason Monk361915c2017-03-21 20:33:59 -04001161 /**
Aran Inkcf038272020-03-31 17:48:37 -04001162 * The adapter used for power menu items shown in the global actions dialog.
Jason Monk361915c2017-03-21 20:33:59 -04001163 */
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001164 public class MyAdapter extends MultiListAdapter {
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001165 private int countItems(boolean separated) {
Jason Monk361915c2017-03-21 20:33:59 -04001166 int count = 0;
Jason Monk361915c2017-03-21 20:33:59 -04001167 for (int i = 0; i < mItems.size(); i++) {
1168 final Action action = mItems.get(i);
1169
Aran Inkcf038272020-03-31 17:48:37 -04001170 if (action.shouldBeSeparated() == separated) {
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001171 count++;
Jason Monk361915c2017-03-21 20:33:59 -04001172 }
Jason Monk361915c2017-03-21 20:33:59 -04001173 }
1174 return count;
1175 }
1176
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001177 @Override
1178 public int countSeparatedItems() {
1179 return countItems(true);
1180 }
1181
1182 @Override
1183 public int countListItems() {
1184 return countItems(false);
1185 }
1186
1187 @Override
1188 public int getCount() {
1189 return countSeparatedItems() + countListItems();
1190 }
1191
Jason Monk361915c2017-03-21 20:33:59 -04001192 @Override
1193 public boolean isEnabled(int position) {
1194 return getItem(position).isEnabled();
1195 }
1196
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001197 @Override
Jason Monk361915c2017-03-21 20:33:59 -04001198 public boolean areAllItemsEnabled() {
1199 return false;
1200 }
1201
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001202 @Override
Jason Monk361915c2017-03-21 20:33:59 -04001203 public Action getItem(int position) {
Jason Monk361915c2017-03-21 20:33:59 -04001204 int filteredPos = 0;
1205 for (int i = 0; i < mItems.size(); i++) {
1206 final Action action = mItems.get(i);
Aran Inkcf038272020-03-31 17:48:37 -04001207 if (!shouldShowAction(action)) {
Jason Monk361915c2017-03-21 20:33:59 -04001208 continue;
1209 }
1210 if (filteredPos == position) {
1211 return action;
1212 }
1213 filteredPos++;
1214 }
1215
1216 throw new IllegalArgumentException("position " + position
1217 + " out of range of showable actions"
1218 + ", filtered count=" + getCount()
1219 + ", keyguardshowing=" + mKeyguardShowing
1220 + ", provisioned=" + mDeviceProvisioned);
1221 }
1222
1223
1224 public long getItemId(int position) {
1225 return position;
1226 }
1227
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001228 @Override
Jason Monk361915c2017-03-21 20:33:59 -04001229 public View getView(int position, View convertView, ViewGroup parent) {
1230 Action action = getItem(position);
Jason Monk16fbd9d2017-04-27 14:28:49 -04001231 View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001232 view.setOnClickListener(v -> onClickItem(position));
Aran Inkb4199d92020-02-07 13:25:21 -05001233 if (action instanceof LongPressAction) {
1234 view.setOnLongClickListener(v -> onLongClickItem(position));
1235 }
Jason Monk16fbd9d2017-04-27 14:28:49 -04001236 return view;
Jason Monk361915c2017-03-21 20:33:59 -04001237 }
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001238
1239 @Override
1240 public boolean onLongClickItem(int position) {
1241 final Action action = mAdapter.getItem(position);
1242 if (action instanceof LongPressAction) {
Aran Inkbaa25862019-06-11 15:48:55 -04001243 if (mDialog != null) {
1244 mDialog.dismiss();
1245 } else {
1246 Log.w(TAG, "Action long-clicked while mDialog is null.");
1247 }
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001248 return ((LongPressAction) action).onLongPress();
1249 }
1250 return false;
1251 }
1252
1253 @Override
1254 public void onClickItem(int position) {
1255 Action item = mAdapter.getItem(position);
1256 if (!(item instanceof SilentModeTriStateAction)) {
Aran Inkbaa25862019-06-11 15:48:55 -04001257 if (mDialog != null) {
1258 mDialog.dismiss();
1259 } else {
1260 Log.w(TAG, "Action clicked while mDialog is null.");
1261 }
1262 item.onPress();
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001263 }
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001264 }
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001265
1266 @Override
1267 public boolean shouldBeSeparated(int position) {
1268 return getItem(position).shouldBeSeparated();
1269 }
Jason Monk361915c2017-03-21 20:33:59 -04001270 }
1271
Aran Inkcf038272020-03-31 17:48:37 -04001272 /**
1273 * The adapter used for items in the overflow menu.
1274 */
1275 public class MyOverflowAdapter extends BaseAdapter {
1276 @Override
1277 public int getCount() {
1278 return mOverflowItems != null ? mOverflowItems.size() : 0;
1279 }
1280
1281 @Override
1282 public Action getItem(int position) {
1283 return mOverflowItems != null ? mOverflowItems.get(position) : null;
1284 }
1285
1286 @Override
1287 public long getItemId(int position) {
1288 return position;
1289 }
1290
1291 @Override
1292 public View getView(int position, View convertView, ViewGroup parent) {
1293 Action action = getItem(position);
1294 if (action == null) {
1295 Log.w(TAG, "No overflow action found at position: " + position);
1296 return null;
1297 }
1298 int viewLayoutResource = com.android.systemui.R.layout.controls_more_item;
1299 View view = convertView != null ? convertView
1300 : LayoutInflater.from(mContext).inflate(viewLayoutResource, parent, false);
1301 TextView textView = (TextView) view;
1302 textView.setOnClickListener(v -> onClickItem(position));
1303 if (action.getMessageResId() != 0) {
1304 textView.setText(action.getMessageResId());
1305 } else {
1306 textView.setText(action.getMessage());
1307 }
1308
1309 if (action instanceof LongPressAction) {
1310 textView.setOnLongClickListener(v -> onLongClickItem(position));
1311 } else {
1312 textView.setOnLongClickListener(null);
1313 }
1314 return textView;
1315 }
1316
1317 private boolean onLongClickItem(int position) {
1318 final Action action = getItem(position);
1319 if (action instanceof LongPressAction) {
1320 if (mDialog != null) {
1321 mDialog.hidePowerOverflowMenu();
1322 mDialog.dismiss();
1323 } else {
1324 Log.w(TAG, "Action long-clicked while mDialog is null.");
1325 }
1326 return ((LongPressAction) action).onLongPress();
1327 }
1328 return false;
1329 }
1330
1331 private void onClickItem(int position) {
1332 Action item = getItem(position);
1333 if (!(item instanceof SilentModeTriStateAction)) {
1334 if (mDialog != null) {
1335 mDialog.hidePowerOverflowMenu();
1336 mDialog.dismiss();
1337 } else {
1338 Log.w(TAG, "Action clicked while mDialog is null.");
1339 }
1340 item.onPress();
1341 }
1342 }
1343 }
1344
Jason Monk361915c2017-03-21 20:33:59 -04001345 // note: the scheme below made more sense when we were planning on having
1346 // 8 different things in the global actions dialog. seems overkill with
1347 // only 3 items now, but may as well keep this flexible approach so it will
1348 // be easy should someone decide at the last minute to include something
1349 // else, such as 'enable wifi', or 'enable bluetooth'
1350
1351 /**
1352 * What each item in the global actions dialog must be able to support.
1353 */
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001354 public interface Action {
Jason Monk361915c2017-03-21 20:33:59 -04001355 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001356 * @return Text that will be announced when dialog is created. null for none.
Jason Monk361915c2017-03-21 20:33:59 -04001357 */
1358 CharSequence getLabelForAccessibility(Context context);
1359
1360 View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
1361
1362 void onPress();
1363
1364 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001365 * @return whether this action should appear in the dialog when the keygaurd is showing.
Jason Monk361915c2017-03-21 20:33:59 -04001366 */
1367 boolean showDuringKeyguard();
1368
1369 /**
Aran Inkcf038272020-03-31 17:48:37 -04001370 * @return whether this action should appear in the dialog before the
1371 * device is provisioned.f
Jason Monk361915c2017-03-21 20:33:59 -04001372 */
1373 boolean showBeforeProvisioning();
1374
1375 boolean isEnabled();
Aaron Heuckrothf708d472019-01-10 16:54:51 -05001376
1377 default boolean shouldBeSeparated() {
1378 return false;
1379 }
Aran Inkcf038272020-03-31 17:48:37 -04001380
1381 /**
1382 * Return the id of the message associated with this action, or 0 if it doesn't have one.
1383 * @return
1384 */
1385 int getMessageResId();
1386
1387 /**
1388 * Return the message associated with this action, or null if it doesn't have one.
1389 * @return
1390 */
1391 CharSequence getMessage();
Jason Monk361915c2017-03-21 20:33:59 -04001392 }
1393
1394 /**
1395 * An action that also supports long press.
1396 */
1397 private interface LongPressAction extends Action {
1398 boolean onLongPress();
1399 }
1400
1401 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001402 * A single press action maintains no state, just responds to a press and takes an action.
Jason Monk361915c2017-03-21 20:33:59 -04001403 */
Matt Pietale0661b62020-01-29 14:35:31 -05001404
1405 private abstract class SinglePressAction implements Action {
Jason Monk361915c2017-03-21 20:33:59 -04001406 private final int mIconResId;
1407 private final Drawable mIcon;
1408 private final int mMessageResId;
1409 private final CharSequence mMessage;
1410
1411 protected SinglePressAction(int iconResId, int messageResId) {
1412 mIconResId = iconResId;
1413 mMessageResId = messageResId;
1414 mMessage = null;
1415 mIcon = null;
1416 }
1417
1418 protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
1419 mIconResId = iconResId;
1420 mMessageResId = 0;
1421 mMessage = message;
1422 mIcon = icon;
1423 }
1424
1425 public boolean isEnabled() {
1426 return true;
1427 }
1428
1429 public String getStatus() {
1430 return null;
1431 }
1432
1433 abstract public void onPress();
1434
1435 public CharSequence getLabelForAccessibility(Context context) {
1436 if (mMessage != null) {
1437 return mMessage;
1438 } else {
1439 return context.getString(mMessageResId);
1440 }
1441 }
1442
Aran Inkcf038272020-03-31 17:48:37 -04001443
1444 public int getMessageResId() {
1445 return mMessageResId;
1446 }
1447
1448 public CharSequence getMessage() {
1449 return mMessage;
1450 }
1451
Jason Monk361915c2017-03-21 20:33:59 -04001452 public View create(
1453 Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
Lucas Dupincb6726f2020-04-07 19:32:38 -07001454 View v = inflater.inflate(getActionLayoutId(), parent, false /* attach */);
Jason Monk361915c2017-03-21 20:33:59 -04001455
Lucas Dupincb6726f2020-04-07 19:32:38 -07001456 ImageView icon = v.findViewById(R.id.icon);
1457 TextView messageView = v.findViewById(R.id.message);
Aaron Heuckroth3f2d8b52019-04-05 13:27:51 -04001458 messageView.setSelected(true); // necessary for marquee to work
Jason Monk361915c2017-03-21 20:33:59 -04001459
Jason Monk361915c2017-03-21 20:33:59 -04001460 if (mIcon != null) {
1461 icon.setImageDrawable(mIcon);
1462 icon.setScaleType(ScaleType.CENTER_CROP);
1463 } else if (mIconResId != 0) {
1464 icon.setImageDrawable(context.getDrawable(mIconResId));
1465 }
1466 if (mMessage != null) {
1467 messageView.setText(mMessage);
1468 } else {
1469 messageView.setText(mMessageResId);
1470 }
1471
1472 return v;
1473 }
1474 }
1475
Lucas Dupincb6726f2020-04-07 19:32:38 -07001476 private enum ToggleState {
1477 Off(false),
1478 TurningOn(true),
1479 TurningOff(true),
1480 On(false);
1481
1482 private final boolean mInTransition;
1483
1484 ToggleState(boolean intermediate) {
1485 mInTransition = intermediate;
1486 }
1487
1488 public boolean inTransition() {
1489 return mInTransition;
1490 }
1491 }
1492
Jason Monk361915c2017-03-21 20:33:59 -04001493 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001494 * A toggle action knows whether it is on or off, and displays an icon and status message
1495 * accordingly.
Jason Monk361915c2017-03-21 20:33:59 -04001496 */
Lucas Dupincb6726f2020-04-07 19:32:38 -07001497 private abstract class ToggleAction implements Action {
Jason Monk361915c2017-03-21 20:33:59 -04001498
Lucas Dupincb6726f2020-04-07 19:32:38 -07001499 protected ToggleState mState = ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001500
1501 // prefs
1502 protected int mEnabledIconResId;
1503 protected int mDisabledIconResid;
1504 protected int mMessageResId;
1505 protected int mEnabledStatusMessageResId;
1506 protected int mDisabledStatusMessageResId;
1507
1508 /**
Jason Monk16fbd9d2017-04-27 14:28:49 -04001509 * @param enabledIconResId The icon for when this action is on.
1510 * @param disabledIconResid The icon for when this action is off.
1511 * @param message The general information message, e.g 'Silent Mode'
1512 * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
Jason Monk361915c2017-03-21 20:33:59 -04001513 * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
1514 */
1515 public ToggleAction(int enabledIconResId,
1516 int disabledIconResid,
1517 int message,
1518 int enabledStatusMessageResId,
1519 int disabledStatusMessageResId) {
1520 mEnabledIconResId = enabledIconResId;
1521 mDisabledIconResid = disabledIconResid;
1522 mMessageResId = message;
1523 mEnabledStatusMessageResId = enabledStatusMessageResId;
1524 mDisabledStatusMessageResId = disabledStatusMessageResId;
1525 }
1526
1527 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001528 * Override to make changes to resource IDs just before creating the View.
Jason Monk361915c2017-03-21 20:33:59 -04001529 */
1530 void willCreate() {
1531
1532 }
1533
1534 @Override
1535 public CharSequence getLabelForAccessibility(Context context) {
1536 return context.getString(mMessageResId);
1537 }
1538
Aran Inkcf038272020-03-31 17:48:37 -04001539 private boolean isOn() {
1540 return mState == ToggleState.On || mState == ToggleState.TurningOn;
1541 }
1542
1543 @Override
1544 public CharSequence getMessage() {
1545 return null;
1546 }
1547 @Override
1548 public int getMessageResId() {
1549 return isOn() ? mEnabledStatusMessageResId : mDisabledStatusMessageResId;
1550 }
1551
1552 private int getIconResId() {
1553 return isOn() ? mEnabledIconResId : mDisabledIconResid;
1554 }
1555
Jason Monk361915c2017-03-21 20:33:59 -04001556 public View create(Context context, View convertView, ViewGroup parent,
1557 LayoutInflater inflater) {
1558 willCreate();
1559
Lucas Dupincb6726f2020-04-07 19:32:38 -07001560 View v = inflater.inflate(getActionLayoutId(), parent, false /* attach */);
Jason Monk361915c2017-03-21 20:33:59 -04001561
1562 ImageView icon = (ImageView) v.findViewById(R.id.icon);
1563 TextView messageView = (TextView) v.findViewById(R.id.message);
Jason Monk361915c2017-03-21 20:33:59 -04001564 final boolean enabled = isEnabled();
1565
1566 if (messageView != null) {
Aran Inkcf038272020-03-31 17:48:37 -04001567 messageView.setText(getMessageResId());
Jason Monk361915c2017-03-21 20:33:59 -04001568 messageView.setEnabled(enabled);
Aaron Heuckroth3f2d8b52019-04-05 13:27:51 -04001569 messageView.setSelected(true); // necessary for marquee to work
Jason Monk361915c2017-03-21 20:33:59 -04001570 }
1571
Jason Monk361915c2017-03-21 20:33:59 -04001572 if (icon != null) {
Aran Inkcf038272020-03-31 17:48:37 -04001573 icon.setImageDrawable(context.getDrawable(getIconResId()));
Jason Monk361915c2017-03-21 20:33:59 -04001574 icon.setEnabled(enabled);
1575 }
1576
Jason Monk361915c2017-03-21 20:33:59 -04001577 v.setEnabled(enabled);
1578
1579 return v;
1580 }
1581
1582 public final void onPress() {
1583 if (mState.inTransition()) {
1584 Log.w(TAG, "shouldn't be able to toggle when in transition");
1585 return;
1586 }
1587
Lucas Dupincb6726f2020-04-07 19:32:38 -07001588 final boolean nowOn = !(mState == ToggleState.On);
Jason Monk361915c2017-03-21 20:33:59 -04001589 onToggle(nowOn);
1590 changeStateFromPress(nowOn);
1591 }
1592
1593 public boolean isEnabled() {
1594 return !mState.inTransition();
1595 }
1596
1597 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001598 * Implementations may override this if their state can be in on of the intermediate states
1599 * until some notification is received (e.g airplane mode is 'turning off' until we know the
1600 * wireless connections are back online
Jason Monk16fbd9d2017-04-27 14:28:49 -04001601 *
Jason Monk361915c2017-03-21 20:33:59 -04001602 * @param buttonOn Whether the button was turned on or off
1603 */
1604 protected void changeStateFromPress(boolean buttonOn) {
Lucas Dupincb6726f2020-04-07 19:32:38 -07001605 mState = buttonOn ? ToggleState.On : ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001606 }
1607
1608 abstract void onToggle(boolean on);
1609
Lucas Dupincb6726f2020-04-07 19:32:38 -07001610 public void updateState(ToggleState state) {
Jason Monk361915c2017-03-21 20:33:59 -04001611 mState = state;
1612 }
1613 }
1614
Aran Ink780d4502020-02-14 10:39:58 -05001615 private class AirplaneModeAction extends ToggleAction {
1616 AirplaneModeAction() {
1617 super(
Sean Pont9d4fb032020-03-04 18:54:32 -08001618 R.drawable.ic_lock_airplane_mode,
1619 R.drawable.ic_lock_airplane_mode_off,
1620 R.string.global_actions_toggle_airplane_mode,
1621 R.string.global_actions_airplane_mode_on_status,
1622 R.string.global_actions_airplane_mode_off_status);
Aran Ink780d4502020-02-14 10:39:58 -05001623 }
Sean Pont9d4fb032020-03-04 18:54:32 -08001624
Aran Ink780d4502020-02-14 10:39:58 -05001625 void onToggle(boolean on) {
1626 if (mHasTelephony && TelephonyProperties.in_ecm_mode().orElse(false)) {
1627 mIsWaitingForEcmExit = true;
1628 // Launch ECM exit dialog
1629 Intent ecmDialogIntent =
1630 new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
1631 ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1632 mContext.startActivity(ecmDialogIntent);
1633 } else {
1634 changeAirplaneModeSystemSetting(on);
1635 }
1636 }
1637
1638 @Override
1639 protected void changeStateFromPress(boolean buttonOn) {
1640 if (!mHasTelephony) return;
1641
1642 // In ECM mode airplane state cannot be changed
1643 if (!TelephonyProperties.in_ecm_mode().orElse(false)) {
Lucas Dupincb6726f2020-04-07 19:32:38 -07001644 mState = buttonOn ? ToggleState.TurningOn : ToggleState.TurningOff;
Aran Ink780d4502020-02-14 10:39:58 -05001645 mAirplaneState = mState;
1646 }
1647 }
1648
1649 public boolean showDuringKeyguard() {
1650 return true;
1651 }
1652
1653 public boolean showBeforeProvisioning() {
1654 return false;
1655 }
1656 }
1657
Jason Monk361915c2017-03-21 20:33:59 -04001658 private class SilentModeToggleAction extends ToggleAction {
1659 public SilentModeToggleAction() {
1660 super(R.drawable.ic_audio_vol_mute,
1661 R.drawable.ic_audio_vol,
1662 R.string.global_action_toggle_silent_mode,
1663 R.string.global_action_silent_mode_on_status,
1664 R.string.global_action_silent_mode_off_status);
1665 }
1666
1667 void onToggle(boolean on) {
1668 if (on) {
1669 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
1670 } else {
1671 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
1672 }
1673 }
1674
1675 public boolean showDuringKeyguard() {
1676 return true;
1677 }
1678
1679 public boolean showBeforeProvisioning() {
1680 return false;
1681 }
1682 }
1683
1684 private static class SilentModeTriStateAction implements Action, View.OnClickListener {
1685
Jason Monk16fbd9d2017-04-27 14:28:49 -04001686 private final int[] ITEM_IDS = {R.id.option1, R.id.option2, R.id.option3};
Jason Monk361915c2017-03-21 20:33:59 -04001687
1688 private final AudioManager mAudioManager;
1689 private final Handler mHandler;
Jason Monk361915c2017-03-21 20:33:59 -04001690
Lucas Dupin40ec6b782018-06-05 19:07:16 -07001691 SilentModeTriStateAction(AudioManager audioManager, Handler handler) {
Jason Monk361915c2017-03-21 20:33:59 -04001692 mAudioManager = audioManager;
1693 mHandler = handler;
Jason Monk361915c2017-03-21 20:33:59 -04001694 }
1695
1696 private int ringerModeToIndex(int ringerMode) {
1697 // They just happen to coincide
1698 return ringerMode;
1699 }
1700
1701 private int indexToRingerMode(int index) {
1702 // They just happen to coincide
1703 return index;
1704 }
1705
1706 @Override
1707 public CharSequence getLabelForAccessibility(Context context) {
1708 return null;
1709 }
1710
Aran Inkcf038272020-03-31 17:48:37 -04001711 @Override
1712 public int getMessageResId() {
1713 return 0;
1714 }
1715
1716 @Override
1717 public CharSequence getMessage() {
1718 return null;
1719 }
1720
Jason Monk361915c2017-03-21 20:33:59 -04001721 public View create(Context context, View convertView, ViewGroup parent,
1722 LayoutInflater inflater) {
1723 View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
1724
1725 int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
1726 for (int i = 0; i < 3; i++) {
1727 View itemView = v.findViewById(ITEM_IDS[i]);
1728 itemView.setSelected(selectedIndex == i);
1729 // Set up click handler
1730 itemView.setTag(i);
1731 itemView.setOnClickListener(this);
1732 }
1733 return v;
1734 }
1735
1736 public void onPress() {
1737 }
1738
1739 public boolean showDuringKeyguard() {
1740 return true;
1741 }
1742
1743 public boolean showBeforeProvisioning() {
1744 return false;
1745 }
1746
1747 public boolean isEnabled() {
1748 return true;
1749 }
1750
1751 void willCreate() {
1752 }
1753
1754 public void onClick(View v) {
1755 if (!(v.getTag() instanceof Integer)) return;
1756
1757 int index = (Integer) v.getTag();
1758 mAudioManager.setRingerMode(indexToRingerMode(index));
1759 mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
1760 }
1761 }
1762
1763 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1764 public void onReceive(Context context, Intent intent) {
1765 String action = intent.getAction();
1766 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
1767 || Intent.ACTION_SCREEN_OFF.equals(action)) {
1768 String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
1769 if (!SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
Lucas Dupin1d4a5792018-04-02 15:14:59 -07001770 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISMISS, reason));
Jason Monk361915c2017-03-21 20:33:59 -04001771 }
Jayachandran C142eae02019-12-13 19:29:20 -08001772 } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
Jason Monk361915c2017-03-21 20:33:59 -04001773 // Airplane mode can be changed after ECM exits if airplane toggle button
1774 // is pressed during ECM mode
Daniel Bright4bcbfce2020-01-09 21:58:16 -08001775 if (!(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false))
1776 && mIsWaitingForEcmExit) {
Jason Monk361915c2017-03-21 20:33:59 -04001777 mIsWaitingForEcmExit = false;
1778 changeAirplaneModeSystemSetting(true);
1779 }
1780 }
1781 }
1782 };
1783
1784 PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
1785 @Override
1786 public void onServiceStateChanged(ServiceState serviceState) {
1787 if (!mHasTelephony) return;
1788 final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
Lucas Dupincb6726f2020-04-07 19:32:38 -07001789 mAirplaneState = inAirplaneMode ? ToggleState.On : ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001790 mAirplaneModeOn.updateState(mAirplaneState);
1791 mAdapter.notifyDataSetChanged();
1792 }
1793 };
1794
Jason Monk361915c2017-03-21 20:33:59 -04001795 private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) {
1796 @Override
1797 public void onChange(boolean selfChange) {
1798 onAirplaneModeChanged();
1799 }
1800 };
1801
1802 private static final int MESSAGE_DISMISS = 0;
1803 private static final int MESSAGE_REFRESH = 1;
1804 private static final int MESSAGE_SHOW = 2;
1805 private static final int DIALOG_DISMISS_DELAY = 300; // ms
Lucas Dupin7387a862020-04-13 10:15:29 -07001806 private static final int DIALOG_PRESS_DELAY = 850; // ms
Chris Wrenaf4ce8462020-04-06 17:36:10 -04001807
1808 @VisibleForTesting void setZeroDialogPressDelayForTesting() {
1809 mDialogPressDelay = 0; // ms
1810 }
Jason Monk361915c2017-03-21 20:33:59 -04001811
1812 private Handler mHandler = new Handler() {
1813 public void handleMessage(Message msg) {
1814 switch (msg.what) {
Jason Monk16fbd9d2017-04-27 14:28:49 -04001815 case MESSAGE_DISMISS:
1816 if (mDialog != null) {
Lucas Dupin1d4a5792018-04-02 15:14:59 -07001817 if (SYSTEM_DIALOG_REASON_DREAM.equals(msg.obj)) {
1818 mDialog.dismissImmediately();
1819 } else {
1820 mDialog.dismiss();
1821 }
Jason Monk16fbd9d2017-04-27 14:28:49 -04001822 mDialog = null;
1823 }
1824 break;
1825 case MESSAGE_REFRESH:
1826 refreshSilentMode();
1827 mAdapter.notifyDataSetChanged();
1828 break;
1829 case MESSAGE_SHOW:
1830 handleShow();
1831 break;
Jason Monk361915c2017-03-21 20:33:59 -04001832 }
1833 }
1834 };
1835
1836 private void onAirplaneModeChanged() {
1837 // Let the service state callbacks handle the state.
1838 if (mHasTelephony) return;
1839
1840 boolean airplaneModeOn = Settings.Global.getInt(
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001841 mContentResolver,
Jason Monk361915c2017-03-21 20:33:59 -04001842 Settings.Global.AIRPLANE_MODE_ON,
1843 0) == 1;
Lucas Dupincb6726f2020-04-07 19:32:38 -07001844 mAirplaneState = airplaneModeOn ? ToggleState.On : ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001845 mAirplaneModeOn.updateState(mAirplaneState);
1846 }
1847
1848 /**
1849 * Change the airplane mode system setting
1850 */
1851 private void changeAirplaneModeSystemSetting(boolean on) {
1852 Settings.Global.putInt(
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001853 mContentResolver,
Jason Monk361915c2017-03-21 20:33:59 -04001854 Settings.Global.AIRPLANE_MODE_ON,
1855 on ? 1 : 0);
1856 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
1857 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1858 intent.putExtra("state", on);
1859 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1860 if (!mHasTelephony) {
Lucas Dupincb6726f2020-04-07 19:32:38 -07001861 mAirplaneState = on ? ToggleState.On : ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001862 }
1863 }
1864
Fabian Kozynskib6a20372020-04-01 09:36:43 -04001865 @NonNull
1866 @Override
1867 public Lifecycle getLifecycle() {
1868 return mLifecycle;
1869 }
1870
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001871 private static final class ActionsDialog extends Dialog implements DialogInterface,
1872 ColorExtractor.OnColorsChangedListener {
Jason Monk361915c2017-03-21 20:33:59 -04001873
Jason Monk16fbd9d2017-04-27 14:28:49 -04001874 private final Context mContext;
1875 private final MyAdapter mAdapter;
Aran Inkcf038272020-03-31 17:48:37 -04001876 private final MyOverflowAdapter mOverflowAdapter;
Steve Elliott53f12ae2019-05-13 17:14:15 -04001877 private final IStatusBarService mStatusBarService;
1878 private final IBinder mToken = new Binder();
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05001879 private MultiListLayout mGlobalActionsLayout;
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04001880 private Drawable mBackgroundDrawable;
Lucas Dupin2bd3af62019-03-25 17:44:28 -07001881 private final SysuiColorExtractor mColorExtractor;
Steve Elliott9b87a442019-03-05 10:24:16 -05001882 private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001883 private boolean mKeyguardShowing;
Beverly526d2d62018-08-15 12:55:33 -04001884 private boolean mShowing;
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04001885 private float mScrimAlpha;
Steve Elliott48f75db2019-05-03 15:03:38 -04001886 private ResetOrientationData mResetOrientationData;
Steve Elliottff2c0d92019-07-30 15:09:54 -04001887 private boolean mHadTopUi;
wilsonshihe8321942019-10-18 18:39:46 +08001888 private final NotificationShadeWindowController mNotificationShadeWindowController;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -08001889 private final NotificationShadeDepthController mDepthController;
Lucas Dupin99f5fba2020-03-12 12:59:18 -07001890 private final BlurUtils mBlurUtils;
Aran Inkcf038272020-03-31 17:48:37 -04001891 private ListPopupWindow mOverflowPopup;
Matt Pietal22231792020-01-23 09:51:09 -05001892
1893 private ControlsUiController mControlsUiController;
1894 private ViewGroup mControlsView;
Jason Monk16fbd9d2017-04-27 14:28:49 -04001895
Aran Inkcf038272020-03-31 17:48:37 -04001896 ActionsDialog(Context context, MyAdapter adapter, MyOverflowAdapter overflowAdapter,
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -08001897 GlobalActionsPanelPlugin.PanelViewController plugin,
1898 NotificationShadeDepthController depthController,
Lucas Dupin991415e2019-11-25 17:48:58 -08001899 SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
1900 NotificationShadeWindowController notificationShadeWindowController,
Lucas Dupin99f5fba2020-03-12 12:59:18 -07001901 ControlsUiController controlsUiController, BlurUtils blurUtils) {
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001902 super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
Lucas Dupin448786c2017-07-24 17:44:25 -07001903 mContext = context;
Jason Monk16fbd9d2017-04-27 14:28:49 -04001904 mAdapter = adapter;
Aran Inkcf038272020-03-31 17:48:37 -04001905 mOverflowAdapter = overflowAdapter;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -08001906 mDepthController = depthController;
Lucas Dupin991415e2019-11-25 17:48:58 -08001907 mColorExtractor = sysuiColorExtractor;
1908 mStatusBarService = statusBarService;
1909 mNotificationShadeWindowController = notificationShadeWindowController;
Matt Pietal22231792020-01-23 09:51:09 -05001910 mControlsUiController = controlsUiController;
Lucas Dupin99f5fba2020-03-12 12:59:18 -07001911 mBlurUtils = blurUtils;
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001912
1913 // Window initialization
1914 Window window = getWindow();
1915 window.requestFeature(Window.FEATURE_NO_TITLE);
Adrian Roosedfab3b2018-03-08 18:39:20 +01001916 // Inflate the decor view, so the attributes below are not overwritten by the theme.
1917 window.getDecorView();
1918 window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
1919 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
1920 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1921 window.setLayout(MATCH_PARENT, MATCH_PARENT);
1922 window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
Alison Cichowlas4f19f4a2017-07-25 10:56:16 -04001923 window.addFlags(
1924 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
Sean Pont9d4fb032020-03-04 18:54:32 -08001925 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
1926 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
1927 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
1928 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
1929 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001930 window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
Tiger Huang52724442020-01-20 21:38:42 +08001931 window.getAttributes().setFitInsetsTypes(0 /* types */);
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05001932 setTitle(R.string.global_actions);
Steve Elliott9b87a442019-03-05 10:24:16 -05001933
1934 mPanelController = plugin;
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04001935 initializeLayout();
Steve Elliott9b87a442019-03-05 10:24:16 -05001936 }
1937
Aaron Heuckrothc7926612019-04-02 14:21:57 -04001938 private boolean shouldUsePanel() {
Aran Ink3f594552019-05-13 14:29:35 -04001939 return mPanelController != null && mPanelController.getPanelContent() != null;
Aaron Heuckrothc7926612019-04-02 14:21:57 -04001940 }
1941
1942 private void initializePanel() {
Steve Elliott48f75db2019-05-03 15:03:38 -04001943 int rotation = RotationUtils.getRotation(mContext);
1944 boolean rotationLocked = RotationPolicy.isRotationLocked(mContext);
1945 if (rotation != RotationUtils.ROTATION_NONE) {
1946 if (rotationLocked) {
1947 if (mResetOrientationData == null) {
1948 mResetOrientationData = new ResetOrientationData();
1949 mResetOrientationData.locked = true;
1950 mResetOrientationData.rotation = rotation;
1951 }
1952
1953 // Unlock rotation, so user can choose to rotate to portrait to see the panel.
Steve Elliotte05817f2019-05-17 14:39:53 -04001954 // This call is posted so that the rotation does not change until post-layout,
1955 // otherwise onConfigurationChanged() may not get invoked.
1956 mGlobalActionsLayout.post(() ->
1957 RotationPolicy.setRotationLockAtAngle(
1958 mContext, false, RotationUtils.ROTATION_NONE));
Steve Elliott48f75db2019-05-03 15:03:38 -04001959 }
1960 } else {
1961 if (!rotationLocked) {
1962 if (mResetOrientationData == null) {
1963 mResetOrientationData = new ResetOrientationData();
1964 mResetOrientationData.locked = false;
1965 }
1966
1967 // Lock to portrait, so the user doesn't accidentally hide the panel.
Steve Elliotte05817f2019-05-17 14:39:53 -04001968 // This call is posted so that the rotation does not change until post-layout,
1969 // otherwise onConfigurationChanged() may not get invoked.
1970 mGlobalActionsLayout.post(() ->
1971 RotationPolicy.setRotationLockAtAngle(
1972 mContext, true, RotationUtils.ROTATION_NONE));
Steve Elliott48f75db2019-05-03 15:03:38 -04001973 }
1974
Steve Elliott53f12ae2019-05-13 17:14:15 -04001975 // Disable rotation suggestions, if enabled
1976 setRotationSuggestionsEnabled(false);
1977
Steve Elliott300b48f2019-05-29 14:13:50 -04001978 FrameLayout panelContainer =
1979 findViewById(com.android.systemui.R.id.global_actions_panel_container);
Steve Elliott48f75db2019-05-03 15:03:38 -04001980 FrameLayout.LayoutParams panelParams =
1981 new FrameLayout.LayoutParams(
1982 FrameLayout.LayoutParams.MATCH_PARENT,
Steve Elliott300b48f2019-05-29 14:13:50 -04001983 FrameLayout.LayoutParams.MATCH_PARENT);
Steve Elliott48f75db2019-05-03 15:03:38 -04001984 panelContainer.addView(mPanelController.getPanelContent(), panelParams);
Steve Elliott48f75db2019-05-03 15:03:38 -04001985 }
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05001986 }
1987
Aran Inkcf038272020-03-31 17:48:37 -04001988 private ListPopupWindow createPowerOverflowPopup() {
1989 ListPopupWindow popup = new ListPopupWindow(new ContextThemeWrapper(
1990 mContext, com.android.systemui.R.style.Control_ListPopupWindow));
1991 popup.setWindowLayoutType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
1992 View overflowButton =
1993 findViewById(com.android.systemui.R.id.global_actions_overflow_button);
1994 popup.setAnchorView(overflowButton);
1995 int parentWidth = mGlobalActionsLayout.getWidth();
1996 // arbitrarily set the menu width to half of parent
1997 // TODO: Logic for menu sizing based on contents.
1998 int halfParentWidth = Math.round(parentWidth * 0.5f);
1999 popup.setContentWidth(halfParentWidth);
2000 popup.setAdapter(mOverflowAdapter);
2001 popup.setModal(true);
2002 return popup;
2003 }
2004
2005 private void showPowerOverflowMenu() {
2006 mOverflowPopup.show();
2007
2008 // Width is fixed to slightly more than half of the GlobalActionsLayout container.
2009 // TODO: Resize the width of this dialog based on the sizes of the items in it.
2010 int width = Math.round(mGlobalActionsLayout.getWidth() * 0.6f);
2011
2012 ListView listView = mOverflowPopup.getListView();
2013 listView.setDividerHeight(mContext.getResources()
2014 .getDimensionPixelSize(com.android.systemui.R.dimen.control_list_divider));
2015 listView.setDivider(mContext.getResources().getDrawable(
2016 com.android.systemui.R.drawable.controls_list_divider));
2017 mOverflowPopup.setWidth(width);
2018 mOverflowPopup.setHorizontalOffset(-width + mOverflowPopup.getAnchorView().getWidth());
2019 mOverflowPopup.setVerticalOffset(mOverflowPopup.getAnchorView().getHeight());
2020 mOverflowPopup.show();
2021 }
2022
2023 private void hidePowerOverflowMenu() {
2024 mOverflowPopup.dismiss();
2025 }
2026
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002027 private void initializeLayout() {
2028 setContentView(getGlobalActionsLayoutId(mContext));
Steve Elliott300b48f2019-05-29 14:13:50 -04002029 fixNavBarClipping();
Matt Pietal22231792020-01-23 09:51:09 -05002030 mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls);
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04002031 mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
Aaron Heuckrothf708d472019-01-10 16:54:51 -05002032 mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
Aaron Heuckrothf708d472019-01-10 16:54:51 -05002033 mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
Phil Weaver9054e092018-04-27 16:28:50 -07002034 @Override
2035 public boolean dispatchPopulateAccessibilityEvent(
2036 View host, AccessibilityEvent event) {
2037 // Populate the title here, just as Activity does
2038 event.getText().add(mContext.getString(R.string.global_actions));
2039 return true;
2040 }
2041 });
Aaron Heuckroth4ea2fdb2019-02-14 16:28:35 -05002042 mGlobalActionsLayout.setRotationListener(this::onRotate);
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05002043 mGlobalActionsLayout.setAdapter(mAdapter);
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04002044
Aran Inkcf038272020-03-31 17:48:37 -04002045 mOverflowPopup = createPowerOverflowPopup();
2046
2047 View overflowButton = findViewById(
2048 com.android.systemui.R.id.global_actions_overflow_button);
2049 if (overflowButton != null) {
2050 if (mOverflowAdapter.getCount() > 0) {
2051 overflowButton.setOnClickListener((view) -> showPowerOverflowMenu());
2052 } else {
2053 overflowButton.setVisibility(View.GONE);
2054 }
2055 }
2056
Aran Ink06090262020-03-03 13:23:17 -05002057 View globalActionsParent = (View) mGlobalActionsLayout.getParent();
2058 globalActionsParent.setOnClickListener(v -> dismiss());
2059
2060 // add fall-through dismiss handling to root view
2061 View rootView = findViewById(com.android.systemui.R.id.global_actions_grid_root);
2062 if (rootView != null) {
2063 rootView.setOnClickListener(v -> dismiss());
2064 }
2065
Steve Elliott86ef6282019-05-08 14:45:04 -04002066 if (shouldUsePanel()) {
Steve Elliottc59eb342019-04-23 16:59:06 -04002067 initializePanel();
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04002068 }
Steve Elliott86ef6282019-05-08 14:45:04 -04002069 if (mBackgroundDrawable == null) {
2070 mBackgroundDrawable = new ScrimDrawable();
Lucas Dupin3a8531e2020-04-06 17:18:09 -07002071 if (mControlsUiController != null) {
2072 mScrimAlpha = 1.0f;
2073 } else {
2074 mScrimAlpha = mBlurUtils.supportsBlursOnWindows()
2075 ? ScrimController.BLUR_SCRIM_ALPHA : ScrimController.BUSY_SCRIM_ALPHA;
2076 }
Steve Elliott86ef6282019-05-08 14:45:04 -04002077 }
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04002078 getWindow().setBackgroundDrawable(mBackgroundDrawable);
Steve Elliott9b87a442019-03-05 10:24:16 -05002079 }
2080
Steve Elliott300b48f2019-05-29 14:13:50 -04002081 private void fixNavBarClipping() {
2082 ViewGroup content = findViewById(android.R.id.content);
2083 content.setClipChildren(false);
2084 content.setClipToPadding(false);
2085 ViewGroup contentParent = (ViewGroup) content.getParent();
2086 contentParent.setClipChildren(false);
2087 contentParent.setClipToPadding(false);
2088 }
2089
Aaron Heuckroth166392f2019-01-17 16:50:59 -05002090 private int getGlobalActionsLayoutId(Context context) {
Matt Pietal22231792020-01-23 09:51:09 -05002091 if (mControlsUiController != null) {
Matt Pietalfd3b6cb2020-01-08 09:43:54 -05002092 return com.android.systemui.R.layout.global_actions_grid_v2;
2093 }
2094
Steve Elliottdc165632019-05-23 14:26:31 -04002095 int rotation = RotationUtils.getRotation(context);
2096 boolean useGridLayout = isForceGridEnabled(context)
2097 || (shouldUsePanel() && rotation == RotationUtils.ROTATION_NONE);
2098 if (rotation == RotationUtils.ROTATION_SEASCAPE) {
Aaron Heuckrothe2d92ac2019-05-01 10:44:59 -04002099 if (useGridLayout) {
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002100 return com.android.systemui.R.layout.global_actions_grid_seascape;
Aaron Heuckrothe2d92ac2019-05-01 10:44:59 -04002101 } else {
2102 return com.android.systemui.R.layout.global_actions_column_seascape;
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002103 }
Aaron Heuckrothe2d92ac2019-05-01 10:44:59 -04002104 } else {
2105 if (useGridLayout) {
2106 return com.android.systemui.R.layout.global_actions_grid;
2107 } else {
2108 return com.android.systemui.R.layout.global_actions_column;
2109 }
Aaron Heuckroth166392f2019-01-17 16:50:59 -05002110 }
Aaron Heuckroth166392f2019-01-17 16:50:59 -05002111 }
2112
Jason Monk361915c2017-03-21 20:33:59 -04002113 @Override
2114 protected void onStart() {
2115 super.setCanceledOnTouchOutside(true);
2116 super.onStart();
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05002117 mGlobalActionsLayout.updateList();
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002118
Lucas Dupin2bd3af62019-03-25 17:44:28 -07002119 if (mBackgroundDrawable instanceof ScrimDrawable) {
Steve Elliott9b87a442019-03-05 10:24:16 -05002120 mColorExtractor.addOnColorsChangedListener(this);
Lucas Dupin2bd3af62019-03-25 17:44:28 -07002121 GradientColors colors = mColorExtractor.getNeutralColors();
Steve Elliott9b87a442019-03-05 10:24:16 -05002122 updateColors(colors, false /* animate */);
2123 }
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002124 }
2125
2126 /**
2127 * Updates background and system bars according to current GradientColors.
Sean Pont9d4fb032020-03-04 18:54:32 -08002128 *
2129 * @param colors Colors and hints to use.
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002130 * @param animate Interpolates gradient if true, just sets otherwise.
2131 */
2132 private void updateColors(GradientColors colors, boolean animate) {
Lucas Dupin2bd3af62019-03-25 17:44:28 -07002133 if (!(mBackgroundDrawable instanceof ScrimDrawable)) {
Steve Elliott9b87a442019-03-05 10:24:16 -05002134 return;
2135 }
Lucas Dupin3a8531e2020-04-06 17:18:09 -07002136 boolean hasControls = mControlsUiController != null;
2137 ((ScrimDrawable) mBackgroundDrawable).setColor(
2138 !hasControls && colors.supportsDarkText() ? Color.WHITE : Color.BLACK, animate);
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002139 View decorView = getWindow().getDecorView();
2140 if (colors.supportsDarkText()) {
2141 decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
Steve Elliott9b87a442019-03-05 10:24:16 -05002142 View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002143 } else {
2144 decorView.setSystemUiVisibility(0);
2145 }
Jason Monk361915c2017-03-21 20:33:59 -04002146 }
2147
2148 @Override
Jason Monk16fbd9d2017-04-27 14:28:49 -04002149 protected void onStop() {
2150 super.onStop();
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002151 mColorExtractor.removeOnColorsChangedListener(this);
Jason Monk16fbd9d2017-04-27 14:28:49 -04002152 }
2153
2154 @Override
2155 public void show() {
2156 super.show();
Beverly526d2d62018-08-15 12:55:33 -04002157 mShowing = true;
wilsonshihe8321942019-10-18 18:39:46 +08002158 mHadTopUi = mNotificationShadeWindowController.getForceHasTopUi();
2159 mNotificationShadeWindowController.setForceHasTopUi(true);
Steve Elliott9b87a442019-03-05 10:24:16 -05002160 mBackgroundDrawable.setAlpha(0);
Aaron Heuckrothc7926612019-04-02 14:21:57 -04002161 mGlobalActionsLayout.setTranslationX(mGlobalActionsLayout.getAnimationOffsetX());
2162 mGlobalActionsLayout.setTranslationY(mGlobalActionsLayout.getAnimationOffsetY());
Aaron Heuckrothf708d472019-01-10 16:54:51 -05002163 mGlobalActionsLayout.setAlpha(0);
2164 mGlobalActionsLayout.animate()
Jason Monk16fbd9d2017-04-27 14:28:49 -04002165 .alpha(1)
2166 .translationX(0)
Aaron Heuckrothc7926612019-04-02 14:21:57 -04002167 .translationY(0)
Lucas Dupinb079daa2020-03-24 15:56:23 -07002168 .setDuration(450)
Lucas Dupinde9db422017-07-19 17:15:41 -07002169 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002170 .setUpdateListener(animation -> {
Lucas Dupin991415e2019-11-25 17:48:58 -08002171 float animatedValue = animation.getAnimatedFraction();
2172 int alpha = (int) (animatedValue * mScrimAlpha * 255);
Steve Elliott9b87a442019-03-05 10:24:16 -05002173 mBackgroundDrawable.setAlpha(alpha);
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -08002174 mDepthController.updateGlobalDialogVisibility(animatedValue,
2175 mGlobalActionsLayout);
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002176 })
Jason Monk16fbd9d2017-04-27 14:28:49 -04002177 .start();
Lucas Dupin26571e92020-04-08 14:55:10 -07002178 ViewGroup root = (ViewGroup) mGlobalActionsLayout.getRootView();
2179 root.setOnApplyWindowInsetsListener((v, windowInsets) -> {
2180 if (mControlsUiController != null) {
Lucas Dupin2b353e62020-04-14 18:23:01 -07002181 root.setPadding(windowInsets.getStableInsetLeft(),
2182 windowInsets.getStableInsetTop(),
2183 windowInsets.getStableInsetRight(),
2184 windowInsets.getStableInsetBottom());
Lucas Dupin26571e92020-04-08 14:55:10 -07002185 }
2186 return WindowInsets.CONSUMED;
2187 });
Matt Pietal22231792020-01-23 09:51:09 -05002188 if (mControlsUiController != null) {
2189 mControlsUiController.show(mControlsView);
2190 }
Jason Monk16fbd9d2017-04-27 14:28:49 -04002191 }
2192
2193 @Override
2194 public void dismiss() {
Beverly526d2d62018-08-15 12:55:33 -04002195 if (!mShowing) {
2196 return;
2197 }
2198 mShowing = false;
Matt Pietal22231792020-01-23 09:51:09 -05002199 if (mControlsUiController != null) mControlsUiController.hide();
Aaron Heuckrothf708d472019-01-10 16:54:51 -05002200 mGlobalActionsLayout.setTranslationX(0);
Aaron Heuckrothc7926612019-04-02 14:21:57 -04002201 mGlobalActionsLayout.setTranslationY(0);
Aaron Heuckrothf708d472019-01-10 16:54:51 -05002202 mGlobalActionsLayout.setAlpha(1);
2203 mGlobalActionsLayout.animate()
Jason Monk16fbd9d2017-04-27 14:28:49 -04002204 .alpha(0)
Aaron Heuckrothc7926612019-04-02 14:21:57 -04002205 .translationX(mGlobalActionsLayout.getAnimationOffsetX())
2206 .translationY(mGlobalActionsLayout.getAnimationOffsetY())
Lucas Dupinb079daa2020-03-24 15:56:23 -07002207 .setDuration(550)
Steve Elliottff2c0d92019-07-30 15:09:54 -04002208 .withEndAction(this::completeDismiss)
Jason Monk16fbd9d2017-04-27 14:28:49 -04002209 .setInterpolator(new LogAccelerateInterpolator())
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002210 .setUpdateListener(animation -> {
Lucas Dupin991415e2019-11-25 17:48:58 -08002211 float animatedValue = 1f - animation.getAnimatedFraction();
2212 int alpha = (int) (animatedValue * mScrimAlpha * 255);
Steve Elliott9b87a442019-03-05 10:24:16 -05002213 mBackgroundDrawable.setAlpha(alpha);
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -08002214 mDepthController.updateGlobalDialogVisibility(animatedValue,
2215 mGlobalActionsLayout);
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002216 })
Jason Monk16fbd9d2017-04-27 14:28:49 -04002217 .start();
Steve Elliott48f75db2019-05-03 15:03:38 -04002218 dismissPanel();
2219 resetOrientation();
Jason Monk16fbd9d2017-04-27 14:28:49 -04002220 }
2221
Lucas Dupin1d4a5792018-04-02 15:14:59 -07002222 void dismissImmediately() {
Beverly526d2d62018-08-15 12:55:33 -04002223 mShowing = false;
Matt Pietal019feaa2020-01-31 14:51:37 -05002224 if (mControlsUiController != null) mControlsUiController.hide();
Steve Elliott48f75db2019-05-03 15:03:38 -04002225 dismissPanel();
2226 resetOrientation();
Steve Elliottff2c0d92019-07-30 15:09:54 -04002227 completeDismiss();
2228 }
2229
2230 private void completeDismiss() {
wilsonshihe8321942019-10-18 18:39:46 +08002231 mNotificationShadeWindowController.setForceHasTopUi(mHadTopUi);
Lucas Dupin77198562020-03-31 14:16:16 -07002232 mDepthController.updateGlobalDialogVisibility(0, null /* view */);
Steve Elliottff2c0d92019-07-30 15:09:54 -04002233 super.dismiss();
Steve Elliott48f75db2019-05-03 15:03:38 -04002234 }
2235
2236 private void dismissPanel() {
Steve Elliott2d206d32019-03-14 16:30:33 -04002237 if (mPanelController != null) {
2238 mPanelController.onDismissed();
2239 }
Lucas Dupin1d4a5792018-04-02 15:14:59 -07002240 }
2241
Steve Elliott53f12ae2019-05-13 17:14:15 -04002242 private void setRotationSuggestionsEnabled(boolean enabled) {
2243 try {
2244 final int userId = Binder.getCallingUserHandle().getIdentifier();
2245 final int what = enabled
2246 ? StatusBarManager.DISABLE2_NONE
2247 : StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS;
2248 mStatusBarService.disable2ForUser(what, mToken, mContext.getPackageName(), userId);
2249 } catch (RemoteException ex) {
2250 throw ex.rethrowFromSystemServer();
2251 }
2252 }
2253
Steve Elliott48f75db2019-05-03 15:03:38 -04002254 private void resetOrientation() {
2255 if (mResetOrientationData != null) {
2256 RotationPolicy.setRotationLockAtAngle(mContext, mResetOrientationData.locked,
2257 mResetOrientationData.rotation);
2258 }
Steve Elliott53f12ae2019-05-13 17:14:15 -04002259 setRotationSuggestionsEnabled(true);
Steve Elliott48f75db2019-05-03 15:03:38 -04002260 }
2261
Jason Monk361915c2017-03-21 20:33:59 -04002262 @Override
Lucas Dupin7aaa3532017-05-28 08:51:07 -07002263 public void onColorsChanged(ColorExtractor extractor, int which) {
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002264 if (mKeyguardShowing) {
2265 if ((WallpaperManager.FLAG_LOCK & which) != 0) {
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002266 updateColors(extractor.getColors(WallpaperManager.FLAG_LOCK),
2267 true /* animate */);
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002268 }
2269 } else {
2270 if ((WallpaperManager.FLAG_SYSTEM & which) != 0) {
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002271 updateColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM),
2272 true /* animate */);
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002273 }
2274 }
2275 }
2276
2277 public void setKeyguardShowing(boolean keyguardShowing) {
2278 mKeyguardShowing = keyguardShowing;
2279 }
Aaron Heuckroth4ea2fdb2019-02-14 16:28:35 -05002280
Aaron Heuckroth4ef3a542019-04-01 14:17:23 -04002281 public void refreshDialog() {
2282 initializeLayout();
2283 mGlobalActionsLayout.updateList();
2284 }
2285
Aaron Heuckroth4ea2fdb2019-02-14 16:28:35 -05002286 public void onRotate(int from, int to) {
Aaron Heuckrothe2d92ac2019-05-01 10:44:59 -04002287 if (mShowing) {
Aaron Heuckroth4ef3a542019-04-01 14:17:23 -04002288 refreshDialog();
Aaron Heuckroth4ea2fdb2019-02-14 16:28:35 -05002289 }
2290 }
Steve Elliott48f75db2019-05-03 15:03:38 -04002291
2292 private static class ResetOrientationData {
2293 public boolean locked;
2294 public int rotation;
2295 }
Jason Monk361915c2017-03-21 20:33:59 -04002296 }
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002297
2298 /**
Aran Ink93dd25c2019-05-09 14:42:14 -04002299 * Determines whether or not debug mode has been activated for the Global Actions Panel.
2300 */
2301 private static boolean isPanelDebugModeEnabled(Context context) {
2302 return Settings.Secure.getInt(context.getContentResolver(),
2303 Settings.Secure.GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED, 0) == 1;
2304 }
2305
2306 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08002307 * Determines whether or not the Global Actions menu should be forced to use the newer
2308 * grid-style layout.
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002309 */
Aaron Heuckrothc7926612019-04-02 14:21:57 -04002310 private static boolean isForceGridEnabled(Context context) {
Aran Ink93dd25c2019-05-09 14:42:14 -04002311 return isPanelDebugModeEnabled(context);
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002312 }
Aaron Heuckrothf19d2722019-03-11 17:06:02 -04002313
Aran Inkcf038272020-03-31 17:48:37 -04002314 @VisibleForTesting
2315 protected boolean shouldShowControls() {
Fabian Kozynskif6063ae2020-02-24 16:14:35 -05002316 return mKeyguardStateController.isUnlocked()
Fabian Kozynski0424ab12020-02-21 12:09:17 -05002317 && mControlsUiController.getAvailable()
Matt Pietalcd757c82020-04-08 10:20:48 -04002318 && !mControlsServiceInfos.isEmpty();
Matt Pietalfd3b6cb2020-01-08 09:43:54 -05002319 }
Matt Pietal69dfb642020-04-16 13:34:46 -04002320}