blob: c84f3db8acb037e86c0289cd586ee60182f9c65e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Joe Onoratofd52b182010-11-10 18:00:52 -080017package com.android.systemui.statusbar.phone;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Wale Ogunwale68278562017-09-23 17:13:55 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
20import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
21import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
22import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
23
Jason Monk697b82a2017-04-19 18:41:06 -040024import android.app.ActivityManager;
Jason Monk324b8862017-02-16 17:19:12 -050025import android.app.ActivityManager.StackInfo;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070026import android.app.ActivityTaskManager;
Jason Monk697b82a2017-04-19 18:41:06 -040027import android.app.AlarmManager;
John Spurlock604a5ee2015-06-01 12:27:22 -040028import android.app.AlarmManager.AlarmClockInfo;
Jason Monk697b82a2017-04-19 18:41:06 -040029import android.app.AppGlobals;
30import android.app.Notification;
Jason Monk324b8862017-02-16 17:19:12 -050031import android.app.Notification.Action;
Jason Monk697b82a2017-04-19 18:41:06 -040032import android.app.NotificationManager;
33import android.app.PendingIntent;
34import android.app.SynchronousUserSwitchObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.content.BroadcastReceiver;
Jason Monk697b82a2017-04-19 18:41:06 -040036import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.content.Context;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.content.Intent;
39import android.content.IntentFilter;
Jason Monk324b8862017-02-16 17:19:12 -050040import android.content.pm.ApplicationInfo;
41import android.content.pm.IPackageManager;
42import android.content.pm.PackageManager;
Jason Monk324b8862017-02-16 17:19:12 -050043import android.graphics.drawable.Icon;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.media.AudioManager;
Jason Monk324b8862017-02-16 17:19:12 -050045import android.net.Uri;
46import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.Handler;
Kenny Guy3094d4a2015-04-01 19:14:10 +010048import android.os.RemoteException;
Adrian Roosc42a1e12014-07-07 23:35:53 +020049import android.os.UserHandle;
Kenny Guy3094d4a2015-04-01 19:14:10 +010050import android.os.UserManager;
Jason Monk324b8862017-02-16 17:19:12 -050051import android.provider.Settings;
John Spurlockae641c92014-06-30 18:11:40 -040052import android.provider.Settings.Global;
Jason Monk324b8862017-02-16 17:19:12 -050053import android.service.notification.StatusBarNotification;
Beverlyb9826dd2018-04-12 15:02:45 -040054import android.service.notification.ZenModeConfig;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070055import android.telecom.TelecomManager;
Evan Lairdbee3eb82018-05-16 15:58:49 -040056import android.text.format.DateFormat;
Jason Monk324b8862017-02-16 17:19:12 -050057import android.util.ArraySet;
John Spurlockcd686b52013-06-05 10:13:46 -040058import android.util.Log;
Jason Monk324b8862017-02-16 17:19:12 -050059import android.util.Pair;
Beverlyff2df9b2018-10-10 16:54:10 -040060
Jason Monk324b8862017-02-16 17:19:12 -050061import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Wink Savillea639b312012-07-10 12:37:54 -070062import com.android.internal.telephony.IccCardConstants;
Wink Saville04e71b32009-04-02 11:00:54 -070063import com.android.internal.telephony.TelephonyIntents;
Jason Monk9c7844c2017-01-18 15:21:53 -050064import com.android.systemui.Dependency;
Jason Monkf85fc962017-04-19 17:13:41 -040065import com.android.systemui.DockedStackExistsListener;
Joe Onorato798ac4c2010-05-27 16:39:00 -040066import com.android.systemui.R;
Jason Monkaa573e92017-01-27 17:00:29 -050067import com.android.systemui.SysUiServiceProvider;
Jorim Jaggifabc7432017-05-15 02:40:05 +020068import com.android.systemui.UiOffloadThread;
Evan Lairdcf1a1032018-11-14 13:46:08 -050069import com.android.systemui.privacy.PrivacyItem;
70import com.android.systemui.privacy.PrivacyItemController;
John Spurlock3c4076a2015-02-24 12:12:25 -050071import com.android.systemui.qs.tiles.DndTile;
Jason Monk3e189872016-01-12 09:10:34 -050072import com.android.systemui.qs.tiles.RotationLockTile;
Winson Chung2cf6ad82017-11-09 17:36:59 -080073import com.android.systemui.shared.system.ActivityManagerWrapper;
Winson Chung67f5c8b2018-09-24 12:09:19 -070074import com.android.systemui.shared.system.TaskStackChangeListener;
Jason Monkaa573e92017-01-27 17:00:29 -050075import com.android.systemui.statusbar.CommandQueue;
76import com.android.systemui.statusbar.CommandQueue.Callbacks;
Jason Monk70364362015-08-06 16:32:18 -040077import com.android.systemui.statusbar.policy.BluetoothController;
78import com.android.systemui.statusbar.policy.BluetoothController.Callback;
John Spurlock96fe98d2014-08-27 09:36:02 -040079import com.android.systemui.statusbar.policy.CastController;
80import com.android.systemui.statusbar.policy.CastController.CastDevice;
Jason Monkf23aa992016-01-22 16:45:21 -050081import com.android.systemui.statusbar.policy.DataSaverController;
Jason Monkaa573e92017-01-27 17:00:29 -050082import com.android.systemui.statusbar.policy.DataSaverController.Listener;
83import com.android.systemui.statusbar.policy.DeviceProvisionedController;
84import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
Jason Monk952d5d82014-10-27 15:28:22 -040085import com.android.systemui.statusbar.policy.HotspotController;
Jason Monkaa573e92017-01-27 17:00:29 -050086import com.android.systemui.statusbar.policy.KeyguardMonitor;
Jason Monk359bb742017-04-13 10:40:40 -040087import com.android.systemui.statusbar.policy.LocationController;
88import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
Juan Flores2ff37202015-04-30 13:44:23 +020089import com.android.systemui.statusbar.policy.NextAlarmController;
Jason Monk3e189872016-01-12 09:10:34 -050090import com.android.systemui.statusbar.policy.RotationLockController;
Jason Monkaa573e92017-01-27 17:00:29 -050091import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
Adrian Roos88b11932015-07-22 14:59:48 -070092import com.android.systemui.statusbar.policy.UserInfoController;
Jason Monkaa573e92017-01-27 17:00:29 -050093import com.android.systemui.statusbar.policy.ZenModeController;
Jason Monk324b8862017-02-16 17:19:12 -050094import com.android.systemui.util.NotificationChannels;
95
Jason Monk697b82a2017-04-19 18:41:06 -040096import java.util.List;
Evan Lairdbee3eb82018-05-16 15:58:49 -040097import java.util.Locale;
Jason Monk697b82a2017-04-19 18:41:06 -040098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099/**
100 * This class contains all of the policy about which icons are installed in the status
Joe Onorato798ac4c2010-05-27 16:39:00 -0400101 * bar at boot time. It goes through the normal API for icons, even though it probably
102 * strictly doesn't need to.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 */
Jason Monkaa573e92017-01-27 17:00:29 -0500104public class PhoneStatusBarPolicy implements Callback, Callbacks,
Jason Monk359bb742017-04-13 10:40:40 -0400105 RotationLockControllerCallback, Listener, LocationChangeCallback,
Evan Lairdcf1a1032018-11-14 13:46:08 -0500106 ZenModeController.Callback, DeviceProvisionedListener, KeyguardMonitor.Callback,
107 PrivacyItemController.Callback {
Joe Onoratofd52b182010-11-10 18:00:52 -0800108 private static final String TAG = "PhoneStatusBarPolicy";
John Spurlocka37e9c82014-07-08 09:40:31 -0400109 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Robert Greenwaltd7085fc2010-09-08 15:24:47 -0700110
Jason Monk359bb742017-04-13 10:40:40 -0400111 public static final int LOCATION_STATUS_ICON_ID = R.drawable.stat_sys_location;
Jason Monk697b82a2017-04-19 18:41:06 -0400112 public static final int NUM_TASKS_FOR_INSTANT_APP_INFO = 5;
Jason Monk359bb742017-04-13 10:40:40 -0400113
Jason Monk3e189872016-01-12 09:10:34 -0500114 private final String mSlotCast;
115 private final String mSlotHotspot;
116 private final String mSlotBluetooth;
117 private final String mSlotTty;
118 private final String mSlotZen;
119 private final String mSlotVolume;
120 private final String mSlotAlarmClock;
121 private final String mSlotManagedProfile;
122 private final String mSlotRotate;
123 private final String mSlotHeadset;
Jason Monkf23aa992016-01-22 16:45:21 -0500124 private final String mSlotDataSaver;
Jason Monk359bb742017-04-13 10:40:40 -0400125 private final String mSlotLocation;
Evan Lairdcf1a1032018-11-14 13:46:08 -0500126 private final String mSlotMicrophone;
127 private final String mSlotCamera;
John Spurlocka37e9c82014-07-08 09:40:31 -0400128
Dianne Hackborn4840e142009-03-24 22:40:29 -0700129 private final Context mContext;
Joe Onorato10523b4d2010-10-25 10:42:46 -0700130 private final Handler mHandler = new Handler();
John Spurlock96fe98d2014-08-27 09:36:02 -0400131 private final CastController mCast;
Jason Monk952d5d82014-10-27 15:28:22 -0400132 private final HotspotController mHotspot;
Evan Lairdbee3eb82018-05-16 15:58:49 -0400133 private final NextAlarmController mNextAlarmController;
John Spurlock15782262015-05-29 15:35:53 -0400134 private final AlarmManager mAlarmManager;
Adrian Roos88b11932015-07-22 14:59:48 -0700135 private final UserInfoController mUserInfoController;
Rubin Xu1205fb12015-11-04 17:45:03 +0000136 private final UserManager mUserManager;
Jason Monk07473ce2016-01-05 14:59:19 -0500137 private final StatusBarIconController mIconController;
Jason Monk3e189872016-01-12 09:10:34 -0500138 private final RotationLockController mRotationLockController;
Jason Monkf23aa992016-01-22 16:45:21 -0500139 private final DataSaverController mDataSaver;
Jason Monkaa573e92017-01-27 17:00:29 -0500140 private final ZenModeController mZenController;
141 private final DeviceProvisionedController mProvisionedController;
142 private final KeyguardMonitor mKeyguardMonitor;
Jason Monk359bb742017-04-13 10:40:40 -0400143 private final LocationController mLocationController;
Evan Lairdcf1a1032018-11-14 13:46:08 -0500144 private final PrivacyItemController mPrivacyItemController;
Jason Monk324b8862017-02-16 17:19:12 -0500145 private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>();
Jorim Jaggifabc7432017-05-15 02:40:05 +0200146 private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 // Assume it's all good unless we hear otherwise. We don't always seem
149 // to get broadcasts that it *is* there.
Wink Savillea639b312012-07-10 12:37:54 -0700150 IccCardConstants.State mSimState = IccCardConstants.State.READY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151
John Spurlocka37e9c82014-07-08 09:40:31 -0400152 private boolean mZenVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 private boolean mVolumeVisible;
John Spurlock604a5ee2015-06-01 12:27:22 -0400154 private boolean mCurrentUserSetup;
Jason Monkf85fc962017-04-19 17:13:41 -0400155 private boolean mDockedStackExists;
Wink Saville04e71b32009-04-02 11:00:54 -0700156
Rubin Xu1205fb12015-11-04 17:45:03 +0000157 private boolean mManagedProfileIconVisible = false;
Kenny Guy3094d4a2015-04-01 19:14:10 +0100158
Jason Monk70364362015-08-06 16:32:18 -0400159 private BluetoothController mBluetooth;
Evan Lairdbee3eb82018-05-16 15:58:49 -0400160 private AlarmManager.AlarmClockInfo mNextAlarm;
Wink Savillee9b06d72009-05-18 21:47:50 -0700161
Jason Monk9c7844c2017-01-18 15:21:53 -0500162 public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 mContext = context;
Jason Monk07473ce2016-01-05 14:59:19 -0500164 mIconController = iconController;
Jason Monk9c7844c2017-01-18 15:21:53 -0500165 mCast = Dependency.get(CastController.class);
166 mHotspot = Dependency.get(HotspotController.class);
167 mBluetooth = Dependency.get(BluetoothController.class);
Evan Lairdbee3eb82018-05-16 15:58:49 -0400168 mNextAlarmController = Dependency.get(NextAlarmController.class);
John Spurlock15782262015-05-29 15:35:53 -0400169 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Jason Monk9c7844c2017-01-18 15:21:53 -0500170 mUserInfoController = Dependency.get(UserInfoController.class);
Rubin Xu1205fb12015-11-04 17:45:03 +0000171 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Jason Monk9c7844c2017-01-18 15:21:53 -0500172 mRotationLockController = Dependency.get(RotationLockController.class);
173 mDataSaver = Dependency.get(DataSaverController.class);
Jason Monkaa573e92017-01-27 17:00:29 -0500174 mZenController = Dependency.get(ZenModeController.class);
175 mProvisionedController = Dependency.get(DeviceProvisionedController.class);
176 mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
Jason Monk359bb742017-04-13 10:40:40 -0400177 mLocationController = Dependency.get(LocationController.class);
Evan Lairdcf1a1032018-11-14 13:46:08 -0500178 mPrivacyItemController = new PrivacyItemController(mContext, this);
Jason Monk3e189872016-01-12 09:10:34 -0500179
180 mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
181 mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
182 mSlotBluetooth = context.getString(com.android.internal.R.string.status_bar_bluetooth);
183 mSlotTty = context.getString(com.android.internal.R.string.status_bar_tty);
184 mSlotZen = context.getString(com.android.internal.R.string.status_bar_zen);
185 mSlotVolume = context.getString(com.android.internal.R.string.status_bar_volume);
186 mSlotAlarmClock = context.getString(com.android.internal.R.string.status_bar_alarm_clock);
187 mSlotManagedProfile = context.getString(
188 com.android.internal.R.string.status_bar_managed_profile);
189 mSlotRotate = context.getString(com.android.internal.R.string.status_bar_rotate);
190 mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);
Jason Monkf23aa992016-01-22 16:45:21 -0500191 mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);
Jason Monk359bb742017-04-13 10:40:40 -0400192 mSlotLocation = context.getString(com.android.internal.R.string.status_bar_location);
Evan Lairdcf1a1032018-11-14 13:46:08 -0500193 mSlotMicrophone = context.getString(com.android.internal.R.string.status_bar_microphone);
194 mSlotCamera = context.getString(com.android.internal.R.string.status_bar_camera);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
Daniel Sandlere3b7a2d2011-10-27 16:16:15 -0400196 // listen for broadcasts
197 IntentFilter filter = new IntentFilter();
Daniel Sandlere3b7a2d2011-10-27 16:16:15 -0400198 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
John Spurlockbcc10872014-11-28 15:29:21 -0500199 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
Jason Monk3e189872016-01-12 09:10:34 -0500200 filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
Daniel Sandlere3b7a2d2011-10-27 16:16:15 -0400201 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700202 filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
Rubin Xue95057a2016-04-01 16:49:25 +0100203 filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
204 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Nicolas Prevot6c7b8742016-04-13 10:28:58 +0100205 filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Daniel Sandlere3b7a2d2011-10-27 16:16:15 -0400206 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
207
Kenny Guy3094d4a2015-04-01 19:14:10 +0100208 // listen for user / profile change.
209 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800210 ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG);
Kenny Guy3094d4a2015-04-01 19:14:10 +0100211 } catch (RemoteException e) {
212 // Ignore
213 }
214
Wink Saville04e71b32009-04-02 11:00:54 -0700215 // TTY status
Hall Liu108ca202017-07-24 15:19:04 -0700216 updateTTY();
Wink Saville04e71b32009-04-02 11:00:54 -0700217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 // bluetooth status
Jorim Jaggi2d75f9f2014-10-08 17:10:58 -0700219 updateBluetooth();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 // Alarm clock
Jason Monk3e189872016-01-12 09:10:34 -0500222 mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
223 mIconController.setIconVisibility(mSlotAlarmClock, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224
John Spurlocka37e9c82014-07-08 09:40:31 -0400225 // zen
Jason Monk3e189872016-01-12 09:10:34 -0500226 mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null);
227 mIconController.setIconVisibility(mSlotZen, false);
John Spurlocka37e9c82014-07-08 09:40:31 -0400228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 // volume
Jason Monk3e189872016-01-12 09:10:34 -0500230 mIconController.setIcon(mSlotVolume, R.drawable.stat_sys_ringer_vibrate, null);
231 mIconController.setIconVisibility(mSlotVolume, false);
John Spurlocka37e9c82014-07-08 09:40:31 -0400232 updateVolumeZen();
John Spurlock96fe98d2014-08-27 09:36:02 -0400233
234 // cast
Jason Monk3e189872016-01-12 09:10:34 -0500235 mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
236 mIconController.setIconVisibility(mSlotCast, false);
Jason Monk952d5d82014-10-27 15:28:22 -0400237
238 // hotspot
Jason Monk3e189872016-01-12 09:10:34 -0500239 mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
Jason Monk08187a42015-06-09 14:33:51 -0400240 mContext.getString(R.string.accessibility_status_bar_hotspot));
Jason Monk3e189872016-01-12 09:10:34 -0500241 mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());
Kenny Guy3094d4a2015-04-01 19:14:10 +0100242
243 // managed profile
Jason Monk3e189872016-01-12 09:10:34 -0500244 mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,
Adrian Roos1b5eb972015-06-11 18:22:52 -0700245 mContext.getString(R.string.accessibility_managed_profile));
Jason Monk3e189872016-01-12 09:10:34 -0500246 mIconController.setIconVisibility(mSlotManagedProfile, mManagedProfileIconVisible);
Jason Monkf23aa992016-01-22 16:45:21 -0500247
248 // data saver
249 mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
250 context.getString(R.string.accessibility_data_saver_on));
251 mIconController.setIconVisibility(mSlotDataSaver, false);
Jason Monkaa573e92017-01-27 17:00:29 -0500252
Evan Lairdcf1a1032018-11-14 13:46:08 -0500253 // privacy items
254 mIconController.setIcon(mSlotMicrophone, R.drawable.stat_sys_mic_none, null);
255 mIconController.setIconVisibility(mSlotMicrophone, false);
256 mIconController.setIcon(mSlotCamera, R.drawable.stat_sys_camera, null);
257 mIconController.setIconVisibility(mSlotCamera, false);
258
Jason Monkaa573e92017-01-27 17:00:29 -0500259 mRotationLockController.addCallback(this);
260 mBluetooth.addCallback(this);
261 mProvisionedController.addCallback(this);
262 mZenController.addCallback(this);
263 mCast.addCallback(mCastCallback);
264 mHotspot.addCallback(mHotspotCallback);
Evan Lairdbee3eb82018-05-16 15:58:49 -0400265 mNextAlarmController.addCallback(mNextAlarmCallback);
Jason Monk88529052016-11-04 13:29:58 -0400266 mDataSaver.addCallback(this);
Jason Monkaa573e92017-01-27 17:00:29 -0500267 mKeyguardMonitor.addCallback(this);
Jason Monk359bb742017-04-13 10:40:40 -0400268 mLocationController.addCallback(this);
Evan Lairdcf1a1032018-11-14 13:46:08 -0500269 mPrivacyItemController.setListening(true);
Jason Monkaa573e92017-01-27 17:00:29 -0500270
271 SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
Winson Chung2cf6ad82017-11-09 17:36:59 -0800272 ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
Jason Monk324b8862017-02-16 17:19:12 -0500273
274 // Clear out all old notifications on startup (only present in the case where sysui dies)
275 NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
276 for (StatusBarNotification notification : noMan.getActiveNotifications()) {
277 if (notification.getId() == SystemMessage.NOTE_INSTANT_APPS) {
278 noMan.cancel(notification.getTag(), notification.getId());
279 }
280 }
Jason Monkf85fc962017-04-19 17:13:41 -0400281 DockedStackExistsListener.register(exists -> {
282 mDockedStackExists = exists;
283 updateForegroundInstantApps();
284 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 }
286
Jason Monkaa573e92017-01-27 17:00:29 -0500287 public void destroy() {
288 mRotationLockController.removeCallback(this);
289 mBluetooth.removeCallback(this);
290 mProvisionedController.removeCallback(this);
291 mZenController.removeCallback(this);
292 mCast.removeCallback(mCastCallback);
293 mHotspot.removeCallback(mHotspotCallback);
Evan Lairdbee3eb82018-05-16 15:58:49 -0400294 mNextAlarmController.removeCallback(mNextAlarmCallback);
Jason Monkaa573e92017-01-27 17:00:29 -0500295 mDataSaver.removeCallback(this);
296 mKeyguardMonitor.removeCallback(this);
Jason Monk359bb742017-04-13 10:40:40 -0400297 mLocationController.removeCallback(this);
Evan Lairdcf1a1032018-11-14 13:46:08 -0500298 mPrivacyItemController.setListening(false);
Jason Monkaa573e92017-01-27 17:00:29 -0500299 SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallbacks(this);
300 mContext.unregisterReceiver(mIntentReceiver);
Jason Monk324b8862017-02-16 17:19:12 -0500301
302 NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
303 mCurrentNotifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS,
304 new UserHandle(v.second)));
Nicolas Prevot1dbbe7d2016-05-17 12:52:54 +0100305 }
306
Jason Monkaa573e92017-01-27 17:00:29 -0500307 @Override
308 public void onZenChanged(int zen) {
John Spurlocka37e9c82014-07-08 09:40:31 -0400309 updateVolumeZen();
John Spurlockba2c6a02014-05-19 09:44:06 -0400310 }
311
Jason Monk359bb742017-04-13 10:40:40 -0400312 @Override
Beverlyb9826dd2018-04-12 15:02:45 -0400313 public void onConfigChanged(ZenModeConfig config) {
314 updateVolumeZen();
315 }
316
317 @Override
Jason Monk359bb742017-04-13 10:40:40 -0400318 public void onLocationActiveChanged(boolean active) {
319 updateLocation();
320 }
321
322 // Updates the status view based on the current state of location requests.
323 private void updateLocation() {
324 if (mLocationController.isLocationActive()) {
325 mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
326 mContext.getString(R.string.accessibility_location_active));
327 } else {
Evan Lairde1d13c92018-03-20 16:58:01 -0400328 mIconController.removeAllIconsForSlot(mSlotLocation);
Jason Monk359bb742017-04-13 10:40:40 -0400329 }
330 }
331
Adrian Roosc42a1e12014-07-07 23:35:53 +0200332 private void updateAlarm() {
John Spurlock604a5ee2015-06-01 12:27:22 -0400333 final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
334 final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
Jason Monk20c0eb42017-03-02 17:35:49 -0500335 int zen = mZenController.getZen();
336 final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
Jason Monk3e189872016-01-12 09:10:34 -0500337 mIconController.setIcon(mSlotAlarmClock, zenNone ? R.drawable.stat_sys_alarm_dim
Evan Lairdbee3eb82018-05-16 15:58:49 -0400338 : R.drawable.stat_sys_alarm, buildAlarmContentDescription());
Jason Monk3e189872016-01-12 09:10:34 -0500339 mIconController.setIconVisibility(mSlotAlarmClock, mCurrentUserSetup && hasAlarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 }
341
Evan Lairdbee3eb82018-05-16 15:58:49 -0400342 private String buildAlarmContentDescription() {
343 if (mNextAlarm == null) {
344 return mContext.getString(R.string.status_bar_alarm);
345 }
346 return formatNextAlarm(mNextAlarm, mContext);
347 }
348
349 private static String formatNextAlarm(AlarmManager.AlarmClockInfo info, Context context) {
350 if (info == null) {
351 return "";
352 }
353 String skeleton = DateFormat.is24HourFormat(
354 context, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
355 String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
356 String dateString = DateFormat.format(pattern, info.getTriggerTime()).toString();
357
358 return context.getString(R.string.accessibility_quick_settings_alarm, dateString);
359 }
360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 private final void updateSimState(Intent intent) {
Wink Savillea639b312012-07-10 12:37:54 -0700362 String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
363 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
364 mSimState = IccCardConstants.State.ABSENT;
Jason Monk07473ce2016-01-05 14:59:19 -0500365 } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
Rakesh Pallerlaf099a5f2013-02-06 11:44:23 +0530366 mSimState = IccCardConstants.State.CARD_IO_ERROR;
Junda Liua2f6a672016-05-24 10:07:40 -0700367 } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED.equals(stateExtra)) {
368 mSimState = IccCardConstants.State.CARD_RESTRICTED;
Jason Monk07473ce2016-01-05 14:59:19 -0500369 } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
Wink Savillea639b312012-07-10 12:37:54 -0700370 mSimState = IccCardConstants.State.READY;
Jason Monk07473ce2016-01-05 14:59:19 -0500371 } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
Wink Savillea639b312012-07-10 12:37:54 -0700372 final String lockedReason =
373 intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
374 if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
375 mSimState = IccCardConstants.State.PIN_REQUIRED;
Jason Monk07473ce2016-01-05 14:59:19 -0500376 } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
Wink Savillea639b312012-07-10 12:37:54 -0700377 mSimState = IccCardConstants.State.PUK_REQUIRED;
Jason Monk07473ce2016-01-05 14:59:19 -0500378 } else {
Wink Savillea639b312012-07-10 12:37:54 -0700379 mSimState = IccCardConstants.State.NETWORK_LOCKED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 }
381 } else {
Wink Savillea639b312012-07-10 12:37:54 -0700382 mSimState = IccCardConstants.State.UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 }
385
John Spurlockbcc10872014-11-28 15:29:21 -0500386 private final void updateVolumeZen() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
John Spurlocka37e9c82014-07-08 09:40:31 -0400388
389 boolean zenVisible = false;
390 int zenIconId = 0;
391 String zenDescription = null;
392
393 boolean volumeVisible = false;
394 int volumeIconId = 0;
395 String volumeDescription = null;
Jason Monk20c0eb42017-03-02 17:35:49 -0500396 int zen = mZenController.getZen();
John Spurlocka37e9c82014-07-08 09:40:31 -0400397
John Spurlockf88d8082015-03-25 18:09:51 -0400398 if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) {
Jason Monk20c0eb42017-03-02 17:35:49 -0500399 zenVisible = zen != Global.ZEN_MODE_OFF;
Evan Lairda9adbd52018-05-16 11:32:08 -0400400 zenIconId = R.drawable.stat_sys_dnd;
John Spurlock3c4076a2015-02-24 12:12:25 -0500401 zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
Jason Monk20c0eb42017-03-02 17:35:49 -0500402 } else if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
John Spurlocka37e9c82014-07-08 09:40:31 -0400403 zenVisible = true;
404 zenIconId = R.drawable.stat_sys_zen_none;
John Spurlockd9c75db2015-04-28 11:19:13 -0400405 zenDescription = mContext.getString(R.string.interruption_level_none);
Jason Monk20c0eb42017-03-02 17:35:49 -0500406 } else if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
John Spurlocka37e9c82014-07-08 09:40:31 -0400407 zenVisible = true;
408 zenIconId = R.drawable.stat_sys_zen_important;
John Spurlockd9c75db2015-04-28 11:19:13 -0400409 zenDescription = mContext.getString(R.string.interruption_level_priority);
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700410 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411
Beverlyff2df9b2018-10-10 16:54:10 -0400412 if (!ZenModeConfig.isZenOverridingRinger(zen, mZenController.getConsolidatedPolicy())) {
Beverlyb9826dd2018-04-12 15:02:45 -0400413 if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
414 volumeVisible = true;
415 volumeIconId = R.drawable.stat_sys_ringer_vibrate;
416 volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
417 } else if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
418 volumeVisible = true;
419 volumeIconId = R.drawable.stat_sys_ringer_silent;
420 volumeDescription = mContext.getString(R.string.accessibility_ringer_silent);
421 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 }
John Spurlocka37e9c82014-07-08 09:40:31 -0400423
424 if (zenVisible) {
Jason Monk3e189872016-01-12 09:10:34 -0500425 mIconController.setIcon(mSlotZen, zenIconId, zenDescription);
John Spurlocka37e9c82014-07-08 09:40:31 -0400426 }
427 if (zenVisible != mZenVisible) {
Jason Monk3e189872016-01-12 09:10:34 -0500428 mIconController.setIconVisibility(mSlotZen, zenVisible);
John Spurlocka37e9c82014-07-08 09:40:31 -0400429 mZenVisible = zenVisible;
430 }
431
432 if (volumeVisible) {
Jason Monk3e189872016-01-12 09:10:34 -0500433 mIconController.setIcon(mSlotVolume, volumeIconId, volumeDescription);
John Spurlocka37e9c82014-07-08 09:40:31 -0400434 }
435 if (volumeVisible != mVolumeVisible) {
Jason Monk3e189872016-01-12 09:10:34 -0500436 mIconController.setIconVisibility(mSlotVolume, volumeVisible);
John Spurlocka37e9c82014-07-08 09:40:31 -0400437 mVolumeVisible = volumeVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 }
John Spurlock15782262015-05-29 15:35:53 -0400439 updateAlarm();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 }
441
Jason Monk70364362015-08-06 16:32:18 -0400442 @Override
443 public void onBluetoothDevicesChanged() {
444 updateBluetooth();
445 }
446
447 @Override
448 public void onBluetoothStateChange(boolean enabled) {
449 updateBluetooth();
450 }
451
Jorim Jaggi2d75f9f2014-10-08 17:10:58 -0700452 private final void updateBluetooth() {
Joe Onorato798ac4c2010-05-27 16:39:00 -0400453 int iconId = R.drawable.stat_sys_data_bluetooth;
Jorim Jaggi2d75f9f2014-10-08 17:10:58 -0700454 String contentDescription =
Jason Monk1aa32822015-07-14 16:10:32 -0400455 mContext.getString(R.string.accessibility_quick_settings_bluetooth_on);
Evan Laird3cdf47e2018-01-29 16:01:41 -0500456 boolean bluetoothVisible = false;
Jason Monk70364362015-08-06 16:32:18 -0400457 if (mBluetooth != null) {
Jason Monk70364362015-08-06 16:32:18 -0400458 if (mBluetooth.isBluetoothConnected()) {
Jaikumar Ganeshd9bb6882010-09-27 17:05:24 -0700459 iconId = R.drawable.stat_sys_data_bluetooth_connected;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700460 contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected);
Evan Laird3cdf47e2018-01-29 16:01:41 -0500461 bluetoothVisible = mBluetooth.isBluetoothEnabled();
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800462 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 }
Wink Savillee9b06d72009-05-18 21:47:50 -0700464
Jason Monk3e189872016-01-12 09:10:34 -0500465 mIconController.setIcon(mSlotBluetooth, iconId, contentDescription);
Evan Laird3cdf47e2018-01-29 16:01:41 -0500466 mIconController.setIconVisibility(mSlotBluetooth, bluetoothVisible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 }
468
Hall Liu108ca202017-07-24 15:19:04 -0700469 private final void updateTTY() {
470 TelecomManager telecomManager =
471 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
472 if (telecomManager == null) {
473 updateTTY(TelecomManager.TTY_MODE_OFF);
474 } else {
475 updateTTY(telecomManager.getCurrentTtyMode());
476 }
477 }
478
479 private final void updateTTY(int currentTtyMode) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700480 boolean enabled = currentTtyMode != TelecomManager.TTY_MODE_OFF;
Wink Saville04e71b32009-04-02 11:00:54 -0700481
John Spurlocka37e9c82014-07-08 09:40:31 -0400482 if (DEBUG) Log.v(TAG, "updateTTY: enabled: " + enabled);
Wink Saville04e71b32009-04-02 11:00:54 -0700483
484 if (enabled) {
485 // TTY is on
John Spurlocka37e9c82014-07-08 09:40:31 -0400486 if (DEBUG) Log.v(TAG, "updateTTY: set TTY on");
Jason Monk3e189872016-01-12 09:10:34 -0500487 mIconController.setIcon(mSlotTty, R.drawable.stat_sys_tty_mode,
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700488 mContext.getString(R.string.accessibility_tty_enabled));
Jason Monk3e189872016-01-12 09:10:34 -0500489 mIconController.setIconVisibility(mSlotTty, true);
Wink Saville04e71b32009-04-02 11:00:54 -0700490 } else {
491 // TTY is off
John Spurlocka37e9c82014-07-08 09:40:31 -0400492 if (DEBUG) Log.v(TAG, "updateTTY: set TTY off");
Jason Monk3e189872016-01-12 09:10:34 -0500493 mIconController.setIconVisibility(mSlotTty, false);
Wink Saville04e71b32009-04-02 11:00:54 -0700494 }
495 }
John Spurlock96fe98d2014-08-27 09:36:02 -0400496
497 private void updateCast() {
498 boolean isCasting = false;
499 for (CastDevice device : mCast.getCastDevices()) {
500 if (device.state == CastDevice.STATE_CONNECTING
501 || device.state == CastDevice.STATE_CONNECTED) {
502 isCasting = true;
503 break;
504 }
505 }
506 if (DEBUG) Log.v(TAG, "updateCast: isCasting: " + isCasting);
Dan Sandler8fd25bf2015-10-20 16:01:27 -0700507 mHandler.removeCallbacks(mRemoveCastIconRunnable);
John Spurlock96fe98d2014-08-27 09:36:02 -0400508 if (isCasting) {
Jason Monk3e189872016-01-12 09:10:34 -0500509 mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast,
John Spurlock96fe98d2014-08-27 09:36:02 -0400510 mContext.getString(R.string.accessibility_casting));
Jason Monk3e189872016-01-12 09:10:34 -0500511 mIconController.setIconVisibility(mSlotCast, true);
Dan Sandler8fd25bf2015-10-20 16:01:27 -0700512 } else {
513 // don't turn off the screen-record icon for a few seconds, just to make sure the user
514 // has seen it
515 if (DEBUG) Log.v(TAG, "updateCast: hiding icon in 3 sec...");
516 mHandler.postDelayed(mRemoveCastIconRunnable, 3000);
John Spurlock96fe98d2014-08-27 09:36:02 -0400517 }
John Spurlock96fe98d2014-08-27 09:36:02 -0400518 }
519
Kenny Guy3094d4a2015-04-01 19:14:10 +0100520 private void updateManagedProfile() {
Jorim Jaggifabc7432017-05-15 02:40:05 +0200521 // getLastResumedActivityUserId needds to acquire the AM lock, which may be contended in
522 // some cases. Since it doesn't really matter here whether it's updated in this frame
523 // or in the next one, we call this method from our UI offload thread.
524 mUiOffloadThread.submit(() -> {
525 final int userId;
526 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700527 userId = ActivityTaskManager.getService().getLastResumedActivityUserId();
Jorim Jaggifabc7432017-05-15 02:40:05 +0200528 boolean isManagedProfile = mUserManager.isManagedProfile(userId);
529 mHandler.post(() -> {
530 final boolean showIcon;
Pavel Grafov410d8082017-06-29 18:42:32 +0100531 if (isManagedProfile &&
532 (!mKeyguardMonitor.isShowing() || mKeyguardMonitor.isOccluded())) {
Jorim Jaggifabc7432017-05-15 02:40:05 +0200533 showIcon = true;
534 mIconController.setIcon(mSlotManagedProfile,
535 R.drawable.stat_sys_managed_profile_status,
536 mContext.getString(R.string.accessibility_managed_profile));
Jorim Jaggifabc7432017-05-15 02:40:05 +0200537 } else {
538 showIcon = false;
539 }
540 if (mManagedProfileIconVisible != showIcon) {
541 mIconController.setIconVisibility(mSlotManagedProfile, showIcon);
542 mManagedProfileIconVisible = showIcon;
543 }
544 });
545 } catch (RemoteException e) {
546 Log.w(TAG, "updateManagedProfile: ", e);
Tony Makec319ab2017-03-28 18:50:01 +0100547 }
Jorim Jaggifabc7432017-05-15 02:40:05 +0200548 });
Kenny Guy3094d4a2015-04-01 19:14:10 +0100549 }
550
Jason Monk324b8862017-02-16 17:19:12 -0500551 private void updateForegroundInstantApps() {
552 NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
553 ArraySet<Pair<String, Integer>> notifs = new ArraySet<>(mCurrentNotifs);
554 IPackageManager pm = AppGlobals.getPackageManager();
555 mCurrentNotifs.clear();
Jorim Jaggifabc7432017-05-15 02:40:05 +0200556 mUiOffloadThread.submit(() -> {
557 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700558 final StackInfo focusedStack =
559 ActivityTaskManager.getService().getFocusedStackInfo();
Wale Ogunwale68278562017-09-23 17:13:55 -0700560 if (focusedStack != null) {
561 final int windowingMode =
562 focusedStack.configuration.windowConfiguration.getWindowingMode();
563 if (windowingMode == WINDOWING_MODE_FULLSCREEN
564 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
565 checkStack(focusedStack, notifs, noMan, pm);
566 }
Jorim Jaggifabc7432017-05-15 02:40:05 +0200567 }
568 if (mDockedStackExists) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700569 checkStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED,
570 notifs, noMan, pm);
Jorim Jaggifabc7432017-05-15 02:40:05 +0200571 }
572 } catch (RemoteException e) {
573 e.rethrowFromSystemServer();
Jason Monkf85fc962017-04-19 17:13:41 -0400574 }
Jorim Jaggifabc7432017-05-15 02:40:05 +0200575 // Cancel all the leftover notifications that don't have a foreground process anymore.
576 notifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS,
577 new UserHandle(v.second)));
578 });
Jason Monk324b8862017-02-16 17:19:12 -0500579 }
580
Wale Ogunwale68278562017-09-23 17:13:55 -0700581 private void checkStack(int windowingMode, int activityType,
582 ArraySet<Pair<String, Integer>> notifs, NotificationManager noMan, IPackageManager pm) {
583 try {
584 final StackInfo info =
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700585 ActivityTaskManager.getService().getStackInfo(windowingMode, activityType);
Wale Ogunwale68278562017-09-23 17:13:55 -0700586 checkStack(info, notifs, noMan, pm);
587 } catch (RemoteException e) {
588 e.rethrowFromSystemServer();
589 }
590 }
591 private void checkStack(StackInfo info, ArraySet<Pair<String, Integer>> notifs,
Jason Monkf85fc962017-04-19 17:13:41 -0400592 NotificationManager noMan, IPackageManager pm) {
593 try {
Jason Monkf85fc962017-04-19 17:13:41 -0400594 if (info == null || info.topActivity == null) return;
595 String pkg = info.topActivity.getPackageName();
596 if (!hasNotif(notifs, pkg, info.userId)) {
597 // TODO: Optimize by not always needing to get application info.
598 // Maybe cache non-ephemeral packages?
599 ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
600 PackageManager.MATCH_UNINSTALLED_PACKAGES, info.userId);
601 if (appInfo.isInstantApp()) {
Jason Monk697b82a2017-04-19 18:41:06 -0400602 postEphemeralNotif(pkg, info.userId, appInfo, noMan, info.taskIds[info.taskIds.length - 1]);
Jason Monkf85fc962017-04-19 17:13:41 -0400603 }
604 }
605 } catch (RemoteException e) {
606 e.rethrowFromSystemServer();
607 }
608 }
609
Jason Monk324b8862017-02-16 17:19:12 -0500610 private void postEphemeralNotif(String pkg, int userId, ApplicationInfo appInfo,
Jason Monk697b82a2017-04-19 18:41:06 -0400611 NotificationManager noMan, int taskId) {
Jason Monk324b8862017-02-16 17:19:12 -0500612 final Bundle extras = new Bundle();
613 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
614 mContext.getString(R.string.instant_apps));
615 mCurrentNotifs.add(new Pair<>(pkg, userId));
Gus Prevas71e15d12018-09-21 09:46:28 -0400616
617 String helpUrl = mContext.getString(R.string.instant_apps_help_url);
618 boolean hasHelpUrl = !helpUrl.isEmpty();
619 String message = mContext.getString(hasHelpUrl
620 ? R.string.instant_apps_message_with_help
621 : R.string.instant_apps_message);
622
Hai Zhang6102dfa2018-08-29 15:55:33 -0700623 UserHandle user = UserHandle.of(userId);
624 PendingIntent appInfoAction = PendingIntent.getActivityAsUser(mContext, 0,
Jason Monk324b8862017-02-16 17:19:12 -0500625 new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
Hai Zhang6102dfa2018-08-29 15:55:33 -0700626 .setData(Uri.fromParts("package", pkg, null)), 0, null, user);
Jason Monk324b8862017-02-16 17:19:12 -0500627 Action action = new Notification.Action.Builder(null, mContext.getString(R.string.app_info),
628 appInfoAction).build();
Gus Prevas71e15d12018-09-21 09:46:28 -0400629 PendingIntent helpCenterIntent = hasHelpUrl
630 ? PendingIntent.getActivityAsUser(mContext, 0,
631 new Intent(Intent.ACTION_VIEW).setData(Uri.parse(
632 helpUrl)),
633 0, null, user)
634 : null;
Jason Monk324b8862017-02-16 17:19:12 -0500635
Jason Monk697b82a2017-04-19 18:41:06 -0400636 Intent browserIntent = getTaskIntent(taskId, userId);
Gus Prevas71e15d12018-09-21 09:46:28 -0400637 Notification.Builder builder = new Notification.Builder(mContext,
638 NotificationChannels.GENERAL);
Patrick Baumann531db462018-02-13 13:01:47 -0800639 if (browserIntent != null && browserIntent.isWebIntent()) {
Jesse Evansa2024a22017-04-20 14:44:49 -0700640 // Make sure that this doesn't resolve back to an instant app
641 browserIntent.setComponent(null)
642 .setPackage(null)
643 .addFlags(Intent.FLAG_IGNORE_EPHEMERAL)
644 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
645
Hai Zhang6102dfa2018-08-29 15:55:33 -0700646 PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext,
647 0 /* requestCode */, browserIntent, 0 /* flags */, null, user);
Jason Monk697b82a2017-04-19 18:41:06 -0400648 ComponentName aiaComponent = null;
649 try {
650 aiaComponent = AppGlobals.getPackageManager().getInstantAppInstallerComponent();
651 } catch (RemoteException e) {
652 e.rethrowFromSystemServer();
653 }
654 Intent goToWebIntent = new Intent()
655 .setComponent(aiaComponent)
656 .setAction(Intent.ACTION_VIEW)
657 .addCategory(Intent.CATEGORY_BROWSABLE)
Jason Monk83c00512017-05-08 11:23:14 -0400658 .addCategory("unique:" + System.currentTimeMillis())
Jason Monk697b82a2017-04-19 18:41:06 -0400659 .putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
Dianne Hackborn3accca02013-09-20 09:32:11 -0700660 .putExtra(Intent.EXTRA_VERSION_CODE, (int) (appInfo.versionCode & 0x7fffffff))
Patrick Baumann531db462018-02-13 13:01:47 -0800661 .putExtra(Intent.EXTRA_LONG_VERSION_CODE, appInfo.versionCode)
Patrick Baumann531db462018-02-13 13:01:47 -0800662 .putExtra(Intent.EXTRA_INSTANT_APP_FAILURE, pendingIntent);
Jason Monk697b82a2017-04-19 18:41:06 -0400663
Hai Zhang6102dfa2018-08-29 15:55:33 -0700664 PendingIntent webPendingIntent = PendingIntent.getActivityAsUser(mContext, 0,
665 goToWebIntent, 0, null, user);
Gus Prevas71e15d12018-09-21 09:46:28 -0400666 Action webAction = new Notification.Action.Builder(null,
667 mContext.getString(R.string.go_to_web),
Jason Monk697b82a2017-04-19 18:41:06 -0400668 webPendingIntent).build();
669 builder.addAction(webAction);
670 }
671
672 noMan.notifyAsUser(pkg, SystemMessage.NOTE_INSTANT_APPS, builder
Jason Monk324b8862017-02-16 17:19:12 -0500673 .addExtras(extras)
674 .addAction(action)
Gus Prevas71e15d12018-09-21 09:46:28 -0400675 .setContentIntent(helpCenterIntent)
Jason Monk324b8862017-02-16 17:19:12 -0500676 .setColor(mContext.getColor(R.color.instant_apps_color))
Gus Prevas71e15d12018-09-21 09:46:28 -0400677 .setContentTitle(mContext.getString(R.string.instant_apps_title,
678 appInfo.loadLabel(mContext.getPackageManager())))
Jason Monk324b8862017-02-16 17:19:12 -0500679 .setLargeIcon(Icon.createWithResource(pkg, appInfo.icon))
680 .setSmallIcon(Icon.createWithResource(mContext.getPackageName(),
681 R.drawable.instant_icon))
682 .setContentText(message)
Gus Prevas71e15d12018-09-21 09:46:28 -0400683 .setStyle(new Notification.BigTextStyle().bigText(message))
Jason Monk324b8862017-02-16 17:19:12 -0500684 .setOngoing(true)
685 .build(),
686 new UserHandle(userId));
687 }
688
Jason Monk697b82a2017-04-19 18:41:06 -0400689 private Intent getTaskIntent(int taskId, int userId) {
Winson Chung5fa39752017-10-04 14:50:15 -0700690 try {
691 final List<ActivityManager.RecentTaskInfo> tasks =
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700692 ActivityTaskManager.getService().getRecentTasks(
Winson Chung5fa39752017-10-04 14:50:15 -0700693 NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId).getList();
694 for (int i = 0; i < tasks.size(); i++) {
695 if (tasks.get(i).id == taskId) {
696 return tasks.get(i).baseIntent;
697 }
Jason Monk697b82a2017-04-19 18:41:06 -0400698 }
Winson Chung5fa39752017-10-04 14:50:15 -0700699 } catch (RemoteException e) {
700 // Fall through
Jason Monk697b82a2017-04-19 18:41:06 -0400701 }
702 return null;
703 }
704
Jason Monk324b8862017-02-16 17:19:12 -0500705 private boolean hasNotif(ArraySet<Pair<String, Integer>> notifs, String pkg, int userId) {
706 Pair<String, Integer> key = new Pair<>(pkg, userId);
707 if (notifs.remove(key)) {
708 mCurrentNotifs.add(key);
709 return true;
710 }
711 return false;
712 }
713
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -0800714 private final SynchronousUserSwitchObserver mUserSwitchListener =
715 new SynchronousUserSwitchObserver() {
Kenny Guy3094d4a2015-04-01 19:14:10 +0100716 @Override
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -0800717 public void onUserSwitching(int newUserId) throws RemoteException {
Tony Makec319ab2017-03-28 18:50:01 +0100718 mHandler.post(() -> mUserInfoController.reloadUserInfo());
Kenny Guy3094d4a2015-04-01 19:14:10 +0100719 }
720
721 @Override
722 public void onUserSwitchComplete(int newUserId) throws RemoteException {
Tony Makec319ab2017-03-28 18:50:01 +0100723 mHandler.post(() -> {
724 updateAlarm();
Tony Makec319ab2017-03-28 18:50:01 +0100725 updateManagedProfile();
726 updateForegroundInstantApps();
Toni Barzice97f9232016-04-27 18:10:58 -0700727 });
Kenny Guy3094d4a2015-04-01 19:14:10 +0100728 }
729 };
730
Jason Monk952d5d82014-10-27 15:28:22 -0400731 private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() {
732 @Override
Rohan Shahe4071122018-01-22 15:16:09 -0800733 public void onHotspotChanged(boolean enabled, int numDevices) {
Jason Monk3e189872016-01-12 09:10:34 -0500734 mIconController.setIconVisibility(mSlotHotspot, enabled);
Jason Monk952d5d82014-10-27 15:28:22 -0400735 }
736 };
737
John Spurlock96fe98d2014-08-27 09:36:02 -0400738 private final CastController.Callback mCastCallback = new CastController.Callback() {
739 @Override
740 public void onCastDevicesChanged() {
741 updateCast();
742 }
743 };
Kenny Guy3094d4a2015-04-01 19:14:10 +0100744
Juan Flores2ff37202015-04-30 13:44:23 +0200745 private final NextAlarmController.NextAlarmChangeCallback mNextAlarmCallback =
746 new NextAlarmController.NextAlarmChangeCallback() {
Jason Monk324b8862017-02-16 17:19:12 -0500747 @Override
748 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
Evan Lairdbee3eb82018-05-16 15:58:49 -0400749 mNextAlarm = nextAlarm;
Jason Monk324b8862017-02-16 17:19:12 -0500750 updateAlarm();
751 }
752 };
Juan Flores2ff37202015-04-30 13:44:23 +0200753
Jason Monkaa573e92017-01-27 17:00:29 -0500754 @Override
755 public void appTransitionStarting(long startTime, long duration, boolean forced) {
Kenny Guy3094d4a2015-04-01 19:14:10 +0100756 updateManagedProfile();
Jason Monk324b8862017-02-16 17:19:12 -0500757 updateForegroundInstantApps();
Kenny Guy3094d4a2015-04-01 19:14:10 +0100758 }
759
Jason Monkaa573e92017-01-27 17:00:29 -0500760 @Override
761 public void onKeyguardShowingChanged() {
Kenny Guy3094d4a2015-04-01 19:14:10 +0100762 updateManagedProfile();
Jason Monk324b8862017-02-16 17:19:12 -0500763 updateForegroundInstantApps();
Kenny Guy3094d4a2015-04-01 19:14:10 +0100764 }
John Spurlock604a5ee2015-06-01 12:27:22 -0400765
Jason Monkaa573e92017-01-27 17:00:29 -0500766 @Override
767 public void onUserSetupChanged() {
768 boolean userSetup = mProvisionedController.isUserSetup(
769 mProvisionedController.getCurrentUser());
John Spurlock604a5ee2015-06-01 12:27:22 -0400770 if (mCurrentUserSetup == userSetup) return;
771 mCurrentUserSetup = userSetup;
772 updateAlarm();
773 }
Jason Monk3e189872016-01-12 09:10:34 -0500774
775 @Override
Jason Monk324b8862017-02-16 17:19:12 -0500776 public void preloadRecentApps() {
777 updateForegroundInstantApps();
778 }
779
780 @Override
Jason Monk3e189872016-01-12 09:10:34 -0500781 public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
782 boolean portrait = RotationLockTile.isCurrentOrientationLockPortrait(
783 mRotationLockController, mContext);
784 if (rotationLocked) {
785 if (portrait) {
786 mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_portrait,
787 mContext.getString(R.string.accessibility_rotation_lock_on_portrait));
788 } else {
789 mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_landscape,
790 mContext.getString(R.string.accessibility_rotation_lock_on_landscape));
791 }
Jason Monk8816dff2016-02-09 21:50:36 -0500792 mIconController.setIconVisibility(mSlotRotate, true);
Jason Monk3e189872016-01-12 09:10:34 -0500793 } else {
Jason Monk8816dff2016-02-09 21:50:36 -0500794 mIconController.setIconVisibility(mSlotRotate, false);
Jason Monk3e189872016-01-12 09:10:34 -0500795 }
796 }
797
798 private void updateHeadsetPlug(Intent intent) {
799 boolean connected = intent.getIntExtra("state", 0) != 0;
800 boolean hasMic = intent.getIntExtra("microphone", 0) != 0;
801 if (connected) {
802 String contentDescription = mContext.getString(hasMic
803 ? R.string.accessibility_status_bar_headset
804 : R.string.accessibility_status_bar_headphones);
805 mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.ic_headset_mic
806 : R.drawable.ic_headset, contentDescription);
807 mIconController.setIconVisibility(mSlotHeadset, true);
808 } else {
809 mIconController.setIconVisibility(mSlotHeadset, false);
810 }
811 }
812
Jason Monkf23aa992016-01-22 16:45:21 -0500813 @Override
814 public void onDataSaverChanged(boolean isDataSaving) {
815 mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);
816 }
817
Evan Lairdcf1a1032018-11-14 13:46:08 -0500818 @Override // PrivacyItemController.Callback
819 public void privacyChanged(List<PrivacyItem> privacyItems) {
820 updatePrivacyItems(privacyItems);
821 }
822
823 private void updatePrivacyItems(List<PrivacyItem> items) {
824 boolean showCamera = false;
825 boolean showMicrophone = false;
826 boolean showLocation = false;
827 for (PrivacyItem item : items) {
828 switch (item.getPrivacyType()) {
829 case TYPE_CAMERA:
830 showCamera = true;
831 break;
832 case TYPE_LOCATION:
833 showLocation = true;
834 break;
835 case TYPE_MICROPHONE:
836 showMicrophone = true;
837 break;
838 }
839 }
840
841 mIconController.setIconVisibility(mSlotCamera, showCamera);
842 mIconController.setIconVisibility(mSlotMicrophone, showMicrophone);
843 mIconController.setIconVisibility(mSlotLocation, showLocation);
844 }
845
Winson Chung67f5c8b2018-09-24 12:09:19 -0700846 private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() {
Jason Monk324b8862017-02-16 17:19:12 -0500847 @Override
848 public void onTaskStackChanged() {
849 // Listen for changes to stacks and then check which instant apps are foreground.
850 updateForegroundInstantApps();
851 }
852 };
853
Jason Monk3e189872016-01-12 09:10:34 -0500854 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
855 @Override
856 public void onReceive(Context context, Intent intent) {
857 String action = intent.getAction();
Lucas Dupin5e0f0d22018-02-26 13:32:16 -0800858 switch (action) {
859 case AudioManager.RINGER_MODE_CHANGED_ACTION:
860 case AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION:
861 updateVolumeZen();
862 break;
863 case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
864 // Avoid rebroadcast because SysUI is direct boot aware.
865 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK,
866 false)) {
867 break;
868 }
869 updateSimState(intent);
870 break;
871 case TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED:
872 updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE,
873 TelecomManager.TTY_MODE_OFF));
874 break;
875 case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
876 case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
877 case Intent.ACTION_MANAGED_PROFILE_REMOVED:
878 updateManagedProfile();
879 break;
880 case AudioManager.ACTION_HEADSET_PLUG:
881 updateHeadsetPlug(intent);
882 break;
Jason Monk3e189872016-01-12 09:10:34 -0500883 }
884 }
885 };
886
887 private Runnable mRemoveCastIconRunnable = new Runnable() {
888 @Override
889 public void run() {
890 if (DEBUG) Log.v(TAG, "updateCast: hiding icon NOW");
891 mIconController.setIconVisibility(mSlotCast, false);
892 }
893 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894}