blob: e02b1ecaef328399e16e5f14a9389173faea55df [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 Roos284b32d2020-05-08 14:26:13 +020018import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
Adrian Roos2f05bb32018-02-19 16:42:27 +010019import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
Miranda Kephart7b2c3132020-03-27 09:54:14 -040020import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS;
21import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
Adrian Roos2f05bb32018-02-19 16:42:27 +010022
Chad Brubakerf4075fe2018-01-03 13:23:22 -080023import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
24import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
Chad Brubaker4f28f0d2017-09-07 14:28:13 -070025import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
26
Matt Pietale9440b72020-05-01 11:36:01 -040027import android.animation.Animator;
28import android.animation.AnimatorListenerAdapter;
29import android.animation.AnimatorSet;
30import android.animation.ObjectAnimator;
Dave Mankoffc88a2d72020-01-10 15:59:31 -050031import android.annotation.Nullable;
Jason Monk361915c2017-03-21 20:33:59 -040032import android.app.ActivityManager;
33import android.app.Dialog;
Dave Mankoffc88a2d72020-01-10 15:59:31 -050034import android.app.IActivityManager;
Steve Elliott4c868852019-03-14 16:25:41 -040035import android.app.PendingIntent;
Steve Elliott53f12ae2019-05-13 17:14:15 -040036import android.app.StatusBarManager;
Lucas Dupinc1cc7592017-05-22 15:56:16 -070037import android.app.WallpaperManager;
Alex Chau04458852017-11-27 18:21:23 +000038import android.app.admin.DevicePolicyManager;
Pavel Grafov059021b2018-05-02 13:44:46 +010039import android.app.trust.TrustManager;
Jason Monk361915c2017-03-21 20:33:59 -040040import android.content.BroadcastReceiver;
Matt Pietal61266442020-03-17 12:53:44 -040041import android.content.ComponentName;
Dave Mankoffc88a2d72020-01-10 15:59:31 -050042import android.content.ContentResolver;
Jason Monk361915c2017-03-21 20:33:59 -040043import android.content.Context;
44import android.content.DialogInterface;
45import android.content.Intent;
46import android.content.IntentFilter;
Matt Pietal61266442020-03-17 12:53:44 -040047import android.content.SharedPreferences;
Jason Monk361915c2017-03-21 20:33:59 -040048import android.content.pm.UserInfo;
Lucas Dupincb6726f2020-04-07 19:32:38 -070049import android.content.res.ColorStateList;
Dave Mankoffc88a2d72020-01-10 15:59:31 -050050import android.content.res.Resources;
Jason Monk361915c2017-03-21 20:33:59 -040051import android.database.ContentObserver;
Matt Pietale0661b62020-01-29 14:35:31 -050052import android.graphics.Color;
Jason Monk361915c2017-03-21 20:33:59 -040053import android.graphics.drawable.Drawable;
54import android.media.AudioManager;
55import android.net.ConnectivityManager;
Steve Elliott53f12ae2019-05-13 17:14:15 -040056import android.os.Binder;
Jason Monk361915c2017-03-21 20:33:59 -040057import android.os.Handler;
Steve Elliott53f12ae2019-05-13 17:14:15 -040058import android.os.IBinder;
Jason Monk361915c2017-03-21 20:33:59 -040059import android.os.Message;
60import android.os.RemoteException;
Jason Monk361915c2017-03-21 20:33:59 -040061import android.os.SystemProperties;
62import android.os.UserHandle;
63import android.os.UserManager;
64import android.os.Vibrator;
65import android.provider.Settings;
Jason Monk361915c2017-03-21 20:33:59 -040066import android.service.dreams.IDreamManager;
Inseob Kim5e82f732019-11-08 15:08:38 +090067import android.sysprop.TelephonyProperties;
Fan Zhangf9914762019-11-01 15:58:38 -070068import android.telecom.TelecomManager;
Jason Monk361915c2017-03-21 20:33:59 -040069import android.telephony.PhoneStateListener;
70import android.telephony.ServiceState;
71import android.telephony.TelephonyManager;
Jason Monk361915c2017-03-21 20:33:59 -040072import android.util.ArraySet;
yuanjiahsu88363e92018-09-06 19:23:52 +080073import android.util.FeatureFlagUtils;
Jason Monk361915c2017-03-21 20:33:59 -040074import android.util.Log;
Lucas Dupin448786c2017-07-24 17:44:25 -070075import android.view.ContextThemeWrapper;
Dave Mankoff8df818e2020-02-12 14:22:26 -050076import android.view.IWindowManager;
Jason Monk361915c2017-03-21 20:33:59 -040077import android.view.LayoutInflater;
78import android.view.View;
79import android.view.ViewGroup;
Lucas Dupinc1cc7592017-05-22 15:56:16 -070080import android.view.Window;
Lucas Dupin26571e92020-04-08 14:55:10 -070081import android.view.WindowInsets;
Jason Monk361915c2017-03-21 20:33:59 -040082import android.view.WindowManager;
Jason Monk361915c2017-03-21 20:33:59 -040083import android.view.accessibility.AccessibilityEvent;
Aran Inkcf038272020-03-31 17:48:37 -040084import android.widget.BaseAdapter;
Steve Elliott9b87a442019-03-05 10:24:16 -050085import android.widget.FrameLayout;
Jason Monk361915c2017-03-21 20:33:59 -040086import android.widget.ImageView;
87import android.widget.ImageView.ScaleType;
Aran Ink7c8fea92020-04-17 14:40:14 -040088import android.widget.LinearLayout;
Aran Inkcf038272020-03-31 17:48:37 -040089import android.widget.ListPopupWindow;
Jason Monk361915c2017-03-21 20:33:59 -040090import android.widget.TextView;
91
Fabian Kozynskib6a20372020-04-01 09:36:43 -040092import androidx.annotation.NonNull;
93import androidx.lifecycle.Lifecycle;
94import androidx.lifecycle.LifecycleOwner;
95import androidx.lifecycle.LifecycleRegistry;
96
Charles He9851a8d2017-10-10 17:31:30 +010097import com.android.internal.R;
Chris Wren65a70c92020-04-02 10:43:46 -040098import com.android.internal.annotations.VisibleForTesting;
Charles He9851a8d2017-10-10 17:31:30 +010099import com.android.internal.colorextraction.ColorExtractor;
100import com.android.internal.colorextraction.ColorExtractor.GradientColors;
Lucas Dupin2bd3af62019-03-25 17:44:28 -0700101import com.android.internal.colorextraction.drawable.ScrimDrawable;
Charles He9851a8d2017-10-10 17:31:30 +0100102import com.android.internal.logging.MetricsLogger;
Chris Wren65a70c92020-04-02 10:43:46 -0400103import com.android.internal.logging.UiEvent;
104import com.android.internal.logging.UiEventLogger;
Charles He9851a8d2017-10-10 17:31:30 +0100105import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Steve Elliott53f12ae2019-05-13 17:14:15 -0400106import com.android.internal.statusbar.IStatusBarService;
Charles He9851a8d2017-10-10 17:31:30 +0100107import com.android.internal.util.EmergencyAffordanceManager;
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400108import com.android.internal.util.ScreenRecordHelper;
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500109import com.android.internal.util.ScreenshotHelper;
Steve Elliott48f75db2019-05-03 15:03:38 -0400110import com.android.internal.view.RotationPolicy;
Charles He9851a8d2017-10-10 17:31:30 +0100111import com.android.internal.widget.LockPatternUtils;
Charles He9851a8d2017-10-10 17:31:30 +0100112import com.android.systemui.Interpolators;
Aaron Heuckrothf708d472019-01-10 16:54:51 -0500113import com.android.systemui.MultiListLayout;
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500114import com.android.systemui.MultiListLayout.MultiListAdapter;
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -0400115import com.android.systemui.broadcast.BroadcastDispatcher;
Charles He9851a8d2017-10-10 17:31:30 +0100116import com.android.systemui.colorextraction.SysuiColorExtractor;
Matt Pietal61266442020-03-17 12:53:44 -0400117import com.android.systemui.controls.ControlsServiceInfo;
118import com.android.systemui.controls.controller.ControlsController;
Matt Pietalf4b870b2020-04-17 17:11:36 -0400119import com.android.systemui.controls.management.ControlsAnimations;
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500120import com.android.systemui.controls.management.ControlsListingController;
Matt Pietal22231792020-01-23 09:51:09 -0500121import com.android.systemui.controls.ui.ControlsUiController;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500122import com.android.systemui.dagger.qualifiers.Background;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500123import com.android.systemui.dagger.qualifiers.Main;
Steve Elliott4c868852019-03-14 16:25:41 -0400124import com.android.systemui.plugins.ActivityStarter;
Charles He9851a8d2017-10-10 17:31:30 +0100125import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
Steve Elliott9b87a442019-03-05 10:24:16 -0500126import com.android.systemui.plugins.GlobalActionsPanelPlugin;
Lucas Dupin99f5fba2020-03-12 12:59:18 -0700127import com.android.systemui.statusbar.BlurUtils;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -0800128import com.android.systemui.statusbar.NotificationShadeDepthController;
Matt Pietal22231792020-01-23 09:51:09 -0500129import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
Lucas Dupin43d01242020-02-03 11:58:33 -0800130import com.android.systemui.statusbar.phone.ScrimController;
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700131import com.android.systemui.statusbar.policy.ConfigurationController;
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400132import com.android.systemui.statusbar.policy.KeyguardStateController;
Shaotang Li5c422632018-07-04 14:18:40 +0800133import com.android.systemui.util.EmergencyDialerConstants;
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400134import com.android.systemui.util.RingerModeTracker;
Aaron Heuckroth75e249f2019-02-01 15:59:57 -0500135import com.android.systemui.util.leak.RotationUtils;
Lucas Dupinc1cc7592017-05-22 15:56:16 -0700136
Jason Monk361915c2017-03-21 20:33:59 -0400137import java.util.ArrayList;
138import java.util.List;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500139import java.util.concurrent.Executor;
Jason Monk361915c2017-03-21 20:33:59 -0400140
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500141import javax.inject.Inject;
142
Jason Monk361915c2017-03-21 20:33:59 -0400143/**
Sean Pont9d4fb032020-03-04 18:54:32 -0800144 * Helper to show the global actions dialog. Each item is an {@link Action} that may show depending
145 * on whether the keyguard is showing, and whether the device is provisioned.
Jason Monk361915c2017-03-21 20:33:59 -0400146 */
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500147public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
Sean Pont9d4fb032020-03-04 18:54:32 -0800148 DialogInterface.OnShowListener,
149 ConfigurationController.ConfigurationListener,
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400150 GlobalActionsPanelPlugin.Callbacks,
151 LifecycleOwner {
Jason Monk361915c2017-03-21 20:33:59 -0400152
Sean Pont9d4fb032020-03-04 18:54:32 -0800153 public static final String SYSTEM_DIALOG_REASON_KEY = "reason";
154 public static final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
155 public static final String SYSTEM_DIALOG_REASON_DREAM = "dream";
Jason Monk361915c2017-03-21 20:33:59 -0400156
157 private static final String TAG = "GlobalActionsDialog";
158
159 private static final boolean SHOW_SILENT_TOGGLE = true;
160
161 /* Valid settings for global actions keys.
162 * see config.xml config_globalActionList */
Aran Inkcf038272020-03-31 17:48:37 -0400163 @VisibleForTesting
164 protected static final String GLOBAL_ACTION_KEY_POWER = "power";
165 protected static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
166 protected static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
167 protected static final String GLOBAL_ACTION_KEY_SILENT = "silent";
168 protected static final String GLOBAL_ACTION_KEY_USERS = "users";
169 protected static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
170 protected static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
171 protected static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
172 protected static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
173 protected static final String GLOBAL_ACTION_KEY_RESTART = "restart";
174 protected static final String GLOBAL_ACTION_KEY_LOGOUT = "logout";
175 protected static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
176 protected static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
Jason Monk361915c2017-03-21 20:33:59 -0400177
Matt Pietal61266442020-03-17 12:53:44 -0400178 private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "ControlsSeedingCompleted";
179 private static final String PREFS_CONTROLS_FILE = "controls_prefs";
180
Jason Monk361915c2017-03-21 20:33:59 -0400181 private final Context mContext;
182 private final GlobalActionsManager mWindowManagerFuncs;
183 private final AudioManager mAudioManager;
184 private final IDreamManager mDreamManager;
Alex Chau04458852017-11-27 18:21:23 +0000185 private final DevicePolicyManager mDevicePolicyManager;
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800186 private final LockPatternUtils mLockPatternUtils;
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500187 private final KeyguardStateController mKeyguardStateController;
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000188 private final BroadcastDispatcher mBroadcastDispatcher;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500189 private final ContentResolver mContentResolver;
190 private final Resources mResources;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500191 private final ConfigurationController mConfigurationController;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500192 private final UserManager mUserManager;
193 private final TrustManager mTrustManager;
194 private final IActivityManager mIActivityManager;
195 private final TelecomManager mTelecomManager;
196 private final MetricsLogger mMetricsLogger;
Chris Wren65a70c92020-04-02 10:43:46 -0400197 private final UiEventLogger mUiEventLogger;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -0800198 private final NotificationShadeDepthController mDepthController;
Lucas Dupin99f5fba2020-03-12 12:59:18 -0700199 private final BlurUtils mBlurUtils;
Jason Monk361915c2017-03-21 20:33:59 -0400200
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400201 // Used for RingerModeTracker
202 private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
203
Aran Inkcf038272020-03-31 17:48:37 -0400204 @VisibleForTesting
Aran Inka65e68362020-04-14 15:23:24 -0400205 protected final ArrayList<Action> mItems = new ArrayList<>();
Aran Inkcf038272020-03-31 17:48:37 -0400206 @VisibleForTesting
Aran Inka65e68362020-04-14 15:23:24 -0400207 protected final ArrayList<Action> mOverflowItems = new ArrayList<>();
Aran Inkcf038272020-03-31 17:48:37 -0400208
Jason Monk361915c2017-03-21 20:33:59 -0400209 private ActionsDialog mDialog;
210
211 private Action mSilentModeAction;
212 private ToggleAction mAirplaneModeOn;
213
214 private MyAdapter mAdapter;
Aran Inkcf038272020-03-31 17:48:37 -0400215 private MyOverflowAdapter mOverflowAdapter;
Jason Monk361915c2017-03-21 20:33:59 -0400216
217 private boolean mKeyguardShowing = false;
218 private boolean mDeviceProvisioned = false;
Lucas Dupincb6726f2020-04-07 19:32:38 -0700219 private ToggleState mAirplaneState = ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -0400220 private boolean mIsWaitingForEcmExit = false;
221 private boolean mHasTelephony;
222 private boolean mHasVibrator;
223 private final boolean mShowSilentToggle;
224 private final EmergencyAffordanceManager mEmergencyAffordanceManager;
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500225 private final ScreenshotHelper mScreenshotHelper;
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400226 private final ScreenRecordHelper mScreenRecordHelper;
Steve Elliotta3f5207922019-03-18 13:37:22 -0400227 private final ActivityStarter mActivityStarter;
Lucas Dupin991415e2019-11-25 17:48:58 -0800228 private final SysuiColorExtractor mSysuiColorExtractor;
229 private final IStatusBarService mStatusBarService;
230 private final NotificationShadeWindowController mNotificationShadeWindowController;
Steve Elliotta3f5207922019-03-18 13:37:22 -0400231 private GlobalActionsPanelPlugin mPanelPlugin;
Matt Pietal22231792020-01-23 09:51:09 -0500232 private ControlsUiController mControlsUiController;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500233 private final IWindowManager mIWindowManager;
234 private final Executor mBackgroundExecutor;
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500235 private final ControlsListingController mControlsListingController;
Matt Pietalcd757c82020-04-08 10:20:48 -0400236 private List<ControlsServiceInfo> mControlsServiceInfos = new ArrayList<>();
237 private ControlsController mControlsController;
238 private SharedPreferences mControlsPreferences;
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400239 private final RingerModeTracker mRingerModeTracker;
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400240 private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
Matt Pietal677981d2020-04-24 14:38:32 -0400241 private Handler mMainHandler;
242 private boolean mShowLockScreenCardsAndControls = false;
Steve Elliott9b87a442019-03-05 10:24:16 -0500243
Chris Wren65a70c92020-04-02 10:43:46 -0400244 @VisibleForTesting
245 public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum {
246 @UiEvent(doc = "The global actions / power menu surface became visible on the screen.")
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400247 GA_POWER_MENU_OPEN(337),
248
249 @UiEvent(doc = "The global actions bugreport button was pressed.")
250 GA_BUGREPORT_PRESS(344),
251
252 @UiEvent(doc = "The global actions bugreport button was long pressed.")
253 GA_BUGREPORT_LONG_PRESS(345),
254
255 @UiEvent(doc = "The global actions emergency button was pressed.")
256 GA_EMERGENCY_DIALER_PRESS(346),
257
258 @UiEvent(doc = "The global actions screenshot button was pressed.")
259 GA_SCREENSHOT_PRESS(347),
260
261 @UiEvent(doc = "The global actions screenshot button was long pressed.")
262 GA_SCREENSHOT_LONG_PRESS(348);
Chris Wren65a70c92020-04-02 10:43:46 -0400263
264 private final int mId;
265
266 GlobalActionsEvent(int id) {
267 mId = id;
268 }
269
270 @Override
271 public int getId() {
272 return mId;
273 }
274 }
275
Jason Monk361915c2017-03-21 20:33:59 -0400276 /**
277 * @param context everything needs a context :(
278 */
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500279 @Inject
280 public GlobalActionsDialog(Context context, GlobalActionsManager windowManagerFuncs,
281 AudioManager audioManager, IDreamManager iDreamManager,
282 DevicePolicyManager devicePolicyManager, LockPatternUtils lockPatternUtils,
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500283 BroadcastDispatcher broadcastDispatcher,
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500284 ConnectivityManager connectivityManager, TelephonyManager telephonyManager,
285 ContentResolver contentResolver, @Nullable Vibrator vibrator, @Main Resources resources,
286 ConfigurationController configurationController, ActivityStarter activityStarter,
287 KeyguardStateController keyguardStateController, UserManager userManager,
288 TrustManager trustManager, IActivityManager iActivityManager,
Dave Mankoff3c6aaab2020-01-10 17:50:34 -0500289 @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -0800290 NotificationShadeDepthController depthController, SysuiColorExtractor colorExtractor,
Lucas Dupin99f5fba2020-03-12 12:59:18 -0700291 IStatusBarService statusBarService, BlurUtils blurUtils,
Matt Pietal22231792020-01-23 09:51:09 -0500292 NotificationShadeWindowController notificationShadeWindowController,
Dave Mankoff8df818e2020-02-12 14:22:26 -0500293 ControlsUiController controlsUiController, IWindowManager iWindowManager,
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500294 @Background Executor backgroundExecutor,
Matt Pietal61266442020-03-17 12:53:44 -0400295 ControlsListingController controlsListingController,
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400296 ControlsController controlsController, UiEventLogger uiEventLogger,
Matt Pietal677981d2020-04-24 14:38:32 -0400297 RingerModeTracker ringerModeTracker, @Main Handler handler) {
Lucas Dupin448786c2017-07-24 17:44:25 -0700298 mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
Jason Monk361915c2017-03-21 20:33:59 -0400299 mWindowManagerFuncs = windowManagerFuncs;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500300 mAudioManager = audioManager;
301 mDreamManager = iDreamManager;
302 mDevicePolicyManager = devicePolicyManager;
303 mLockPatternUtils = lockPatternUtils;
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500304 mKeyguardStateController = keyguardStateController;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500305 mBroadcastDispatcher = broadcastDispatcher;
306 mContentResolver = contentResolver;
307 mResources = resources;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500308 mConfigurationController = configurationController;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500309 mUserManager = userManager;
310 mTrustManager = trustManager;
311 mIActivityManager = iActivityManager;
312 mTelecomManager = telecomManager;
313 mMetricsLogger = metricsLogger;
Chris Wren65a70c92020-04-02 10:43:46 -0400314 mUiEventLogger = uiEventLogger;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -0800315 mDepthController = depthController;
Lucas Dupin991415e2019-11-25 17:48:58 -0800316 mSysuiColorExtractor = colorExtractor;
317 mStatusBarService = statusBarService;
318 mNotificationShadeWindowController = notificationShadeWindowController;
Matt Pietal22231792020-01-23 09:51:09 -0500319 mControlsUiController = controlsUiController;
Dave Mankoff8df818e2020-02-12 14:22:26 -0500320 mIWindowManager = iWindowManager;
321 mBackgroundExecutor = backgroundExecutor;
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500322 mControlsListingController = controlsListingController;
Lucas Dupin99f5fba2020-03-12 12:59:18 -0700323 mBlurUtils = blurUtils;
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400324 mRingerModeTracker = ringerModeTracker;
Matt Pietalcd757c82020-04-08 10:20:48 -0400325 mControlsController = controlsController;
Matt Pietal677981d2020-04-24 14:38:32 -0400326 mMainHandler = handler;
Jason Monk361915c2017-03-21 20:33:59 -0400327
328 // receive broadcasts
329 IntentFilter filter = new IntentFilter();
330 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
331 filter.addAction(Intent.ACTION_SCREEN_OFF);
Jayachandran C142eae02019-12-13 19:29:20 -0800332 filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000333 mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
Jason Monk361915c2017-03-21 20:33:59 -0400334
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500335 mHasTelephony = connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
Jason Monk361915c2017-03-21 20:33:59 -0400336
337 // get notified of phone state changes
Jason Monk361915c2017-03-21 20:33:59 -0400338 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500339 contentResolver.registerContentObserver(
Jason Monk361915c2017-03-21 20:33:59 -0400340 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
341 mAirplaneModeObserver);
Jason Monk361915c2017-03-21 20:33:59 -0400342 mHasVibrator = vibrator != null && vibrator.hasVibrator();
343
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500344 mShowSilentToggle = SHOW_SILENT_TOGGLE && !resources.getBoolean(
Jason Monk361915c2017-03-21 20:33:59 -0400345 R.bool.config_useFixedVolume);
Fabian Kozynskib6a20372020-04-01 09:36:43 -0400346 if (mShowSilentToggle) {
347 mRingerModeTracker.getRingerMode().observe(this, ringer ->
348 mHandler.sendEmptyMessage(MESSAGE_REFRESH)
349 );
350 }
Jason Monk361915c2017-03-21 20:33:59 -0400351
352 mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500353 mScreenshotHelper = new ScreenshotHelper(context);
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400354 mScreenRecordHelper = new ScreenRecordHelper(context);
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700355
Dave Mankoff8df818e2020-02-12 14:22:26 -0500356 mConfigurationController.addCallback(this);
Steve Elliott9b87a442019-03-05 10:24:16 -0500357
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500358 mActivityStarter = activityStarter;
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400359 keyguardStateController.addCallback(new KeyguardStateController.Callback() {
360 @Override
361 public void onUnlockedChanged() {
Matt Pietal677981d2020-04-24 14:38:32 -0400362 if (mDialog != null) {
Sean Pont9d4fb032020-03-04 18:54:32 -0800363 boolean unlocked = keyguardStateController.isUnlocked()
364 || keyguardStateController.canDismissLockScreen();
Matt Pietal677981d2020-04-24 14:38:32 -0400365 if (mDialog.mPanelController != null) {
366 mDialog.mPanelController.onDeviceLockStateChanged(unlocked);
367 }
368 if (!mDialog.isShowingControls() && shouldShowControls()) {
369 mDialog.showControls(mControlsUiController);
370 }
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400371 }
372 }
373 });
Fabian Kozynski0424ab12020-02-21 12:09:17 -0500374
Matt Pietal61266442020-03-17 12:53:44 -0400375 mControlsListingController.addCallback(list -> {
Matt Pietalcd757c82020-04-08 10:20:48 -0400376 mControlsServiceInfos = list;
Matt Pietal61266442020-03-17 12:53:44 -0400377 });
Matt Pietalcd757c82020-04-08 10:20:48 -0400378
379 // Need to be user-specific with the context to make sure we read the correct prefs
380 Context userContext = context.createContextAsUser(
381 new UserHandle(mUserManager.getUserHandle()), 0);
382 mControlsPreferences = userContext.getSharedPreferences(PREFS_CONTROLS_FILE,
383 Context.MODE_PRIVATE);
384
Matt Pietal677981d2020-04-24 14:38:32 -0400385 // Listen for changes to show controls on the power menu while locked
386 onPowerMenuLockScreenSettingsChanged();
387 mContext.getContentResolver().registerContentObserver(
388 Settings.Secure.getUriFor(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT),
389 false /* notifyForDescendants */,
390 new ContentObserver(mMainHandler) {
391 @Override
392 public void onChange(boolean selfChange) {
393 onPowerMenuLockScreenSettingsChanged();
394 }
395 });
Jason Monk361915c2017-03-21 20:33:59 -0400396 }
397
Matt Pietalcd757c82020-04-08 10:20:48 -0400398 private void seedFavorites() {
399 if (mControlsServiceInfos.isEmpty()
400 || mControlsController.getFavorites().size() > 0
401 || mControlsPreferences.getBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, false)) {
402 return;
403 }
Matt Pietal61266442020-03-17 12:53:44 -0400404
Matt Pietalcd757c82020-04-08 10:20:48 -0400405 /*
406 * See if any service providers match the preferred component. If they do,
407 * and there are no current favorites, and we haven't successfully loaded favorites to
408 * date, query the preferred component for a limited number of suggested controls.
409 */
410 String preferredControlsPackage = mContext.getResources()
411 .getString(com.android.systemui.R.string.config_controlsPreferredPackage);
Matt Pietal61266442020-03-17 12:53:44 -0400412
Matt Pietalcd757c82020-04-08 10:20:48 -0400413 ComponentName preferredComponent = null;
414 for (ControlsServiceInfo info : mControlsServiceInfos) {
415 if (info.componentName.getPackageName().equals(preferredControlsPackage)) {
416 preferredComponent = info.componentName;
417 break;
418 }
419 }
420
421 if (preferredComponent == null) {
422 Log.i(TAG, "Controls seeding: No preferred component has been set, will not seed");
423 mControlsPreferences.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, true).apply();
Matt Pietal69dfb642020-04-16 13:34:46 -0400424 return;
Matt Pietalcd757c82020-04-08 10:20:48 -0400425 }
426
427 mControlsController.seedFavoritesForComponent(
428 preferredComponent,
429 (accepted) -> {
430 Log.i(TAG, "Controls seeded: " + accepted);
431 mControlsPreferences.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED,
432 accepted).apply();
433 });
434 }
Matt Pietal61266442020-03-17 12:53:44 -0400435
Jason Monk361915c2017-03-21 20:33:59 -0400436 /**
437 * Show the global actions dialog (creating if necessary)
Jason Monk16fbd9d2017-04-27 14:28:49 -0400438 *
Jason Monk361915c2017-03-21 20:33:59 -0400439 * @param keyguardShowing True if keyguard is showing
440 */
Matt Pietal6ce0a902020-04-24 10:30:57 -0400441 public void showOrHideDialog(boolean keyguardShowing, boolean isDeviceProvisioned,
Steve Elliotta3f5207922019-03-18 13:37:22 -0400442 GlobalActionsPanelPlugin panelPlugin) {
Jason Monk361915c2017-03-21 20:33:59 -0400443 mKeyguardShowing = keyguardShowing;
444 mDeviceProvisioned = isDeviceProvisioned;
Steve Elliotta3f5207922019-03-18 13:37:22 -0400445 mPanelPlugin = panelPlugin;
Matt Pietal6ce0a902020-04-24 10:30:57 -0400446 if (mDialog != null && mDialog.isShowing()) {
447 // In order to force global actions to hide on the same affordance press, we must
448 // register a call to onGlobalActionsShown() first to prevent the default actions
449 // menu from showing. This will be followed by a subsequent call to
450 // onGlobalActionsHidden() on dismiss()
451 mWindowManagerFuncs.onGlobalActionsShown();
Jason Monk361915c2017-03-21 20:33:59 -0400452 mDialog.dismiss();
453 mDialog = null;
Jason Monk361915c2017-03-21 20:33:59 -0400454 } else {
455 handleShow();
456 }
457 }
458
Charles He9851a8d2017-10-10 17:31:30 +0100459 /**
460 * Dismiss the global actions dialog, if it's currently shown
461 */
462 public void dismissDialog() {
463 mHandler.removeMessages(MESSAGE_DISMISS);
464 mHandler.sendEmptyMessage(MESSAGE_DISMISS);
465 }
466
Jason Monk361915c2017-03-21 20:33:59 -0400467 private void awakenIfNecessary() {
468 if (mDreamManager != null) {
469 try {
470 if (mDreamManager.isDreaming()) {
471 mDreamManager.awaken();
472 }
473 } catch (RemoteException e) {
474 // we tried
475 }
476 }
477 }
478
479 private void handleShow() {
480 awakenIfNecessary();
481 mDialog = createDialog();
482 prepareDialog();
Matt Pietalcd757c82020-04-08 10:20:48 -0400483 seedFavorites();
Jason Monk361915c2017-03-21 20:33:59 -0400484
Aran Inka65e68362020-04-14 15:23:24 -0400485 WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
486 attrs.setTitle("ActionsDialog");
487 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
488 mDialog.getWindow().setAttributes(attrs);
Adrian Roos284b32d2020-05-08 14:26:13 +0200489 // Don't acquire soft keyboard focus, to avoid destroying state when capturing bugreports
490 mDialog.getWindow().setFlags(FLAG_ALT_FOCUSABLE_IM, FLAG_ALT_FOCUSABLE_IM);
Aran Inka65e68362020-04-14 15:23:24 -0400491 mDialog.show();
492 mWindowManagerFuncs.onGlobalActionsShown();
Jason Monk361915c2017-03-21 20:33:59 -0400493 }
494
Aran Inkcf038272020-03-31 17:48:37 -0400495 @VisibleForTesting
496 protected boolean shouldShowAction(Action action) {
497 if (mKeyguardShowing && !action.showDuringKeyguard()) {
498 return false;
499 }
500 if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
501 return false;
502 }
503 return true;
504 }
505
Jason Monk361915c2017-03-21 20:33:59 -0400506 /**
Aran Inkcf038272020-03-31 17:48:37 -0400507 * Returns the maximum number of power menu items to show based on which GlobalActions
508 * layout is being used.
Jason Monk361915c2017-03-21 20:33:59 -0400509 */
Aran Inkcf038272020-03-31 17:48:37 -0400510 @VisibleForTesting
511 protected int getMaxShownPowerItems() {
Aran Inkd397b902020-04-21 17:53:41 -0400512 if (shouldUseControlsLayout()) {
Matt Pietal677981d2020-04-24 14:38:32 -0400513 return mResources.getInteger(com.android.systemui.R.integer.power_menu_max_columns);
Aran Inkcf038272020-03-31 17:48:37 -0400514 } else {
515 return Integer.MAX_VALUE;
516 }
517 }
518
519 /**
520 * Add a power menu action item for to either the main or overflow items lists, depending on
521 * whether controls are enabled and whether the max number of shown items has been reached.
522 */
523 private void addActionItem(Action action) {
Aran Inka65e68362020-04-14 15:23:24 -0400524 if (shouldShowAction(action)) {
Aran Inkcf038272020-03-31 17:48:37 -0400525 if (mItems.size() < getMaxShownPowerItems()) {
526 mItems.add(action);
Aran Inka65e68362020-04-14 15:23:24 -0400527 } else {
Aran Inkcf038272020-03-31 17:48:37 -0400528 mOverflowItems.add(action);
529 }
530 }
531 }
532
533 @VisibleForTesting
534 protected String[] getDefaultActions() {
535 return mResources.getStringArray(R.array.config_globalActionsList);
536 }
537
538 @VisibleForTesting
539 protected void createActionItems() {
Jason Monk361915c2017-03-21 20:33:59 -0400540 // Simple toggle style if there's no vibrator, otherwise use a tri-state
541 if (!mHasVibrator) {
542 mSilentModeAction = new SilentModeToggleAction();
543 } else {
Lucas Dupin40ec6b782018-06-05 19:07:16 -0700544 mSilentModeAction = new SilentModeTriStateAction(mAudioManager, mHandler);
Jason Monk361915c2017-03-21 20:33:59 -0400545 }
Aran Ink780d4502020-02-14 10:39:58 -0500546 mAirplaneModeOn = new AirplaneModeAction();
Jason Monk361915c2017-03-21 20:33:59 -0400547 onAirplaneModeChanged();
548
Aran Inka65e68362020-04-14 15:23:24 -0400549 mItems.clear();
550 mOverflowItems.clear();
Aran Inkcf038272020-03-31 17:48:37 -0400551 String[] defaultActions = getDefaultActions();
552
553 // make sure emergency affordance action is first, if needed
554 if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
555 addActionItem(new EmergencyAffordanceAction());
556 }
Jason Monk361915c2017-03-21 20:33:59 -0400557
558 ArraySet<String> addedKeys = new ArraySet<String>();
559 for (int i = 0; i < defaultActions.length; i++) {
560 String actionKey = defaultActions[i];
561 if (addedKeys.contains(actionKey)) {
562 // If we already have added this, don't add it again.
563 continue;
564 }
565 if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400566 addActionItem(new PowerAction());
Jason Monk361915c2017-03-21 20:33:59 -0400567 } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400568 addActionItem(mAirplaneModeOn);
Jason Monk361915c2017-03-21 20:33:59 -0400569 } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500570 if (Settings.Global.getInt(mContentResolver,
Jason Monk361915c2017-03-21 20:33:59 -0400571 Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
Aran Inkcf038272020-03-31 17:48:37 -0400572 addActionItem(new BugReportAction());
Jason Monk361915c2017-03-21 20:33:59 -0400573 }
574 } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
575 if (mShowSilentToggle) {
Aran Inkcf038272020-03-31 17:48:37 -0400576 addActionItem(mSilentModeAction);
Jason Monk361915c2017-03-21 20:33:59 -0400577 }
578 } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
579 if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
Aran Inkcf038272020-03-31 17:48:37 -0400580 addUsersToMenu();
Jason Monk361915c2017-03-21 20:33:59 -0400581 }
582 } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400583 addActionItem(getSettingsAction());
Jason Monk361915c2017-03-21 20:33:59 -0400584 } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500585 if (Settings.Secure.getIntForUser(mContentResolver,
Sean Pont9d4fb032020-03-04 18:54:32 -0800586 Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, getCurrentUser().id) != 0
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800587 && shouldDisplayLockdown()) {
Aran Inkcf038272020-03-31 17:48:37 -0400588 addActionItem(getLockdownAction());
Chad Brubaker4f28f0d2017-09-07 14:28:13 -0700589 }
Jason Monk361915c2017-03-21 20:33:59 -0400590 } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400591 addActionItem(getVoiceAssistAction());
Jason Monk361915c2017-03-21 20:33:59 -0400592 } else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400593 addActionItem(getAssistAction());
Jason Monk361915c2017-03-21 20:33:59 -0400594 } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400595 addActionItem(new RestartAction());
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500596 } else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
Aran Inkcf038272020-03-31 17:48:37 -0400597 addActionItem(new ScreenshotAction());
Alex Chau04458852017-11-27 18:21:23 +0000598 } else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) {
Alex Chaud7958272017-12-08 11:30:52 +0000599 if (mDevicePolicyManager.isLogoutEnabled()
Alex Chau04458852017-11-27 18:21:23 +0000600 && getCurrentUser().id != UserHandle.USER_SYSTEM) {
Aran Inkcf038272020-03-31 17:48:37 -0400601 addActionItem(new LogoutAction());
Alex Chau04458852017-11-27 18:21:23 +0000602 }
Wesley.CW Wanga9de7922018-07-06 15:26:21 +0800603 } else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400604 if (!mEmergencyAffordanceManager.needsEmergencyAffordance()) {
Aran Inkcf038272020-03-31 17:48:37 -0400605 addActionItem(new EmergencyDialerAction());
Wesley.CW Wanga9de7922018-07-06 15:26:21 +0800606 }
Jason Monk361915c2017-03-21 20:33:59 -0400607 } else {
608 Log.e(TAG, "Invalid global action key " + actionKey);
609 }
610 // Add here so we don't add more than one.
611 addedKeys.add(actionKey);
612 }
Aran Inkcf038272020-03-31 17:48:37 -0400613 }
Jason Monk361915c2017-03-21 20:33:59 -0400614
Aran Inka65e68362020-04-14 15:23:24 -0400615 private void onRotate() {
616 // re-allocate actions between main and overflow lists
617 this.createActionItems();
618 }
619
Aran Inkcf038272020-03-31 17:48:37 -0400620 /**
621 * Create the global actions dialog.
622 *
623 * @return A new dialog.
624 */
625 private ActionsDialog createDialog() {
626 createActionItems();
Jason Monk361915c2017-03-21 20:33:59 -0400627
628 mAdapter = new MyAdapter();
Aran Inkcf038272020-03-31 17:48:37 -0400629 mOverflowAdapter = new MyOverflowAdapter();
Jason Monk361915c2017-03-21 20:33:59 -0400630
Aran Inka65e68362020-04-14 15:23:24 -0400631 mDepthController.setShowingHomeControls(shouldUseControlsLayout());
Aran Inkcf038272020-03-31 17:48:37 -0400632 ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mOverflowAdapter,
633 getWalletPanelViewController(), mDepthController, mSysuiColorExtractor,
634 mStatusBarService, mNotificationShadeWindowController,
Aran Inka65e68362020-04-14 15:23:24 -0400635 shouldShowControls() ? mControlsUiController : null, mBlurUtils,
Aran Ink99c452d2020-04-28 14:23:13 -0400636 shouldUseControlsLayout(), this::onRotate, mKeyguardShowing);
Jason Monk361915c2017-03-21 20:33:59 -0400637 dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
Jason Monk361915c2017-03-21 20:33:59 -0400638 dialog.setOnDismissListener(this);
Shaotang Li786da902018-08-02 11:18:00 +0800639 dialog.setOnShowListener(this);
Jason Monk361915c2017-03-21 20:33:59 -0400640
641 return dialog;
642 }
643
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800644 private boolean shouldDisplayLockdown() {
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800645 // Lockdown is meaningless without a place to go.
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500646 if (!mKeyguardStateController.isMethodSecure()) {
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800647 return false;
648 }
649
Fabian Kozynskif6063ae2020-02-24 16:14:35 -0500650 int userId = getCurrentUser().id;
Chad Brubakerf4075fe2018-01-03 13:23:22 -0800651 // Only show the lockdown button if the device isn't locked down (for whatever reason).
652 int state = mLockPatternUtils.getStrongAuthForUser(userId);
653 return (state == STRONG_AUTH_NOT_REQUIRED
654 || state == SOME_AUTH_REQUIRED_AFTER_USER_REQUEST);
655 }
656
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700657 @Override
658 public void onUiModeChanged() {
659 mContext.getTheme().applyStyle(mContext.getThemeResId(), true);
Lucas Dupina4e12ba2019-04-18 11:56:28 -0700660 if (mDialog != null && mDialog.isShowing()) {
Aaron Heuckroth4ef3a542019-04-01 14:17:23 -0400661 mDialog.refreshDialog();
662 }
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700663 }
664
665 public void destroy() {
Dave Mankoff8df818e2020-02-12 14:22:26 -0500666 mConfigurationController.removeCallback(this);
Lucas Dupine5b7dc72018-10-02 15:18:05 -0700667 }
668
Sean Pont9d4fb032020-03-04 18:54:32 -0800669 @Nullable
670 private GlobalActionsPanelPlugin.PanelViewController getWalletPanelViewController() {
671 if (mPanelPlugin == null) {
672 return null;
673 }
674 return mPanelPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked());
675 }
676
677 /**
678 * Implements {@link GlobalActionsPanelPlugin.Callbacks#dismissGlobalActionsMenu()}, which is
679 * called when the quick access wallet requests dismissal.
680 */
681 @Override
682 public void dismissGlobalActionsMenu() {
683 dismissDialog();
684 }
685
686 /**
687 * Implements {@link GlobalActionsPanelPlugin.Callbacks#dismissGlobalActionsMenu()}, which is
688 * called when the quick access wallet requests that an intent be started (with lock screen
689 * shown first if needed).
690 */
691 @Override
692 public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
693 mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
694 }
695
Jason Monk361915c2017-03-21 20:33:59 -0400696 private final class PowerAction extends SinglePressAction implements LongPressAction {
697 private PowerAction() {
698 super(R.drawable.ic_lock_power_off,
Jason Monk16fbd9d2017-04-27 14:28:49 -0400699 R.string.global_action_power_off);
Jason Monk361915c2017-03-21 20:33:59 -0400700 }
701
702 @Override
703 public boolean onLongPress() {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500704 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
Jason Monk361915c2017-03-21 20:33:59 -0400705 mWindowManagerFuncs.reboot(true);
706 return true;
707 }
708 return false;
709 }
710
711 @Override
712 public boolean showDuringKeyguard() {
713 return true;
714 }
715
716 @Override
717 public boolean showBeforeProvisioning() {
718 return true;
719 }
720
721 @Override
722 public void onPress() {
723 // shutdown by making sure radio and power are handled accordingly.
724 mWindowManagerFuncs.shutdown();
725 }
726 }
727
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400728 private abstract class EmergencyAction extends SinglePressAction {
729 EmergencyAction(int iconResId, int messageResId) {
730 super(iconResId, messageResId);
731 }
732
733 @Override
734 public boolean shouldBeSeparated() {
Aran Inka65e68362020-04-14 15:23:24 -0400735 return !shouldUseControlsLayout();
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400736 }
737
738 @Override
739 public View create(
740 Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
741 View v = super.create(context, convertView, parent, inflater);
742 int textColor;
Aran Inka65e68362020-04-14 15:23:24 -0400743 if (shouldUseControlsLayout()) {
Lucas Dupincb6726f2020-04-07 19:32:38 -0700744 v.setBackgroundTintList(ColorStateList.valueOf(v.getResources().getColor(
745 com.android.systemui.R.color.global_actions_emergency_background)));
746 textColor = v.getResources().getColor(
747 com.android.systemui.R.color.global_actions_emergency_text);
748 } else if (shouldBeSeparated()) {
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400749 textColor = v.getResources().getColor(
750 com.android.systemui.R.color.global_actions_alert_text);
751 } else {
752 textColor = v.getResources().getColor(
753 com.android.systemui.R.color.global_actions_text);
754 }
755 TextView messageView = v.findViewById(R.id.message);
756 messageView.setTextColor(textColor);
Aaron Heuckroth3f2d8b52019-04-05 13:27:51 -0400757 messageView.setSelected(true); // necessary for marquee to work
Lucas Dupincb6726f2020-04-07 19:32:38 -0700758 ImageView icon = v.findViewById(R.id.icon);
Aaron Heuckrothc8343402019-03-13 16:27:15 -0400759 icon.getDrawable().setTint(textColor);
760 return v;
761 }
762
763 @Override
764 public boolean showDuringKeyguard() {
765 return true;
766 }
767
768 @Override
769 public boolean showBeforeProvisioning() {
770 return true;
771 }
772 }
773
774 private class EmergencyAffordanceAction extends EmergencyAction {
775 EmergencyAffordanceAction() {
776 super(R.drawable.emergency_icon,
777 R.string.global_action_emergency);
778 }
779
780 @Override
781 public void onPress() {
782 mEmergencyAffordanceManager.performEmergencyCall();
783 }
784 }
785
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400786 @VisibleForTesting
787 class EmergencyDialerAction extends EmergencyAction {
Wesley.CW Wanga9de7922018-07-06 15:26:21 +0800788 private EmergencyDialerAction() {
Aran Ink50195262019-05-30 10:55:37 -0400789 super(com.android.systemui.R.drawable.ic_emergency_star,
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800790 R.string.global_action_emergency);
Wesley.CW Wang8d072762018-05-28 16:39:27 +0800791 }
792
793 @Override
794 public void onPress() {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500795 mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_DIALER_FROM_POWER_MENU);
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400796 mUiEventLogger.log(GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS);
Dave Mankoff3c6aaab2020-01-10 17:50:34 -0500797 if (mTelecomManager != null) {
798 Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent(
799 null /* number */);
800 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
801 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
802 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
803 intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
804 EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU);
805 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
806 }
Wesley.CW Wang8d072762018-05-28 16:39:27 +0800807 }
Wesley.CW Wang8d072762018-05-28 16:39:27 +0800808 }
809
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400810 @VisibleForTesting
811 EmergencyDialerAction makeEmergencyDialerActionForTesting() {
812 return new EmergencyDialerAction();
813 }
814
Jason Monk361915c2017-03-21 20:33:59 -0400815 private final class RestartAction extends SinglePressAction implements LongPressAction {
816 private RestartAction() {
817 super(R.drawable.ic_restart, R.string.global_action_restart);
818 }
819
820 @Override
821 public boolean onLongPress() {
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500822 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
Jason Monk361915c2017-03-21 20:33:59 -0400823 mWindowManagerFuncs.reboot(true);
824 return true;
825 }
826 return false;
827 }
828
829 @Override
830 public boolean showDuringKeyguard() {
831 return true;
832 }
833
834 @Override
835 public boolean showBeforeProvisioning() {
836 return true;
837 }
838
839 @Override
840 public void onPress() {
841 mWindowManagerFuncs.reboot(false);
842 }
843 }
844
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400845 @VisibleForTesting
846 class ScreenshotAction extends SinglePressAction implements LongPressAction {
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500847 public ScreenshotAction() {
848 super(R.drawable.ic_screenshot, R.string.global_action_screenshot);
849 }
850
851 @Override
852 public void onPress() {
853 // Add a little delay before executing, to give the
854 // dialog a chance to go away before it takes a
855 // screenshot.
856 // TODO: instead, omit global action dialog layer
857 mHandler.postDelayed(new Runnable() {
858 @Override
859 public void run() {
Miranda Kephart7b2c3132020-03-27 09:54:14 -0400860 mScreenshotHelper.takeScreenshot(TAKE_SCREENSHOT_FULLSCREEN, true, true,
861 SCREENSHOT_GLOBAL_ACTIONS, mHandler, null);
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500862 mMetricsLogger.action(MetricsEvent.ACTION_SCREENSHOT_POWER_MENU);
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400863 mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_PRESS);
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500864 }
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400865 }, mDialogPressDelay);
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500866 }
867
868 @Override
869 public boolean showDuringKeyguard() {
870 return true;
871 }
872
873 @Override
874 public boolean showBeforeProvisioning() {
875 return false;
876 }
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400877
878 @Override
879 public boolean onLongPress() {
880 if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS)) {
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400881 mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS);
Beth Thibodeau5898ac42018-10-26 13:00:09 -0400882 mScreenRecordHelper.launchRecordPrompt();
883 } else {
884 onPress();
885 }
886 return true;
887 }
Alison Cichowlasa2cd19e2017-12-06 10:51:21 -0500888 }
889
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400890 @VisibleForTesting
891 ScreenshotAction makeScreenshotActionForTesting() {
892 return new ScreenshotAction();
893 }
894
895 @VisibleForTesting
896 class BugReportAction extends SinglePressAction implements LongPressAction {
Jason Monk361915c2017-03-21 20:33:59 -0400897
898 public BugReportAction() {
899 super(R.drawable.ic_lock_bugreport, R.string.bugreport_title);
900 }
901
902 @Override
903 public void onPress() {
904 // don't actually trigger the bugreport if we are running stability
905 // tests via monkey
906 if (ActivityManager.isUserAMonkey()) {
907 return;
908 }
909 // Add a little delay before executing, to give the
910 // dialog a chance to go away before it takes a
911 // screenshot.
912 mHandler.postDelayed(new Runnable() {
913 @Override
914 public void run() {
915 try {
916 // Take an "interactive" bugreport.
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500917 mMetricsLogger.action(
Jason Monk361915c2017-03-21 20:33:59 -0400918 MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400919 mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_PRESS);
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500920 if (!mIActivityManager.launchBugReportHandlerApp()) {
Paul Changc40f5782019-11-04 18:55:31 +0800921 Log.w(TAG, "Bugreport handler could not be launched");
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500922 mIActivityManager.requestInteractiveBugReport();
Paul Changc40f5782019-11-04 18:55:31 +0800923 }
Jason Monk361915c2017-03-21 20:33:59 -0400924 } catch (RemoteException e) {
925 }
926 }
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400927 }, mDialogPressDelay);
Jason Monk361915c2017-03-21 20:33:59 -0400928 }
929
930 @Override
931 public boolean onLongPress() {
932 // don't actually trigger the bugreport if we are running stability
933 // tests via monkey
934 if (ActivityManager.isUserAMonkey()) {
935 return false;
936 }
937 try {
938 // Take a "full" bugreport.
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500939 mMetricsLogger.action(MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400940 mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS);
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500941 mIActivityManager.requestFullBugReport();
Jason Monk361915c2017-03-21 20:33:59 -0400942 } catch (RemoteException e) {
943 }
944 return false;
945 }
946
947 public boolean showDuringKeyguard() {
948 return true;
949 }
950
951 @Override
952 public boolean showBeforeProvisioning() {
953 return false;
954 }
Jason Monk361915c2017-03-21 20:33:59 -0400955 }
956
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400957 @VisibleForTesting
958 BugReportAction makeBugReportActionForTesting() {
959 return new BugReportAction();
960 }
961
Alex Chau04458852017-11-27 18:21:23 +0000962 private final class LogoutAction extends SinglePressAction {
963 private LogoutAction() {
964 super(R.drawable.ic_logout, R.string.global_action_logout);
965 }
966
967 @Override
968 public boolean showDuringKeyguard() {
969 return true;
970 }
971
972 @Override
973 public boolean showBeforeProvisioning() {
974 return false;
975 }
976
977 @Override
978 public void onPress() {
979 // Add a little delay before executing, to give the dialog a chance to go away before
980 // switching user
981 mHandler.postDelayed(() -> {
982 try {
Alex Chauedb6a012018-01-26 12:52:43 +0000983 int currentUserId = getCurrentUser().id;
Dave Mankoffc88a2d72020-01-10 15:59:31 -0500984 mIActivityManager.switchUser(UserHandle.USER_SYSTEM);
985 mIActivityManager.stopUser(currentUserId, true /*force*/, null);
Alex Chau04458852017-11-27 18:21:23 +0000986 } catch (RemoteException re) {
987 Log.e(TAG, "Couldn't logout user " + re);
988 }
Chris Wrenaf4ce8462020-04-06 17:36:10 -0400989 }, mDialogPressDelay);
Alex Chau04458852017-11-27 18:21:23 +0000990 }
991 }
992
Jason Monk361915c2017-03-21 20:33:59 -0400993 private Action getSettingsAction() {
994 return new SinglePressAction(R.drawable.ic_settings,
995 R.string.global_action_settings) {
996
997 @Override
998 public void onPress() {
999 Intent intent = new Intent(Settings.ACTION_SETTINGS);
1000 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1001 mContext.startActivity(intent);
1002 }
1003
1004 @Override
1005 public boolean showDuringKeyguard() {
1006 return true;
1007 }
1008
1009 @Override
1010 public boolean showBeforeProvisioning() {
1011 return true;
1012 }
1013 };
1014 }
1015
Jason Monk361915c2017-03-21 20:33:59 -04001016 private Action getAssistAction() {
1017 return new SinglePressAction(R.drawable.ic_action_assist_focused,
1018 R.string.global_action_assist) {
1019 @Override
1020 public void onPress() {
1021 Intent intent = new Intent(Intent.ACTION_ASSIST);
1022 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1023 mContext.startActivity(intent);
1024 }
1025
1026 @Override
1027 public boolean showDuringKeyguard() {
1028 return true;
1029 }
1030
1031 @Override
1032 public boolean showBeforeProvisioning() {
1033 return true;
1034 }
1035 };
1036 }
1037
1038 private Action getVoiceAssistAction() {
1039 return new SinglePressAction(R.drawable.ic_voice_search,
1040 R.string.global_action_voice_assist) {
1041 @Override
1042 public void onPress() {
1043 Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
1044 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1045 mContext.startActivity(intent);
1046 }
1047
1048 @Override
1049 public boolean showDuringKeyguard() {
1050 return true;
1051 }
1052
1053 @Override
1054 public boolean showBeforeProvisioning() {
1055 return true;
1056 }
1057 };
1058 }
1059
1060 private Action getLockdownAction() {
Alison Cichowlas21125432018-05-16 15:40:45 -04001061 return new SinglePressAction(R.drawable.ic_lock_lockdown,
Jason Monk361915c2017-03-21 20:33:59 -04001062 R.string.global_action_lockdown) {
1063
1064 @Override
1065 public void onPress() {
Dave Mankoff8df818e2020-02-12 14:22:26 -05001066 mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
1067 UserHandle.USER_ALL);
Jason Monk361915c2017-03-21 20:33:59 -04001068 try {
Dave Mankoff8df818e2020-02-12 14:22:26 -05001069 mIWindowManager.lockNow(null);
Pavel Grafov059021b2018-05-02 13:44:46 +01001070 // Lock profiles (if any) on the background thread.
Dave Mankoff8df818e2020-02-12 14:22:26 -05001071 mBackgroundExecutor.execute(() -> lockProfiles());
Jason Monk361915c2017-03-21 20:33:59 -04001072 } catch (RemoteException e) {
1073 Log.e(TAG, "Error while trying to lock device.", e);
1074 }
1075 }
1076
1077 @Override
1078 public boolean showDuringKeyguard() {
1079 return true;
1080 }
1081
1082 @Override
1083 public boolean showBeforeProvisioning() {
1084 return false;
1085 }
1086 };
1087 }
1088
Pavel Grafov059021b2018-05-02 13:44:46 +01001089 private void lockProfiles() {
Pavel Grafov059021b2018-05-02 13:44:46 +01001090 final int currentUserId = getCurrentUser().id;
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001091 final int[] profileIds = mUserManager.getEnabledProfileIds(currentUserId);
Pavel Grafov059021b2018-05-02 13:44:46 +01001092 for (final int id : profileIds) {
1093 if (id != currentUserId) {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001094 mTrustManager.setDeviceLockedForUser(id, true);
Pavel Grafov059021b2018-05-02 13:44:46 +01001095 }
1096 }
1097 }
1098
Jason Monk361915c2017-03-21 20:33:59 -04001099 private UserInfo getCurrentUser() {
1100 try {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001101 return mIActivityManager.getCurrentUser();
Jason Monk361915c2017-03-21 20:33:59 -04001102 } catch (RemoteException re) {
1103 return null;
1104 }
1105 }
1106
1107 private boolean isCurrentUserOwner() {
1108 UserInfo currentUser = getCurrentUser();
1109 return currentUser == null || currentUser.isPrimary();
1110 }
1111
Aran Inkcf038272020-03-31 17:48:37 -04001112 private void addUsersToMenu() {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001113 if (mUserManager.isUserSwitcherEnabled()) {
1114 List<UserInfo> users = mUserManager.getUsers();
Jason Monk361915c2017-03-21 20:33:59 -04001115 UserInfo currentUser = getCurrentUser();
1116 for (final UserInfo user : users) {
1117 if (user.supportsSwitchToByUser()) {
1118 boolean isCurrentUser = currentUser == null
1119 ? user.id == 0 : (currentUser.id == user.id);
1120 Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
1121 : null;
1122 SinglePressAction switchToUser = new SinglePressAction(
1123 R.drawable.ic_menu_cc, icon,
1124 (user.name != null ? user.name : "Primary")
Jason Monk16fbd9d2017-04-27 14:28:49 -04001125 + (isCurrentUser ? " \u2714" : "")) {
Jason Monk361915c2017-03-21 20:33:59 -04001126 public void onPress() {
1127 try {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001128 mIActivityManager.switchUser(user.id);
Jason Monk361915c2017-03-21 20:33:59 -04001129 } catch (RemoteException re) {
1130 Log.e(TAG, "Couldn't switch user " + re);
1131 }
1132 }
1133
1134 public boolean showDuringKeyguard() {
1135 return true;
1136 }
1137
1138 public boolean showBeforeProvisioning() {
1139 return false;
1140 }
1141 };
Aran Inkcf038272020-03-31 17:48:37 -04001142 addActionItem(switchToUser);
Jason Monk361915c2017-03-21 20:33:59 -04001143 }
1144 }
1145 }
1146 }
1147
1148 private void prepareDialog() {
1149 refreshSilentMode();
1150 mAirplaneModeOn.updateState(mAirplaneState);
1151 mAdapter.notifyDataSetChanged();
Fabian Kozynskib6a20372020-04-01 09:36:43 -04001152 mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
Jason Monk361915c2017-03-21 20:33:59 -04001153 }
1154
1155 private void refreshSilentMode() {
1156 if (!mHasVibrator) {
Fabian Kozynskib6a20372020-04-01 09:36:43 -04001157 Integer value = mRingerModeTracker.getRingerMode().getValue();
1158 final boolean silentModeOn = value != null && value != AudioManager.RINGER_MODE_NORMAL;
Jason Monk16fbd9d2017-04-27 14:28:49 -04001159 ((ToggleAction) mSilentModeAction).updateState(
Lucas Dupincb6726f2020-04-07 19:32:38 -07001160 silentModeOn ? ToggleState.On : ToggleState.Off);
Jason Monk361915c2017-03-21 20:33:59 -04001161 }
1162 }
1163
Sean Pont9d4fb032020-03-04 18:54:32 -08001164 /**
1165 * {@inheritDoc}
1166 */
Jason Monk361915c2017-03-21 20:33:59 -04001167 public void onDismiss(DialogInterface dialog) {
Steve Elliottc3147e22019-11-20 19:34:57 -05001168 if (mDialog == dialog) {
1169 mDialog = null;
1170 }
Jason Monk361915c2017-03-21 20:33:59 -04001171 mWindowManagerFuncs.onGlobalActionsHidden();
Fabian Kozynskib6a20372020-04-01 09:36:43 -04001172 mLifecycle.setCurrentState(Lifecycle.State.DESTROYED);
Jason Monk361915c2017-03-21 20:33:59 -04001173 }
1174
Sean Pont9d4fb032020-03-04 18:54:32 -08001175 /**
1176 * {@inheritDoc}
1177 */
Shaotang Li786da902018-08-02 11:18:00 +08001178 public void onShow(DialogInterface dialog) {
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001179 mMetricsLogger.visible(MetricsEvent.POWER_MENU);
Chris Wren65a70c92020-04-02 10:43:46 -04001180 mUiEventLogger.log(GlobalActionsEvent.GA_POWER_MENU_OPEN);
Shaotang Li786da902018-08-02 11:18:00 +08001181 }
1182
Lucas Dupincb6726f2020-04-07 19:32:38 -07001183 private int getActionLayoutId() {
Aran Inka65e68362020-04-14 15:23:24 -04001184 if (shouldUseControlsLayout()) {
Lucas Dupincb6726f2020-04-07 19:32:38 -07001185 return com.android.systemui.R.layout.global_actions_grid_item_v2;
1186 }
1187 return com.android.systemui.R.layout.global_actions_grid_item;
1188 }
1189
Jason Monk361915c2017-03-21 20:33:59 -04001190 /**
Aran Inkcf038272020-03-31 17:48:37 -04001191 * The adapter used for power menu items shown in the global actions dialog.
Jason Monk361915c2017-03-21 20:33:59 -04001192 */
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001193 public class MyAdapter extends MultiListAdapter {
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001194 private int countItems(boolean separated) {
Jason Monk361915c2017-03-21 20:33:59 -04001195 int count = 0;
Jason Monk361915c2017-03-21 20:33:59 -04001196 for (int i = 0; i < mItems.size(); i++) {
1197 final Action action = mItems.get(i);
1198
Aran Inkcf038272020-03-31 17:48:37 -04001199 if (action.shouldBeSeparated() == separated) {
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001200 count++;
Jason Monk361915c2017-03-21 20:33:59 -04001201 }
Jason Monk361915c2017-03-21 20:33:59 -04001202 }
1203 return count;
1204 }
1205
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001206 @Override
1207 public int countSeparatedItems() {
1208 return countItems(true);
1209 }
1210
1211 @Override
1212 public int countListItems() {
1213 return countItems(false);
1214 }
1215
1216 @Override
1217 public int getCount() {
1218 return countSeparatedItems() + countListItems();
1219 }
1220
Jason Monk361915c2017-03-21 20:33:59 -04001221 @Override
1222 public boolean isEnabled(int position) {
1223 return getItem(position).isEnabled();
1224 }
1225
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001226 @Override
Jason Monk361915c2017-03-21 20:33:59 -04001227 public boolean areAllItemsEnabled() {
1228 return false;
1229 }
1230
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001231 @Override
Jason Monk361915c2017-03-21 20:33:59 -04001232 public Action getItem(int position) {
Jason Monk361915c2017-03-21 20:33:59 -04001233 int filteredPos = 0;
1234 for (int i = 0; i < mItems.size(); i++) {
1235 final Action action = mItems.get(i);
Aran Inkcf038272020-03-31 17:48:37 -04001236 if (!shouldShowAction(action)) {
Jason Monk361915c2017-03-21 20:33:59 -04001237 continue;
1238 }
1239 if (filteredPos == position) {
1240 return action;
1241 }
1242 filteredPos++;
1243 }
1244
1245 throw new IllegalArgumentException("position " + position
1246 + " out of range of showable actions"
1247 + ", filtered count=" + getCount()
1248 + ", keyguardshowing=" + mKeyguardShowing
1249 + ", provisioned=" + mDeviceProvisioned);
1250 }
1251
1252
1253 public long getItemId(int position) {
1254 return position;
1255 }
1256
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001257 @Override
Jason Monk361915c2017-03-21 20:33:59 -04001258 public View getView(int position, View convertView, ViewGroup parent) {
1259 Action action = getItem(position);
Jason Monk16fbd9d2017-04-27 14:28:49 -04001260 View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001261 view.setOnClickListener(v -> onClickItem(position));
Aran Inkb4199d92020-02-07 13:25:21 -05001262 if (action instanceof LongPressAction) {
1263 view.setOnLongClickListener(v -> onLongClickItem(position));
1264 }
Jason Monk16fbd9d2017-04-27 14:28:49 -04001265 return view;
Jason Monk361915c2017-03-21 20:33:59 -04001266 }
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001267
1268 @Override
1269 public boolean onLongClickItem(int position) {
1270 final Action action = mAdapter.getItem(position);
1271 if (action instanceof LongPressAction) {
Aran Inkbaa25862019-06-11 15:48:55 -04001272 if (mDialog != null) {
1273 mDialog.dismiss();
1274 } else {
1275 Log.w(TAG, "Action long-clicked while mDialog is null.");
1276 }
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001277 return ((LongPressAction) action).onLongPress();
1278 }
1279 return false;
1280 }
1281
1282 @Override
1283 public void onClickItem(int position) {
1284 Action item = mAdapter.getItem(position);
1285 if (!(item instanceof SilentModeTriStateAction)) {
Aran Inkbaa25862019-06-11 15:48:55 -04001286 if (mDialog != null) {
1287 mDialog.dismiss();
1288 } else {
1289 Log.w(TAG, "Action clicked while mDialog is null.");
1290 }
1291 item.onPress();
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001292 }
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001293 }
Aaron Heuckroth5e28f8c82019-04-24 13:26:12 -04001294
1295 @Override
1296 public boolean shouldBeSeparated(int position) {
1297 return getItem(position).shouldBeSeparated();
1298 }
Jason Monk361915c2017-03-21 20:33:59 -04001299 }
1300
Aran Inkcf038272020-03-31 17:48:37 -04001301 /**
1302 * The adapter used for items in the overflow menu.
1303 */
1304 public class MyOverflowAdapter extends BaseAdapter {
1305 @Override
1306 public int getCount() {
Aran Inka65e68362020-04-14 15:23:24 -04001307 return mOverflowItems.size();
Aran Inkcf038272020-03-31 17:48:37 -04001308 }
1309
1310 @Override
1311 public Action getItem(int position) {
Aran Inka65e68362020-04-14 15:23:24 -04001312 return mOverflowItems.get(position);
Aran Inkcf038272020-03-31 17:48:37 -04001313 }
1314
1315 @Override
1316 public long getItemId(int position) {
1317 return position;
1318 }
1319
1320 @Override
1321 public View getView(int position, View convertView, ViewGroup parent) {
1322 Action action = getItem(position);
1323 if (action == null) {
1324 Log.w(TAG, "No overflow action found at position: " + position);
1325 return null;
1326 }
1327 int viewLayoutResource = com.android.systemui.R.layout.controls_more_item;
1328 View view = convertView != null ? convertView
1329 : LayoutInflater.from(mContext).inflate(viewLayoutResource, parent, false);
1330 TextView textView = (TextView) view;
1331 textView.setOnClickListener(v -> onClickItem(position));
1332 if (action.getMessageResId() != 0) {
1333 textView.setText(action.getMessageResId());
1334 } else {
1335 textView.setText(action.getMessage());
1336 }
1337
1338 if (action instanceof LongPressAction) {
1339 textView.setOnLongClickListener(v -> onLongClickItem(position));
1340 } else {
1341 textView.setOnLongClickListener(null);
1342 }
1343 return textView;
1344 }
1345
1346 private boolean onLongClickItem(int position) {
1347 final Action action = getItem(position);
1348 if (action instanceof LongPressAction) {
1349 if (mDialog != null) {
1350 mDialog.hidePowerOverflowMenu();
1351 mDialog.dismiss();
1352 } else {
1353 Log.w(TAG, "Action long-clicked while mDialog is null.");
1354 }
1355 return ((LongPressAction) action).onLongPress();
1356 }
1357 return false;
1358 }
1359
1360 private void onClickItem(int position) {
1361 Action item = getItem(position);
1362 if (!(item instanceof SilentModeTriStateAction)) {
1363 if (mDialog != null) {
1364 mDialog.hidePowerOverflowMenu();
1365 mDialog.dismiss();
1366 } else {
1367 Log.w(TAG, "Action clicked while mDialog is null.");
1368 }
1369 item.onPress();
1370 }
1371 }
1372 }
1373
Jason Monk361915c2017-03-21 20:33:59 -04001374 // note: the scheme below made more sense when we were planning on having
1375 // 8 different things in the global actions dialog. seems overkill with
1376 // only 3 items now, but may as well keep this flexible approach so it will
1377 // be easy should someone decide at the last minute to include something
1378 // else, such as 'enable wifi', or 'enable bluetooth'
1379
1380 /**
1381 * What each item in the global actions dialog must be able to support.
1382 */
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05001383 public interface Action {
Jason Monk361915c2017-03-21 20:33:59 -04001384 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001385 * @return Text that will be announced when dialog is created. null for none.
Jason Monk361915c2017-03-21 20:33:59 -04001386 */
1387 CharSequence getLabelForAccessibility(Context context);
1388
1389 View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
1390
1391 void onPress();
1392
1393 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001394 * @return whether this action should appear in the dialog when the keygaurd is showing.
Jason Monk361915c2017-03-21 20:33:59 -04001395 */
1396 boolean showDuringKeyguard();
1397
1398 /**
Aran Inkcf038272020-03-31 17:48:37 -04001399 * @return whether this action should appear in the dialog before the
1400 * device is provisioned.f
Jason Monk361915c2017-03-21 20:33:59 -04001401 */
1402 boolean showBeforeProvisioning();
1403
1404 boolean isEnabled();
Aaron Heuckrothf708d472019-01-10 16:54:51 -05001405
1406 default boolean shouldBeSeparated() {
1407 return false;
1408 }
Aran Inkcf038272020-03-31 17:48:37 -04001409
1410 /**
1411 * Return the id of the message associated with this action, or 0 if it doesn't have one.
1412 * @return
1413 */
1414 int getMessageResId();
1415
1416 /**
1417 * Return the message associated with this action, or null if it doesn't have one.
1418 * @return
1419 */
1420 CharSequence getMessage();
Jason Monk361915c2017-03-21 20:33:59 -04001421 }
1422
1423 /**
1424 * An action that also supports long press.
1425 */
1426 private interface LongPressAction extends Action {
1427 boolean onLongPress();
1428 }
1429
1430 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001431 * A single press action maintains no state, just responds to a press and takes an action.
Jason Monk361915c2017-03-21 20:33:59 -04001432 */
Matt Pietale0661b62020-01-29 14:35:31 -05001433
1434 private abstract class SinglePressAction implements Action {
Jason Monk361915c2017-03-21 20:33:59 -04001435 private final int mIconResId;
1436 private final Drawable mIcon;
1437 private final int mMessageResId;
1438 private final CharSequence mMessage;
1439
1440 protected SinglePressAction(int iconResId, int messageResId) {
1441 mIconResId = iconResId;
1442 mMessageResId = messageResId;
1443 mMessage = null;
1444 mIcon = null;
1445 }
1446
1447 protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
1448 mIconResId = iconResId;
1449 mMessageResId = 0;
1450 mMessage = message;
1451 mIcon = icon;
1452 }
1453
1454 public boolean isEnabled() {
1455 return true;
1456 }
1457
1458 public String getStatus() {
1459 return null;
1460 }
1461
1462 abstract public void onPress();
1463
1464 public CharSequence getLabelForAccessibility(Context context) {
1465 if (mMessage != null) {
1466 return mMessage;
1467 } else {
1468 return context.getString(mMessageResId);
1469 }
1470 }
1471
Aran Inkcf038272020-03-31 17:48:37 -04001472
1473 public int getMessageResId() {
1474 return mMessageResId;
1475 }
1476
1477 public CharSequence getMessage() {
1478 return mMessage;
1479 }
1480
Jason Monk361915c2017-03-21 20:33:59 -04001481 public View create(
1482 Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
Lucas Dupincb6726f2020-04-07 19:32:38 -07001483 View v = inflater.inflate(getActionLayoutId(), parent, false /* attach */);
Jason Monk361915c2017-03-21 20:33:59 -04001484
Lucas Dupincb6726f2020-04-07 19:32:38 -07001485 ImageView icon = v.findViewById(R.id.icon);
1486 TextView messageView = v.findViewById(R.id.message);
Aaron Heuckroth3f2d8b52019-04-05 13:27:51 -04001487 messageView.setSelected(true); // necessary for marquee to work
Jason Monk361915c2017-03-21 20:33:59 -04001488
Jason Monk361915c2017-03-21 20:33:59 -04001489 if (mIcon != null) {
1490 icon.setImageDrawable(mIcon);
1491 icon.setScaleType(ScaleType.CENTER_CROP);
1492 } else if (mIconResId != 0) {
1493 icon.setImageDrawable(context.getDrawable(mIconResId));
1494 }
1495 if (mMessage != null) {
1496 messageView.setText(mMessage);
1497 } else {
1498 messageView.setText(mMessageResId);
1499 }
1500
1501 return v;
1502 }
1503 }
1504
Lucas Dupincb6726f2020-04-07 19:32:38 -07001505 private enum ToggleState {
1506 Off(false),
1507 TurningOn(true),
1508 TurningOff(true),
1509 On(false);
1510
1511 private final boolean mInTransition;
1512
1513 ToggleState(boolean intermediate) {
1514 mInTransition = intermediate;
1515 }
1516
1517 public boolean inTransition() {
1518 return mInTransition;
1519 }
1520 }
1521
Jason Monk361915c2017-03-21 20:33:59 -04001522 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001523 * A toggle action knows whether it is on or off, and displays an icon and status message
1524 * accordingly.
Jason Monk361915c2017-03-21 20:33:59 -04001525 */
Lucas Dupincb6726f2020-04-07 19:32:38 -07001526 private abstract class ToggleAction implements Action {
Jason Monk361915c2017-03-21 20:33:59 -04001527
Lucas Dupincb6726f2020-04-07 19:32:38 -07001528 protected ToggleState mState = ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001529
1530 // prefs
1531 protected int mEnabledIconResId;
1532 protected int mDisabledIconResid;
1533 protected int mMessageResId;
1534 protected int mEnabledStatusMessageResId;
1535 protected int mDisabledStatusMessageResId;
1536
1537 /**
Jason Monk16fbd9d2017-04-27 14:28:49 -04001538 * @param enabledIconResId The icon for when this action is on.
1539 * @param disabledIconResid The icon for when this action is off.
1540 * @param message The general information message, e.g 'Silent Mode'
1541 * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
Jason Monk361915c2017-03-21 20:33:59 -04001542 * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
1543 */
1544 public ToggleAction(int enabledIconResId,
1545 int disabledIconResid,
1546 int message,
1547 int enabledStatusMessageResId,
1548 int disabledStatusMessageResId) {
1549 mEnabledIconResId = enabledIconResId;
1550 mDisabledIconResid = disabledIconResid;
1551 mMessageResId = message;
1552 mEnabledStatusMessageResId = enabledStatusMessageResId;
1553 mDisabledStatusMessageResId = disabledStatusMessageResId;
1554 }
1555
1556 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001557 * Override to make changes to resource IDs just before creating the View.
Jason Monk361915c2017-03-21 20:33:59 -04001558 */
1559 void willCreate() {
1560
1561 }
1562
1563 @Override
1564 public CharSequence getLabelForAccessibility(Context context) {
1565 return context.getString(mMessageResId);
1566 }
1567
Aran Inkcf038272020-03-31 17:48:37 -04001568 private boolean isOn() {
1569 return mState == ToggleState.On || mState == ToggleState.TurningOn;
1570 }
1571
1572 @Override
1573 public CharSequence getMessage() {
1574 return null;
1575 }
1576 @Override
1577 public int getMessageResId() {
1578 return isOn() ? mEnabledStatusMessageResId : mDisabledStatusMessageResId;
1579 }
1580
1581 private int getIconResId() {
1582 return isOn() ? mEnabledIconResId : mDisabledIconResid;
1583 }
1584
Jason Monk361915c2017-03-21 20:33:59 -04001585 public View create(Context context, View convertView, ViewGroup parent,
1586 LayoutInflater inflater) {
1587 willCreate();
1588
Lucas Dupincb6726f2020-04-07 19:32:38 -07001589 View v = inflater.inflate(getActionLayoutId(), parent, false /* attach */);
Jason Monk361915c2017-03-21 20:33:59 -04001590
1591 ImageView icon = (ImageView) v.findViewById(R.id.icon);
1592 TextView messageView = (TextView) v.findViewById(R.id.message);
Jason Monk361915c2017-03-21 20:33:59 -04001593 final boolean enabled = isEnabled();
1594
1595 if (messageView != null) {
Aran Inkcf038272020-03-31 17:48:37 -04001596 messageView.setText(getMessageResId());
Jason Monk361915c2017-03-21 20:33:59 -04001597 messageView.setEnabled(enabled);
Aaron Heuckroth3f2d8b52019-04-05 13:27:51 -04001598 messageView.setSelected(true); // necessary for marquee to work
Jason Monk361915c2017-03-21 20:33:59 -04001599 }
1600
Jason Monk361915c2017-03-21 20:33:59 -04001601 if (icon != null) {
Aran Inkcf038272020-03-31 17:48:37 -04001602 icon.setImageDrawable(context.getDrawable(getIconResId()));
Jason Monk361915c2017-03-21 20:33:59 -04001603 icon.setEnabled(enabled);
1604 }
1605
Jason Monk361915c2017-03-21 20:33:59 -04001606 v.setEnabled(enabled);
1607
1608 return v;
1609 }
1610
1611 public final void onPress() {
1612 if (mState.inTransition()) {
1613 Log.w(TAG, "shouldn't be able to toggle when in transition");
1614 return;
1615 }
1616
Lucas Dupincb6726f2020-04-07 19:32:38 -07001617 final boolean nowOn = !(mState == ToggleState.On);
Jason Monk361915c2017-03-21 20:33:59 -04001618 onToggle(nowOn);
1619 changeStateFromPress(nowOn);
1620 }
1621
1622 public boolean isEnabled() {
1623 return !mState.inTransition();
1624 }
1625
1626 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08001627 * Implementations may override this if their state can be in on of the intermediate states
1628 * until some notification is received (e.g airplane mode is 'turning off' until we know the
1629 * wireless connections are back online
Jason Monk16fbd9d2017-04-27 14:28:49 -04001630 *
Jason Monk361915c2017-03-21 20:33:59 -04001631 * @param buttonOn Whether the button was turned on or off
1632 */
1633 protected void changeStateFromPress(boolean buttonOn) {
Lucas Dupincb6726f2020-04-07 19:32:38 -07001634 mState = buttonOn ? ToggleState.On : ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001635 }
1636
1637 abstract void onToggle(boolean on);
1638
Lucas Dupincb6726f2020-04-07 19:32:38 -07001639 public void updateState(ToggleState state) {
Jason Monk361915c2017-03-21 20:33:59 -04001640 mState = state;
1641 }
1642 }
1643
Aran Ink780d4502020-02-14 10:39:58 -05001644 private class AirplaneModeAction extends ToggleAction {
1645 AirplaneModeAction() {
1646 super(
Sean Pont9d4fb032020-03-04 18:54:32 -08001647 R.drawable.ic_lock_airplane_mode,
1648 R.drawable.ic_lock_airplane_mode_off,
1649 R.string.global_actions_toggle_airplane_mode,
1650 R.string.global_actions_airplane_mode_on_status,
1651 R.string.global_actions_airplane_mode_off_status);
Aran Ink780d4502020-02-14 10:39:58 -05001652 }
Sean Pont9d4fb032020-03-04 18:54:32 -08001653
Aran Ink780d4502020-02-14 10:39:58 -05001654 void onToggle(boolean on) {
1655 if (mHasTelephony && TelephonyProperties.in_ecm_mode().orElse(false)) {
1656 mIsWaitingForEcmExit = true;
1657 // Launch ECM exit dialog
1658 Intent ecmDialogIntent =
1659 new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
1660 ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1661 mContext.startActivity(ecmDialogIntent);
1662 } else {
1663 changeAirplaneModeSystemSetting(on);
1664 }
1665 }
1666
1667 @Override
1668 protected void changeStateFromPress(boolean buttonOn) {
1669 if (!mHasTelephony) return;
1670
1671 // In ECM mode airplane state cannot be changed
1672 if (!TelephonyProperties.in_ecm_mode().orElse(false)) {
Lucas Dupincb6726f2020-04-07 19:32:38 -07001673 mState = buttonOn ? ToggleState.TurningOn : ToggleState.TurningOff;
Aran Ink780d4502020-02-14 10:39:58 -05001674 mAirplaneState = mState;
1675 }
1676 }
1677
1678 public boolean showDuringKeyguard() {
1679 return true;
1680 }
1681
1682 public boolean showBeforeProvisioning() {
1683 return false;
1684 }
1685 }
1686
Jason Monk361915c2017-03-21 20:33:59 -04001687 private class SilentModeToggleAction extends ToggleAction {
1688 public SilentModeToggleAction() {
1689 super(R.drawable.ic_audio_vol_mute,
1690 R.drawable.ic_audio_vol,
1691 R.string.global_action_toggle_silent_mode,
1692 R.string.global_action_silent_mode_on_status,
1693 R.string.global_action_silent_mode_off_status);
1694 }
1695
1696 void onToggle(boolean on) {
1697 if (on) {
1698 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
1699 } else {
1700 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
1701 }
1702 }
1703
1704 public boolean showDuringKeyguard() {
1705 return true;
1706 }
1707
1708 public boolean showBeforeProvisioning() {
1709 return false;
1710 }
1711 }
1712
1713 private static class SilentModeTriStateAction implements Action, View.OnClickListener {
1714
Jason Monk16fbd9d2017-04-27 14:28:49 -04001715 private final int[] ITEM_IDS = {R.id.option1, R.id.option2, R.id.option3};
Jason Monk361915c2017-03-21 20:33:59 -04001716
1717 private final AudioManager mAudioManager;
1718 private final Handler mHandler;
Jason Monk361915c2017-03-21 20:33:59 -04001719
Lucas Dupin40ec6b782018-06-05 19:07:16 -07001720 SilentModeTriStateAction(AudioManager audioManager, Handler handler) {
Jason Monk361915c2017-03-21 20:33:59 -04001721 mAudioManager = audioManager;
1722 mHandler = handler;
Jason Monk361915c2017-03-21 20:33:59 -04001723 }
1724
1725 private int ringerModeToIndex(int ringerMode) {
1726 // They just happen to coincide
1727 return ringerMode;
1728 }
1729
1730 private int indexToRingerMode(int index) {
1731 // They just happen to coincide
1732 return index;
1733 }
1734
1735 @Override
1736 public CharSequence getLabelForAccessibility(Context context) {
1737 return null;
1738 }
1739
Aran Inkcf038272020-03-31 17:48:37 -04001740 @Override
1741 public int getMessageResId() {
1742 return 0;
1743 }
1744
1745 @Override
1746 public CharSequence getMessage() {
1747 return null;
1748 }
1749
Jason Monk361915c2017-03-21 20:33:59 -04001750 public View create(Context context, View convertView, ViewGroup parent,
1751 LayoutInflater inflater) {
1752 View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
1753
1754 int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
1755 for (int i = 0; i < 3; i++) {
1756 View itemView = v.findViewById(ITEM_IDS[i]);
1757 itemView.setSelected(selectedIndex == i);
1758 // Set up click handler
1759 itemView.setTag(i);
1760 itemView.setOnClickListener(this);
1761 }
1762 return v;
1763 }
1764
1765 public void onPress() {
1766 }
1767
1768 public boolean showDuringKeyguard() {
1769 return true;
1770 }
1771
1772 public boolean showBeforeProvisioning() {
1773 return false;
1774 }
1775
1776 public boolean isEnabled() {
1777 return true;
1778 }
1779
1780 void willCreate() {
1781 }
1782
1783 public void onClick(View v) {
1784 if (!(v.getTag() instanceof Integer)) return;
1785
1786 int index = (Integer) v.getTag();
1787 mAudioManager.setRingerMode(indexToRingerMode(index));
1788 mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
1789 }
1790 }
1791
1792 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1793 public void onReceive(Context context, Intent intent) {
1794 String action = intent.getAction();
1795 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
1796 || Intent.ACTION_SCREEN_OFF.equals(action)) {
1797 String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
1798 if (!SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
Lucas Dupin1d4a5792018-04-02 15:14:59 -07001799 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISMISS, reason));
Jason Monk361915c2017-03-21 20:33:59 -04001800 }
Jayachandran C142eae02019-12-13 19:29:20 -08001801 } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
Jason Monk361915c2017-03-21 20:33:59 -04001802 // Airplane mode can be changed after ECM exits if airplane toggle button
1803 // is pressed during ECM mode
Daniel Bright4bcbfce2020-01-09 21:58:16 -08001804 if (!(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false))
1805 && mIsWaitingForEcmExit) {
Jason Monk361915c2017-03-21 20:33:59 -04001806 mIsWaitingForEcmExit = false;
1807 changeAirplaneModeSystemSetting(true);
1808 }
1809 }
1810 }
1811 };
1812
1813 PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
1814 @Override
1815 public void onServiceStateChanged(ServiceState serviceState) {
1816 if (!mHasTelephony) return;
1817 final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
Lucas Dupincb6726f2020-04-07 19:32:38 -07001818 mAirplaneState = inAirplaneMode ? ToggleState.On : ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001819 mAirplaneModeOn.updateState(mAirplaneState);
1820 mAdapter.notifyDataSetChanged();
1821 }
1822 };
1823
Matt Pietal677981d2020-04-24 14:38:32 -04001824 private ContentObserver mAirplaneModeObserver = new ContentObserver(mMainHandler) {
Jason Monk361915c2017-03-21 20:33:59 -04001825 @Override
1826 public void onChange(boolean selfChange) {
1827 onAirplaneModeChanged();
1828 }
1829 };
1830
1831 private static final int MESSAGE_DISMISS = 0;
1832 private static final int MESSAGE_REFRESH = 1;
Jason Monk361915c2017-03-21 20:33:59 -04001833 private static final int DIALOG_DISMISS_DELAY = 300; // ms
Lucas Dupin7387a862020-04-13 10:15:29 -07001834 private static final int DIALOG_PRESS_DELAY = 850; // ms
Chris Wrenaf4ce8462020-04-06 17:36:10 -04001835
1836 @VisibleForTesting void setZeroDialogPressDelayForTesting() {
1837 mDialogPressDelay = 0; // ms
1838 }
Jason Monk361915c2017-03-21 20:33:59 -04001839
1840 private Handler mHandler = new Handler() {
1841 public void handleMessage(Message msg) {
1842 switch (msg.what) {
Jason Monk16fbd9d2017-04-27 14:28:49 -04001843 case MESSAGE_DISMISS:
1844 if (mDialog != null) {
Lucas Dupin1d4a5792018-04-02 15:14:59 -07001845 if (SYSTEM_DIALOG_REASON_DREAM.equals(msg.obj)) {
Matt Pietalf4b870b2020-04-17 17:11:36 -04001846 mDialog.completeDismiss();
Lucas Dupin1d4a5792018-04-02 15:14:59 -07001847 } else {
1848 mDialog.dismiss();
1849 }
Jason Monk16fbd9d2017-04-27 14:28:49 -04001850 mDialog = null;
1851 }
1852 break;
1853 case MESSAGE_REFRESH:
1854 refreshSilentMode();
1855 mAdapter.notifyDataSetChanged();
1856 break;
Jason Monk361915c2017-03-21 20:33:59 -04001857 }
1858 }
1859 };
1860
1861 private void onAirplaneModeChanged() {
1862 // Let the service state callbacks handle the state.
1863 if (mHasTelephony) return;
1864
1865 boolean airplaneModeOn = Settings.Global.getInt(
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001866 mContentResolver,
Jason Monk361915c2017-03-21 20:33:59 -04001867 Settings.Global.AIRPLANE_MODE_ON,
1868 0) == 1;
Lucas Dupincb6726f2020-04-07 19:32:38 -07001869 mAirplaneState = airplaneModeOn ? ToggleState.On : ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001870 mAirplaneModeOn.updateState(mAirplaneState);
1871 }
1872
1873 /**
1874 * Change the airplane mode system setting
1875 */
1876 private void changeAirplaneModeSystemSetting(boolean on) {
1877 Settings.Global.putInt(
Dave Mankoffc88a2d72020-01-10 15:59:31 -05001878 mContentResolver,
Jason Monk361915c2017-03-21 20:33:59 -04001879 Settings.Global.AIRPLANE_MODE_ON,
1880 on ? 1 : 0);
1881 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
1882 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1883 intent.putExtra("state", on);
1884 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1885 if (!mHasTelephony) {
Lucas Dupincb6726f2020-04-07 19:32:38 -07001886 mAirplaneState = on ? ToggleState.On : ToggleState.Off;
Jason Monk361915c2017-03-21 20:33:59 -04001887 }
1888 }
1889
Fabian Kozynskib6a20372020-04-01 09:36:43 -04001890 @NonNull
1891 @Override
1892 public Lifecycle getLifecycle() {
1893 return mLifecycle;
1894 }
1895
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001896 private static final class ActionsDialog extends Dialog implements DialogInterface,
1897 ColorExtractor.OnColorsChangedListener {
Jason Monk361915c2017-03-21 20:33:59 -04001898
Jason Monk16fbd9d2017-04-27 14:28:49 -04001899 private final Context mContext;
1900 private final MyAdapter mAdapter;
Aran Inkcf038272020-03-31 17:48:37 -04001901 private final MyOverflowAdapter mOverflowAdapter;
Steve Elliott53f12ae2019-05-13 17:14:15 -04001902 private final IStatusBarService mStatusBarService;
1903 private final IBinder mToken = new Binder();
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05001904 private MultiListLayout mGlobalActionsLayout;
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04001905 private Drawable mBackgroundDrawable;
Lucas Dupin2bd3af62019-03-25 17:44:28 -07001906 private final SysuiColorExtractor mColorExtractor;
Steve Elliott9b87a442019-03-05 10:24:16 -05001907 private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001908 private boolean mKeyguardShowing;
Beverly526d2d62018-08-15 12:55:33 -04001909 private boolean mShowing;
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04001910 private float mScrimAlpha;
Steve Elliott48f75db2019-05-03 15:03:38 -04001911 private ResetOrientationData mResetOrientationData;
Steve Elliottff2c0d92019-07-30 15:09:54 -04001912 private boolean mHadTopUi;
wilsonshihe8321942019-10-18 18:39:46 +08001913 private final NotificationShadeWindowController mNotificationShadeWindowController;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -08001914 private final NotificationShadeDepthController mDepthController;
Lucas Dupin99f5fba2020-03-12 12:59:18 -07001915 private final BlurUtils mBlurUtils;
Aran Inka65e68362020-04-14 15:23:24 -04001916 private final boolean mUseControlsLayout;
Aran Inkcf038272020-03-31 17:48:37 -04001917 private ListPopupWindow mOverflowPopup;
Aran Inka65e68362020-04-14 15:23:24 -04001918 private final Runnable mOnRotateCallback;
Matt Pietal22231792020-01-23 09:51:09 -05001919
1920 private ControlsUiController mControlsUiController;
1921 private ViewGroup mControlsView;
Lucas Dupin5f9c8632020-04-20 14:47:43 -07001922 private ViewGroup mContainer;
Jason Monk16fbd9d2017-04-27 14:28:49 -04001923
Aran Inkcf038272020-03-31 17:48:37 -04001924 ActionsDialog(Context context, MyAdapter adapter, MyOverflowAdapter overflowAdapter,
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -08001925 GlobalActionsPanelPlugin.PanelViewController plugin,
1926 NotificationShadeDepthController depthController,
Lucas Dupin991415e2019-11-25 17:48:58 -08001927 SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
1928 NotificationShadeWindowController notificationShadeWindowController,
Aran Inka65e68362020-04-14 15:23:24 -04001929 ControlsUiController controlsUiController, BlurUtils blurUtils,
Aran Ink99c452d2020-04-28 14:23:13 -04001930 boolean useControlsLayout, Runnable onRotateCallback, boolean keyguardShowing) {
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001931 super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
Lucas Dupin448786c2017-07-24 17:44:25 -07001932 mContext = context;
Jason Monk16fbd9d2017-04-27 14:28:49 -04001933 mAdapter = adapter;
Aran Inkcf038272020-03-31 17:48:37 -04001934 mOverflowAdapter = overflowAdapter;
Santiago Etchebehere68eb53e2020-02-25 14:25:34 -08001935 mDepthController = depthController;
Lucas Dupin991415e2019-11-25 17:48:58 -08001936 mColorExtractor = sysuiColorExtractor;
1937 mStatusBarService = statusBarService;
1938 mNotificationShadeWindowController = notificationShadeWindowController;
Matt Pietal22231792020-01-23 09:51:09 -05001939 mControlsUiController = controlsUiController;
Lucas Dupin99f5fba2020-03-12 12:59:18 -07001940 mBlurUtils = blurUtils;
Aran Inka65e68362020-04-14 15:23:24 -04001941 mUseControlsLayout = useControlsLayout;
1942 mOnRotateCallback = onRotateCallback;
Aran Ink99c452d2020-04-28 14:23:13 -04001943 mKeyguardShowing = keyguardShowing;
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001944
1945 // Window initialization
1946 Window window = getWindow();
1947 window.requestFeature(Window.FEATURE_NO_TITLE);
Adrian Roosedfab3b2018-03-08 18:39:20 +01001948 // Inflate the decor view, so the attributes below are not overwritten by the theme.
1949 window.getDecorView();
1950 window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
1951 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
1952 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1953 window.setLayout(MATCH_PARENT, MATCH_PARENT);
1954 window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
Alison Cichowlas4f19f4a2017-07-25 10:56:16 -04001955 window.addFlags(
1956 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
Sean Pont9d4fb032020-03-04 18:54:32 -08001957 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
1958 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
1959 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
1960 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
1961 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
Lucas Dupinc1cc7592017-05-22 15:56:16 -07001962 window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
Tiger Huang52724442020-01-20 21:38:42 +08001963 window.getAttributes().setFitInsetsTypes(0 /* types */);
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05001964 setTitle(R.string.global_actions);
Steve Elliott9b87a442019-03-05 10:24:16 -05001965
1966 mPanelController = plugin;
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04001967 initializeLayout();
Steve Elliott9b87a442019-03-05 10:24:16 -05001968 }
1969
Matt Pietal677981d2020-04-24 14:38:32 -04001970 private boolean isShowingControls() {
1971 return mControlsUiController != null;
1972 }
1973
1974 private void showControls(ControlsUiController controller) {
1975 mControlsUiController = controller;
1976 mControlsUiController.show(mControlsView, this::dismissForControlsActivity);
1977 }
1978
Aaron Heuckrothc7926612019-04-02 14:21:57 -04001979 private boolean shouldUsePanel() {
Aran Ink3f594552019-05-13 14:29:35 -04001980 return mPanelController != null && mPanelController.getPanelContent() != null;
Aaron Heuckrothc7926612019-04-02 14:21:57 -04001981 }
1982
1983 private void initializePanel() {
Steve Elliott48f75db2019-05-03 15:03:38 -04001984 int rotation = RotationUtils.getRotation(mContext);
1985 boolean rotationLocked = RotationPolicy.isRotationLocked(mContext);
1986 if (rotation != RotationUtils.ROTATION_NONE) {
1987 if (rotationLocked) {
1988 if (mResetOrientationData == null) {
1989 mResetOrientationData = new ResetOrientationData();
1990 mResetOrientationData.locked = true;
1991 mResetOrientationData.rotation = rotation;
1992 }
1993
1994 // Unlock rotation, so user can choose to rotate to portrait to see the panel.
Steve Elliotte05817f2019-05-17 14:39:53 -04001995 // This call is posted so that the rotation does not change until post-layout,
1996 // otherwise onConfigurationChanged() may not get invoked.
1997 mGlobalActionsLayout.post(() ->
1998 RotationPolicy.setRotationLockAtAngle(
1999 mContext, false, RotationUtils.ROTATION_NONE));
Steve Elliott48f75db2019-05-03 15:03:38 -04002000 }
2001 } else {
2002 if (!rotationLocked) {
2003 if (mResetOrientationData == null) {
2004 mResetOrientationData = new ResetOrientationData();
2005 mResetOrientationData.locked = false;
2006 }
2007
2008 // Lock to portrait, so the user doesn't accidentally hide the panel.
Steve Elliotte05817f2019-05-17 14:39:53 -04002009 // This call is posted so that the rotation does not change until post-layout,
2010 // otherwise onConfigurationChanged() may not get invoked.
2011 mGlobalActionsLayout.post(() ->
2012 RotationPolicy.setRotationLockAtAngle(
2013 mContext, true, RotationUtils.ROTATION_NONE));
Steve Elliott48f75db2019-05-03 15:03:38 -04002014 }
2015
Steve Elliott53f12ae2019-05-13 17:14:15 -04002016 // Disable rotation suggestions, if enabled
2017 setRotationSuggestionsEnabled(false);
2018
Steve Elliott300b48f2019-05-29 14:13:50 -04002019 FrameLayout panelContainer =
2020 findViewById(com.android.systemui.R.id.global_actions_panel_container);
Steve Elliott48f75db2019-05-03 15:03:38 -04002021 FrameLayout.LayoutParams panelParams =
2022 new FrameLayout.LayoutParams(
2023 FrameLayout.LayoutParams.MATCH_PARENT,
Steve Elliott300b48f2019-05-29 14:13:50 -04002024 FrameLayout.LayoutParams.MATCH_PARENT);
Steve Elliott48f75db2019-05-03 15:03:38 -04002025 panelContainer.addView(mPanelController.getPanelContent(), panelParams);
Steve Elliott48f75db2019-05-03 15:03:38 -04002026 }
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002027 }
2028
Aran Inkcf038272020-03-31 17:48:37 -04002029 private ListPopupWindow createPowerOverflowPopup() {
Matt Pietalf74554f2020-04-29 13:43:55 -04002030 ListPopupWindow popup = new GlobalActionsPopupMenu(
2031 mContext, false /* isDropDownMode */);
Aran Inkcf038272020-03-31 17:48:37 -04002032 View overflowButton =
2033 findViewById(com.android.systemui.R.id.global_actions_overflow_button);
2034 popup.setAnchorView(overflowButton);
Aran Inkcf038272020-03-31 17:48:37 -04002035 popup.setAdapter(mOverflowAdapter);
Aran Inkcf038272020-03-31 17:48:37 -04002036 return popup;
2037 }
2038
2039 private void showPowerOverflowMenu() {
Matt Pietalf74554f2020-04-29 13:43:55 -04002040 mOverflowPopup = createPowerOverflowPopup();
Aran Inkcf038272020-03-31 17:48:37 -04002041 mOverflowPopup.show();
2042 }
2043
2044 private void hidePowerOverflowMenu() {
2045 mOverflowPopup.dismiss();
Matt Pietalf74554f2020-04-29 13:43:55 -04002046 mOverflowPopup = null;
Aran Inkcf038272020-03-31 17:48:37 -04002047 }
2048
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002049 private void initializeLayout() {
2050 setContentView(getGlobalActionsLayoutId(mContext));
Steve Elliott300b48f2019-05-29 14:13:50 -04002051 fixNavBarClipping();
Matt Pietal22231792020-01-23 09:51:09 -05002052 mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls);
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04002053 mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
Aaron Heuckrothf708d472019-01-10 16:54:51 -05002054 mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
Phil Weaver9054e092018-04-27 16:28:50 -07002055 @Override
2056 public boolean dispatchPopulateAccessibilityEvent(
2057 View host, AccessibilityEvent event) {
2058 // Populate the title here, just as Activity does
2059 event.getText().add(mContext.getString(R.string.global_actions));
2060 return true;
2061 }
2062 });
Aaron Heuckroth4ea2fdb2019-02-14 16:28:35 -05002063 mGlobalActionsLayout.setRotationListener(this::onRotate);
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05002064 mGlobalActionsLayout.setAdapter(mAdapter);
Lucas Dupin5f9c8632020-04-20 14:47:43 -07002065 mContainer = findViewById(com.android.systemui.R.id.global_actions_container);
2066 // Some legacy dialog layouts don't have the outer container
2067 if (mContainer == null) {
2068 mContainer = mGlobalActionsLayout;
2069 }
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04002070
Aran Inkcf038272020-03-31 17:48:37 -04002071 View overflowButton = findViewById(
2072 com.android.systemui.R.id.global_actions_overflow_button);
2073 if (overflowButton != null) {
Matt Pietal677981d2020-04-24 14:38:32 -04002074 if (mOverflowAdapter.getCount() > 0) {
Aran Inkcf038272020-03-31 17:48:37 -04002075 overflowButton.setOnClickListener((view) -> showPowerOverflowMenu());
Aran Ink7c8fea92020-04-17 14:40:14 -04002076 LinearLayout.LayoutParams params =
2077 (LinearLayout.LayoutParams) mGlobalActionsLayout.getLayoutParams();
2078 params.setMarginEnd(0);
2079 mGlobalActionsLayout.setLayoutParams(params);
Aran Inkcf038272020-03-31 17:48:37 -04002080 } else {
2081 overflowButton.setVisibility(View.GONE);
Aran Ink7c8fea92020-04-17 14:40:14 -04002082 LinearLayout.LayoutParams params =
2083 (LinearLayout.LayoutParams) mGlobalActionsLayout.getLayoutParams();
2084 params.setMarginEnd(mContext.getResources().getDimensionPixelSize(
2085 com.android.systemui.R.dimen.global_actions_side_margin));
2086 mGlobalActionsLayout.setLayoutParams(params);
Aran Inkcf038272020-03-31 17:48:37 -04002087 }
2088 }
2089
Steve Elliott86ef6282019-05-08 14:45:04 -04002090 if (shouldUsePanel()) {
Steve Elliottc59eb342019-04-23 16:59:06 -04002091 initializePanel();
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04002092 }
Steve Elliott86ef6282019-05-08 14:45:04 -04002093 if (mBackgroundDrawable == null) {
2094 mBackgroundDrawable = new ScrimDrawable();
Aran Inka65e68362020-04-14 15:23:24 -04002095 if (mUseControlsLayout) {
Lucas Dupin3a8531e2020-04-06 17:18:09 -07002096 mScrimAlpha = 1.0f;
2097 } else {
2098 mScrimAlpha = mBlurUtils.supportsBlursOnWindows()
2099 ? ScrimController.BLUR_SCRIM_ALPHA : ScrimController.BUSY_SCRIM_ALPHA;
2100 }
Steve Elliott86ef6282019-05-08 14:45:04 -04002101 }
Steve Elliotte9e7e1f2019-03-18 15:54:59 -04002102 getWindow().setBackgroundDrawable(mBackgroundDrawable);
Steve Elliott9b87a442019-03-05 10:24:16 -05002103 }
2104
Steve Elliott300b48f2019-05-29 14:13:50 -04002105 private void fixNavBarClipping() {
2106 ViewGroup content = findViewById(android.R.id.content);
2107 content.setClipChildren(false);
2108 content.setClipToPadding(false);
2109 ViewGroup contentParent = (ViewGroup) content.getParent();
2110 contentParent.setClipChildren(false);
2111 contentParent.setClipToPadding(false);
2112 }
2113
Aaron Heuckroth166392f2019-01-17 16:50:59 -05002114 private int getGlobalActionsLayoutId(Context context) {
Aran Inka65e68362020-04-14 15:23:24 -04002115 if (mUseControlsLayout) {
Matt Pietalfd3b6cb2020-01-08 09:43:54 -05002116 return com.android.systemui.R.layout.global_actions_grid_v2;
2117 }
2118
Steve Elliottdc165632019-05-23 14:26:31 -04002119 int rotation = RotationUtils.getRotation(context);
2120 boolean useGridLayout = isForceGridEnabled(context)
2121 || (shouldUsePanel() && rotation == RotationUtils.ROTATION_NONE);
2122 if (rotation == RotationUtils.ROTATION_SEASCAPE) {
Aaron Heuckrothe2d92ac2019-05-01 10:44:59 -04002123 if (useGridLayout) {
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002124 return com.android.systemui.R.layout.global_actions_grid_seascape;
Aaron Heuckrothe2d92ac2019-05-01 10:44:59 -04002125 } else {
2126 return com.android.systemui.R.layout.global_actions_column_seascape;
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002127 }
Aaron Heuckrothe2d92ac2019-05-01 10:44:59 -04002128 } else {
2129 if (useGridLayout) {
2130 return com.android.systemui.R.layout.global_actions_grid;
2131 } else {
2132 return com.android.systemui.R.layout.global_actions_column;
2133 }
Aaron Heuckroth166392f2019-01-17 16:50:59 -05002134 }
Aaron Heuckroth166392f2019-01-17 16:50:59 -05002135 }
2136
Jason Monk361915c2017-03-21 20:33:59 -04002137 @Override
2138 protected void onStart() {
2139 super.setCanceledOnTouchOutside(true);
2140 super.onStart();
Aaron Heuckroth57d60d22019-03-05 14:00:12 -05002141 mGlobalActionsLayout.updateList();
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002142
Lucas Dupin2bd3af62019-03-25 17:44:28 -07002143 if (mBackgroundDrawable instanceof ScrimDrawable) {
Steve Elliott9b87a442019-03-05 10:24:16 -05002144 mColorExtractor.addOnColorsChangedListener(this);
Lucas Dupin2bd3af62019-03-25 17:44:28 -07002145 GradientColors colors = mColorExtractor.getNeutralColors();
Steve Elliott9b87a442019-03-05 10:24:16 -05002146 updateColors(colors, false /* animate */);
2147 }
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002148 }
2149
2150 /**
2151 * Updates background and system bars according to current GradientColors.
Sean Pont9d4fb032020-03-04 18:54:32 -08002152 *
2153 * @param colors Colors and hints to use.
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002154 * @param animate Interpolates gradient if true, just sets otherwise.
2155 */
2156 private void updateColors(GradientColors colors, boolean animate) {
Lucas Dupin2bd3af62019-03-25 17:44:28 -07002157 if (!(mBackgroundDrawable instanceof ScrimDrawable)) {
Steve Elliott9b87a442019-03-05 10:24:16 -05002158 return;
2159 }
Lucas Dupin3a8531e2020-04-06 17:18:09 -07002160 ((ScrimDrawable) mBackgroundDrawable).setColor(
Aran Inka65e68362020-04-14 15:23:24 -04002161 !mUseControlsLayout && colors.supportsDarkText()
2162 ? Color.WHITE : Color.BLACK, animate);
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002163 View decorView = getWindow().getDecorView();
2164 if (colors.supportsDarkText()) {
2165 decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
Steve Elliott9b87a442019-03-05 10:24:16 -05002166 View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002167 } else {
2168 decorView.setSystemUiVisibility(0);
2169 }
Jason Monk361915c2017-03-21 20:33:59 -04002170 }
2171
2172 @Override
Jason Monk16fbd9d2017-04-27 14:28:49 -04002173 protected void onStop() {
2174 super.onStop();
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002175 mColorExtractor.removeOnColorsChangedListener(this);
Jason Monk16fbd9d2017-04-27 14:28:49 -04002176 }
2177
2178 @Override
2179 public void show() {
2180 super.show();
Beverly526d2d62018-08-15 12:55:33 -04002181 mShowing = true;
wilsonshihe8321942019-10-18 18:39:46 +08002182 mHadTopUi = mNotificationShadeWindowController.getForceHasTopUi();
2183 mNotificationShadeWindowController.setForceHasTopUi(true);
Matt Pietale9440b72020-05-01 11:36:01 -04002184
Lucas Dupin26571e92020-04-08 14:55:10 -07002185 ViewGroup root = (ViewGroup) mGlobalActionsLayout.getRootView();
2186 root.setOnApplyWindowInsetsListener((v, windowInsets) -> {
Aran Inka65e68362020-04-14 15:23:24 -04002187 if (mUseControlsLayout) {
Lucas Dupin2b353e62020-04-14 18:23:01 -07002188 root.setPadding(windowInsets.getStableInsetLeft(),
2189 windowInsets.getStableInsetTop(),
2190 windowInsets.getStableInsetRight(),
2191 windowInsets.getStableInsetBottom());
Lucas Dupin26571e92020-04-08 14:55:10 -07002192 }
2193 return WindowInsets.CONSUMED;
2194 });
Matt Pietal22231792020-01-23 09:51:09 -05002195 if (mControlsUiController != null) {
Matt Pietalf4b870b2020-04-17 17:11:36 -04002196 mControlsUiController.show(mControlsView, this::dismissForControlsActivity);
Matt Pietal22231792020-01-23 09:51:09 -05002197 }
Matt Pietale9440b72020-05-01 11:36:01 -04002198
2199 mBackgroundDrawable.setAlpha(0);
2200 float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
2201 ObjectAnimator alphaAnimator =
2202 ObjectAnimator.ofFloat(mContainer, "transitionAlpha", 0f, 1f);
2203 alphaAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
2204 alphaAnimator.setDuration(183);
2205 alphaAnimator.addUpdateListener((animation) -> {
2206 float animatedValue = animation.getAnimatedFraction();
2207 int alpha = (int) (animatedValue * mScrimAlpha * 255);
2208 mBackgroundDrawable.setAlpha(alpha);
2209 mDepthController.updateGlobalDialogVisibility(animatedValue,
2210 mGlobalActionsLayout);
2211 });
2212
2213 ObjectAnimator xAnimator =
2214 ObjectAnimator.ofFloat(mContainer, "translationX", xOffset, 0f);
2215 alphaAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
2216 alphaAnimator.setDuration(350);
2217
2218 AnimatorSet animatorSet = new AnimatorSet();
2219 animatorSet.playTogether(alphaAnimator, xAnimator);
2220 animatorSet.start();
Jason Monk16fbd9d2017-04-27 14:28:49 -04002221 }
2222
2223 @Override
2224 public void dismiss() {
Matt Pietalf4b870b2020-04-17 17:11:36 -04002225 dismissWithAnimation(() -> {
Lucas Dupin5f9c8632020-04-20 14:47:43 -07002226 mContainer.setTranslationX(0);
Matt Pietale9440b72020-05-01 11:36:01 -04002227 ObjectAnimator alphaAnimator =
2228 ObjectAnimator.ofFloat(mContainer, "transitionAlpha", 1f, 0f);
2229 alphaAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
2230 alphaAnimator.setDuration(233);
2231 alphaAnimator.addUpdateListener((animation) -> {
2232 float animatedValue = 1f - animation.getAnimatedFraction();
2233 int alpha = (int) (animatedValue * mScrimAlpha * 255);
2234 mBackgroundDrawable.setAlpha(alpha);
2235 mDepthController.updateGlobalDialogVisibility(animatedValue,
2236 mGlobalActionsLayout);
2237 });
2238
2239 float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
2240 ObjectAnimator xAnimator =
2241 ObjectAnimator.ofFloat(mContainer, "translationX", 0f, xOffset);
2242 alphaAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
2243 alphaAnimator.setDuration(350);
2244
2245 AnimatorSet animatorSet = new AnimatorSet();
2246 animatorSet.playTogether(alphaAnimator, xAnimator);
2247 animatorSet.addListener(new AnimatorListenerAdapter() {
2248 public void onAnimationEnd(Animator animation) {
2249 completeDismiss();
2250 }
2251 });
2252
2253 animatorSet.start();
2254
2255 // close first, as popup windows will not fade during the animation
2256 dismissOverflow(false);
2257 if (mControlsUiController != null) mControlsUiController.closeDialogs(false);
Matt Pietalf4b870b2020-04-17 17:11:36 -04002258 });
2259 }
2260
2261 private void dismissForControlsActivity() {
2262 dismissWithAnimation(() -> {
Matt Pietald8a6ca62020-04-21 15:00:15 -04002263 ViewGroup root = (ViewGroup) mGlobalActionsLayout.getParent();
Matt Pietalf4b870b2020-04-17 17:11:36 -04002264 ControlsAnimations.exitAnimation(root, this::completeDismiss).start();
2265 });
2266 }
2267
2268 void dismissWithAnimation(Runnable animation) {
Beverly526d2d62018-08-15 12:55:33 -04002269 if (!mShowing) {
2270 return;
2271 }
2272 mShowing = false;
Matt Pietalf4b870b2020-04-17 17:11:36 -04002273 animation.run();
Steve Elliottff2c0d92019-07-30 15:09:54 -04002274 }
2275
2276 private void completeDismiss() {
Matt Pietalf4b870b2020-04-17 17:11:36 -04002277 mShowing = false;
2278 resetOrientation();
2279 dismissPanel();
Aran Inkd397b902020-04-21 17:53:41 -04002280 dismissOverflow(true);
Matt Pietalf4b870b2020-04-17 17:11:36 -04002281 if (mControlsUiController != null) mControlsUiController.hide();
wilsonshihe8321942019-10-18 18:39:46 +08002282 mNotificationShadeWindowController.setForceHasTopUi(mHadTopUi);
Lucas Dupin77198562020-03-31 14:16:16 -07002283 mDepthController.updateGlobalDialogVisibility(0, null /* view */);
Steve Elliottff2c0d92019-07-30 15:09:54 -04002284 super.dismiss();
Steve Elliott48f75db2019-05-03 15:03:38 -04002285 }
2286
2287 private void dismissPanel() {
Steve Elliott2d206d32019-03-14 16:30:33 -04002288 if (mPanelController != null) {
2289 mPanelController.onDismissed();
2290 }
Lucas Dupin1d4a5792018-04-02 15:14:59 -07002291 }
2292
Aran Inkd397b902020-04-21 17:53:41 -04002293 private void dismissOverflow(boolean immediate) {
Aran Ink6560ab72020-04-20 16:04:29 -04002294 if (mOverflowPopup != null) {
Aran Inkd397b902020-04-21 17:53:41 -04002295 if (immediate) {
2296 mOverflowPopup.dismissImmediate();
2297 } else {
2298 mOverflowPopup.dismiss();
2299 }
Aran Ink6560ab72020-04-20 16:04:29 -04002300 }
2301 }
2302
Steve Elliott53f12ae2019-05-13 17:14:15 -04002303 private void setRotationSuggestionsEnabled(boolean enabled) {
2304 try {
2305 final int userId = Binder.getCallingUserHandle().getIdentifier();
2306 final int what = enabled
2307 ? StatusBarManager.DISABLE2_NONE
2308 : StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS;
2309 mStatusBarService.disable2ForUser(what, mToken, mContext.getPackageName(), userId);
2310 } catch (RemoteException ex) {
2311 throw ex.rethrowFromSystemServer();
2312 }
2313 }
2314
Steve Elliott48f75db2019-05-03 15:03:38 -04002315 private void resetOrientation() {
2316 if (mResetOrientationData != null) {
2317 RotationPolicy.setRotationLockAtAngle(mContext, mResetOrientationData.locked,
2318 mResetOrientationData.rotation);
2319 }
Steve Elliott53f12ae2019-05-13 17:14:15 -04002320 setRotationSuggestionsEnabled(true);
Steve Elliott48f75db2019-05-03 15:03:38 -04002321 }
2322
Jason Monk361915c2017-03-21 20:33:59 -04002323 @Override
Lucas Dupin7aaa3532017-05-28 08:51:07 -07002324 public void onColorsChanged(ColorExtractor extractor, int which) {
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002325 if (mKeyguardShowing) {
2326 if ((WallpaperManager.FLAG_LOCK & which) != 0) {
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002327 updateColors(extractor.getColors(WallpaperManager.FLAG_LOCK),
2328 true /* animate */);
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002329 }
2330 } else {
2331 if ((WallpaperManager.FLAG_SYSTEM & which) != 0) {
Lucas Dupinb5f59fe2017-09-14 17:09:39 -07002332 updateColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM),
2333 true /* animate */);
Lucas Dupinc1cc7592017-05-22 15:56:16 -07002334 }
2335 }
2336 }
2337
2338 public void setKeyguardShowing(boolean keyguardShowing) {
2339 mKeyguardShowing = keyguardShowing;
2340 }
Aaron Heuckroth4ea2fdb2019-02-14 16:28:35 -05002341
Aaron Heuckroth4ef3a542019-04-01 14:17:23 -04002342 public void refreshDialog() {
2343 initializeLayout();
2344 mGlobalActionsLayout.updateList();
Aran Inka65e68362020-04-14 15:23:24 -04002345 if (mControlsUiController != null) {
Matt Pietalf4b870b2020-04-17 17:11:36 -04002346 mControlsUiController.show(mControlsView, this::dismissForControlsActivity);
Aran Inka65e68362020-04-14 15:23:24 -04002347 }
Aaron Heuckroth4ef3a542019-04-01 14:17:23 -04002348 }
2349
Aaron Heuckroth4ea2fdb2019-02-14 16:28:35 -05002350 public void onRotate(int from, int to) {
Aaron Heuckrothe2d92ac2019-05-01 10:44:59 -04002351 if (mShowing) {
Aran Inka65e68362020-04-14 15:23:24 -04002352 mOnRotateCallback.run();
Aaron Heuckroth4ef3a542019-04-01 14:17:23 -04002353 refreshDialog();
Aaron Heuckroth4ea2fdb2019-02-14 16:28:35 -05002354 }
2355 }
Steve Elliott48f75db2019-05-03 15:03:38 -04002356
2357 private static class ResetOrientationData {
2358 public boolean locked;
2359 public int rotation;
2360 }
Jason Monk361915c2017-03-21 20:33:59 -04002361 }
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002362
2363 /**
Aran Ink93dd25c2019-05-09 14:42:14 -04002364 * Determines whether or not debug mode has been activated for the Global Actions Panel.
2365 */
2366 private static boolean isPanelDebugModeEnabled(Context context) {
2367 return Settings.Secure.getInt(context.getContentResolver(),
2368 Settings.Secure.GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED, 0) == 1;
2369 }
2370
2371 /**
Sean Pont9d4fb032020-03-04 18:54:32 -08002372 * Determines whether or not the Global Actions menu should be forced to use the newer
2373 * grid-style layout.
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002374 */
Aaron Heuckrothc7926612019-04-02 14:21:57 -04002375 private static boolean isForceGridEnabled(Context context) {
Aran Ink93dd25c2019-05-09 14:42:14 -04002376 return isPanelDebugModeEnabled(context);
Aaron Heuckroth75e249f2019-02-01 15:59:57 -05002377 }
Aaron Heuckrothf19d2722019-03-11 17:06:02 -04002378
Aran Inkcf038272020-03-31 17:48:37 -04002379 @VisibleForTesting
2380 protected boolean shouldShowControls() {
Matt Pietal677981d2020-04-24 14:38:32 -04002381 boolean isUnlocked = mKeyguardStateController.isUnlocked()
2382 || mKeyguardStateController.canDismissLockScreen();
2383 return (isUnlocked || mShowLockScreenCardsAndControls)
Fabian Kozynski0424ab12020-02-21 12:09:17 -05002384 && mControlsUiController.getAvailable()
Matt Pietalcd757c82020-04-08 10:20:48 -04002385 && !mControlsServiceInfos.isEmpty();
Matt Pietalfd3b6cb2020-01-08 09:43:54 -05002386 }
Aran Inka65e68362020-04-14 15:23:24 -04002387 // TODO: Remove legacy layout XML and classes.
2388 protected boolean shouldUseControlsLayout() {
2389 // always use new controls layout
2390 return true;
2391 }
Matt Pietal677981d2020-04-24 14:38:32 -04002392
2393 private void onPowerMenuLockScreenSettingsChanged() {
2394 mShowLockScreenCardsAndControls = Settings.Secure.getInt(mContentResolver,
2395 Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 0) != 0;
2396 }
Matt Pietalf4b870b2020-04-17 17:11:36 -04002397}