blob: e66dc74c7958b863f178ba1bbcf88a566d0ed0d3 [file] [log] [blame]
Joe Onorato2314aab2010-04-08 16:41:23 -05001/*
2 * Copyright (C) 2010 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 Onorato79de0c52010-05-26 17:03:26 -040017package com.android.systemui.statusbar;
Joe Onorato2314aab2010-04-08 16:41:23 -050018
Dan Sandler4247a5c2014-07-23 15:58:08 -040019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Christopher Tate5e08af02012-09-21 17:17:22 -070021import android.app.ActivityManager;
Jorim Jaggie6e108e2016-03-28 13:38:45 -070022import android.app.ActivityManager.StackId;
Daniel Sandler6a858c32012-03-12 14:38:58 -040023import android.app.ActivityManagerNative;
Jorim Jaggie6e108e2016-03-28 13:38:45 -070024import android.app.ActivityOptions;
Ricky Wai7fa01712016-03-16 12:13:54 +000025import android.app.KeyguardManager;
Chris Wren51c75102013-07-16 20:49:17 -040026import android.app.Notification;
Chris Wrencd8f4f72014-08-27 18:48:13 -040027import android.app.NotificationManager;
Daniel Sandler6a858c32012-03-12 14:38:58 -040028import android.app.PendingIntent;
Adrian Roos497ab022015-02-10 20:49:33 +010029import android.app.RemoteInput;
Adam Powell0fc5b2b2012-07-18 18:20:29 -070030import android.app.TaskStackBuilder;
Adrian Roosbd3409c2014-08-12 18:21:09 +020031import android.app.admin.DevicePolicyManager;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040032import android.content.BroadcastReceiver;
Christoph Studer60748e72014-05-22 16:51:41 +020033import android.content.ComponentName;
Joe Onorato808182d2010-07-09 18:52:06 -040034import android.content.Context;
Daniel Sandler6a858c32012-03-12 14:38:58 -040035import android.content.Intent;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040036import android.content.IntentFilter;
Ricky Wai7fa01712016-03-16 12:13:54 +000037import android.content.IntentSender;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040038import android.content.pm.ApplicationInfo;
Dan Sandlera5e0f412014-01-23 15:11:54 -050039import android.content.pm.PackageManager;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040040import android.content.pm.PackageManager.NameNotFoundException;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000041import android.content.pm.UserInfo;
John Spurlockde84f0e2013-06-12 12:41:00 -040042import android.content.res.Configuration;
Chris Wrencd8f4f72014-08-27 18:48:13 -040043import android.content.res.Resources;
Daniel Sandler26cda272012-05-22 15:44:08 -040044import android.database.ContentObserver;
Jorim Jaggi86905582016-02-09 21:36:09 -080045import android.graphics.Rect;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +010046import android.graphics.drawable.Drawable;
Dan Sandler33439812015-08-10 15:49:56 -040047import android.graphics.drawable.Icon;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +020048import android.os.AsyncTask;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040049import android.os.Build;
Jorim Jaggi165ce062015-07-06 16:18:11 -070050import android.os.Bundle;
Michael Jurka7f2668c2012-03-27 07:49:52 -070051import android.os.Handler;
Joe Onorato808182d2010-07-09 18:52:06 -040052import android.os.IBinder;
Michael Jurka7f2668c2012-03-27 07:49:52 -070053import android.os.Message;
Chris Wren157026f2013-06-28 16:54:01 -040054import android.os.PowerManager;
Joe Onorato808182d2010-07-09 18:52:06 -040055import android.os.RemoteException;
56import android.os.ServiceManager;
Adrian Roos497ab022015-02-10 20:49:33 +010057import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070058import android.os.UserHandle;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000059import android.os.UserManager;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040060import android.provider.Settings;
Chris Wren157026f2013-06-28 16:54:01 -040061import android.service.dreams.DreamService;
62import android.service.dreams.IDreamManager;
Christoph Studer60748e72014-05-22 16:51:41 +020063import android.service.notification.NotificationListenerService;
Christoph Studerd0694b62014-06-04 16:36:01 +020064import android.service.notification.NotificationListenerService.RankingMap;
John Spurlockde84f0e2013-06-12 12:41:00 -040065import android.service.notification.StatusBarNotification;
Dan Sandlerdc34df52016-04-07 21:04:46 -040066import android.service.vr.IVrManager;
67import android.service.vr.IVrStateCallbacks;
Chris Wren0c8275b2012-05-08 13:36:48 -040068import android.text.TextUtils;
Selim Cinek2d79f632015-11-02 15:13:29 -080069import android.util.ArraySet;
Joe Onorato808182d2010-07-09 18:52:06 -040070import android.util.Log;
Dan Sandlere163a642015-03-01 22:58:32 -050071import android.util.Slog;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000072import android.util.SparseArray;
Dan Sandlerfd16d562014-02-13 18:43:31 -080073import android.util.SparseBooleanArray;
Daniel Sandlerc638c1e2011-08-24 16:19:23 -070074import android.view.Display;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050075import android.view.IWindowManager;
Michael Jurka7f2668c2012-03-27 07:49:52 -070076import android.view.LayoutInflater;
77import android.view.MotionEvent;
Joe Onorato808182d2010-07-09 18:52:06 -040078import android.view.View;
Dan Sandler4247a5c2014-07-23 15:58:08 -040079import android.view.ViewAnimationUtils;
Daniel Sandler6a858c32012-03-12 14:38:58 -040080import android.view.ViewGroup;
Christoph Studer4da84cd2014-10-21 17:24:20 +020081import android.view.ViewParent;
Joe Onorato808182d2010-07-09 18:52:06 -040082import android.view.WindowManager;
Michael Jurka80343f62012-10-18 13:13:46 +020083import android.view.WindowManagerGlobal;
Selim Cineka8fefa52014-09-08 16:10:50 +020084import android.view.accessibility.AccessibilityManager;
Chris Wren0c8275b2012-05-08 13:36:48 -040085import android.widget.ImageView;
Michael Jurkaa600fd92012-06-25 15:57:05 -070086import android.widget.RemoteViews;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040087import android.widget.TextView;
Kenny Guydae30d52015-04-01 19:11:35 +010088import android.widget.Toast;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050089
Chris Wrenbd6b5fb2015-06-09 14:58:34 -040090import com.android.internal.logging.MetricsLogger;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050091import com.android.internal.logging.MetricsProto.MetricsEvent;
John Spurlockde84f0e2013-06-12 12:41:00 -040092import com.android.internal.statusbar.IStatusBarService;
93import com.android.internal.statusbar.StatusBarIcon;
Chris Wrencd8f4f72014-08-27 18:48:13 -040094import com.android.internal.widget.LockPatternUtils;
Mady Mellor97c8df42016-03-22 18:09:39 -070095import com.android.keyguard.KeyguardHostView.OnDismissAction;
Selim Cinekfa760d42016-05-10 15:50:53 -040096import com.android.keyguard.KeyguardUpdateMonitor;
Jorim Jaggi5eb67c22015-08-19 19:50:49 -070097import com.android.systemui.DejankUtils;
Winsonc0d70582016-01-29 10:24:39 -080098import com.android.systemui.Interpolators;
John Spurlockde84f0e2013-06-12 12:41:00 -040099import com.android.systemui.R;
John Spurlockd08de372013-06-24 13:06:08 -0400100import com.android.systemui.RecentsComponent;
Dan Sandler4247a5c2014-07-23 15:58:08 -0400101import com.android.systemui.SwipeHelper;
John Spurlockde84f0e2013-06-12 12:41:00 -0400102import com.android.systemui.SystemUI;
Jorim Jaggib835dd72015-06-08 12:28:42 -0700103import com.android.systemui.assist.AssistManager;
Jorim Jaggid61f2272014-12-19 20:35:35 +0100104import com.android.systemui.recents.Recents;
Christoph Studer37fe6932014-05-26 13:10:30 +0200105import com.android.systemui.statusbar.NotificationData.Entry;
Mady Mellor97c8df42016-03-22 18:09:39 -0700106import com.android.systemui.statusbar.NotificationGuts.OnGutsClosedListener;
Selim Cinek92d892c2014-09-11 15:11:00 +0200107import com.android.systemui.statusbar.phone.NavigationBarView;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100108import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200109import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700110import com.android.systemui.statusbar.policy.HeadsUpManager;
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200111import com.android.systemui.statusbar.policy.PreviewInflater;
Adrian Roos497ab022015-02-10 20:49:33 +0100112import com.android.systemui.statusbar.policy.RemoteInputView;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100113import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekd84a5932015-12-15 11:45:36 -0800114import com.android.systemui.statusbar.stack.StackStateAnimator;
John Spurlockde84f0e2013-06-12 12:41:00 -0400115
Michael Jurkaa600fd92012-06-25 15:57:05 -0700116import java.util.ArrayList;
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200117import java.util.List;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700118import java.util.Locale;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400119
Julia Reynoldsf0f629f2016-02-25 09:34:04 -0500120import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200121
Michael Jurka7f2668c2012-03-27 07:49:52 -0700122public abstract class BaseStatusBar extends SystemUI implements
Winson Chung9214eff2014-06-12 13:59:25 -0700123 CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
Selim Cinek570981d2015-12-01 11:37:01 -0800124 ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
Mady Mellor97c8df42016-03-22 18:09:39 -0700125 ExpandableNotificationRow.OnExpandClickListener,
126 OnGutsClosedListener {
Daniel Sandler198a0302012-08-17 16:04:31 -0400127 public static final String TAG = "StatusBar";
Jorim Jaggi86905582016-02-09 21:36:09 -0800128 public static final boolean DEBUG = false;
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400129 public static final boolean MULTIUSER_DEBUG = false;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400130
Adrian Roos497ab022015-02-10 20:49:33 +0100131 public static final boolean ENABLE_REMOTE_INPUT =
Adrian Roos9531c9b2015-11-03 17:43:01 -0800132 SystemProperties.getBoolean("debug.enable_remote_input", true);
Selim Cinek40412492015-12-08 18:03:22 -0800133 public static final boolean ENABLE_CHILD_NOTIFICATIONS
134 = SystemProperties.getBoolean("debug.child_notifs", true);
Adrian Roosc0a579e2016-03-30 16:43:58 -0700135 public static final boolean FORCE_REMOTE_INPUT_HISTORY =
136 SystemProperties.getBoolean("debug.force_remoteinput_history", false);
Adrian Roos497ab022015-02-10 20:49:33 +0100137
Winson Chung1e8d71b2014-05-16 17:05:22 -0700138 protected static final int MSG_SHOW_RECENT_APPS = 1019;
139 protected static final int MSG_HIDE_RECENT_APPS = 1020;
140 protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700141 protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
142 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
Winson Chungb1f74992014-08-08 12:53:09 -0700143 protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
144 protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +0000145 protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
Andrei Stingaceanu0bf096f2016-04-14 18:11:57 +0100146 protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
Chris Wren0c8275b2012-05-08 13:36:48 -0400147
Chris Wren157026f2013-06-28 16:54:01 -0400148 protected static final boolean ENABLE_HEADS_UP = true;
Chris Wren22ae46e2014-02-26 18:08:09 -0500149 protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
Chris Wren0c8275b2012-05-08 13:36:48 -0400150
Ricky Wai7fa01712016-03-16 12:13:54 +0000151 private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
152
Winsond8b1d632016-01-04 17:51:18 -0800153 // Should match the values in PhoneWindowManager
Michael Jurka56a57832012-05-14 13:24:43 -0700154 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
Winsond8b1d632016-01-04 17:51:18 -0800155 public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
Michael Jurka56a57832012-05-14 13:24:43 -0700156
Chris Wrencd8f4f72014-08-27 18:48:13 -0400157 private static final String BANNER_ACTION_CANCEL =
158 "com.android.systemui.statusbar.banner_action_cancel";
159 private static final String BANNER_ACTION_SETUP =
160 "com.android.systemui.statusbar.banner_action_setup";
Ricky Wai7fa01712016-03-16 12:13:54 +0000161 private static final String WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION
162 = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
Chris Wrencd8f4f72014-08-27 18:48:13 -0400163
Joe Onorato808182d2010-07-09 18:52:06 -0400164 protected CommandQueue mCommandQueue;
165 protected IStatusBarService mBarService;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700166 protected H mHandler = createHandler();
167
Chris Wren0c8275b2012-05-08 13:36:48 -0400168 // all notifications
Christoph Studerc8db24b2014-07-25 17:50:30 +0200169 protected NotificationData mNotificationData;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100170 protected NotificationStackScrollLayout mStackScroller;
Chris Wren0c8275b2012-05-08 13:36:48 -0400171
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100172 protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
173
Adrian Roosb88b1a12015-12-09 18:51:05 -0800174 protected RemoteInputController mRemoteInputController;
175
Chris Wrena4ef6202014-06-09 18:07:30 -0400176 // for heads up notifications
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700177 protected HeadsUpManager mHeadsUpManager;
Chris Wren0c8275b2012-05-08 13:36:48 -0400178
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400179 protected int mCurrentUserId = 0;
Kenny Guy2a764942014-04-02 13:29:20 +0100180 final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400181
Daniel Sandler777dcde2013-09-30 10:21:45 -0400182 protected int mLayoutDirection = -1; // invalid
Selim Cineka8fefa52014-09-08 16:10:50 +0200183 protected AccessibilityManager mAccessibilityManager;
Selim Cinek92d892c2014-09-11 15:11:00 +0200184
185 // on-screen navigation buttons
186 protected NavigationBarView mNavigationBarView = null;
Christoph Studere8e28652014-10-29 17:27:53 +0100187
Jorim Jaggi50ff3af2015-08-12 18:35:42 -0700188 protected boolean mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +0100189
190 protected boolean mVisible;
Selim Cinek2d79f632015-11-02 15:13:29 -0800191 protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
Christoph Studere8e28652014-10-29 17:27:53 +0100192
Adrian Roosc0a579e2016-03-30 16:43:58 -0700193 /**
194 * Notifications with keys in this set are not actually around anymore. We kept them around
195 * when they were canceled in response to a remote input interaction. This allows us to show
196 * what you replied and allows you to continue typing into it.
197 */
198 protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
199
Christoph Studere8e28652014-10-29 17:27:53 +0100200 // mScreenOnFromKeyguard && mVisible.
201 private boolean mVisibleToUser;
202
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700203 private Locale mLocale;
Dan Sandler539aad42014-08-04 00:43:39 -0400204 private float mFontScale;
205
Chris Wrenf6e83f42013-09-11 14:02:59 -0400206 protected boolean mUseHeadsUp = false;
Chris Wren22ae46e2014-02-26 18:08:09 -0500207 protected boolean mHeadsUpTicker = false;
Jason Monkf7019542014-07-31 12:42:25 -0400208 protected boolean mDisableNotificationAlerts = false;
Chris Wren157026f2013-06-28 16:54:01 -0400209
Adrian Roosbd3409c2014-08-12 18:21:09 +0200210 protected DevicePolicyManager mDevicePolicyManager;
Chris Wren157026f2013-06-28 16:54:01 -0400211 protected IDreamManager mDreamManager;
Julia Reynolds0971cb02016-01-26 17:00:22 -0500212 protected PowerManager mPowerManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200213 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Dan Sandlerfd16d562014-02-13 18:43:31 -0800214
215 // public mode, private notifications, etc
216 private boolean mLockscreenPublicMode = false;
217 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
Julia Reynolds26fa8a52016-02-24 08:31:22 -0500218 private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700219
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000220 private UserManager mUserManager;
Selim Cinek01af3342016-02-09 19:25:31 -0800221 private int mDensity;
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000222
Ricky Wai7fa01712016-03-16 12:13:54 +0000223 private KeyguardManager mKeyguardManager;
224 private LockPatternUtils mLockPatternUtils;
225
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500226 // UI-specific methods
Daniel Sandler6a858c32012-03-12 14:38:58 -0400227
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500228 /**
229 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
230 * and add them to the window manager.
231 */
232 protected abstract void createAndAddWindows();
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400233
Jeff Brown98365d72012-08-19 20:30:52 -0700234 protected WindowManager mWindowManager;
235 protected IWindowManager mWindowManagerService;
Christoph Studer60748e72014-05-22 16:51:41 +0200236
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700237 protected abstract void refreshLayout(int layoutDirection);
238
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500239 protected Display mDisplay;
Jeff Brown98365d72012-08-19 20:30:52 -0700240
Daniel Sandler26cda272012-05-22 15:44:08 -0400241 private boolean mDeviceProvisioned = false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400242
Jorim Jaggi75b25972015-10-21 14:51:10 +0200243 protected RecentsComponent mRecents;
John Spurlockd08de372013-06-24 13:06:08 -0400244
John Spurlocke677d712014-02-13 12:52:19 -0500245 protected int mZenMode;
246
Dan Sandler4247a5c2014-07-23 15:58:08 -0400247 // which notification is currently being longpress-examined by the user
Selim Cinek024ca592014-09-01 15:11:28 +0200248 private NotificationGuts mNotificationGutsExposed;
Dan Sandler4247a5c2014-07-23 15:58:08 -0400249
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +0100250 private KeyboardShortcuts mKeyboardShortcuts;
251
Jorim Jaggiecbab362014-04-23 16:13:15 +0200252 /**
253 * The {@link StatusBarState} of the status bar.
254 */
255 protected int mState;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200256 protected boolean mBouncerShowing;
John Spurlock4b3bda22014-05-22 14:32:20 -0400257 protected boolean mShowLockscreenNotifications;
Adrian Roos3aec6382016-02-05 14:19:01 -0800258 protected boolean mAllowLockscreenRemoteInput;
Jorim Jaggiecbab362014-04-23 16:13:15 +0200259
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200260 protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
Dan Sandlereceda3d2014-07-21 15:35:01 -0400261 protected DismissView mDismissView;
Jorim Jaggia2052ea2014-08-05 16:22:30 +0200262 protected EmptyShadeView mEmptyShadeView;
Jorim Jaggi649b7082014-04-03 13:15:18 +0200263
Chris Wren42d5dd42015-05-01 10:39:26 -0400264 private NotificationClicker mNotificationClicker = new NotificationClicker();
265
Jorim Jaggib835dd72015-06-08 12:28:42 -0700266 protected AssistManager mAssistManager;
267
Dan Sandlerdc34df52016-04-07 21:04:46 -0400268 protected boolean mVrMode;
269
Christoph Studerc8db24b2014-07-25 17:50:30 +0200270 @Override // NotificationData.Environment
Daniel Sandler3ffdcc72012-09-23 14:31:48 -0400271 public boolean isDeviceProvisioned() {
Daniel Sandler26cda272012-05-22 15:44:08 -0400272 return mDeviceProvisioned;
273 }
274
Dan Sandlerdc34df52016-04-07 21:04:46 -0400275 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
276 @Override
277 public void onVrStateChanged(boolean enabled) {
278 mVrMode = enabled;
279 }
280 };
281
282 public boolean isDeviceInVrMode() {
283 return mVrMode;
284 }
285
John Spurlocke677d712014-02-13 12:52:19 -0500286 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
Daniel Sandler26cda272012-05-22 15:44:08 -0400287 @Override
288 public void onChange(boolean selfChange) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700289 final boolean provisioned = 0 != Settings.Global.getInt(
290 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
Daniel Sandler26cda272012-05-22 15:44:08 -0400291 if (provisioned != mDeviceProvisioned) {
292 mDeviceProvisioned = provisioned;
Christoph Studer37fe6932014-05-26 13:10:30 +0200293 updateNotifications();
Daniel Sandler26cda272012-05-22 15:44:08 -0400294 }
John Spurlocke677d712014-02-13 12:52:19 -0500295 final int mode = Settings.Global.getInt(mContext.getContentResolver(),
296 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
297 setZenMode(mode);
Dan Sandler52e5701e2014-07-22 23:14:54 -0400298
299 updateLockscreenNotificationSetting();
Daniel Sandler26cda272012-05-22 15:44:08 -0400300 }
301 };
302
Dan Sandlerfd16d562014-02-13 18:43:31 -0800303 private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
304 @Override
305 public void onChange(boolean selfChange) {
Daniel U57454872016-03-29 20:28:21 +0100306 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
307 // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
Dan Sandlerfd16d562014-02-13 18:43:31 -0800308 mUsersAllowingPrivateNotifications.clear();
Daniel U57454872016-03-29 20:28:21 +0100309 mUsersAllowingNotifications.clear();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800310 // ... and refresh all the notifications
Christoph Studer37fe6932014-05-26 13:10:30 +0200311 updateNotifications();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800312 }
313 };
314
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700315 private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
316 @Override
Adrian Roos7d7090d2014-05-21 13:10:23 +0200317 public boolean onClickHandler(
318 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800319 if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
320 return true;
321 }
322
Daniel Sandler198a0302012-08-17 16:04:31 -0400323 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400324 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
Daniel Sandler198a0302012-08-17 16:04:31 -0400325 }
Christoph Studer4da84cd2014-10-21 17:24:20 +0200326 logActionClick(view);
Jorim Jaggi89f7f282014-10-17 19:54:15 +0200327 // The intent we are sending is for the application, which
328 // won't have permission to immediately start an activity after
329 // the user switches to home. We know it is safe to do at this
330 // point, so make sure new activity switches are now allowed.
331 try {
332 ActivityManagerNative.getDefault().resumeAppSwitches();
333 } catch (RemoteException e) {
334 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700335 final boolean isActivity = pendingIntent.isActivity();
336 if (isActivity) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200337 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200338 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
339 mContext, pendingIntent.getIntent(), mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +0200340 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200341 @Override
342 public boolean onDismiss() {
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200343 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200344 try {
345 ActivityManagerNative.getDefault()
346 .keyguardWaitingForActivityDrawn();
Jorim Jaggi91617a72015-06-25 15:01:29 -0700347 ActivityManagerNative.getDefault().resumeAppSwitches();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200348 } catch (RemoteException e) {
349 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200350 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700351
Adrian Roos7d7090d2014-05-21 13:10:23 +0200352 boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200353 overrideActivityPendingAppTransition(keyguardShowing && !afterKeyguardGone);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700354
Adrian Roos7d7090d2014-05-21 13:10:23 +0200355 // close the shade if it was open
356 if (handled) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100357 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
358 true /* force */);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200359 visibilityChanged(false);
Jorim Jaggi91617a72015-06-25 15:01:29 -0700360 mAssistManager.hideAssist();
Adrian Roos7d7090d2014-05-21 13:10:23 +0200361 }
Jorim Jaggi91617a72015-06-25 15:01:29 -0700362
Adrian Roos4314f6d2014-05-28 14:10:27 +0200363 // Wait for activity start.
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200364 return handled;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200365 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200366 }, afterKeyguardGone);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200367 return true;
368 } else {
Jorim Jaggie6e108e2016-03-28 13:38:45 -0700369 return superOnClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700370 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200371 }
372
Christoph Studer4da84cd2014-10-21 17:24:20 +0200373 private void logActionClick(View view) {
374 ViewParent parent = view.getParent();
375 String key = getNotificationKeyForParent(parent);
376 if (key == null) {
377 Log.w(TAG, "Couldn't determine notification for click.");
378 return;
379 }
380 int index = -1;
381 // If this is a default template, determine the index of the button.
382 if (view.getId() == com.android.internal.R.id.action0 &&
383 parent != null && parent instanceof ViewGroup) {
384 ViewGroup actionGroup = (ViewGroup) parent;
385 index = actionGroup.indexOfChild(view);
386 }
387 try {
388 mBarService.onNotificationActionClick(key, index);
389 } catch (RemoteException e) {
390 // Ignore
391 }
392 }
393
394 private String getNotificationKeyForParent(ViewParent parent) {
395 while (parent != null) {
396 if (parent instanceof ExpandableNotificationRow) {
397 return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
398 }
399 parent = parent.getParent();
400 }
401 return null;
402 }
403
Adrian Roos7d7090d2014-05-21 13:10:23 +0200404 private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
405 Intent fillInIntent) {
Jorim Jaggie6e108e2016-03-28 13:38:45 -0700406 return super.onClickHandler(view, pendingIntent, fillInIntent,
407 StackId.FULLSCREEN_WORKSPACE_STACK_ID);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700408 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800409
410 private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
411 Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
412 RemoteInput[] inputs = null;
413 if (tag instanceof RemoteInput[]) {
414 inputs = (RemoteInput[]) tag;
415 }
416
417 if (inputs == null) {
418 return false;
419 }
420
421 RemoteInput input = null;
422
423 for (RemoteInput i : inputs) {
424 if (i.getAllowFreeFormInput()) {
425 input = i;
426 }
427 }
428
429 if (input == null) {
430 return false;
431 }
432
433 ViewParent p = view.getParent();
434 RemoteInputView riv = null;
435 while (p != null) {
436 if (p instanceof View) {
437 View pv = (View) p;
438 if (pv.isRootNamespace()) {
439 riv = (RemoteInputView) pv.findViewWithTag(RemoteInputView.VIEW_TAG);
440 break;
441 }
442 }
443 p = p.getParent();
444 }
Adrian Roos3aec6382016-02-05 14:19:01 -0800445 ExpandableNotificationRow row = null;
446 while (p != null) {
447 if (p instanceof ExpandableNotificationRow) {
448 row = (ExpandableNotificationRow) p;
449 break;
450 }
451 p = p.getParent();
452 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800453
Adrian Roos3aec6382016-02-05 14:19:01 -0800454 if (riv == null || row == null) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800455 return false;
456 }
457
Adrian Roos3aec6382016-02-05 14:19:01 -0800458 row.setUserExpanded(true);
459
Ricky Waicd35def2016-05-03 11:07:07 +0100460 if (!mAllowLockscreenRemoteInput) {
461 if (isLockscreenPublicMode()) {
462 onLockedRemoteInput(row, view);
463 return true;
464 }
465 final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
466 if (mUserManager.getUserInfo(userId).isManagedProfile()
467 && mKeyguardManager.isDeviceLocked(userId)) {
468 onLockedWorkRemoteInput(userId, row, view);
469 return true;
470 }
Adrian Roos3aec6382016-02-05 14:19:01 -0800471 }
472
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800473 riv.setVisibility(View.VISIBLE);
474 int cx = view.getLeft() + view.getWidth() / 2;
475 int cy = view.getTop() + view.getHeight() / 2;
476 int w = riv.getWidth();
477 int h = riv.getHeight();
478 int r = Math.max(
479 Math.max(cx + cy, cx + (h - cy)),
480 Math.max((w - cx) + cy, (w - cx) + (h - cy)));
481 ViewAnimationUtils.createCircularReveal(riv, cx, cy, 0, r)
482 .start();
483
484 riv.setPendingIntent(pendingIntent);
485 riv.setRemoteInput(inputs, input);
486 riv.focus();
487
488 return true;
489 }
490
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700491 };
492
John Spurlock5c454122013-06-17 07:35:46 -0400493 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
494 @Override
495 public void onReceive(Context context, Intent intent) {
496 String action = intent.getAction();
497 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
498 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Kenny Guy2a764942014-04-02 13:29:20 +0100499 updateCurrentProfilesCache();
John Spurlock5c454122013-06-17 07:35:46 -0400500 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
Dan Sandler52e5701e2014-07-22 23:14:54 -0400501
502 updateLockscreenNotificationSetting();
503
John Spurlock5c454122013-06-17 07:35:46 -0400504 userSwitched(mCurrentUserId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000505 } else if (Intent.ACTION_USER_ADDED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +0100506 updateCurrentProfilesCache();
Kenny Guydae30d52015-04-01 19:11:35 +0100507 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
508 List<ActivityManager.RecentTaskInfo> recentTask = null;
509 try {
510 recentTask = ActivityManagerNative.getDefault().getRecentTasks(1,
511 ActivityManager.RECENT_WITH_EXCLUDED
512 | ActivityManager.RECENT_INCLUDE_PROFILES,
513 mCurrentUserId);
514 } catch (RemoteException e) {
515 // Abandon hope activity manager not running.
516 }
517 if (recentTask != null && recentTask.size() > 0) {
518 UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
519 if (user != null && user.isManagedProfile()) {
Kenny Guy63bf8ac2015-06-18 15:09:09 +0100520 Toast toast = Toast.makeText(mContext,
521 R.string.managed_profile_foreground_toast,
522 Toast.LENGTH_SHORT);
523 TextView text = (TextView) toast.getView().findViewById(
524 android.R.id.message);
525 text.setCompoundDrawablesRelativeWithIntrinsicBounds(
526 R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
527 int paddingPx = mContext.getResources().getDimensionPixelSize(
528 R.dimen.managed_profile_toast_padding);
529 text.setCompoundDrawablePadding(paddingPx);
Kenny Guy540f7d22015-06-08 20:24:23 +0100530 toast.show();
Kenny Guydae30d52015-04-01 19:11:35 +0100531 }
532 }
Chris Wrencd8f4f72014-08-27 18:48:13 -0400533 } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
534 NotificationManager noMan = (NotificationManager)
535 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500536 noMan.cancel(R.id.notification_hidden);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400537
538 Settings.Secure.putInt(mContext.getContentResolver(),
539 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
540 if (BANNER_ACTION_SETUP.equals(action)) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100541 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
542 true /* force */);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400543 mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
544 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
545
546 );
547 }
Ricky Wai7fa01712016-03-16 12:13:54 +0000548 } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
Tony Mak646fe992016-04-21 16:43:08 +0100549 final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
Ricky Wai7fa01712016-03-16 12:13:54 +0000550 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
Ricky Waicd35def2016-05-03 11:07:07 +0100551 if (intentSender != null) {
552 try {
553 mContext.startIntentSender(intentSender, null, 0, 0, 0);
554 } catch (IntentSender.SendIntentException e) {
555 /* ignore */
556 }
Ricky Wai7fa01712016-03-16 12:13:54 +0000557 }
Ricky Waicd35def2016-05-03 11:07:07 +0100558 if (notificationKey != null) {
559 try {
560 mBarService.onNotificationClick(notificationKey);
561 } catch (RemoteException e) {
562 /* ignore */
563 }
Ricky Wai7fa01712016-03-16 12:13:54 +0000564 }
Ricky Waicd35def2016-05-03 11:07:07 +0100565 onWorkChallengeUnlocked();
John Spurlock5c454122013-06-17 07:35:46 -0400566 }
567 }
568 };
569
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000570 private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
571 @Override
572 public void onReceive(Context context, Intent intent) {
573 String action = intent.getAction();
574 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
575 isCurrentProfile(getSendingUserId())) {
576 mUsersAllowingPrivateNotifications.clear();
577 updateLockscreenNotificationSetting();
578 updateNotifications();
579 }
580 }
581 };
582
Christoph Studer60748e72014-05-22 16:51:41 +0200583 private final NotificationListenerService mNotificationListener =
584 new NotificationListenerService() {
585 @Override
586 public void onListenerConnected() {
587 if (DEBUG) Log.d(TAG, "onListenerConnected");
588 final StatusBarNotification[] notifications = getActiveNotifications();
Christoph Studerd0694b62014-06-04 16:36:01 +0200589 final RankingMap currentRanking = getCurrentRanking();
Christoph Studer60748e72014-05-22 16:51:41 +0200590 mHandler.post(new Runnable() {
591 @Override
592 public void run() {
593 for (StatusBarNotification sbn : notifications) {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100594 addNotification(sbn, currentRanking, null /* oldEntry */);
Christoph Studer60748e72014-05-22 16:51:41 +0200595 }
596 }
597 });
598 }
599
600 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200601 public void onNotificationPosted(final StatusBarNotification sbn,
602 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200603 if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500604 if (sbn != null) {
605 mHandler.post(new Runnable() {
606 @Override
607 public void run() {
Adrian Roos497ab022015-02-10 20:49:33 +0100608 processForRemoteInput(sbn.getNotification());
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700609 String key = sbn.getKey();
Adrian Roosc0a579e2016-03-30 16:43:58 -0700610 mKeysKeptForRemoteInput.remove(key);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700611 boolean isUpdate = mNotificationData.get(key) != null;
Selim Cinekb5605e52015-02-20 18:21:41 +0100612 // In case we don't allow child notifications, we ignore children of
613 // notifications that have a summary, since we're not going to show them
614 // anyway. This is true also when the summary is canceled,
Chris Wren56919552015-02-24 15:56:34 -0500615 // because children are automatically canceled by NoMan in that case.
Selim Cinekb5605e52015-02-20 18:21:41 +0100616 if (!ENABLE_CHILD_NOTIFICATIONS
617 && mGroupManager.isChildInGroupWithSummary(sbn)) {
Chris Wren56919552015-02-24 15:56:34 -0500618 if (DEBUG) {
619 Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
620 }
621
622 // Remove existing notification to avoid stale data.
623 if (isUpdate) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700624 removeNotification(key, rankingMap);
Chris Wren56919552015-02-24 15:56:34 -0500625 } else {
626 mNotificationData.updateRanking(rankingMap);
627 }
628 return;
Christoph Studerd722f272014-09-02 11:49:19 +0200629 }
Christoph Studerd722f272014-09-02 11:49:19 +0200630 if (isUpdate) {
Chris Wren56919552015-02-24 15:56:34 -0500631 updateNotification(sbn, rankingMap);
Christoph Studerd722f272014-09-02 11:49:19 +0200632 } else {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100633 addNotification(sbn, rankingMap, null /* oldEntry */);
Christoph Studerd722f272014-09-02 11:49:19 +0200634 }
Christoph Studerd722f272014-09-02 11:49:19 +0200635 }
Chris Wren56919552015-02-24 15:56:34 -0500636 });
637 }
Christoph Studer60748e72014-05-22 16:51:41 +0200638 }
639
640 @Override
Chris Wren56919552015-02-24 15:56:34 -0500641 public void onNotificationRemoved(StatusBarNotification sbn,
Christoph Studerd0694b62014-06-04 16:36:01 +0200642 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200643 if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500644 if (sbn != null) {
645 final String key = sbn.getKey();
646 mHandler.post(new Runnable() {
647 @Override
648 public void run() {
649 removeNotification(key, rankingMap);
650 }
651 });
652 }
Christoph Studer37fe6932014-05-26 13:10:30 +0200653 }
654
655 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200656 public void onNotificationRankingUpdate(final RankingMap rankingMap) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200657 if (DEBUG) Log.d(TAG, "onRankingUpdate");
Chris Wren56919552015-02-24 15:56:34 -0500658 if (rankingMap != null) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200659 mHandler.post(new Runnable() {
660 @Override
661 public void run() {
Christoph Studere71fefc2014-06-24 16:16:49 +0200662 updateNotificationRanking(rankingMap);
Christoph Studer60748e72014-05-22 16:51:41 +0200663 }
664 });
Chris Wren56919552015-02-24 15:56:34 -0500665 } }
Christoph Studer5b638262014-07-07 11:21:49 +0200666
Christoph Studer60748e72014-05-22 16:51:41 +0200667 };
668
Kenny Guy2a764942014-04-02 13:29:20 +0100669 private void updateCurrentProfilesCache() {
670 synchronized (mCurrentProfiles) {
671 mCurrentProfiles.clear();
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000672 if (mUserManager != null) {
Kenny Guy2a764942014-04-02 13:29:20 +0100673 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
674 mCurrentProfiles.put(user.id, user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000675 }
676 }
677 }
678 }
679
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400680 public void start() {
Jeff Brown98365d72012-08-19 20:30:52 -0700681 mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
682 mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
683 mDisplay = mWindowManager.getDefaultDisplay();
Adrian Roosbd3409c2014-08-12 18:21:09 +0200684 mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
685 Context.DEVICE_POLICY_SERVICE);
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500686
Christoph Studerc8db24b2014-07-25 17:50:30 +0200687 mNotificationData = new NotificationData(this);
688
Selim Cineka8fefa52014-09-08 16:10:50 +0200689 mAccessibilityManager = (AccessibilityManager)
690 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
691
Chris Wren157026f2013-06-28 16:54:01 -0400692 mDreamManager = IDreamManager.Stub.asInterface(
693 ServiceManager.checkService(DreamService.DREAM_SERVICE));
Chris Wren157026f2013-06-28 16:54:01 -0400694 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
695
Daniel Sandler26cda272012-05-22 15:44:08 -0400696 mContext.getContentResolver().registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700697 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
John Spurlocke677d712014-02-13 12:52:19 -0500698 mSettingsObserver);
699 mContext.getContentResolver().registerContentObserver(
700 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
701 mSettingsObserver);
John Spurlock4b3bda22014-05-22 14:32:20 -0400702 mContext.getContentResolver().registerContentObserver(
Dan Sandler52e5701e2014-07-22 23:14:54 -0400703 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
704 mSettingsObserver,
705 UserHandle.USER_ALL);
Adrian Roos3aec6382016-02-05 14:19:01 -0800706 mContext.getContentResolver().registerContentObserver(
707 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), false,
708 mSettingsObserver,
709 UserHandle.USER_ALL);
Daniel Sandler26cda272012-05-22 15:44:08 -0400710
Dan Sandlerfd16d562014-02-13 18:43:31 -0800711 mContext.getContentResolver().registerContentObserver(
712 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
713 true,
714 mLockscreenSettingsObserver,
715 UserHandle.USER_ALL);
716
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500717 mBarService = IStatusBarService.Stub.asInterface(
718 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400719
Jorim Jaggid61f2272014-12-19 20:35:35 +0100720 mRecents = getComponent(Recents.class);
John Spurlockd08de372013-06-24 13:06:08 -0400721
Dan Sandler539aad42014-08-04 00:43:39 -0400722 final Configuration currentConfig = mContext.getResources().getConfiguration();
723 mLocale = currentConfig.locale;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700724 mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
Dan Sandler539aad42014-08-04 00:43:39 -0400725 mFontScale = currentConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800726 mDensity = currentConfig.densityDpi;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700727
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000728 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Ricky Wai7fa01712016-03-16 12:13:54 +0000729 mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
730 mLockPatternUtils = new LockPatternUtils(mContext);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000731
Joe Onorato2314aab2010-04-08 16:41:23 -0500732 // Connect in to the status bar manager service
Jason Monk07473ce2016-01-05 14:59:19 -0500733 mCommandQueue = new CommandQueue(this);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400734
Jorim Jaggi86905582016-02-09 21:36:09 -0800735 int[] switches = new int[9];
satokcd7cd292010-11-20 15:46:23 +0900736 ArrayList<IBinder> binders = new ArrayList<IBinder>();
Jason Monk07473ce2016-01-05 14:59:19 -0500737 ArrayList<String> iconSlots = new ArrayList<>();
738 ArrayList<StatusBarIcon> icons = new ArrayList<>();
Jorim Jaggi86905582016-02-09 21:36:09 -0800739 Rect fullscreenStackBounds = new Rect();
740 Rect dockedStackBounds = new Rect();
Joe Onorato2314aab2010-04-08 16:41:23 -0500741 try {
Jorim Jaggi86905582016-02-09 21:36:09 -0800742 mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
743 fullscreenStackBounds, dockedStackBounds);
Joe Onorato2314aab2010-04-08 16:41:23 -0500744 } catch (RemoteException ex) {
745 // If the system process isn't there we're doomed anyway.
746 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400747
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500748 createAndAddWindows();
Joe Onorato0cbda992010-05-02 16:28:15 -0700749
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100750 mSettingsObserver.onChange(false); // set up
Benjamin Franzcde0a2a2015-04-23 17:19:48 +0100751 disable(switches[0], switches[6], false /* animate */);
Jorim Jaggi86905582016-02-09 21:36:09 -0800752 setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
753 fullscreenStackBounds, dockedStackBounds);
Dianne Hackborn7d049322011-06-14 15:00:32 -0700754 topAppWindowChanged(switches[2] != 0);
satokcd7cd292010-11-20 15:46:23 +0900755 // StatusBarManagerService has a back up of IME token and it's restored here.
Michael Wright665366a2014-08-07 15:44:40 -0700756 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
Joe Onorato93056472010-09-10 10:30:46 -0400757
Joe Onorato0cbda992010-05-02 16:28:15 -0700758 // Set up the initial icon state
Jason Monk07473ce2016-01-05 14:59:19 -0500759 int N = iconSlots.size();
Joe Onorato0cbda992010-05-02 16:28:15 -0700760 int viewIndex = 0;
Jason Monk07473ce2016-01-05 14:59:19 -0500761 for (int i=0; i < N; i++) {
762 setIcon(iconSlots.get(i), icons.get(i));
Joe Onorato0cbda992010-05-02 16:28:15 -0700763 }
764
Christoph Studer71f18fd2014-05-20 17:02:04 +0200765 // Set up the initial notification state.
Christoph Studere71fefc2014-06-24 16:16:49 +0200766 try {
Christoph Studer4600f9b2014-07-22 22:44:43 +0200767 mNotificationListener.registerAsSystemService(mContext,
Christoph Studere71fefc2014-06-24 16:16:49 +0200768 new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
769 UserHandle.USER_ALL);
770 } catch (RemoteException e) {
771 Log.e(TAG, "Unable to register notification listener", e);
Joe Onorato75199e32010-05-29 17:22:51 -0400772 }
773
Christoph Studer60748e72014-05-22 16:51:41 +0200774
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500775 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400776 Log.d(TAG, String.format(
Daniel Sandler6a858c32012-03-12 14:38:58 -0400777 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
Jason Monk07473ce2016-01-05 14:59:19 -0500778 icons.size(),
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500779 switches[0],
780 switches[1],
781 switches[2],
782 switches[3]
783 ));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400784 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400785
Christopher Tate5e08af02012-09-21 17:17:22 -0700786 mCurrentUserId = ActivityManager.getCurrentUser();
Chris Wrena6d4fb62014-11-20 14:46:23 -0500787 setHeadsUpUser(mCurrentUserId);
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400788
789 IntentFilter filter = new IntentFilter();
790 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000791 filter.addAction(Intent.ACTION_USER_ADDED);
Kenny Guydae30d52015-04-01 19:11:35 +0100792 filter.addAction(Intent.ACTION_USER_PRESENT);
John Spurlock5c454122013-06-17 07:35:46 -0400793 mContext.registerReceiver(mBroadcastReceiver, filter);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000794
Ricky Wai7fa01712016-03-16 12:13:54 +0000795 IntentFilter internalFilter = new IntentFilter();
796 internalFilter.addAction(WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
797 internalFilter.addAction(BANNER_ACTION_CANCEL);
798 internalFilter.addAction(BANNER_ACTION_SETUP);
799 mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
800
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000801 IntentFilter allUsersFilter = new IntentFilter();
802 allUsersFilter.addAction(
803 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
804 mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
805 null, null);
Kenny Guy2a764942014-04-02 13:29:20 +0100806 updateCurrentProfilesCache();
Dan Sandlerdc34df52016-04-07 21:04:46 -0400807
808 IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
809 try {
810 vrManager.registerListener(mVrStateCallbacks);
811 } catch (RemoteException e) {
812 Slog.e(TAG, "Failed to register VR mode state listener: " + e);
813 }
814
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400815 }
816
Chris Wrencd8f4f72014-08-27 18:48:13 -0400817 protected void notifyUserAboutHiddenNotifications() {
818 if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
819 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
820 Log.d(TAG, "user hasn't seen notification about hidden notifications");
Ricky Wai7fa01712016-03-16 12:13:54 +0000821 if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
Chris Wrencd8f4f72014-08-27 18:48:13 -0400822 Log.d(TAG, "insecure lockscreen, skipping notification");
823 Settings.Secure.putInt(mContext.getContentResolver(),
824 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
825 return;
826 }
827 Log.d(TAG, "disabling lockecreen notifications and alerting the user");
828 // disable lockscreen notifications until user acts on the banner.
829 Settings.Secure.putInt(mContext.getContentResolver(),
830 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
Adrian Roosaee70462014-09-03 16:27:39 +0200831 Settings.Secure.putInt(mContext.getContentResolver(),
832 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400833
834 final String packageName = mContext.getPackageName();
835 PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
836 new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
837 PendingIntent.FLAG_CANCEL_CURRENT);
838 PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
839 new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
840 PendingIntent.FLAG_CANCEL_CURRENT);
841
842 final Resources res = mContext.getResources();
843 final int colorRes = com.android.internal.R.color.system_notification_accent_color;
844 Notification.Builder note = new Notification.Builder(mContext)
845 .setSmallIcon(R.drawable.ic_android)
846 .setContentTitle(mContext.getString(R.string.hidden_notifications_title))
847 .setContentText(mContext.getString(R.string.hidden_notifications_text))
848 .setPriority(Notification.PRIORITY_HIGH)
849 .setOngoing(true)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700850 .setColor(mContext.getColor(colorRes))
Chris Wrencd8f4f72014-08-27 18:48:13 -0400851 .setContentIntent(setupIntent)
852 .addAction(R.drawable.ic_close,
853 mContext.getString(R.string.hidden_notifications_cancel),
854 cancelIntent)
855 .addAction(R.drawable.ic_settings,
856 mContext.getString(R.string.hidden_notifications_setup),
857 setupIntent);
858
859 NotificationManager noMan =
860 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500861 noMan.notify(R.id.notification_hidden, note.build());
Chris Wrencd8f4f72014-08-27 18:48:13 -0400862 }
863 }
864
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400865 public void userSwitched(int newUserId) {
Chris Wrena6d4fb62014-11-20 14:46:23 -0500866 setHeadsUpUser(newUserId);
867 }
868
Selim Cinek29fa89b2015-04-17 10:39:11 -0700869 protected abstract void setHeadsUpUser(int newUserId);
Chris Wrend04f6ce2014-06-11 17:37:28 -0400870
Christoph Studerc8db24b2014-07-25 17:50:30 +0200871 @Override // NotificationData.Environment
872 public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400873 final int thisUserId = mCurrentUserId;
874 final int notificationUserId = n.getUserId();
875 if (DEBUG && MULTIUSER_DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400876 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400877 n, thisUserId, notificationUserId));
878 }
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500879 return isCurrentProfile(notificationUserId);
Joe Onorato2314aab2010-04-08 16:41:23 -0500880 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400881
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700882 protected void setNotificationShown(StatusBarNotification n) {
Chris Wren26505582015-07-22 17:03:17 -0400883 setNotificationsShown(new String[]{n.getKey()});
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700884 }
885
886 protected void setNotificationsShown(String[] keys) {
Chris Wren26505582015-07-22 17:03:17 -0400887 try {
888 mNotificationListener.setNotificationsShown(keys);
889 } catch (RuntimeException e) {
890 Log.d(TAG, "failed setNotificationsShown: ", e);
891 }
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700892 }
893
Kenny Guy44fc65f2014-11-28 22:18:14 +0000894 protected boolean isCurrentProfile(int userId) {
895 synchronized (mCurrentProfiles) {
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500896 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
Kenny Guy44fc65f2014-11-28 22:18:14 +0000897 }
898 }
899
Christoph Studer2e731b52014-08-22 16:01:51 +0200900 @Override
901 public String getCurrentMediaNotificationKey() {
902 return null;
903 }
904
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100905 @Override
906 public NotificationGroupManager getGroupManager() {
907 return mGroupManager;
908 }
909
Adrian Roos7d7090d2014-05-21 13:10:23 +0200910 /**
911 * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
912 * @param action A dismiss action that is called if it's safe to start the activity.
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200913 * @param afterKeyguardGone Whether the action should be executed after the Keyguard is gone.
Adrian Roos7d7090d2014-05-21 13:10:23 +0200914 */
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200915 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200916 action.onDismiss();
917 }
918
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700919 @Override
920 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400921 final Locale locale = mContext.getResources().getConfiguration().locale;
922 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
Dan Sandler539aad42014-08-04 00:43:39 -0400923 final float fontScale = newConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800924 final int density = newConfig.densityDpi;
925 if (density != mDensity || mFontScale != fontScale) {
Selim Cinek3e7592d2016-04-11 09:35:54 +0800926 onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -0800927 mDensity = density;
928 mFontScale = fontScale;
929 }
930 if (! locale.equals(mLocale) || ld != mLayoutDirection) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400931 if (DEBUG) {
932 Log.v(TAG, String.format(
933 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
934 locale, ld));
935 }
936 mLocale = locale;
937 mLayoutDirection = ld;
938 refreshLayout(ld);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700939 }
940 }
941
Selim Cinek3e7592d2016-04-11 09:35:54 +0800942 protected void onDensityOrFontScaleChanged() {
Selim Cinek01af3342016-02-09 19:25:31 -0800943 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
944 for (int i = 0; i < activeNotifications.size(); i++) {
945 Entry entry = activeNotifications.get(i);
946 boolean exposedGuts = entry.row.getGuts() == mNotificationGutsExposed;
947 entry.row.reInflateViews();
948 if (exposedGuts) {
949 mNotificationGutsExposed = entry.row.getGuts();
950 bindGuts(entry.row);
951 }
952 entry.cacheContentViews(mContext, null /* updatedNotification */);
953 inflateViews(entry, mStackScroller);
954 }
955 }
956
Adrian Roosc0a579e2016-03-30 16:43:58 -0700957 protected View bindVetoButtonClickListener(View row, final StatusBarNotification n) {
Winson Chungc57ccf02011-10-13 15:04:59 -0700958 View vetoButton = row.findViewById(R.id.veto);
Selim Cinek757d8792016-01-28 16:21:08 -0800959 vetoButton.setOnClickListener(new View.OnClickListener() {
960 public void onClick(View v) {
961 // Accessibility feedback
962 v.announceForAccessibility(
963 mContext.getString(R.string.accessibility_notification_dismissed));
Selim Cinek36b02232016-05-11 23:07:05 -0400964 performRemoveNotification(n, false /* removeView */);
Selim Cinek757d8792016-01-28 16:21:08 -0800965 }
966 });
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700967 vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
Winson Chungc57ccf02011-10-13 15:04:59 -0700968 return vetoButton;
969 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400970
Selim Cinek36b02232016-05-11 23:07:05 -0400971 private void performRemoveNotification(StatusBarNotification n, boolean removeView) {
972 final String pkg = n.getPackageName();
973 final String tag = n.getTag();
974 final int id = n.getId();
975 final int userId = n.getUserId();
976 try {
977 mBarService.onNotificationClear(pkg, tag, id, userId);
978 if (FORCE_REMOTE_INPUT_HISTORY
979 && mKeysKeptForRemoteInput.contains(n.getKey())) {
980 mKeysKeptForRemoteInput.remove(n.getKey());
981 removeView = true;
982 }
983 if (removeView) {
984 removeNotification(n.getKey(), null);
985 }
986
987 } catch (RemoteException ex) {
988 // system process is dead if we're here.
989 }
990 }
991
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400992
Christoph Studer13b895122014-08-26 15:42:12 +0200993 protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
Jorim Jaggi46739852014-04-15 09:58:24 +0200994 NotificationData.Entry entry) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400995
Selim Cinek684a4422015-04-15 16:18:39 -0700996 if (entry.getContentView().getId()
997 != com.android.internal.R.id.status_bar_latest_event_content) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400998 // Using custom RemoteViews
Jorim Jaggia1eeade2014-09-08 22:34:39 +0200999 if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
Dianne Hackborn955d8d62014-10-07 20:17:19 -07001000 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
Selim Cinek697178b2014-07-02 19:40:30 +02001001 entry.row.setShowingLegacyBackground(true);
Jorim Jaggi36b15232014-06-10 17:24:20 +02001002 entry.legacy = true;
Daniel Sandler96fd7c12012-03-30 16:37:36 -04001003 }
1004 }
Christoph Studer13b895122014-08-26 15:42:12 +02001005
1006 if (entry.icon != null) {
Jorim Jaggidd0107a2015-01-21 22:23:48 +01001007 entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
Christoph Studer13b895122014-08-26 15:42:12 +02001008 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -04001009 }
1010
Dan Sandler16128f42014-05-21 12:48:22 -04001011 public boolean isMediaNotification(NotificationData.Entry entry) {
Dan Sandler842dd772014-05-15 09:36:47 -04001012 // TODO: confirm that there's a valid media key
Selim Cinek684a4422015-04-15 16:18:39 -07001013 return entry.getExpandedContentView() != null &&
1014 entry.getExpandedContentView()
1015 .findViewById(com.android.internal.R.id.media_actions) != null;
Dan Sandler842dd772014-05-15 09:36:47 -04001016 }
1017
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001018 // The (i) button in the guts that links to the system notification settings for that app
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001019 private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
1020 final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
Dan Sandlere9a4e902014-07-31 01:06:43 -04001021 intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
1022 intent.putExtra(Settings.EXTRA_APP_UID, appUid);
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001023 startNotificationGutsIntent(intent, appUid);
1024 }
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001025
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001026 private void startNotificationGutsIntent(final Intent intent, final int appUid) {
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001027 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
1028 dismissKeyguardThenExecute(new OnDismissAction() {
1029 @Override
1030 public boolean onDismiss() {
1031 AsyncTask.execute(new Runnable() {
1032 public void run() {
1033 try {
1034 if (keyguardShowing) {
1035 ActivityManagerNative.getDefault()
1036 .keyguardWaitingForActivityDrawn();
1037 }
1038 TaskStackBuilder.create(mContext)
1039 .addNextIntentWithParentStack(intent)
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001040 .startActivities(getActivityOptions(),
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001041 new UserHandle(UserHandle.getUserId(appUid)));
1042 overrideActivityPendingAppTransition(keyguardShowing);
1043 } catch (RemoteException e) {
1044 }
1045 }
1046 });
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +01001047 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001048 return true;
1049 }
Jorim Jaggi746f7fa2014-08-27 17:52:46 +02001050 }, false /* afterKeyguardGone */);
Dan Sandler4247a5c2014-07-23 15:58:08 -04001051 }
1052
Mady Mellorb53bc272016-02-11 18:28:23 -08001053 private void bindGuts(final ExpandableNotificationRow row) {
Selim Cinekab29aeb2015-02-20 18:18:32 +01001054 row.inflateGuts();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001055 final StatusBarNotification sbn = row.getStatusBarNotification();
Selim Cinekeef84282015-10-30 16:28:00 -07001056 PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001057 row.setTag(sbn.getPackageName());
Julia Reynoldsa07af882015-12-17 08:32:48 -05001058 final NotificationGuts guts = row.getGuts();
Mady Mellor97c8df42016-03-22 18:09:39 -07001059 guts.setClosedListener(this);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001060 final String pkg = sbn.getPackageName();
1061 String appname = pkg;
1062 Drawable pkgicon = null;
1063 int appUid = -1;
1064 try {
1065 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
1066 PackageManager.GET_UNINSTALLED_PACKAGES
1067 | PackageManager.GET_DISABLED_COMPONENTS);
1068 if (info != null) {
1069 appname = String.valueOf(pmUser.getApplicationLabel(info));
1070 pkgicon = pmUser.getApplicationIcon(info);
1071 appUid = info.uid;
1072 }
1073 } catch (NameNotFoundException e) {
1074 // app is gone, just show package name and generic icon
1075 pkgicon = pmUser.getDefaultActivityIcon();
1076 }
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001077
Julia Reynoldsbe018462016-03-01 12:22:48 -05001078 ((ImageView) row.findViewById(R.id.app_icon)).setImageDrawable(pkgicon);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001079 ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001080
Julia Reynolds56821922016-01-04 15:24:01 -05001081 final View settingsButton = guts.findViewById(R.id.more_settings);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001082 if (appUid >= 0) {
1083 final int appUidF = appUid;
1084 settingsButton.setOnClickListener(new View.OnClickListener() {
1085 public void onClick(View v) {
Chris Wrenf6e9228b2016-01-26 18:04:35 -05001086 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
Mady Mellor97c8df42016-03-22 18:09:39 -07001087 guts.resetFalsingCheck();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001088 startAppNotificationSettingsActivity(pkg, appUidF);
1089 }
1090 });
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001091 } else {
1092 settingsButton.setVisibility(View.GONE);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001093 }
1094
Julia Reynolds56821922016-01-04 15:24:01 -05001095 row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
1096 @Override
1097 public void onClick(View v) {
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001098 // If the user has security enabled, show challenge if the setting is changed.
1099 if (guts.hasImportanceChanged() && isLockscreenPublicMode() &&
1100 (mState == StatusBarState.KEYGUARD
1101 || mState == StatusBarState.SHADE_LOCKED)) {
1102 OnDismissAction dismissAction = new OnDismissAction() {
1103 @Override
1104 public boolean onDismiss() {
1105 saveImportanceCloseControls(sbn, row, guts, v);
1106 return true;
1107 }
1108 };
1109 onLockedNotificationImportanceChange(dismissAction);
1110 } else {
1111 saveImportanceCloseControls(sbn, row, guts, v);
1112 }
Julia Reynolds56821922016-01-04 15:24:01 -05001113 }
1114 });
Julia Reynolds40779452016-02-23 13:43:32 -05001115 guts.bindImportance(pmUser, sbn, row, mNotificationData.getImportance(sbn.getKey()));
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001116 }
1117
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001118 private void saveImportanceCloseControls(StatusBarNotification sbn,
1119 ExpandableNotificationRow row, NotificationGuts guts, View done) {
Mady Mellor97c8df42016-03-22 18:09:39 -07001120 guts.resetFalsingCheck();
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001121 guts.saveImportance(sbn);
1122
1123 int[] rowLocation = new int[2];
1124 int[] doneLocation = new int[2];
1125 row.getLocationOnScreen(rowLocation);
1126 done.getLocationOnScreen(doneLocation);
1127
1128 final int centerX = done.getWidth() / 2;
1129 final int centerY = done.getHeight() / 2;
1130 final int x = doneLocation[0] - rowLocation[0] + centerX;
1131 final int y = doneLocation[1] - rowLocation[1] + centerY;
1132 dismissPopups(x, y);
1133 }
1134
Dan Sandler4247a5c2014-07-23 15:58:08 -04001135 protected SwipeHelper.LongPressListener getNotificationLongClicker() {
1136 return new SwipeHelper.LongPressListener() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001137 @Override
Selim Cinekd84a5932015-12-15 11:45:36 -08001138 public boolean onLongPress(View v, final int x, final int y) {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001139 if (!(v instanceof ExpandableNotificationRow)) {
1140 return false;
1141 }
Selim Cinekabdc5a02014-09-02 13:46:00 +02001142 if (v.getWindowToken() == null) {
1143 Log.e(TAG, "Trying to show notification guts, but not attached to window");
1144 return false;
1145 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001146
Mady Mellor4b80b102016-01-22 08:03:58 -08001147 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
Selim Cinekab29aeb2015-02-20 18:18:32 +01001148 bindGuts(row);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001149
Dan Sandler4247a5c2014-07-23 15:58:08 -04001150 // Assume we are a status_bar_notification_row
Selim Cinekab29aeb2015-02-20 18:18:32 +01001151 final NotificationGuts guts = row.getGuts();
Selim Cinekbdefcdf2014-09-11 12:41:47 +02001152 if (guts == null) {
1153 // This view has no guts. Examples are the more card or the dismiss all view
1154 return false;
1155 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001156
1157 // Already showing?
Selim Cinekabdc5a02014-09-02 13:46:00 +02001158 if (guts.getVisibility() == View.VISIBLE) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001159 dismissPopups(x, y);
Selim Cinekabdc5a02014-09-02 13:46:00 +02001160 return false;
1161 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001162
Chris Wrenf6e9228b2016-01-26 18:04:35 -05001163 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001164
Julia Reynolds40779452016-02-23 13:43:32 -05001165 // ensure that it's laid but not visible until actually laid out
Selim Cinekd84a5932015-12-15 11:45:36 -08001166 guts.setVisibility(View.INVISIBLE);
Julia Reynolds40779452016-02-23 13:43:32 -05001167 // Post to ensure the the guts are properly laid out.
Selim Cinekd84a5932015-12-15 11:45:36 -08001168 guts.post(new Runnable() {
1169 public void run() {
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001170 dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */,
1171 false /* animate */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001172 guts.setVisibility(View.VISIBLE);
1173 final double horz = Math.max(guts.getWidth() - x, x);
1174 final double vert = Math.max(guts.getHeight() - y, y);
1175 final float r = (float) Math.hypot(horz, vert);
1176 final Animator a
1177 = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
1178 a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc18010f2016-01-20 13:41:30 -08001179 a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Mady Mellor4b80b102016-01-22 08:03:58 -08001180 a.addListener(new AnimatorListenerAdapter() {
1181 @Override
1182 public void onAnimationEnd(Animator animation) {
1183 super.onAnimationEnd(animation);
1184 // Move the notification view back over the gear
1185 row.resetTranslation();
1186 }
1187 });
Selim Cinekd84a5932015-12-15 11:45:36 -08001188 a.start();
Mady Mellor97c8df42016-03-22 18:09:39 -07001189 guts.setExposed(true /* exposed */,
1190 mState == StatusBarState.KEYGUARD /* needsFalsingProtection */);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001191 row.closeRemoteInput();
Selim Cinekd84a5932015-12-15 11:45:36 -08001192 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
1193 mNotificationGutsExposed = guts;
1194 }
1195 });
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001196 return true;
1197 }
1198 };
1199 }
1200
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001201 /**
1202 * Returns the exposed NotificationGuts or null if none are exposed.
1203 */
1204 public NotificationGuts getExposedGuts() {
1205 return mNotificationGutsExposed;
Mady Mellor4b80b102016-01-22 08:03:58 -08001206 }
1207
Daniel Sandler469e96e2012-05-04 15:56:19 -04001208 public void dismissPopups() {
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001209 dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */, false /* animate */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001210 }
1211
1212 private void dismissPopups(int x, int y) {
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001213 dismissPopups(x, y, true /* resetGear */, false /* animate */);
Mady Mellorb53bc272016-02-11 18:28:23 -08001214 }
1215
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001216 public void dismissPopups(int x, int y, boolean resetGear, boolean animate) {
Dan Sandler4247a5c2014-07-23 15:58:08 -04001217 if (mNotificationGutsExposed != null) {
Mady Mellor97c8df42016-03-22 18:09:39 -07001218 mNotificationGutsExposed.closeControls(x, y, true /* notify */);
Daniel Sandler469e96e2012-05-04 15:56:19 -04001219 }
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001220 if (resetGear) {
1221 mStackScroller.resetExposedGearView(animate, true /* force */);
Mady Mellor4b80b102016-01-22 08:03:58 -08001222 }
Daniel Sandler469e96e2012-05-04 15:56:19 -04001223 }
1224
Michael Jurka7f2668c2012-03-27 07:49:52 -07001225 @Override
Mady Mellor97c8df42016-03-22 18:09:39 -07001226 public void onGutsClosed(NotificationGuts guts) {
1227 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
1228 mNotificationGutsExposed = null;
1229 }
1230
1231 @Override
Jorim Jaggi681fc7b2016-04-14 22:02:39 -07001232 public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001233 int msg = MSG_SHOW_RECENT_APPS;
1234 mHandler.removeMessages(msg);
Jorim Jaggi681fc7b2016-04-14 22:02:39 -07001235 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, fromHome ? 1 : 0).sendToTarget();
Winson Chung1e8d71b2014-05-16 17:05:22 -07001236 }
1237
1238 @Override
Winson Chungcdcd4872014-08-05 18:00:13 -07001239 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001240 int msg = MSG_HIDE_RECENT_APPS;
1241 mHandler.removeMessages(msg);
Winson Chungcdcd4872014-08-05 18:00:13 -07001242 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0,
1243 triggeredFromHomeKey ? 1 : 0).sendToTarget();
Winson Chung1e8d71b2014-05-16 17:05:22 -07001244 }
1245
1246 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001247 public void toggleRecentApps() {
Jorim Jaggi900fb482015-06-02 15:07:33 -07001248 toggleRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001249 }
1250
1251 @Override
Phil Weaver315c34e2016-02-19 15:12:29 -08001252 public void toggleSplitScreen() {
Jorim Jaggi29379ec2016-04-11 23:43:42 -07001253 toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
Phil Weaver315c34e2016-02-19 15:12:29 -08001254 }
1255
1256 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001257 public void preloadRecentApps() {
1258 int msg = MSG_PRELOAD_RECENT_APPS;
1259 mHandler.removeMessages(msg);
1260 mHandler.sendEmptyMessage(msg);
1261 }
1262
1263 @Override
1264 public void cancelPreloadRecentApps() {
1265 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
1266 mHandler.removeMessages(msg);
1267 mHandler.sendEmptyMessage(msg);
1268 }
1269
Clara Bayarrif2debb12015-07-10 14:47:17 +01001270 @Override
Andrei Stingaceanu0bf096f2016-04-14 18:11:57 +01001271 public void dismissKeyboardShortcutsMenu() {
1272 int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
1273 mHandler.removeMessages(msg);
1274 mHandler.sendEmptyMessage(msg);
1275 }
1276
1277 @Override
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001278 public void toggleKeyboardShortcutsMenu(int deviceId) {
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001279 int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
Clara Bayarrif2debb12015-07-10 14:47:17 +01001280 mHandler.removeMessages(msg);
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001281 mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
Clara Bayarrif2debb12015-07-10 14:47:17 +01001282 }
1283
Winson Chungb1f74992014-08-08 12:53:09 -07001284 /** Jumps to the next affiliated task in the group. */
1285 public void showNextAffiliatedTask() {
1286 int msg = MSG_SHOW_NEXT_AFFILIATED_TASK;
1287 mHandler.removeMessages(msg);
1288 mHandler.sendEmptyMessage(msg);
1289 }
1290
1291 /** Jumps to the previous affiliated task in the group. */
1292 public void showPreviousAffiliatedTask() {
1293 int msg = MSG_SHOW_PREV_AFFILIATED_TASK;
1294 mHandler.removeMessages(msg);
1295 mHandler.sendEmptyMessage(msg);
1296 }
1297
Michael Jurkaecc395a2012-03-30 05:31:46 -07001298 protected H createHandler() {
Michael Jurka7f2668c2012-03-27 07:49:52 -07001299 return new H();
1300 }
1301
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001302 protected void sendCloseSystemWindows(String reason) {
Michael Jurka56a57832012-05-14 13:24:43 -07001303 if (ActivityManagerNative.isSystemReady()) {
1304 try {
1305 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
1306 } catch (RemoteException e) {
1307 }
1308 }
1309 }
1310
Michael Jurkacb2522c2012-04-13 09:32:47 -07001311 protected abstract View getStatusBarView();
1312
Michael Jurka80343f62012-10-18 13:13:46 +02001313 protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
1314 // additional optimization when we have software system buttons - start loading the recent
1315 // tasks on touch down
1316 @Override
1317 public boolean onTouch(View v, MotionEvent event) {
1318 int action = event.getAction() & MotionEvent.ACTION_MASK;
1319 if (action == MotionEvent.ACTION_DOWN) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001320 preloadRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001321 } else if (action == MotionEvent.ACTION_CANCEL) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001322 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001323 } else if (action == MotionEvent.ACTION_UP) {
1324 if (!v.isPressed()) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001325 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001326 }
1327
1328 }
1329 return false;
1330 }
1331 };
1332
Phil Weaver315c34e2016-02-19 15:12:29 -08001333 /**
1334 * Toggle docking the app window
1335 *
Jorim Jaggi29379ec2016-04-11 23:43:42 -07001336 * @param metricsDockAction the action to log when docking is successful, or -1 to not log
1337 * anything on successful docking
1338 * @param metricsUndockAction the action to log when undocking, or -1 to not log anything when
1339 * undocking
Phil Weaver315c34e2016-02-19 15:12:29 -08001340 */
Jorim Jaggi29379ec2016-04-11 23:43:42 -07001341 protected abstract void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction);
Phil Weaver315c34e2016-02-19 15:12:29 -08001342
Winson Chung1e8d71b2014-05-16 17:05:22 -07001343 /** Proxy for RecentsComponent */
1344
Jorim Jaggi681fc7b2016-04-14 22:02:39 -07001345 protected void showRecents(boolean triggeredFromAltTab, boolean fromHome) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001346 if (mRecents != null) {
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001347 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001348 mRecents.showRecents(triggeredFromAltTab, fromHome);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001349 }
1350 }
1351
Winson Chungcdcd4872014-08-05 18:00:13 -07001352 protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001353 if (mRecents != null) {
Winson Chungcdcd4872014-08-05 18:00:13 -07001354 mRecents.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001355 }
1356 }
1357
1358 protected void toggleRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001359 if (mRecents != null) {
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001360 mRecents.toggleRecents(mDisplay);
John Spurlockd08de372013-06-24 13:06:08 -04001361 }
1362 }
Michael Jurka80343f62012-10-18 13:13:46 +02001363
Winson Chung1e8d71b2014-05-16 17:05:22 -07001364 protected void preloadRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001365 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001366 mRecents.preloadRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001367 }
Michael Jurka80343f62012-10-18 13:13:46 +02001368 }
1369
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001370 protected void toggleKeyboardShortcuts(int deviceId) {
Andrei Stingaceanuf86bc972016-04-12 15:29:25 +01001371 KeyboardShortcuts.toggle(mContext, deviceId);
Clara Bayarrif2debb12015-07-10 14:47:17 +01001372 }
1373
Andrei Stingaceanu0bf096f2016-04-14 18:11:57 +01001374 protected void dismissKeyboardShortcuts() {
1375 KeyboardShortcuts.dismiss();
1376 }
1377
Winson Chung1e8d71b2014-05-16 17:05:22 -07001378 protected void cancelPreloadingRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001379 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001380 mRecents.cancelPreloadingRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001381 }
Michael Jurka80343f62012-10-18 13:13:46 +02001382 }
1383
Winson Chungb1f74992014-08-08 12:53:09 -07001384 protected void showRecentsNextAffiliatedTask() {
1385 if (mRecents != null) {
1386 mRecents.showNextAffiliatedTask();
1387 }
1388 }
1389
1390 protected void showRecentsPreviousAffiliatedTask() {
1391 if (mRecents != null) {
1392 mRecents.showPrevAffiliatedTask();
1393 }
1394 }
1395
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001396 /**
Selim Cinek684a4422015-04-15 16:18:39 -07001397 * If there is an active heads-up notification and it has a fullscreen intent, fire it now.
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001398 */
Selim Cinek684a4422015-04-15 16:18:39 -07001399 public abstract void maybeEscalateHeadsUp();
Chris Wrena4ef6202014-06-09 18:07:30 -04001400
Dan Sandlerfd16d562014-02-13 18:43:31 -08001401 /**
1402 * Save the current "public" (locked and secure) state of the lockscreen.
1403 */
1404 public void setLockscreenPublicMode(boolean publicMode) {
1405 mLockscreenPublicMode = publicMode;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001406 }
1407
Dan Sandlerfd16d562014-02-13 18:43:31 -08001408 public boolean isLockscreenPublicMode() {
1409 return mLockscreenPublicMode;
1410 }
1411
Ricky Waicd35def2016-05-03 11:07:07 +01001412 protected void onWorkChallengeUnlocked() {}
1413
Dan Sandlerfd16d562014-02-13 18:43:31 -08001414 /**
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001415 * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
1416 * "public" (secure & locked) mode?
1417 */
1418 public boolean userAllowsNotificationsInPublic(int userHandle) {
1419 if (userHandle == UserHandle.USER_ALL) {
1420 return true;
1421 }
1422
1423 if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
1424 final boolean allowed = 0 != Settings.Secure.getIntForUser(
1425 mContext.getContentResolver(),
1426 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
1427 mUsersAllowingNotifications.append(userHandle, allowed);
1428 return allowed;
1429 }
1430
1431 return mUsersAllowingNotifications.get(userHandle);
1432 }
1433
1434 /**
Dan Sandlerfd16d562014-02-13 18:43:31 -08001435 * Has the given user chosen to allow their private (full) notifications to be shown even
1436 * when the lockscreen is in "public" (secure & locked) mode?
1437 */
1438 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
1439 if (userHandle == UserHandle.USER_ALL) {
1440 return true;
1441 }
1442
1443 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001444 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
Dan Sandlerfd16d562014-02-13 18:43:31 -08001445 mContext.getContentResolver(),
1446 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001447 final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001448 final boolean allowed = allowedByUser && allowedByDpm;
1449 mUsersAllowingPrivateNotifications.append(userHandle, allowed);
Dan Sandlerfd16d562014-02-13 18:43:31 -08001450 return allowed;
1451 }
1452
1453 return mUsersAllowingPrivateNotifications.get(userHandle);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001454 }
1455
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001456 private boolean adminAllowsUnredactedNotifications(int userHandle) {
1457 if (userHandle == UserHandle.USER_ALL) {
1458 return true;
1459 }
1460 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
1461 userHandle);
1462 return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
1463 }
1464
Christoph Studerc8db24b2014-07-25 17:50:30 +02001465 /**
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001466 * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
1467 * If so, notifications should be hidden.
Christoph Studerc8db24b2014-07-25 17:50:30 +02001468 */
1469 @Override // NotificationData.Environment
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001470 public boolean shouldHideNotifications(int userid) {
1471 return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
1472 }
1473
1474 /**
1475 * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
1476 * package-specific override.
1477 */
1478 @Override // NotificationDate.Environment
1479 public boolean shouldHideNotifications(String key) {
1480 return isLockscreenPublicMode()
1481 && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
1482 }
1483
1484 /**
1485 * Returns true if we're on a secure lockscreen.
1486 */
1487 @Override // NotificationData.Environment
1488 public boolean onSecureLockScreen() {
1489 return isLockscreenPublicMode();
Christoph Studerc8db24b2014-07-25 17:50:30 +02001490 }
1491
Chris Wrena4ef6202014-06-09 18:07:30 -04001492 public void onNotificationClear(StatusBarNotification notification) {
1493 try {
1494 mBarService.onNotificationClear(
1495 notification.getPackageName(),
1496 notification.getTag(),
1497 notification.getId(),
1498 notification.getUserId());
1499 } catch (android.os.RemoteException ex) {
1500 // oh well
1501 }
1502 }
1503
Selim Cinek5f71bee2015-11-18 10:25:23 -08001504 /**
Selim Cinek5fbc6322016-01-15 17:17:58 -08001505 * Called when the notification panel layouts
Selim Cinek5f71bee2015-11-18 10:25:23 -08001506 */
Selim Cinek5fbc6322016-01-15 17:17:58 -08001507 public void onPanelLaidOut() {
Selim Cinek5f71bee2015-11-18 10:25:23 -08001508 if (mState == StatusBarState.KEYGUARD) {
1509 // Since the number of notifications is determined based on the height of the view, we
1510 // need to update them.
Selim Cinek5fbc6322016-01-15 17:17:58 -08001511 int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
1512 int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
1513 if (maxBefore != maxNotifications) {
1514 updateRowStates();
1515 }
Selim Cinek5f71bee2015-11-18 10:25:23 -08001516 }
1517 }
1518
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001519 protected void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {}
1520
Adrian Roos3aec6382016-02-05 14:19:01 -08001521 protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
1522
Ricky Waicd35def2016-05-03 11:07:07 +01001523 protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
1524 View clicked) {}
1525
Selim Cinek570981d2015-12-01 11:37:01 -08001526 @Override
Selim Cinek31aada42015-12-18 17:51:15 -08001527 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
Selim Cinek570981d2015-12-01 11:37:01 -08001528 }
1529
Michael Jurka7f2668c2012-03-27 07:49:52 -07001530 protected class H extends Handler {
1531 public void handleMessage(Message m) {
1532 switch (m.what) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001533 case MSG_SHOW_RECENT_APPS:
Jorim Jaggi681fc7b2016-04-14 22:02:39 -07001534 showRecents(m.arg1 > 0, m.arg2 != 0);
Michael Jurkacb2522c2012-04-13 09:32:47 -07001535 break;
Winson Chung1e8d71b2014-05-16 17:05:22 -07001536 case MSG_HIDE_RECENT_APPS:
Winson Chungcdcd4872014-08-05 18:00:13 -07001537 hideRecents(m.arg1 > 0, m.arg2 > 0);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001538 break;
1539 case MSG_TOGGLE_RECENTS_APPS:
1540 toggleRecents();
Michael Jurkacb2522c2012-04-13 09:32:47 -07001541 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001542 case MSG_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001543 preloadRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001544 break;
1545 case MSG_CANCEL_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001546 cancelPreloadingRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001547 break;
Winson Chungb1f74992014-08-08 12:53:09 -07001548 case MSG_SHOW_NEXT_AFFILIATED_TASK:
1549 showRecentsNextAffiliatedTask();
1550 break;
1551 case MSG_SHOW_PREV_AFFILIATED_TASK:
1552 showRecentsPreviousAffiliatedTask();
1553 break;
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001554 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001555 toggleKeyboardShortcuts(m.arg1);
Clara Bayarrif2debb12015-07-10 14:47:17 +01001556 break;
Andrei Stingaceanu0bf096f2016-04-14 18:11:57 +01001557 case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
1558 dismissKeyboardShortcuts();
1559 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001560 }
1561 }
1562 }
1563
Daniel Sandler6a858c32012-03-12 14:38:58 -04001564 protected void workAroundBadLayerDrawableOpacity(View v) {
1565 }
1566
Selim Cinek8d490d42015-04-10 00:05:50 -07001567 protected boolean inflateViews(Entry entry, ViewGroup parent) {
Selim Cinekeef84282015-10-30 16:28:00 -07001568 PackageManager pmUser = getPackageManagerForUser(mContext,
Dan Sandlere9a4e902014-07-31 01:06:43 -04001569 entry.notification.getUser().getIdentifier());
1570
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001571 final StatusBarNotification sbn = entry.notification;
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001572 entry.cacheContentViews(mContext, null);
1573
1574 final RemoteViews contentView = entry.cachedContentView;
1575 final RemoteViews bigContentView = entry.cachedBigContentView;
1576 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
1577 final RemoteViews publicContentView = entry.cachedPublicContentView;
Chris Wren8fd39ec2014-02-27 17:43:26 -05001578
Chris Wren574a55e2013-07-15 18:48:37 -04001579 if (contentView == null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001580 Log.v(TAG, "no contentView for: " + sbn.getNotification());
Daniel Sandler6a858c32012-03-12 14:38:58 -04001581 return false;
1582 }
1583
Dan Sandlerf68448e2014-04-24 15:54:16 -04001584 if (DEBUG) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001585 Log.v(TAG, "publicContentView: " + publicContentView);
Dan Sandlerf68448e2014-04-24 15:54:16 -04001586 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001587
Christoph Studera7fe6312014-06-27 19:32:44 +02001588 ExpandableNotificationRow row;
1589
1590 // Stash away previous user expansion state so we can restore it at
1591 // the end.
1592 boolean hasUserChangedExpansion = false;
1593 boolean userExpanded = false;
1594 boolean userLocked = false;
1595
1596 if (entry.row != null) {
1597 row = entry.row;
1598 hasUserChangedExpansion = row.hasUserChangedExpansion();
1599 userExpanded = row.isUserExpanded();
1600 userLocked = row.isUserLocked();
Christoph Studer22f2ee52014-07-29 22:57:21 +02001601 entry.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +02001602 if (hasUserChangedExpansion) {
1603 row.setUserExpanded(userExpanded);
1604 }
1605 } else {
1606 // create the row view
1607 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
1608 Context.LAYOUT_INFLATER_SERVICE);
1609 row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
1610 parent, false);
Chris Wren78403d72014-07-28 10:23:24 +01001611 row.setExpansionLogger(this, entry.notification.getKey());
Selim Cinekb5605e52015-02-20 18:21:41 +01001612 row.setGroupManager(mGroupManager);
Selim Cinek31aada42015-12-18 17:51:15 -08001613 row.setHeadsUpManager(mHeadsUpManager);
Adrian Roosb88b1a12015-12-09 18:51:05 -08001614 row.setRemoteInputController(mRemoteInputController);
Selim Cinek570981d2015-12-01 11:37:01 -08001615 row.setOnExpandClickListener(this);
Mady Mellor3fd273e2016-03-15 21:08:14 -07001616
Dan Sandler732bd6c2016-04-12 14:20:32 -04001617 // Get the app name.
1618 // Note that Notification.Builder#bindHeaderAppName has similar logic
1619 // but since this field is used in the guts, it must be accurate.
1620 // Therefore we will only show the application label, or, failing that, the
1621 // package name. No substitutions.
Mady Mellor3fd273e2016-03-15 21:08:14 -07001622 final String pkg = sbn.getPackageName();
1623 String appname = pkg;
1624 try {
1625 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
1626 PackageManager.GET_UNINSTALLED_PACKAGES
1627 | PackageManager.GET_DISABLED_COMPONENTS);
1628 if (info != null) {
1629 appname = String.valueOf(pmUser.getApplicationLabel(info));
1630 }
1631 } catch (NameNotFoundException e) {
1632 // Do nothing
1633 }
1634 row.setAppName(appname);
Christoph Studera7fe6312014-06-27 19:32:44 +02001635 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001636
Daniel Sandler6a858c32012-03-12 14:38:58 -04001637 workAroundBadLayerDrawableOpacity(row);
Selim Cinek757d8792016-01-28 16:21:08 -08001638 View vetoButton = bindVetoButtonClickListener(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001639 vetoButton.setContentDescription(mContext.getString(
1640 R.string.accessibility_remove_notification));
1641
1642 // NB: the large icon is now handled entirely by the template
1643
1644 // bind the click event to the content area
Selim Cinek8d490d42015-04-10 00:05:50 -07001645 NotificationContentView contentContainer = row.getPrivateLayout();
1646 NotificationContentView contentContainerPublic = row.getPublicLayout();
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001647
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001648 row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
Adrian Roos497ab022015-02-10 20:49:33 +01001649 if (ENABLE_REMOTE_INPUT) {
1650 row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
1651 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001652
Chris Wren42d5dd42015-05-01 10:39:26 -04001653 mNotificationClicker.register(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001654
Dan Sandlera5e0f412014-01-23 15:11:54 -05001655 // set up the adaptive layout
Chris Wren574a55e2013-07-15 18:48:37 -04001656 View contentViewLocal = null;
1657 View bigContentViewLocal = null;
Selim Cinek8d490d42015-04-10 00:05:50 -07001658 View headsUpContentViewLocal = null;
Selim Cinek624c02db2015-12-14 21:00:02 -08001659 View publicViewLocal = null;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001660 try {
Dan Sandler68079d52015-07-22 10:45:30 -04001661 contentViewLocal = contentView.apply(
1662 sbn.getPackageContext(mContext),
1663 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001664 mOnClickHandler);
Chris Wren574a55e2013-07-15 18:48:37 -04001665 if (bigContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001666 bigContentViewLocal = bigContentView.apply(
1667 sbn.getPackageContext(mContext),
1668 contentContainer,
Selim Cinek8d490d42015-04-10 00:05:50 -07001669 mOnClickHandler);
1670 }
1671 if (headsUpContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001672 headsUpContentViewLocal = headsUpContentView.apply(
1673 sbn.getPackageContext(mContext),
1674 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001675 mOnClickHandler);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001676 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001677 if (publicContentView != null) {
1678 publicViewLocal = publicContentView.apply(
1679 sbn.getPackageContext(mContext),
1680 contentContainerPublic, mOnClickHandler);
1681 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001682 }
1683 catch (RuntimeException e) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001684 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
John Spurlockcd686b52013-06-05 10:13:46 -04001685 Log.e(TAG, "couldn't inflate view for notification " + ident, e);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001686 return false;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001687 }
1688
Chris Wren574a55e2013-07-15 18:48:37 -04001689 if (contentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001690 contentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001691 contentContainer.setContractedChild(contentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001692 }
Chris Wren574a55e2013-07-15 18:48:37 -04001693 if (bigContentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001694 bigContentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001695 contentContainer.setExpandedChild(bigContentViewLocal);
1696 }
1697 if (headsUpContentViewLocal != null) {
1698 headsUpContentViewLocal.setIsRootNamespace(true);
1699 contentContainer.setHeadsUpChild(headsUpContentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001700 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001701 if (publicViewLocal != null) {
1702 publicViewLocal.setIsRootNamespace(true);
1703 contentContainerPublic.setContractedChild(publicViewLocal);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001704 }
1705
Jorim Jaggia1eeade2014-09-08 22:34:39 +02001706 // Extract target SDK version.
1707 try {
1708 ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
1709 entry.targetSdk = info.targetSdkVersion;
1710 } catch (NameNotFoundException ex) {
1711 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
1712 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001713 entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001714
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001715 if (MULTIUSER_DEBUG) {
1716 TextView debug = (TextView) row.findViewById(R.id.debug_info);
1717 if (debug != null) {
1718 debug.setVisibility(View.VISIBLE);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001719 debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId());
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001720 }
1721 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001722 entry.row = row;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001723 entry.row.setOnActivatedListener(this);
Selim Cinek684a4422015-04-15 16:18:39 -07001724 entry.row.setExpandable(bigContentViewLocal != null);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001725
Christoph Studer13b895122014-08-26 15:42:12 +02001726 applyColorsAndBackgrounds(sbn, entry);
Jorim Jaggi46739852014-04-15 09:58:24 +02001727
Christoph Studera7fe6312014-06-27 19:32:44 +02001728 // Restore previous flags.
1729 if (hasUserChangedExpansion) {
1730 // Note: setUserExpanded() conveniently ignores calls with
1731 // userExpanded=true if !isExpandable().
1732 row.setUserExpanded(userExpanded);
1733 }
1734 row.setUserLocked(userLocked);
Selim Cinekda42d652015-12-04 15:51:16 -08001735 row.onNotificationUpdated(entry);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001736 return true;
1737 }
1738
Adrian Roos497ab022015-02-10 20:49:33 +01001739 /**
1740 * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
1741 * via first-class API.
1742 *
1743 * TODO: Remove once enough apps specify remote inputs on their own.
1744 */
1745 private void processForRemoteInput(Notification n) {
1746 if (!ENABLE_REMOTE_INPUT) return;
1747
1748 if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
1749 (n.actions == null || n.actions.length == 0)) {
1750 Notification.Action viableAction = null;
1751 Notification.WearableExtender we = new Notification.WearableExtender(n);
1752
1753 List<Notification.Action> actions = we.getActions();
1754 final int numActions = actions.size();
1755
1756 for (int i = 0; i < numActions; i++) {
1757 Notification.Action action = actions.get(i);
Adrian Roosa3539cb2015-12-16 16:47:02 -08001758 if (action == null) {
1759 continue;
1760 }
Adrian Roos497ab022015-02-10 20:49:33 +01001761 RemoteInput[] remoteInputs = action.getRemoteInputs();
Adrian Roosa3539cb2015-12-16 16:47:02 -08001762 if (remoteInputs == null) {
1763 continue;
1764 }
1765 for (RemoteInput ri : remoteInputs) {
Adrian Roos497ab022015-02-10 20:49:33 +01001766 if (ri.getAllowFreeFormInput()) {
1767 viableAction = action;
1768 break;
1769 }
1770 }
1771 if (viableAction != null) {
1772 break;
1773 }
1774 }
1775
1776 if (viableAction != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001777 Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
1778 rebuilder.setActions(viableAction);
1779 rebuilder.build(); // will rewrite n
Adrian Roos497ab022015-02-10 20:49:33 +01001780 }
1781 }
1782 }
1783
Adrian Roos62692b22015-09-11 17:46:23 -07001784 public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
1785 if (!isDeviceProvisioned()) return;
1786
1787 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
1788 final boolean afterKeyguardGone = intent.isActivity()
1789 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
1790 mCurrentUserId);
1791 dismissKeyguardThenExecute(new OnDismissAction() {
1792 public boolean onDismiss() {
1793 new Thread() {
1794 @Override
1795 public void run() {
1796 try {
1797 if (keyguardShowing && !afterKeyguardGone) {
1798 ActivityManagerNative.getDefault()
1799 .keyguardWaitingForActivityDrawn();
1800 }
1801
1802 // The intent we are sending is for the application, which
1803 // won't have permission to immediately start an activity after
1804 // the user switches to home. We know it is safe to do at this
1805 // point, so make sure new activity switches are now allowed.
1806 ActivityManagerNative.getDefault().resumeAppSwitches();
1807 } catch (RemoteException e) {
1808 }
Adrian Roos62692b22015-09-11 17:46:23 -07001809 try {
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001810 intent.send(null, 0, null, null, null, null, getActivityOptions());
Adrian Roos62692b22015-09-11 17:46:23 -07001811 } catch (PendingIntent.CanceledException e) {
1812 // the stack trace isn't very helpful here.
1813 // Just log the exception message.
1814 Log.w(TAG, "Sending intent failed: " + e);
1815
1816 // TODO: Dismiss Keyguard.
1817 }
1818 if (intent.isActivity()) {
1819 mAssistManager.hideAssist();
1820 overrideActivityPendingAppTransition(keyguardShowing
1821 && !afterKeyguardGone);
1822 }
1823 }
1824 }.start();
1825
1826 // close the shade if it was open
1827 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
1828 true /* force */, true /* delayed */);
1829 visibilityChanged(false);
1830
1831 return true;
1832 }
1833 }, afterKeyguardGone);
1834 }
1835
Selim Cinek36b02232016-05-11 23:07:05 -04001836 public void addPostCollapseAction(Runnable r) {
1837 }
1838
1839 public boolean isCollapsing() {
1840 return false;
1841 }
1842
Chris Wren42d5dd42015-05-01 10:39:26 -04001843 private final class NotificationClicker implements View.OnClickListener {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001844 public void onClick(final View v) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001845 if (!(v instanceof ExpandableNotificationRow)) {
1846 Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
1847 return;
1848 }
1849
1850 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
1851 final StatusBarNotification sbn = row.getStatusBarNotification();
1852 if (sbn == null) {
1853 Log.e(TAG, "NotificationClicker called on an unclickable notification,");
1854 return;
1855 }
1856
Mady Mellorf0625802016-02-11 18:03:48 -08001857 // Check if the notification is displaying the gear, if so slide notification back
1858 if (row.getSettingsRow() != null && row.getSettingsRow().isVisible()) {
1859 row.animateTranslateNotification(0);
1860 return;
1861 }
1862
Selim Cinekc6dd5212015-11-02 14:51:54 -08001863 Notification notification = sbn.getNotification();
1864 final PendingIntent intent = notification.contentIntent != null
1865 ? notification.contentIntent
1866 : notification.fullScreenIntent;
Chris Wren42d5dd42015-05-01 10:39:26 -04001867 final String notificationKey = sbn.getKey();
1868
Jorim Jaggi5eb67c22015-08-19 19:50:49 -07001869 // Mark notification for one frame.
1870 row.setJustClicked(true);
1871 DejankUtils.postAfterTraversal(new Runnable() {
1872 @Override
1873 public void run() {
1874 row.setJustClicked(false);
1875 }
1876 });
1877
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001878 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Chris Wren42d5dd42015-05-01 10:39:26 -04001879 final boolean afterKeyguardGone = intent.isActivity()
1880 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001881 mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +02001882 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001883 public boolean onDismiss() {
Chris Wren42d5dd42015-05-01 10:39:26 -04001884 if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
Christoph Studerc6a656c2015-01-22 15:02:49 +01001885 // Release the HUN notification to the shade.
1886 //
1887 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
1888 // become canceled shortly by NoMan, but we can't assume that.
Selim Cinek0fccc722015-07-29 17:04:36 -07001889 HeadsUpManager.setIsClickedNotification(row, true);
Chris Wren42d5dd42015-05-01 10:39:26 -04001890 mHeadsUpManager.releaseImmediately(notificationKey);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001891 }
Selim Cinek36b02232016-05-11 23:07:05 -04001892 StatusBarNotification parentToCancel = null;
1893 if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
1894 StatusBarNotification summarySbn = mGroupManager.getLogicalGroupSummary(sbn)
1895 .getStatusBarNotification();
1896 if (shouldAutoCancel(summarySbn)) {
1897 parentToCancel = summarySbn;
1898 }
1899 }
1900 final StatusBarNotification parentToCancelFinal = parentToCancel;
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001901 new Thread() {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001902 @Override
1903 public void run() {
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001904 try {
1905 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001906 ActivityManagerNative.getDefault()
1907 .keyguardWaitingForActivityDrawn();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001908 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001909
1910 // The intent we are sending is for the application, which
1911 // won't have permission to immediately start an activity after
1912 // the user switches to home. We know it is safe to do at this
1913 // point, so make sure new activity switches are now allowed.
1914 ActivityManagerNative.getDefault().resumeAppSwitches();
1915 } catch (RemoteException e) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001916 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001917 if (intent != null) {
Ricky Wai7fa01712016-03-16 12:13:54 +00001918 // If we are launching a work activity and require to launch
1919 // separate work challenge, we defer the activity action and cancel
1920 // notification until work challenge is unlocked.
1921 if (intent.isActivity()) {
1922 final int userId = intent.getCreatorUserHandle()
1923 .getIdentifier();
1924 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
1925 && mKeyguardManager.isDeviceLocked(userId)) {
Ricky Waia8c37a12016-04-05 17:10:04 +01001926 if (startWorkChallengeIfNecessary(userId,
1927 intent.getIntentSender(), notificationKey)) {
1928 // Show work challenge, do not run pendingintent and
1929 // remove notification
1930 return;
1931 }
Ricky Wai7fa01712016-03-16 12:13:54 +00001932 }
1933 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001934 try {
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001935 intent.send(null, 0, null, null, null, null,
1936 getActivityOptions());
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001937 } catch (PendingIntent.CanceledException e) {
1938 // the stack trace isn't very helpful here.
1939 // Just log the exception message.
1940 Log.w(TAG, "Sending contentIntent failed: " + e);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001941
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001942 // TODO: Dismiss Keyguard.
1943 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001944 if (intent.isActivity()) {
Jorim Jaggib835dd72015-06-08 12:28:42 -07001945 mAssistManager.hideAssist();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001946 overrideActivityPendingAppTransition(keyguardShowing
1947 && !afterKeyguardGone);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001948 }
1949 }
1950
1951 try {
Chris Wren42d5dd42015-05-01 10:39:26 -04001952 mBarService.onNotificationClick(notificationKey);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001953 } catch (RemoteException ex) {
1954 // system process is dead if we're here.
1955 }
Selim Cinek36b02232016-05-11 23:07:05 -04001956 if (parentToCancelFinal != null) {
1957 // We have to post it to the UI thread for synchronization
1958 mHandler.post(new Runnable() {
1959 @Override
1960 public void run() {
1961 Runnable removeRunnable = new Runnable() {
1962 @Override
1963 public void run() {
1964 performRemoveNotification(parentToCancelFinal,
1965 true);
1966 }
1967 };
1968 if (isCollapsing()) {
1969 // To avoid lags we're only performing the remove
1970 // after the shade was collapsed
1971 addPostCollapseAction(removeRunnable);
1972 } else {
1973 removeRunnable.run();
1974 }
1975 }
1976 });
1977 }
Adrian Roos7d7090d2014-05-21 13:10:23 +02001978 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001979 }.start();
Adrian Roos7d7090d2014-05-21 13:10:23 +02001980
1981 // close the shade if it was open
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +01001982 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001983 true /* force */, true /* delayed */);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001984 visibilityChanged(false);
1985
Jorim Jaggi8972c2a2015-06-05 16:05:54 -07001986 return true;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001987 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001988 }, afterKeyguardGone);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001989 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001990
Selim Cinek36b02232016-05-11 23:07:05 -04001991 private boolean shouldAutoCancel(StatusBarNotification sbn) {
1992 int flags = sbn.getNotification().flags;
1993 if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
1994 return false;
1995 }
1996 if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
1997 return false;
1998 }
1999 return true;
2000 }
2001
Chris Wren42d5dd42015-05-01 10:39:26 -04002002 public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
Selim Cinekc6dd5212015-11-02 14:51:54 -08002003 Notification notification = sbn.getNotification();
2004 if (notification.contentIntent != null || notification.fullScreenIntent != null) {
Chris Wren42d5dd42015-05-01 10:39:26 -04002005 row.setOnClickListener(this);
2006 } else {
2007 row.setOnClickListener(null);
2008 }
2009 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04002010 }
Chris Wrenf29c3b42013-11-27 16:30:30 -05002011
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02002012 public void animateCollapsePanels(int flags, boolean force) {
2013 }
2014
Jorim Jaggi27c9b742015-04-09 10:34:49 -07002015 public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
2016 }
2017
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02002018 public void overrideActivityPendingAppTransition(boolean keyguardShowing) {
2019 if (keyguardShowing) {
2020 try {
2021 mWindowManagerService.overridePendingAppTransition(null, 0, 0, null);
2022 } catch (RemoteException e) {
2023 Log.w(TAG, "Error overriding app transition: " + e);
2024 }
2025 }
2026 }
2027
Ricky Waicd35def2016-05-03 11:07:07 +01002028 protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
2029 String notificationKey) {
2030 final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
2031 null, userId);
2032 if (newIntent == null) {
2033 return false;
2034 }
2035 final Intent callBackIntent = new Intent(
2036 WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
2037 callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
2038 callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
2039 callBackIntent.setPackage(mContext.getPackageName());
2040
2041 PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
2042 mContext,
2043 0,
2044 callBackIntent,
2045 PendingIntent.FLAG_CANCEL_CURRENT |
2046 PendingIntent.FLAG_ONE_SHOT |
2047 PendingIntent.FLAG_IMMUTABLE);
2048 newIntent.putExtra(
2049 Intent.EXTRA_INTENT,
2050 callBackPendingIntent.getIntentSender());
2051 try {
2052 ActivityManagerNative.getDefault().startConfirmDeviceCredentialIntent(newIntent);
2053 } catch (RemoteException ex) {
2054 // ignore
2055 }
2056 return true;
2057 }
2058
Jorim Jaggie6e108e2016-03-28 13:38:45 -07002059 protected Bundle getActivityOptions() {
2060 // Anything launched from the notification shade should always go into the
2061 // fullscreen stack.
2062 ActivityOptions options = ActivityOptions.makeBasic();
2063 options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
2064 return options.toBundle();
2065 }
2066
Christoph Studere8e28652014-10-29 17:27:53 +01002067 protected void visibilityChanged(boolean visible) {
2068 if (mVisible != visible) {
2069 mVisible = visible;
2070 if (!visible) {
2071 dismissPopups();
2072 }
2073 }
2074 updateVisibleToUser();
2075 }
2076
2077 protected void updateVisibleToUser() {
2078 boolean oldVisibleToUser = mVisibleToUser;
Jorim Jaggi50ff3af2015-08-12 18:35:42 -07002079 mVisibleToUser = mVisible && mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +01002080
2081 if (oldVisibleToUser != mVisibleToUser) {
2082 handleVisibleToUserChanged(mVisibleToUser);
2083 }
2084 }
2085
Daniel Sandler6a858c32012-03-12 14:38:58 -04002086 /**
Christoph Studere8e28652014-10-29 17:27:53 +01002087 * The LEDs are turned off when the notification panel is shown, even just a little bit.
Dan Sandlercb012892016-03-01 00:45:06 -05002088 * See also NotificationStackScrollLayout.setIsExpanded() for another place where we
2089 * attempt to do this.
Daniel Sandler6a858c32012-03-12 14:38:58 -04002090 */
Christoph Studere8e28652014-10-29 17:27:53 +01002091 protected void handleVisibleToUserChanged(boolean visibleToUser) {
2092 try {
2093 if (visibleToUser) {
Selim Cinek6577cae2015-08-31 16:15:49 -07002094 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
2095 boolean clearNotificationEffects =
Dan Sandlercb012892016-03-01 00:45:06 -05002096 !isPanelFullyCollapsed() &&
2097 (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
Chris Wrenb659c4f2015-06-25 17:12:27 -04002098 int notificationLoad = mNotificationData.getActiveNotifications().size();
Selim Cinek6577cae2015-08-31 16:15:49 -07002099 if (pinnedHeadsUp && isPanelFullyCollapsed()) {
Chris Wrenb659c4f2015-06-25 17:12:27 -04002100 notificationLoad = 1;
2101 } else {
2102 MetricsLogger.histogram(mContext, "note_load", notificationLoad);
2103 }
2104 mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
Christoph Studere8e28652014-10-29 17:27:53 +01002105 } else {
2106 mBarService.onPanelHidden();
Dan Sandler4247a5c2014-07-23 15:58:08 -04002107 }
Christoph Studere8e28652014-10-29 17:27:53 +01002108 } catch (RemoteException ex) {
2109 // Won't fail unless the world has ended.
Daniel Sandler6a858c32012-03-12 14:38:58 -04002110 }
2111 }
2112
Chris Wren0c8275b2012-05-08 13:36:48 -04002113 /**
Chris Wren16895942015-06-23 11:22:20 -04002114 * Clear Buzz/Beep/Blink.
2115 */
2116 public void clearNotificationEffects() {
2117 try {
2118 mBarService.clearNotificationEffects();
2119 } catch (RemoteException e) {
2120 // Won't fail unless the world has ended.
2121 }
2122 }
2123
Yorke Leee4ea6ab2016-03-03 14:51:49 -08002124 public abstract boolean isPanelFullyCollapsed();
Chris Wren16895942015-06-23 11:22:20 -04002125
2126 /**
Chris Wren0c8275b2012-05-08 13:36:48 -04002127 * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
2128 * about the failure.
2129 *
2130 * WARNING: this will call back into us. Don't hold any locks.
2131 */
Christoph Studer71f18fd2014-05-20 17:02:04 +02002132 void handleNotificationError(StatusBarNotification n, String message) {
Christoph Studere71fefc2014-06-24 16:16:49 +02002133 removeNotification(n.getKey(), null);
Chris Wren0c8275b2012-05-08 13:36:48 -04002134 try {
Kenny Guy3a7c4a52014-03-03 18:24:03 +00002135 mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
2136 n.getInitialPid(), message, n.getUserId());
Chris Wren0c8275b2012-05-08 13:36:48 -04002137 } catch (RemoteException ex) {
2138 // The end is nigh.
2139 }
2140 }
2141
Christoph Studerd0694b62014-06-04 16:36:01 +02002142 protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
Christoph Studer37fe6932014-05-26 13:10:30 +02002143 NotificationData.Entry entry = mNotificationData.remove(key, ranking);
Chris Wren0c8275b2012-05-08 13:36:48 -04002144 if (entry == null) {
John Spurlockcd686b52013-06-05 10:13:46 -04002145 Log.w(TAG, "removeNotification for unknown key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -04002146 return null;
2147 }
Christoph Studer37fe6932014-05-26 13:10:30 +02002148 updateNotifications();
Chris Wren0c8275b2012-05-08 13:36:48 -04002149 return entry.notification;
2150 }
2151
Selim Cinek8d490d42015-04-10 00:05:50 -07002152 protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002153 if (DEBUG) {
Christoph Studera0506e72014-07-31 20:27:39 +02002154 Log.d(TAG, "createNotificationViews(notification=" + sbn);
Chris Wren0c8275b2012-05-08 13:36:48 -04002155 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01002156 final StatusBarIconView iconView = createIcon(sbn);
2157 if (iconView == null) {
2158 return null;
2159 }
2160
2161 // Construct the expanded view.
2162 NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
Selim Cinek8d490d42015-04-10 00:05:50 -07002163 if (!inflateViews(entry, mStackScroller)) {
Selim Cinek379ff8f2015-02-20 17:03:16 +01002164 handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
2165 return null;
2166 }
2167 return entry;
2168 }
2169
Xiaohui Chene90c2c52016-02-24 16:08:00 -08002170 public StatusBarIconView createIcon(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002171 // Construct the icon.
Christoph Studera0506e72014-07-31 20:27:39 +02002172 Notification n = sbn.getNotification();
Chris Wren0c8275b2012-05-08 13:36:48 -04002173 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Christoph Studera0506e72014-07-31 20:27:39 +02002174 sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
Chris Wren0c8275b2012-05-08 13:36:48 -04002175 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
2176
Dan Sandler33439812015-08-10 15:49:56 -04002177 final Icon smallIcon = n.getSmallIcon();
2178 if (smallIcon == null) {
2179 handleNotificationError(sbn,
2180 "No small icon in notification from " + sbn.getPackageName());
2181 return null;
2182 }
Dan Sandlerd63f9322015-05-06 15:18:49 -04002183 final StatusBarIcon ic = new StatusBarIcon(
Christoph Studera0506e72014-07-31 20:27:39 +02002184 sbn.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002185 sbn.getPackageName(),
Dan Sandler33439812015-08-10 15:49:56 -04002186 smallIcon,
Dan Sandler4e787062015-06-17 15:09:48 -04002187 n.iconLevel,
2188 n.number,
Adrian Rooseba05822016-04-22 17:09:27 -07002189 StatusBarIconView.contentDescForNotification(mContext, n));
Chris Wren0c8275b2012-05-08 13:36:48 -04002190 if (!iconView.set(ic)) {
Christoph Studera0506e72014-07-31 20:27:39 +02002191 handleNotificationError(sbn, "Couldn't create icon: " + ic);
Chris Wren0c8275b2012-05-08 13:36:48 -04002192 return null;
2193 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01002194 return iconView;
Chris Wrenf0048ce2013-08-07 16:43:43 -04002195 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002196
Christoph Studerd0694b62014-06-04 16:36:01 +02002197 protected void addNotificationViews(Entry entry, RankingMap ranking) {
Raju Yadav5f330262014-03-24 10:44:00 +01002198 if (entry == null) {
2199 return;
2200 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002201 // Add the expanded view and icon.
Christoph Studer37fe6932014-05-26 13:10:30 +02002202 mNotificationData.add(entry, ranking);
2203 updateNotifications();
Selim Cinek8efa6dd2014-05-19 16:27:37 +02002204 }
2205
Jorim Jaggi251957d2014-04-09 04:24:09 +02002206 /**
Selim Cinek5f71bee2015-11-18 10:25:23 -08002207 * @param recompute wheter the number should be recomputed
Jorim Jaggid4a57442014-04-10 02:45:55 +02002208 * @return The number of notifications we show on Keyguard.
2209 */
Selim Cinek5f71bee2015-11-18 10:25:23 -08002210 protected abstract int getMaxKeyguardNotifications(boolean recompute);
Jorim Jaggid4a57442014-04-10 02:45:55 +02002211
2212 /**
Jorim Jaggi251957d2014-04-09 04:24:09 +02002213 * Updates expanded, dimmed and locked states of notification rows.
2214 */
2215 protected void updateRowStates() {
Jorim Jaggif6411742014-08-05 17:10:43 +00002216 mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
2217
Christoph Studerc8db24b2014-07-25 17:50:30 +02002218 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
2219 final int N = activeNotifications.size();
2220
Jorim Jaggif6411742014-08-05 17:10:43 +00002221 int visibleNotifications = 0;
Jorim Jaggiecbab362014-04-23 16:13:15 +02002222 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
Selim Cinek5f71bee2015-11-18 10:25:23 -08002223 int maxNotifications = 0;
2224 if (onKeyguard) {
2225 maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
2226 }
Christoph Studer37fe6932014-05-26 13:10:30 +02002227 for (int i = 0; i < N; i++) {
Christoph Studerc8db24b2014-07-25 17:50:30 +02002228 NotificationData.Entry entry = activeNotifications.get(i);
Selim Cinek2a739342016-03-17 10:28:55 -07002229 boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
Jorim Jaggiecbab362014-04-23 16:13:15 +02002230 if (onKeyguard) {
Selim Cinek83bc7832015-10-22 13:26:54 -07002231 entry.row.setOnKeyguard(true);
Chris Wren3ddab0d2012-08-02 16:52:21 -04002232 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -07002233 entry.row.setOnKeyguard(false);
Selim Cinek2a739342016-03-17 10:28:55 -07002234 entry.row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
Chris Wren8fd12652012-05-09 21:25:57 -04002235 }
Selim Cinek3f19f602016-05-02 18:01:56 -07002236 boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
2237 entry.notification) && !entry.row.isRemoved();
Selim Cinek83bc7832015-10-22 13:26:54 -07002238 boolean childWithVisibleSummary = childNotification
2239 && mGroupManager.getGroupSummary(entry.notification).getVisibility()
2240 == View.VISIBLE;
Jorim Jaggif6411742014-08-05 17:10:43 +00002241 boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
Selim Cinek2a739342016-03-17 10:28:55 -07002242 if (suppressedSummary || (isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
Selim Cinek06416b92016-05-09 16:36:10 -04002243 (onKeyguard && !childWithVisibleSummary
2244 && (visibleNotifications >= maxNotifications || !showOnKeyguard))) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002245 entry.row.setVisibility(View.GONE);
Selim Cinek2a739342016-03-17 10:28:55 -07002246 if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002247 mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
2248 }
2249 } else {
2250 boolean wasGone = entry.row.getVisibility() == View.GONE;
2251 entry.row.setVisibility(View.VISIBLE);
Selim Cinekfa760d42016-05-10 15:50:53 -04002252 if (!childNotification && !entry.row.isRemoved()) {
Selim Cinekb5605e52015-02-20 18:21:41 +01002253 if (wasGone) {
2254 // notify the scroller of a child addition
Selim Cinek2a739342016-03-17 10:28:55 -07002255 mStackScroller.generateAddAnimation(entry.row,
2256 !showOnKeyguard /* fromMoreCard */);
Selim Cinekb5605e52015-02-20 18:21:41 +01002257 }
2258 visibleNotifications++;
Jorim Jaggif6411742014-08-05 17:10:43 +00002259 }
Jorim Jaggif6411742014-08-05 17:10:43 +00002260 }
Chris Wren8fd12652012-05-09 21:25:57 -04002261 }
Jorim Jaggif6411742014-08-05 17:10:43 +00002262
Selim Cinek2cd45df2015-06-09 18:00:07 -07002263 mStackScroller.updateOverflowContainerVisibility(onKeyguard
2264 && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0);
Jorim Jaggif6411742014-08-05 17:10:43 +00002265
Selim Cinek0cce5312015-05-20 22:13:55 -07002266 mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
2267 mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
Jorim Jaggif6411742014-08-05 17:10:43 +00002268 mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
2269 mStackScroller.getChildCount() - 3);
Jorim Jaggif6411742014-08-05 17:10:43 +00002270 }
2271
Selim Cinekfa760d42016-05-10 15:50:53 -04002272 public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002273 return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
Chris Wren8fd12652012-05-09 21:25:57 -04002274 }
2275
John Spurlocke677d712014-02-13 12:52:19 -05002276 protected void setZenMode(int mode) {
John Spurlock110e5b12014-02-27 13:09:35 -05002277 if (!isDeviceProvisioned()) return;
John Spurlocke677d712014-02-13 12:52:19 -05002278 mZenMode = mode;
Christoph Studer37fe6932014-05-26 13:10:30 +02002279 updateNotifications();
John Spurlocke677d712014-02-13 12:52:19 -05002280 }
2281
Dan Sandler52e5701e2014-07-22 23:14:54 -04002282 // extended in PhoneStatusBar
2283 protected void setShowLockscreenNotifications(boolean show) {
2284 mShowLockscreenNotifications = show;
2285 }
2286
Adrian Roos3aec6382016-02-05 14:19:01 -08002287 protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
2288 mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
2289 }
2290
Dan Sandler52e5701e2014-07-22 23:14:54 -04002291 private void updateLockscreenNotificationSetting() {
2292 final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2293 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
2294 1,
2295 mCurrentUserId) != 0;
Adrian Roosbd3409c2014-08-12 18:21:09 +02002296 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
2297 null /* admin */, mCurrentUserId);
2298 final boolean allowedByDpm = (dpmFlags
2299 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
Adrian Roos3aec6382016-02-05 14:19:01 -08002300
2301 final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2302 Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
2303 0,
2304 mCurrentUserId) != 0;
Adrian Roos7f06eed2016-02-05 15:21:02 -08002305 final boolean remoteInputDpm = (dpmFlags
2306 & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
2307
Adrian Roos3aec6382016-02-05 14:19:01 -08002308
Adrian Roosbd3409c2014-08-12 18:21:09 +02002309 setShowLockscreenNotifications(show && allowedByDpm);
Adrian Roos7f06eed2016-02-05 15:21:02 -08002310 setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
Dan Sandler52e5701e2014-07-22 23:14:54 -04002311 }
2312
Chris Wren0c8275b2012-05-08 13:36:48 -04002313 protected abstract void setAreThereNotifications();
Christoph Studer37fe6932014-05-26 13:10:30 +02002314 protected abstract void updateNotifications();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -07002315 public abstract boolean shouldDisableNavbarGestures();
Chris Wren0c8275b2012-05-08 13:36:48 -04002316
Christoph Studere71fefc2014-06-24 16:16:49 +02002317 public abstract void addNotification(StatusBarNotification notification,
Selim Cinek379ff8f2015-02-20 17:03:16 +01002318 RankingMap ranking, Entry oldEntry);
Christoph Studere71fefc2014-06-24 16:16:49 +02002319 protected abstract void updateNotificationRanking(RankingMap ranking);
2320 public abstract void removeNotification(String key, RankingMap ranking);
Christoph Studera7fe6312014-06-27 19:32:44 +02002321
Christoph Studere71fefc2014-06-24 16:16:49 +02002322 public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02002323 if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
Chris Wren0c8275b2012-05-08 13:36:48 -04002324
Chris Wrend04f6ce2014-06-11 17:37:28 -04002325 final String key = notification.getKey();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002326 Entry entry = mNotificationData.get(key);
2327 if (entry == null) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002328 return;
Selim Cinek2d79f632015-11-02 15:13:29 -08002329 } else if (mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
2330 mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
Chris Wren0c8275b2012-05-08 13:36:48 -04002331 }
2332
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002333 Notification n = notification.getNotification();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002334 mNotificationData.updateRanking(ranking);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002335
Selim Cineka6a6f032015-11-23 15:46:24 -08002336 boolean applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
Chris Wrenbdf33762015-12-04 15:50:51 -05002337 boolean shouldPeek = shouldPeek(entry, notification);
Selim Cinek684a4422015-04-15 16:18:39 -07002338 boolean alertAgain = alertAgain(entry, n);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002339 if (DEBUG) {
2340 Log.d(TAG, "applyInPlace=" + applyInPlace
Chris Wrenbdf33762015-12-04 15:50:51 -05002341 + " shouldPeek=" + shouldPeek
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002342 + " alertAgain=" + alertAgain);
2343 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002344
Dan Sandler24813b02016-01-14 15:49:36 -05002345 final StatusBarNotification oldNotification = entry.notification;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002346 entry.notification = notification;
Dan Sandler24813b02016-01-14 15:49:36 -05002347 mGroupManager.onEntryUpdated(entry, oldNotification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002348
2349 boolean updateSuccessful = false;
2350 if (applyInPlace) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002351 if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
2352 try {
2353 if (entry.icon != null) {
2354 // Update the icon
Dan Sandlerd63f9322015-05-06 15:18:49 -04002355 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002356 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002357 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002358 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002359 n.iconLevel,
2360 n.number,
Adrian Rooseba05822016-04-22 17:09:27 -07002361 StatusBarIconView.contentDescForNotification(mContext, n));
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002362 entry.icon.setNotification(n);
2363 if (!entry.icon.set(ic)) {
2364 handleNotificationError(notification, "Couldn't update icon: " + ic);
2365 return;
2366 }
2367 }
Selim Cinek8d490d42015-04-10 00:05:50 -07002368 updateNotificationViews(entry, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002369 updateSuccessful = true;
2370 }
2371 catch (RuntimeException e) {
Selim Cinek684a4422015-04-15 16:18:39 -07002372 // It failed to apply cleanly.
Adrian Roose458aa82015-12-08 16:17:19 -08002373 Log.w(TAG, "Couldn't reapply views for package " +
2374 notification.getPackageName(), e);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002375 }
2376 }
2377 if (!updateSuccessful) {
2378 if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
Dan Sandlerd63f9322015-05-06 15:18:49 -04002379 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002380 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002381 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002382 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002383 n.iconLevel,
2384 n.number,
Adrian Rooseba05822016-04-22 17:09:27 -07002385 StatusBarIconView.contentDescForNotification(mContext, n));
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002386 entry.icon.setNotification(n);
2387 entry.icon.set(ic);
Selim Cinek8d490d42015-04-10 00:05:50 -07002388 inflateViews(entry, mStackScroller);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002389 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002390 updateHeadsUp(key, entry, shouldPeek, alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002391 updateNotifications();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002392
2393 // Update the veto button accordingly (and as a result, whether this row is
2394 // swipe-dismissable)
Selim Cinek757d8792016-01-28 16:21:08 -08002395 bindVetoButtonClickListener(entry.row, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002396
dongwan0605.kim30637e42016-03-02 17:16:47 +09002397 if (!notification.isClearable()) {
2398 // The user may have performed a dismiss action on the notification, since it's
2399 // not clearable we should snap it back.
2400 mStackScroller.snapViewIfNeeded(entry.row);
2401 }
2402
Selim Cinek684a4422015-04-15 16:18:39 -07002403 if (DEBUG) {
2404 // Is this for you?
2405 boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
2406 Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
2407 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002408
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002409 setAreThereNotifications();
2410 }
2411
Chris Wrenbdf33762015-12-04 15:50:51 -05002412 protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
Selim Cinek29fa89b2015-04-17 10:39:11 -07002413 boolean alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002414
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002415 private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
2416 final RemoteViews contentView = entry.cachedContentView;
2417 final RemoteViews bigContentView = entry.cachedBigContentView;
2418 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
2419 final RemoteViews publicContentView = entry.cachedPublicContentView;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002420
Chris Wrene03f4e12013-08-08 16:48:48 -04002421 // Reapply the RemoteViews
Selim Cinek684a4422015-04-15 16:18:39 -07002422 contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
2423 if (bigContentView != null && entry.getExpandedContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002424 bigContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002425 entry.getExpandedContentView(),
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01002426 mOnClickHandler);
Chris Wrene03f4e12013-08-08 16:48:48 -04002427 }
Selim Cinek684a4422015-04-15 16:18:39 -07002428 View headsUpChild = entry.getHeadsUpContentView();
Selim Cinek8d490d42015-04-10 00:05:50 -07002429 if (headsUpContentView != null && headsUpChild != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002430 headsUpContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002431 headsUpChild, mOnClickHandler);
Selim Cinek8d490d42015-04-10 00:05:50 -07002432 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002433 if (publicContentView != null && entry.getPublicContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002434 publicContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002435 entry.getPublicContentView(), mOnClickHandler);
Dan Sandlera5e0f412014-01-23 15:11:54 -05002436 }
Chris Wrene03f4e12013-08-08 16:48:48 -04002437 // update the contentIntent
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002438 mNotificationClicker.register(entry.row, sbn);
Chris Wren42d5dd42015-05-01 10:39:26 -04002439
Selim Cinekda42d652015-12-04 15:51:16 -08002440 entry.row.onNotificationUpdated(entry);
Selim Cinek51ae05d2014-09-09 15:51:38 +02002441 entry.row.resetHeight();
Chris Wren0c8275b2012-05-08 13:36:48 -04002442 }
John Spurlock36231282012-06-23 17:11:27 -04002443
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002444 protected void updatePublicContentView(Entry entry,
2445 StatusBarNotification sbn) {
2446 final RemoteViews publicContentView = entry.cachedPublicContentView;
Selim Cineke4c068d2016-02-19 13:46:55 -08002447 View inflatedView = entry.getPublicContentView();
2448 if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002449 final boolean disabledByPolicy =
2450 !adminAllowsUnredactedNotifications(entry.notification.getUserId());
Selim Cineke4c068d2016-02-19 13:46:55 -08002451 String notificationHiddenText = mContext.getString(disabledByPolicy
2452 ? com.android.internal.R.string.notification_hidden_by_policy_text
2453 : com.android.internal.R.string.notification_hidden_text);
2454 TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
2455 if (titleView != null
2456 && !titleView.getText().toString().equals(notificationHiddenText)) {
2457 publicContentView.setTextViewText(android.R.id.title, notificationHiddenText);
2458 publicContentView.reapply(sbn.getPackageContext(mContext),
2459 inflatedView, mOnClickHandler);
2460 entry.row.onNotificationUpdated(entry);
2461 }
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002462 }
2463 }
2464
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002465 protected void notifyHeadsUpScreenOff() {
Selim Cinek684a4422015-04-15 16:18:39 -07002466 maybeEscalateHeadsUp();
Chris Wrene97f90b2013-08-07 17:39:35 -04002467 }
2468
Chris Wrend93d5ad2014-09-08 16:34:03 -04002469 private boolean alertAgain(Entry oldEntry, Notification newNotification) {
2470 return oldEntry == null || !oldEntry.hasInterrupted()
2471 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
Chris Wrend04f6ce2014-06-11 17:37:28 -04002472 }
2473
Chris Wrenbdf33762015-12-04 15:50:51 -05002474 protected boolean shouldPeek(Entry entry) {
2475 return shouldPeek(entry, entry.notification);
Chris Wren0c274b12015-07-17 10:34:53 -04002476 }
2477
Chris Wrenbdf33762015-12-04 15:50:51 -05002478 protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
Dan Sandlerdc34df52016-04-07 21:04:46 -04002479 if (isDeviceInVrMode()) {
2480 return false;
2481 }
2482
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002483 if (mNotificationData.shouldFilterOut(sbn)) {
Chris Wrenbdf33762015-12-04 15:50:51 -05002484 if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002485 return false;
2486 }
2487
Selim Cinekd5921912016-02-09 10:33:01 -08002488 boolean inUse = mPowerManager.isScreenOn()
2489 && (!mStatusBarKeyguardViewManager.isShowing()
2490 || mStatusBarKeyguardViewManager.isOccluded())
2491 && !mStatusBarKeyguardViewManager.isInputRestricted();
2492 try {
2493 inUse = inUse && !mDreamManager.isDreaming();
2494 } catch (RemoteException e) {
2495 Log.d(TAG, "failed to query dream manager", e);
2496 }
2497
2498 if (!inUse) {
2499 if (DEBUG) {
2500 Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
2501 }
2502 return false;
2503 }
2504
2505 if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
2506 if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
Chris Wrena6d4fb62014-11-20 14:46:23 -05002507 return false;
2508 }
2509
Chris Wrenbdf33762015-12-04 15:50:51 -05002510 if (entry.hasJustLaunchedFullScreenIntent()) {
2511 if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
2512 return false;
2513 }
2514
Julia Reynoldsf0f629f2016-02-25 09:34:04 -05002515 if (isSnoozedPackage(sbn)) {
2516 if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
2517 return false;
2518 }
2519
2520 if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_HIGH) {
2521 if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
2522 return false;
2523 }
2524
Selim Cinekd5921912016-02-09 10:33:01 -08002525 if (sbn.getNotification().fullScreenIntent != null) {
2526 if (mAccessibilityManager.isTouchExplorationEnabled()) {
2527 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
2528 return false;
2529 } else {
2530 return true;
2531 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002532 }
2533
Selim Cinekd5921912016-02-09 10:33:01 -08002534 return true;
Chris Wren157026f2013-06-28 16:54:01 -04002535 }
2536
Selim Cinek29fa89b2015-04-17 10:39:11 -07002537 protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
2538
John Spurlockcfc359a2013-09-05 10:42:03 -04002539 public void setInteracting(int barWindow, boolean interacting) {
John Spurlockad3e6cb2013-04-30 08:47:43 -04002540 // hook for subclasses
2541 }
John Spurlock5c454122013-06-17 07:35:46 -04002542
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002543 public void setBouncerShowing(boolean bouncerShowing) {
2544 mBouncerShowing = bouncerShowing;
2545 }
2546
2547 /**
2548 * @return Whether the security bouncer from Keyguard is showing.
2549 */
2550 public boolean isBouncerShowing() {
2551 return mBouncerShowing;
2552 }
2553
John Spurlock5c454122013-06-17 07:35:46 -04002554 public void destroy() {
John Spurlock5c454122013-06-17 07:35:46 -04002555 mContext.unregisterReceiver(mBroadcastReceiver);
Christoph Studere71fefc2014-06-24 16:16:49 +02002556 try {
2557 mNotificationListener.unregisterAsSystemService();
2558 } catch (RemoteException e) {
2559 // Ignore.
Christoph Studer37fe6932014-05-26 13:10:30 +02002560 }
John Spurlock5c454122013-06-17 07:35:46 -04002561 }
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002562
2563 /**
2564 * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
2565 * return PackageManager for mContext
2566 */
Selim Cinekeef84282015-10-30 16:28:00 -07002567 public static PackageManager getPackageManagerForUser(Context context, int userId) {
2568 Context contextForUser = context;
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002569 // UserHandle defines special userId as negative values, e.g. USER_ALL
2570 if (userId >= 0) {
2571 try {
2572 // Create a context for the correct user so if a package isn't installed
2573 // for user 0 we can still load information about the package.
2574 contextForUser =
Selim Cinekeef84282015-10-30 16:28:00 -07002575 context.createPackageContextAsUser(context.getPackageName(),
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002576 Context.CONTEXT_RESTRICTED,
2577 new UserHandle(userId));
2578 } catch (NameNotFoundException e) {
2579 // Shouldn't fail to find the package name for system ui.
2580 }
2581 }
2582 return contextForUser.getPackageManager();
2583 }
Chris Wren78403d72014-07-28 10:23:24 +01002584
2585 @Override
2586 public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
2587 try {
2588 mBarService.onNotificationExpansionChanged(key, userAction, expanded);
2589 } catch (RemoteException e) {
2590 // Ignore.
2591 }
2592 }
Jim Millerab954542014-10-10 18:21:49 -07002593
2594 public boolean isKeyguardSecure() {
Dan Sandlere163a642015-03-01 22:58:32 -05002595 if (mStatusBarKeyguardViewManager == null) {
2596 // startKeyguard() hasn't been called yet, so we don't know.
2597 // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
2598 // value onVisibilityChanged().
2599 Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
2600 new Throwable());
2601 return false;
2602 }
Jim Millerab954542014-10-10 18:21:49 -07002603 return mStatusBarKeyguardViewManager.isSecure();
2604 }
Adrian Roos4f43dc02015-06-17 16:43:38 -07002605
2606 @Override
2607 public void showAssistDisclosure() {
2608 if (mAssistManager != null) {
2609 mAssistManager.showDisclosure();
2610 }
2611 }
Jorim Jaggi165ce062015-07-06 16:18:11 -07002612
2613 @Override
2614 public void startAssist(Bundle args) {
2615 if (mAssistManager != null) {
2616 mAssistManager.startAssist(args);
2617 }
2618 }
Joe Onorato2314aab2010-04-08 16:41:23 -05002619}