blob: 3ac7b26a99680a80ad3815f67e060188f94bf3f4 [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;
Adrian Roosd6aa6cb2015-04-16 19:31:29 -070095import com.android.keyguard.KeyguardUpdateMonitor;
Mady Mellor97c8df42016-03-22 18:09:39 -070096import com.android.keyguard.KeyguardHostView.OnDismissAction;
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;
Chris Wren0c8275b2012-05-08 13:36:48 -0400146
Chris Wren157026f2013-06-28 16:54:01 -0400147 protected static final boolean ENABLE_HEADS_UP = true;
Chris Wren22ae46e2014-02-26 18:08:09 -0500148 protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
Chris Wren0c8275b2012-05-08 13:36:48 -0400149
Ricky Wai7fa01712016-03-16 12:13:54 +0000150 private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
151
Winsond8b1d632016-01-04 17:51:18 -0800152 // Should match the values in PhoneWindowManager
Michael Jurka56a57832012-05-14 13:24:43 -0700153 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
Winsond8b1d632016-01-04 17:51:18 -0800154 public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
Michael Jurka56a57832012-05-14 13:24:43 -0700155
Chris Wrencd8f4f72014-08-27 18:48:13 -0400156 private static final String BANNER_ACTION_CANCEL =
157 "com.android.systemui.statusbar.banner_action_cancel";
158 private static final String BANNER_ACTION_SETUP =
159 "com.android.systemui.statusbar.banner_action_setup";
Ricky Wai7fa01712016-03-16 12:13:54 +0000160 private static final String WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION
161 = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
Chris Wrencd8f4f72014-08-27 18:48:13 -0400162
Joe Onorato808182d2010-07-09 18:52:06 -0400163 protected CommandQueue mCommandQueue;
164 protected IStatusBarService mBarService;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700165 protected H mHandler = createHandler();
166
Chris Wren0c8275b2012-05-08 13:36:48 -0400167 // all notifications
Christoph Studerc8db24b2014-07-25 17:50:30 +0200168 protected NotificationData mNotificationData;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100169 protected NotificationStackScrollLayout mStackScroller;
Chris Wren0c8275b2012-05-08 13:36:48 -0400170
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100171 protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
172
Adrian Roosb88b1a12015-12-09 18:51:05 -0800173 protected RemoteInputController mRemoteInputController;
174
Chris Wrena4ef6202014-06-09 18:07:30 -0400175 // for heads up notifications
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700176 protected HeadsUpManager mHeadsUpManager;
Chris Wren0c8275b2012-05-08 13:36:48 -0400177
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400178 protected int mCurrentUserId = 0;
Kenny Guy2a764942014-04-02 13:29:20 +0100179 final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400180
Daniel Sandler777dcde2013-09-30 10:21:45 -0400181 protected int mLayoutDirection = -1; // invalid
Selim Cineka8fefa52014-09-08 16:10:50 +0200182 protected AccessibilityManager mAccessibilityManager;
Selim Cinek92d892c2014-09-11 15:11:00 +0200183
184 // on-screen navigation buttons
185 protected NavigationBarView mNavigationBarView = null;
Christoph Studere8e28652014-10-29 17:27:53 +0100186
Jorim Jaggi50ff3af2015-08-12 18:35:42 -0700187 protected boolean mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +0100188
189 protected boolean mVisible;
Selim Cinek2d79f632015-11-02 15:13:29 -0800190 protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
Christoph Studere8e28652014-10-29 17:27:53 +0100191
Adrian Roosc0a579e2016-03-30 16:43:58 -0700192 /**
193 * Notifications with keys in this set are not actually around anymore. We kept them around
194 * when they were canceled in response to a remote input interaction. This allows us to show
195 * what you replied and allows you to continue typing into it.
196 */
197 protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
198
Christoph Studere8e28652014-10-29 17:27:53 +0100199 // mScreenOnFromKeyguard && mVisible.
200 private boolean mVisibleToUser;
201
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700202 private Locale mLocale;
Dan Sandler539aad42014-08-04 00:43:39 -0400203 private float mFontScale;
204
Chris Wrenf6e83f42013-09-11 14:02:59 -0400205 protected boolean mUseHeadsUp = false;
Chris Wren22ae46e2014-02-26 18:08:09 -0500206 protected boolean mHeadsUpTicker = false;
Jason Monkf7019542014-07-31 12:42:25 -0400207 protected boolean mDisableNotificationAlerts = false;
Chris Wren157026f2013-06-28 16:54:01 -0400208
Adrian Roosbd3409c2014-08-12 18:21:09 +0200209 protected DevicePolicyManager mDevicePolicyManager;
Chris Wren157026f2013-06-28 16:54:01 -0400210 protected IDreamManager mDreamManager;
Julia Reynolds0971cb02016-01-26 17:00:22 -0500211 protected PowerManager mPowerManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200212 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Dan Sandlerfd16d562014-02-13 18:43:31 -0800213
214 // public mode, private notifications, etc
215 private boolean mLockscreenPublicMode = false;
216 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
Julia Reynolds26fa8a52016-02-24 08:31:22 -0500217 private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700218
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000219 private UserManager mUserManager;
Selim Cinek01af3342016-02-09 19:25:31 -0800220 private int mDensity;
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000221
Ricky Wai7fa01712016-03-16 12:13:54 +0000222 private KeyguardManager mKeyguardManager;
223 private LockPatternUtils mLockPatternUtils;
224
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500225 // UI-specific methods
Daniel Sandler6a858c32012-03-12 14:38:58 -0400226
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500227 /**
228 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
229 * and add them to the window manager.
230 */
231 protected abstract void createAndAddWindows();
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400232
Jeff Brown98365d72012-08-19 20:30:52 -0700233 protected WindowManager mWindowManager;
234 protected IWindowManager mWindowManagerService;
Christoph Studer60748e72014-05-22 16:51:41 +0200235
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700236 protected abstract void refreshLayout(int layoutDirection);
237
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500238 protected Display mDisplay;
Jeff Brown98365d72012-08-19 20:30:52 -0700239
Daniel Sandler26cda272012-05-22 15:44:08 -0400240 private boolean mDeviceProvisioned = false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400241
Jorim Jaggi75b25972015-10-21 14:51:10 +0200242 protected RecentsComponent mRecents;
John Spurlockd08de372013-06-24 13:06:08 -0400243
John Spurlocke677d712014-02-13 12:52:19 -0500244 protected int mZenMode;
245
Dan Sandler4247a5c2014-07-23 15:58:08 -0400246 // which notification is currently being longpress-examined by the user
Selim Cinek024ca592014-09-01 15:11:28 +0200247 private NotificationGuts mNotificationGutsExposed;
Dan Sandler4247a5c2014-07-23 15:58:08 -0400248
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +0100249 private KeyboardShortcuts mKeyboardShortcuts;
250
Jorim Jaggiecbab362014-04-23 16:13:15 +0200251 /**
252 * The {@link StatusBarState} of the status bar.
253 */
254 protected int mState;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200255 protected boolean mBouncerShowing;
John Spurlock4b3bda22014-05-22 14:32:20 -0400256 protected boolean mShowLockscreenNotifications;
Adrian Roos3aec6382016-02-05 14:19:01 -0800257 protected boolean mAllowLockscreenRemoteInput;
Jorim Jaggiecbab362014-04-23 16:13:15 +0200258
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200259 protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
Dan Sandlereceda3d2014-07-21 15:35:01 -0400260 protected DismissView mDismissView;
Jorim Jaggia2052ea2014-08-05 16:22:30 +0200261 protected EmptyShadeView mEmptyShadeView;
Jorim Jaggi649b7082014-04-03 13:15:18 +0200262
Chris Wren42d5dd42015-05-01 10:39:26 -0400263 private NotificationClicker mNotificationClicker = new NotificationClicker();
264
Jorim Jaggib835dd72015-06-08 12:28:42 -0700265 protected AssistManager mAssistManager;
266
Dan Sandlerdc34df52016-04-07 21:04:46 -0400267 protected boolean mVrMode;
268
Christoph Studerc8db24b2014-07-25 17:50:30 +0200269 @Override // NotificationData.Environment
Daniel Sandler3ffdcc72012-09-23 14:31:48 -0400270 public boolean isDeviceProvisioned() {
Daniel Sandler26cda272012-05-22 15:44:08 -0400271 return mDeviceProvisioned;
272 }
273
Dan Sandlerdc34df52016-04-07 21:04:46 -0400274 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
275 @Override
276 public void onVrStateChanged(boolean enabled) {
277 mVrMode = enabled;
278 }
279 };
280
281 public boolean isDeviceInVrMode() {
282 return mVrMode;
283 }
284
John Spurlocke677d712014-02-13 12:52:19 -0500285 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
Daniel Sandler26cda272012-05-22 15:44:08 -0400286 @Override
287 public void onChange(boolean selfChange) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700288 final boolean provisioned = 0 != Settings.Global.getInt(
289 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
Daniel Sandler26cda272012-05-22 15:44:08 -0400290 if (provisioned != mDeviceProvisioned) {
291 mDeviceProvisioned = provisioned;
Christoph Studer37fe6932014-05-26 13:10:30 +0200292 updateNotifications();
Daniel Sandler26cda272012-05-22 15:44:08 -0400293 }
John Spurlocke677d712014-02-13 12:52:19 -0500294 final int mode = Settings.Global.getInt(mContext.getContentResolver(),
295 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
296 setZenMode(mode);
Dan Sandler52e5701e2014-07-22 23:14:54 -0400297
298 updateLockscreenNotificationSetting();
Daniel Sandler26cda272012-05-22 15:44:08 -0400299 }
300 };
301
Dan Sandlerfd16d562014-02-13 18:43:31 -0800302 private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
303 @Override
304 public void onChange(boolean selfChange) {
Daniel U57454872016-03-29 20:28:21 +0100305 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
306 // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
Dan Sandlerfd16d562014-02-13 18:43:31 -0800307 mUsersAllowingPrivateNotifications.clear();
Daniel U57454872016-03-29 20:28:21 +0100308 mUsersAllowingNotifications.clear();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800309 // ... and refresh all the notifications
Christoph Studer37fe6932014-05-26 13:10:30 +0200310 updateNotifications();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800311 }
312 };
313
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700314 private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
315 @Override
Adrian Roos7d7090d2014-05-21 13:10:23 +0200316 public boolean onClickHandler(
317 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800318 if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
319 return true;
320 }
321
Daniel Sandler198a0302012-08-17 16:04:31 -0400322 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400323 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
Daniel Sandler198a0302012-08-17 16:04:31 -0400324 }
Christoph Studer4da84cd2014-10-21 17:24:20 +0200325 logActionClick(view);
Jorim Jaggi89f7f282014-10-17 19:54:15 +0200326 // The intent we are sending is for the application, which
327 // won't have permission to immediately start an activity after
328 // the user switches to home. We know it is safe to do at this
329 // point, so make sure new activity switches are now allowed.
330 try {
331 ActivityManagerNative.getDefault().resumeAppSwitches();
332 } catch (RemoteException e) {
333 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700334 final boolean isActivity = pendingIntent.isActivity();
335 if (isActivity) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200336 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200337 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
338 mContext, pendingIntent.getIntent(), mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +0200339 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200340 @Override
341 public boolean onDismiss() {
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200342 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200343 try {
344 ActivityManagerNative.getDefault()
345 .keyguardWaitingForActivityDrawn();
Jorim Jaggi91617a72015-06-25 15:01:29 -0700346 ActivityManagerNative.getDefault().resumeAppSwitches();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200347 } catch (RemoteException e) {
348 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200349 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700350
Adrian Roos7d7090d2014-05-21 13:10:23 +0200351 boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200352 overrideActivityPendingAppTransition(keyguardShowing && !afterKeyguardGone);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700353
Adrian Roos7d7090d2014-05-21 13:10:23 +0200354 // close the shade if it was open
355 if (handled) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100356 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
357 true /* force */);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200358 visibilityChanged(false);
Jorim Jaggi91617a72015-06-25 15:01:29 -0700359 mAssistManager.hideAssist();
Adrian Roos7d7090d2014-05-21 13:10:23 +0200360 }
Jorim Jaggi91617a72015-06-25 15:01:29 -0700361
Adrian Roos4314f6d2014-05-28 14:10:27 +0200362 // Wait for activity start.
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200363 return handled;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200364 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200365 }, afterKeyguardGone);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200366 return true;
367 } else {
Jorim Jaggie6e108e2016-03-28 13:38:45 -0700368 return superOnClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700369 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200370 }
371
Christoph Studer4da84cd2014-10-21 17:24:20 +0200372 private void logActionClick(View view) {
373 ViewParent parent = view.getParent();
374 String key = getNotificationKeyForParent(parent);
375 if (key == null) {
376 Log.w(TAG, "Couldn't determine notification for click.");
377 return;
378 }
379 int index = -1;
380 // If this is a default template, determine the index of the button.
381 if (view.getId() == com.android.internal.R.id.action0 &&
382 parent != null && parent instanceof ViewGroup) {
383 ViewGroup actionGroup = (ViewGroup) parent;
384 index = actionGroup.indexOfChild(view);
385 }
386 try {
387 mBarService.onNotificationActionClick(key, index);
388 } catch (RemoteException e) {
389 // Ignore
390 }
391 }
392
393 private String getNotificationKeyForParent(ViewParent parent) {
394 while (parent != null) {
395 if (parent instanceof ExpandableNotificationRow) {
396 return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
397 }
398 parent = parent.getParent();
399 }
400 return null;
401 }
402
Adrian Roos7d7090d2014-05-21 13:10:23 +0200403 private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
404 Intent fillInIntent) {
Jorim Jaggie6e108e2016-03-28 13:38:45 -0700405 return super.onClickHandler(view, pendingIntent, fillInIntent,
406 StackId.FULLSCREEN_WORKSPACE_STACK_ID);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700407 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800408
409 private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
410 Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
411 RemoteInput[] inputs = null;
412 if (tag instanceof RemoteInput[]) {
413 inputs = (RemoteInput[]) tag;
414 }
415
416 if (inputs == null) {
417 return false;
418 }
419
420 RemoteInput input = null;
421
422 for (RemoteInput i : inputs) {
423 if (i.getAllowFreeFormInput()) {
424 input = i;
425 }
426 }
427
428 if (input == null) {
429 return false;
430 }
431
432 ViewParent p = view.getParent();
433 RemoteInputView riv = null;
434 while (p != null) {
435 if (p instanceof View) {
436 View pv = (View) p;
437 if (pv.isRootNamespace()) {
438 riv = (RemoteInputView) pv.findViewWithTag(RemoteInputView.VIEW_TAG);
439 break;
440 }
441 }
442 p = p.getParent();
443 }
Adrian Roos3aec6382016-02-05 14:19:01 -0800444 ExpandableNotificationRow row = null;
445 while (p != null) {
446 if (p instanceof ExpandableNotificationRow) {
447 row = (ExpandableNotificationRow) p;
448 break;
449 }
450 p = p.getParent();
451 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800452
Adrian Roos3aec6382016-02-05 14:19:01 -0800453 if (riv == null || row == null) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800454 return false;
455 }
456
Adrian Roos3aec6382016-02-05 14:19:01 -0800457 row.setUserExpanded(true);
458
459 if (isLockscreenPublicMode() && !mAllowLockscreenRemoteInput) {
460 onLockedRemoteInput(row, view);
461 return true;
462 }
463
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800464 riv.setVisibility(View.VISIBLE);
465 int cx = view.getLeft() + view.getWidth() / 2;
466 int cy = view.getTop() + view.getHeight() / 2;
467 int w = riv.getWidth();
468 int h = riv.getHeight();
469 int r = Math.max(
470 Math.max(cx + cy, cx + (h - cy)),
471 Math.max((w - cx) + cy, (w - cx) + (h - cy)));
472 ViewAnimationUtils.createCircularReveal(riv, cx, cy, 0, r)
473 .start();
474
475 riv.setPendingIntent(pendingIntent);
476 riv.setRemoteInput(inputs, input);
477 riv.focus();
478
479 return true;
480 }
481
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700482 };
483
John Spurlock5c454122013-06-17 07:35:46 -0400484 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
485 @Override
486 public void onReceive(Context context, Intent intent) {
487 String action = intent.getAction();
488 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
489 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Kenny Guy2a764942014-04-02 13:29:20 +0100490 updateCurrentProfilesCache();
John Spurlock5c454122013-06-17 07:35:46 -0400491 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
Dan Sandler52e5701e2014-07-22 23:14:54 -0400492
493 updateLockscreenNotificationSetting();
494
John Spurlock5c454122013-06-17 07:35:46 -0400495 userSwitched(mCurrentUserId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000496 } else if (Intent.ACTION_USER_ADDED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +0100497 updateCurrentProfilesCache();
Kenny Guydae30d52015-04-01 19:11:35 +0100498 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
499 List<ActivityManager.RecentTaskInfo> recentTask = null;
500 try {
501 recentTask = ActivityManagerNative.getDefault().getRecentTasks(1,
502 ActivityManager.RECENT_WITH_EXCLUDED
503 | ActivityManager.RECENT_INCLUDE_PROFILES,
504 mCurrentUserId);
505 } catch (RemoteException e) {
506 // Abandon hope activity manager not running.
507 }
508 if (recentTask != null && recentTask.size() > 0) {
509 UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
510 if (user != null && user.isManagedProfile()) {
Kenny Guy63bf8ac2015-06-18 15:09:09 +0100511 Toast toast = Toast.makeText(mContext,
512 R.string.managed_profile_foreground_toast,
513 Toast.LENGTH_SHORT);
514 TextView text = (TextView) toast.getView().findViewById(
515 android.R.id.message);
516 text.setCompoundDrawablesRelativeWithIntrinsicBounds(
517 R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
518 int paddingPx = mContext.getResources().getDimensionPixelSize(
519 R.dimen.managed_profile_toast_padding);
520 text.setCompoundDrawablePadding(paddingPx);
Kenny Guy540f7d22015-06-08 20:24:23 +0100521 toast.show();
Kenny Guydae30d52015-04-01 19:11:35 +0100522 }
523 }
Chris Wrencd8f4f72014-08-27 18:48:13 -0400524 } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
525 NotificationManager noMan = (NotificationManager)
526 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500527 noMan.cancel(R.id.notification_hidden);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400528
529 Settings.Secure.putInt(mContext.getContentResolver(),
530 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
531 if (BANNER_ACTION_SETUP.equals(action)) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100532 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
533 true /* force */);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400534 mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
535 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
536
537 );
538 }
Ricky Wai7fa01712016-03-16 12:13:54 +0000539 } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
540 final IntentSender intentSender = (IntentSender) intent
541 .getParcelableExtra(Intent.EXTRA_INTENT);
542 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
543 try {
544 mContext.startIntentSender(intentSender, null, 0, 0, 0);
545 } catch (IntentSender.SendIntentException e) {
546 /* ignore */
547 }
548 try {
549 mBarService.onNotificationClick(notificationKey);
550 } catch (RemoteException e) {
551 /* ignore */
552 }
John Spurlock5c454122013-06-17 07:35:46 -0400553 }
554 }
555 };
556
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000557 private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
558 @Override
559 public void onReceive(Context context, Intent intent) {
560 String action = intent.getAction();
561 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
562 isCurrentProfile(getSendingUserId())) {
563 mUsersAllowingPrivateNotifications.clear();
564 updateLockscreenNotificationSetting();
565 updateNotifications();
566 }
567 }
568 };
569
Christoph Studer60748e72014-05-22 16:51:41 +0200570 private final NotificationListenerService mNotificationListener =
571 new NotificationListenerService() {
572 @Override
573 public void onListenerConnected() {
574 if (DEBUG) Log.d(TAG, "onListenerConnected");
575 final StatusBarNotification[] notifications = getActiveNotifications();
Christoph Studerd0694b62014-06-04 16:36:01 +0200576 final RankingMap currentRanking = getCurrentRanking();
Christoph Studer60748e72014-05-22 16:51:41 +0200577 mHandler.post(new Runnable() {
578 @Override
579 public void run() {
580 for (StatusBarNotification sbn : notifications) {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100581 addNotification(sbn, currentRanking, null /* oldEntry */);
Christoph Studer60748e72014-05-22 16:51:41 +0200582 }
583 }
584 });
585 }
586
587 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200588 public void onNotificationPosted(final StatusBarNotification sbn,
589 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200590 if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500591 if (sbn != null) {
592 mHandler.post(new Runnable() {
593 @Override
594 public void run() {
Adrian Roos497ab022015-02-10 20:49:33 +0100595 processForRemoteInput(sbn.getNotification());
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700596 String key = sbn.getKey();
Adrian Roosc0a579e2016-03-30 16:43:58 -0700597 mKeysKeptForRemoteInput.remove(key);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700598 boolean isUpdate = mNotificationData.get(key) != null;
Selim Cinekb5605e52015-02-20 18:21:41 +0100599 // In case we don't allow child notifications, we ignore children of
600 // notifications that have a summary, since we're not going to show them
601 // anyway. This is true also when the summary is canceled,
Chris Wren56919552015-02-24 15:56:34 -0500602 // because children are automatically canceled by NoMan in that case.
Selim Cinekb5605e52015-02-20 18:21:41 +0100603 if (!ENABLE_CHILD_NOTIFICATIONS
604 && mGroupManager.isChildInGroupWithSummary(sbn)) {
Chris Wren56919552015-02-24 15:56:34 -0500605 if (DEBUG) {
606 Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
607 }
608
609 // Remove existing notification to avoid stale data.
610 if (isUpdate) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700611 removeNotification(key, rankingMap);
Chris Wren56919552015-02-24 15:56:34 -0500612 } else {
613 mNotificationData.updateRanking(rankingMap);
614 }
615 return;
Christoph Studerd722f272014-09-02 11:49:19 +0200616 }
Christoph Studerd722f272014-09-02 11:49:19 +0200617 if (isUpdate) {
Chris Wren56919552015-02-24 15:56:34 -0500618 updateNotification(sbn, rankingMap);
Christoph Studerd722f272014-09-02 11:49:19 +0200619 } else {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100620 addNotification(sbn, rankingMap, null /* oldEntry */);
Christoph Studerd722f272014-09-02 11:49:19 +0200621 }
Christoph Studerd722f272014-09-02 11:49:19 +0200622 }
Chris Wren56919552015-02-24 15:56:34 -0500623 });
624 }
Christoph Studer60748e72014-05-22 16:51:41 +0200625 }
626
627 @Override
Chris Wren56919552015-02-24 15:56:34 -0500628 public void onNotificationRemoved(StatusBarNotification sbn,
Christoph Studerd0694b62014-06-04 16:36:01 +0200629 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200630 if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500631 if (sbn != null) {
632 final String key = sbn.getKey();
633 mHandler.post(new Runnable() {
634 @Override
635 public void run() {
636 removeNotification(key, rankingMap);
637 }
638 });
639 }
Christoph Studer37fe6932014-05-26 13:10:30 +0200640 }
641
642 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200643 public void onNotificationRankingUpdate(final RankingMap rankingMap) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200644 if (DEBUG) Log.d(TAG, "onRankingUpdate");
Chris Wren56919552015-02-24 15:56:34 -0500645 if (rankingMap != null) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200646 mHandler.post(new Runnable() {
647 @Override
648 public void run() {
Christoph Studere71fefc2014-06-24 16:16:49 +0200649 updateNotificationRanking(rankingMap);
Christoph Studer60748e72014-05-22 16:51:41 +0200650 }
651 });
Chris Wren56919552015-02-24 15:56:34 -0500652 } }
Christoph Studer5b638262014-07-07 11:21:49 +0200653
Christoph Studer60748e72014-05-22 16:51:41 +0200654 };
655
Kenny Guy2a764942014-04-02 13:29:20 +0100656 private void updateCurrentProfilesCache() {
657 synchronized (mCurrentProfiles) {
658 mCurrentProfiles.clear();
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000659 if (mUserManager != null) {
Kenny Guy2a764942014-04-02 13:29:20 +0100660 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
661 mCurrentProfiles.put(user.id, user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000662 }
663 }
664 }
665 }
666
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400667 public void start() {
Jeff Brown98365d72012-08-19 20:30:52 -0700668 mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
669 mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
670 mDisplay = mWindowManager.getDefaultDisplay();
Adrian Roosbd3409c2014-08-12 18:21:09 +0200671 mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
672 Context.DEVICE_POLICY_SERVICE);
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500673
Christoph Studerc8db24b2014-07-25 17:50:30 +0200674 mNotificationData = new NotificationData(this);
675
Selim Cineka8fefa52014-09-08 16:10:50 +0200676 mAccessibilityManager = (AccessibilityManager)
677 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
678
Chris Wren157026f2013-06-28 16:54:01 -0400679 mDreamManager = IDreamManager.Stub.asInterface(
680 ServiceManager.checkService(DreamService.DREAM_SERVICE));
Chris Wren157026f2013-06-28 16:54:01 -0400681 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
682
Daniel Sandler26cda272012-05-22 15:44:08 -0400683 mContext.getContentResolver().registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700684 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
John Spurlocke677d712014-02-13 12:52:19 -0500685 mSettingsObserver);
686 mContext.getContentResolver().registerContentObserver(
687 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
688 mSettingsObserver);
John Spurlock4b3bda22014-05-22 14:32:20 -0400689 mContext.getContentResolver().registerContentObserver(
Dan Sandler52e5701e2014-07-22 23:14:54 -0400690 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
691 mSettingsObserver,
692 UserHandle.USER_ALL);
Adrian Roos3aec6382016-02-05 14:19:01 -0800693 mContext.getContentResolver().registerContentObserver(
694 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), false,
695 mSettingsObserver,
696 UserHandle.USER_ALL);
Daniel Sandler26cda272012-05-22 15:44:08 -0400697
Dan Sandlerfd16d562014-02-13 18:43:31 -0800698 mContext.getContentResolver().registerContentObserver(
699 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
700 true,
701 mLockscreenSettingsObserver,
702 UserHandle.USER_ALL);
703
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500704 mBarService = IStatusBarService.Stub.asInterface(
705 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400706
Jorim Jaggid61f2272014-12-19 20:35:35 +0100707 mRecents = getComponent(Recents.class);
John Spurlockd08de372013-06-24 13:06:08 -0400708
Dan Sandler539aad42014-08-04 00:43:39 -0400709 final Configuration currentConfig = mContext.getResources().getConfiguration();
710 mLocale = currentConfig.locale;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700711 mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
Dan Sandler539aad42014-08-04 00:43:39 -0400712 mFontScale = currentConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800713 mDensity = currentConfig.densityDpi;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700714
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000715 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Ricky Wai7fa01712016-03-16 12:13:54 +0000716 mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
717 mLockPatternUtils = new LockPatternUtils(mContext);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000718
Joe Onorato2314aab2010-04-08 16:41:23 -0500719 // Connect in to the status bar manager service
Jason Monk07473ce2016-01-05 14:59:19 -0500720 mCommandQueue = new CommandQueue(this);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400721
Jorim Jaggi86905582016-02-09 21:36:09 -0800722 int[] switches = new int[9];
satokcd7cd292010-11-20 15:46:23 +0900723 ArrayList<IBinder> binders = new ArrayList<IBinder>();
Jason Monk07473ce2016-01-05 14:59:19 -0500724 ArrayList<String> iconSlots = new ArrayList<>();
725 ArrayList<StatusBarIcon> icons = new ArrayList<>();
Jorim Jaggi86905582016-02-09 21:36:09 -0800726 Rect fullscreenStackBounds = new Rect();
727 Rect dockedStackBounds = new Rect();
Joe Onorato2314aab2010-04-08 16:41:23 -0500728 try {
Jorim Jaggi86905582016-02-09 21:36:09 -0800729 mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
730 fullscreenStackBounds, dockedStackBounds);
Joe Onorato2314aab2010-04-08 16:41:23 -0500731 } catch (RemoteException ex) {
732 // If the system process isn't there we're doomed anyway.
733 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400734
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500735 createAndAddWindows();
Joe Onorato0cbda992010-05-02 16:28:15 -0700736
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100737 mSettingsObserver.onChange(false); // set up
Benjamin Franzcde0a2a2015-04-23 17:19:48 +0100738 disable(switches[0], switches[6], false /* animate */);
Jorim Jaggi86905582016-02-09 21:36:09 -0800739 setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
740 fullscreenStackBounds, dockedStackBounds);
Dianne Hackborn7d049322011-06-14 15:00:32 -0700741 topAppWindowChanged(switches[2] != 0);
satokcd7cd292010-11-20 15:46:23 +0900742 // StatusBarManagerService has a back up of IME token and it's restored here.
Michael Wright665366a2014-08-07 15:44:40 -0700743 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
Joe Onorato93056472010-09-10 10:30:46 -0400744
Joe Onorato0cbda992010-05-02 16:28:15 -0700745 // Set up the initial icon state
Jason Monk07473ce2016-01-05 14:59:19 -0500746 int N = iconSlots.size();
Joe Onorato0cbda992010-05-02 16:28:15 -0700747 int viewIndex = 0;
Jason Monk07473ce2016-01-05 14:59:19 -0500748 for (int i=0; i < N; i++) {
749 setIcon(iconSlots.get(i), icons.get(i));
Joe Onorato0cbda992010-05-02 16:28:15 -0700750 }
751
Christoph Studer71f18fd2014-05-20 17:02:04 +0200752 // Set up the initial notification state.
Christoph Studere71fefc2014-06-24 16:16:49 +0200753 try {
Christoph Studer4600f9b2014-07-22 22:44:43 +0200754 mNotificationListener.registerAsSystemService(mContext,
Christoph Studere71fefc2014-06-24 16:16:49 +0200755 new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
756 UserHandle.USER_ALL);
757 } catch (RemoteException e) {
758 Log.e(TAG, "Unable to register notification listener", e);
Joe Onorato75199e32010-05-29 17:22:51 -0400759 }
760
Christoph Studer60748e72014-05-22 16:51:41 +0200761
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500762 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400763 Log.d(TAG, String.format(
Daniel Sandler6a858c32012-03-12 14:38:58 -0400764 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
Jason Monk07473ce2016-01-05 14:59:19 -0500765 icons.size(),
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500766 switches[0],
767 switches[1],
768 switches[2],
769 switches[3]
770 ));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400771 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400772
Christopher Tate5e08af02012-09-21 17:17:22 -0700773 mCurrentUserId = ActivityManager.getCurrentUser();
Chris Wrena6d4fb62014-11-20 14:46:23 -0500774 setHeadsUpUser(mCurrentUserId);
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400775
776 IntentFilter filter = new IntentFilter();
777 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000778 filter.addAction(Intent.ACTION_USER_ADDED);
Kenny Guydae30d52015-04-01 19:11:35 +0100779 filter.addAction(Intent.ACTION_USER_PRESENT);
John Spurlock5c454122013-06-17 07:35:46 -0400780 mContext.registerReceiver(mBroadcastReceiver, filter);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000781
Ricky Wai7fa01712016-03-16 12:13:54 +0000782 IntentFilter internalFilter = new IntentFilter();
783 internalFilter.addAction(WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
784 internalFilter.addAction(BANNER_ACTION_CANCEL);
785 internalFilter.addAction(BANNER_ACTION_SETUP);
786 mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
787
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000788 IntentFilter allUsersFilter = new IntentFilter();
789 allUsersFilter.addAction(
790 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
791 mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
792 null, null);
Kenny Guy2a764942014-04-02 13:29:20 +0100793 updateCurrentProfilesCache();
Dan Sandlerdc34df52016-04-07 21:04:46 -0400794
795 IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
796 try {
797 vrManager.registerListener(mVrStateCallbacks);
798 } catch (RemoteException e) {
799 Slog.e(TAG, "Failed to register VR mode state listener: " + e);
800 }
801
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400802 }
803
Chris Wrencd8f4f72014-08-27 18:48:13 -0400804 protected void notifyUserAboutHiddenNotifications() {
805 if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
806 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
807 Log.d(TAG, "user hasn't seen notification about hidden notifications");
Ricky Wai7fa01712016-03-16 12:13:54 +0000808 if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
Chris Wrencd8f4f72014-08-27 18:48:13 -0400809 Log.d(TAG, "insecure lockscreen, skipping notification");
810 Settings.Secure.putInt(mContext.getContentResolver(),
811 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
812 return;
813 }
814 Log.d(TAG, "disabling lockecreen notifications and alerting the user");
815 // disable lockscreen notifications until user acts on the banner.
816 Settings.Secure.putInt(mContext.getContentResolver(),
817 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
Adrian Roosaee70462014-09-03 16:27:39 +0200818 Settings.Secure.putInt(mContext.getContentResolver(),
819 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400820
821 final String packageName = mContext.getPackageName();
822 PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
823 new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
824 PendingIntent.FLAG_CANCEL_CURRENT);
825 PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
826 new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
827 PendingIntent.FLAG_CANCEL_CURRENT);
828
829 final Resources res = mContext.getResources();
830 final int colorRes = com.android.internal.R.color.system_notification_accent_color;
831 Notification.Builder note = new Notification.Builder(mContext)
832 .setSmallIcon(R.drawable.ic_android)
833 .setContentTitle(mContext.getString(R.string.hidden_notifications_title))
834 .setContentText(mContext.getString(R.string.hidden_notifications_text))
835 .setPriority(Notification.PRIORITY_HIGH)
836 .setOngoing(true)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700837 .setColor(mContext.getColor(colorRes))
Chris Wrencd8f4f72014-08-27 18:48:13 -0400838 .setContentIntent(setupIntent)
839 .addAction(R.drawable.ic_close,
840 mContext.getString(R.string.hidden_notifications_cancel),
841 cancelIntent)
842 .addAction(R.drawable.ic_settings,
843 mContext.getString(R.string.hidden_notifications_setup),
844 setupIntent);
845
846 NotificationManager noMan =
847 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500848 noMan.notify(R.id.notification_hidden, note.build());
Chris Wrencd8f4f72014-08-27 18:48:13 -0400849 }
850 }
851
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400852 public void userSwitched(int newUserId) {
Chris Wrena6d4fb62014-11-20 14:46:23 -0500853 setHeadsUpUser(newUserId);
854 }
855
Selim Cinek29fa89b2015-04-17 10:39:11 -0700856 protected abstract void setHeadsUpUser(int newUserId);
Chris Wrend04f6ce2014-06-11 17:37:28 -0400857
Christoph Studerc8db24b2014-07-25 17:50:30 +0200858 @Override // NotificationData.Environment
859 public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400860 final int thisUserId = mCurrentUserId;
861 final int notificationUserId = n.getUserId();
862 if (DEBUG && MULTIUSER_DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400863 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400864 n, thisUserId, notificationUserId));
865 }
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500866 return isCurrentProfile(notificationUserId);
Joe Onorato2314aab2010-04-08 16:41:23 -0500867 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400868
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700869 protected void setNotificationShown(StatusBarNotification n) {
Chris Wren26505582015-07-22 17:03:17 -0400870 setNotificationsShown(new String[]{n.getKey()});
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700871 }
872
873 protected void setNotificationsShown(String[] keys) {
Chris Wren26505582015-07-22 17:03:17 -0400874 try {
875 mNotificationListener.setNotificationsShown(keys);
876 } catch (RuntimeException e) {
877 Log.d(TAG, "failed setNotificationsShown: ", e);
878 }
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700879 }
880
Kenny Guy44fc65f2014-11-28 22:18:14 +0000881 protected boolean isCurrentProfile(int userId) {
882 synchronized (mCurrentProfiles) {
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500883 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
Kenny Guy44fc65f2014-11-28 22:18:14 +0000884 }
885 }
886
Christoph Studer2e731b52014-08-22 16:01:51 +0200887 @Override
888 public String getCurrentMediaNotificationKey() {
889 return null;
890 }
891
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100892 @Override
893 public NotificationGroupManager getGroupManager() {
894 return mGroupManager;
895 }
896
Adrian Roos7d7090d2014-05-21 13:10:23 +0200897 /**
898 * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
899 * @param action A dismiss action that is called if it's safe to start the activity.
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200900 * @param afterKeyguardGone Whether the action should be executed after the Keyguard is gone.
Adrian Roos7d7090d2014-05-21 13:10:23 +0200901 */
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200902 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200903 action.onDismiss();
904 }
905
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700906 @Override
907 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400908 final Locale locale = mContext.getResources().getConfiguration().locale;
909 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
Dan Sandler539aad42014-08-04 00:43:39 -0400910 final float fontScale = newConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800911 final int density = newConfig.densityDpi;
912 if (density != mDensity || mFontScale != fontScale) {
913 reInflateViews();
914 mDensity = density;
915 mFontScale = fontScale;
916 }
917 if (! locale.equals(mLocale) || ld != mLayoutDirection) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400918 if (DEBUG) {
919 Log.v(TAG, String.format(
920 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
921 locale, ld));
922 }
923 mLocale = locale;
924 mLayoutDirection = ld;
925 refreshLayout(ld);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700926 }
927 }
928
Selim Cinek01af3342016-02-09 19:25:31 -0800929 protected void reInflateViews() {
930 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
931 for (int i = 0; i < activeNotifications.size(); i++) {
932 Entry entry = activeNotifications.get(i);
933 boolean exposedGuts = entry.row.getGuts() == mNotificationGutsExposed;
934 entry.row.reInflateViews();
935 if (exposedGuts) {
936 mNotificationGutsExposed = entry.row.getGuts();
937 bindGuts(entry.row);
938 }
939 entry.cacheContentViews(mContext, null /* updatedNotification */);
940 inflateViews(entry, mStackScroller);
941 }
942 }
943
Adrian Roosc0a579e2016-03-30 16:43:58 -0700944 protected View bindVetoButtonClickListener(View row, final StatusBarNotification n) {
Winson Chungc57ccf02011-10-13 15:04:59 -0700945 View vetoButton = row.findViewById(R.id.veto);
Selim Cinek757d8792016-01-28 16:21:08 -0800946 final String _pkg = n.getPackageName();
947 final String _tag = n.getTag();
948 final int _id = n.getId();
949 final int _userId = n.getUserId();
950 vetoButton.setOnClickListener(new View.OnClickListener() {
951 public void onClick(View v) {
952 // Accessibility feedback
953 v.announceForAccessibility(
954 mContext.getString(R.string.accessibility_notification_dismissed));
955 try {
956 mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
Adrian Roosc0a579e2016-03-30 16:43:58 -0700957 if (FORCE_REMOTE_INPUT_HISTORY
958 && mKeysKeptForRemoteInput.contains(n.getKey())) {
959 removeNotification(n.getKey(), null);
960 mKeysKeptForRemoteInput.remove(n.getKey());
961 }
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700962
Selim Cinek757d8792016-01-28 16:21:08 -0800963 } catch (RemoteException ex) {
964 // system process is dead if we're here.
965 }
966 }
967 });
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700968 vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
Winson Chungc57ccf02011-10-13 15:04:59 -0700969 return vetoButton;
970 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400971
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400972
Christoph Studer13b895122014-08-26 15:42:12 +0200973 protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
Jorim Jaggi46739852014-04-15 09:58:24 +0200974 NotificationData.Entry entry) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400975
Selim Cinek684a4422015-04-15 16:18:39 -0700976 if (entry.getContentView().getId()
977 != com.android.internal.R.id.status_bar_latest_event_content) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400978 // Using custom RemoteViews
Jorim Jaggia1eeade2014-09-08 22:34:39 +0200979 if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700980 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
Selim Cinek697178b2014-07-02 19:40:30 +0200981 entry.row.setShowingLegacyBackground(true);
Jorim Jaggi36b15232014-06-10 17:24:20 +0200982 entry.legacy = true;
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400983 }
984 }
Christoph Studer13b895122014-08-26 15:42:12 +0200985
986 if (entry.icon != null) {
Jorim Jaggidd0107a2015-01-21 22:23:48 +0100987 entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
Christoph Studer13b895122014-08-26 15:42:12 +0200988 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400989 }
990
Dan Sandler16128f42014-05-21 12:48:22 -0400991 public boolean isMediaNotification(NotificationData.Entry entry) {
Dan Sandler842dd772014-05-15 09:36:47 -0400992 // TODO: confirm that there's a valid media key
Selim Cinek684a4422015-04-15 16:18:39 -0700993 return entry.getExpandedContentView() != null &&
994 entry.getExpandedContentView()
995 .findViewById(com.android.internal.R.id.media_actions) != null;
Dan Sandler842dd772014-05-15 09:36:47 -0400996 }
997
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200998 // The (i) button in the guts that links to the system notification settings for that app
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200999 private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
1000 final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
Dan Sandlere9a4e902014-07-31 01:06:43 -04001001 intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
1002 intent.putExtra(Settings.EXTRA_APP_UID, appUid);
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001003 startNotificationGutsIntent(intent, appUid);
1004 }
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001005
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001006 private void startNotificationGutsIntent(final Intent intent, final int appUid) {
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001007 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
1008 dismissKeyguardThenExecute(new OnDismissAction() {
1009 @Override
1010 public boolean onDismiss() {
1011 AsyncTask.execute(new Runnable() {
1012 public void run() {
1013 try {
1014 if (keyguardShowing) {
1015 ActivityManagerNative.getDefault()
1016 .keyguardWaitingForActivityDrawn();
1017 }
1018 TaskStackBuilder.create(mContext)
1019 .addNextIntentWithParentStack(intent)
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001020 .startActivities(getActivityOptions(),
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001021 new UserHandle(UserHandle.getUserId(appUid)));
1022 overrideActivityPendingAppTransition(keyguardShowing);
1023 } catch (RemoteException e) {
1024 }
1025 }
1026 });
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +01001027 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001028 return true;
1029 }
Jorim Jaggi746f7fa2014-08-27 17:52:46 +02001030 }, false /* afterKeyguardGone */);
Dan Sandler4247a5c2014-07-23 15:58:08 -04001031 }
1032
Mady Mellorb53bc272016-02-11 18:28:23 -08001033 private void bindGuts(final ExpandableNotificationRow row) {
Selim Cinekab29aeb2015-02-20 18:18:32 +01001034 row.inflateGuts();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001035 final StatusBarNotification sbn = row.getStatusBarNotification();
Selim Cinekeef84282015-10-30 16:28:00 -07001036 PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001037 row.setTag(sbn.getPackageName());
Julia Reynoldsa07af882015-12-17 08:32:48 -05001038 final NotificationGuts guts = row.getGuts();
Mady Mellor97c8df42016-03-22 18:09:39 -07001039 guts.setClosedListener(this);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001040 final String pkg = sbn.getPackageName();
1041 String appname = pkg;
1042 Drawable pkgicon = null;
1043 int appUid = -1;
1044 try {
1045 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
1046 PackageManager.GET_UNINSTALLED_PACKAGES
1047 | PackageManager.GET_DISABLED_COMPONENTS);
1048 if (info != null) {
1049 appname = String.valueOf(pmUser.getApplicationLabel(info));
1050 pkgicon = pmUser.getApplicationIcon(info);
1051 appUid = info.uid;
1052 }
1053 } catch (NameNotFoundException e) {
1054 // app is gone, just show package name and generic icon
1055 pkgicon = pmUser.getDefaultActivityIcon();
1056 }
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001057
Julia Reynoldsbe018462016-03-01 12:22:48 -05001058 ((ImageView) row.findViewById(R.id.app_icon)).setImageDrawable(pkgicon);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001059 ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001060
Julia Reynolds56821922016-01-04 15:24:01 -05001061 final View settingsButton = guts.findViewById(R.id.more_settings);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001062 if (appUid >= 0) {
1063 final int appUidF = appUid;
1064 settingsButton.setOnClickListener(new View.OnClickListener() {
1065 public void onClick(View v) {
Chris Wrenf6e9228b2016-01-26 18:04:35 -05001066 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
Mady Mellor97c8df42016-03-22 18:09:39 -07001067 guts.resetFalsingCheck();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001068 startAppNotificationSettingsActivity(pkg, appUidF);
1069 }
1070 });
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001071 } else {
1072 settingsButton.setVisibility(View.GONE);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001073 }
1074
Julia Reynolds56821922016-01-04 15:24:01 -05001075 row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
1076 @Override
1077 public void onClick(View v) {
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001078 // If the user has security enabled, show challenge if the setting is changed.
1079 if (guts.hasImportanceChanged() && isLockscreenPublicMode() &&
1080 (mState == StatusBarState.KEYGUARD
1081 || mState == StatusBarState.SHADE_LOCKED)) {
1082 OnDismissAction dismissAction = new OnDismissAction() {
1083 @Override
1084 public boolean onDismiss() {
1085 saveImportanceCloseControls(sbn, row, guts, v);
1086 return true;
1087 }
1088 };
1089 onLockedNotificationImportanceChange(dismissAction);
1090 } else {
1091 saveImportanceCloseControls(sbn, row, guts, v);
1092 }
Julia Reynolds56821922016-01-04 15:24:01 -05001093 }
1094 });
Julia Reynolds40779452016-02-23 13:43:32 -05001095 guts.bindImportance(pmUser, sbn, row, mNotificationData.getImportance(sbn.getKey()));
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001096 }
1097
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001098 private void saveImportanceCloseControls(StatusBarNotification sbn,
1099 ExpandableNotificationRow row, NotificationGuts guts, View done) {
Mady Mellor97c8df42016-03-22 18:09:39 -07001100 guts.resetFalsingCheck();
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001101 guts.saveImportance(sbn);
1102
1103 int[] rowLocation = new int[2];
1104 int[] doneLocation = new int[2];
1105 row.getLocationOnScreen(rowLocation);
1106 done.getLocationOnScreen(doneLocation);
1107
1108 final int centerX = done.getWidth() / 2;
1109 final int centerY = done.getHeight() / 2;
1110 final int x = doneLocation[0] - rowLocation[0] + centerX;
1111 final int y = doneLocation[1] - rowLocation[1] + centerY;
1112 dismissPopups(x, y);
1113 }
1114
Dan Sandler4247a5c2014-07-23 15:58:08 -04001115 protected SwipeHelper.LongPressListener getNotificationLongClicker() {
1116 return new SwipeHelper.LongPressListener() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001117 @Override
Selim Cinekd84a5932015-12-15 11:45:36 -08001118 public boolean onLongPress(View v, final int x, final int y) {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001119 if (!(v instanceof ExpandableNotificationRow)) {
1120 return false;
1121 }
Selim Cinekabdc5a02014-09-02 13:46:00 +02001122 if (v.getWindowToken() == null) {
1123 Log.e(TAG, "Trying to show notification guts, but not attached to window");
1124 return false;
1125 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001126
Mady Mellor4b80b102016-01-22 08:03:58 -08001127 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
Selim Cinekab29aeb2015-02-20 18:18:32 +01001128 bindGuts(row);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001129
Dan Sandler4247a5c2014-07-23 15:58:08 -04001130 // Assume we are a status_bar_notification_row
Selim Cinekab29aeb2015-02-20 18:18:32 +01001131 final NotificationGuts guts = row.getGuts();
Selim Cinekbdefcdf2014-09-11 12:41:47 +02001132 if (guts == null) {
1133 // This view has no guts. Examples are the more card or the dismiss all view
1134 return false;
1135 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001136
1137 // Already showing?
Selim Cinekabdc5a02014-09-02 13:46:00 +02001138 if (guts.getVisibility() == View.VISIBLE) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001139 dismissPopups(x, y);
Selim Cinekabdc5a02014-09-02 13:46:00 +02001140 return false;
1141 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001142
Chris Wrenf6e9228b2016-01-26 18:04:35 -05001143 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001144
Julia Reynolds40779452016-02-23 13:43:32 -05001145 // ensure that it's laid but not visible until actually laid out
Selim Cinekd84a5932015-12-15 11:45:36 -08001146 guts.setVisibility(View.INVISIBLE);
Julia Reynolds40779452016-02-23 13:43:32 -05001147 // Post to ensure the the guts are properly laid out.
Selim Cinekd84a5932015-12-15 11:45:36 -08001148 guts.post(new Runnable() {
1149 public void run() {
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001150 dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */,
1151 false /* animate */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001152 guts.setVisibility(View.VISIBLE);
1153 final double horz = Math.max(guts.getWidth() - x, x);
1154 final double vert = Math.max(guts.getHeight() - y, y);
1155 final float r = (float) Math.hypot(horz, vert);
1156 final Animator a
1157 = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
1158 a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc18010f2016-01-20 13:41:30 -08001159 a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Mady Mellor4b80b102016-01-22 08:03:58 -08001160 a.addListener(new AnimatorListenerAdapter() {
1161 @Override
1162 public void onAnimationEnd(Animator animation) {
1163 super.onAnimationEnd(animation);
1164 // Move the notification view back over the gear
1165 row.resetTranslation();
1166 }
1167 });
Selim Cinekd84a5932015-12-15 11:45:36 -08001168 a.start();
Mady Mellor97c8df42016-03-22 18:09:39 -07001169 guts.setExposed(true /* exposed */,
1170 mState == StatusBarState.KEYGUARD /* needsFalsingProtection */);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001171 row.closeRemoteInput();
Selim Cinekd84a5932015-12-15 11:45:36 -08001172 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
1173 mNotificationGutsExposed = guts;
1174 }
1175 });
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001176 return true;
1177 }
1178 };
1179 }
1180
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001181 /**
1182 * Returns the exposed NotificationGuts or null if none are exposed.
1183 */
1184 public NotificationGuts getExposedGuts() {
1185 return mNotificationGutsExposed;
Mady Mellor4b80b102016-01-22 08:03:58 -08001186 }
1187
Daniel Sandler469e96e2012-05-04 15:56:19 -04001188 public void dismissPopups() {
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001189 dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */, false /* animate */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001190 }
1191
1192 private void dismissPopups(int x, int y) {
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001193 dismissPopups(x, y, true /* resetGear */, false /* animate */);
Mady Mellorb53bc272016-02-11 18:28:23 -08001194 }
1195
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001196 public void dismissPopups(int x, int y, boolean resetGear, boolean animate) {
Dan Sandler4247a5c2014-07-23 15:58:08 -04001197 if (mNotificationGutsExposed != null) {
Mady Mellor97c8df42016-03-22 18:09:39 -07001198 mNotificationGutsExposed.closeControls(x, y, true /* notify */);
Daniel Sandler469e96e2012-05-04 15:56:19 -04001199 }
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001200 if (resetGear) {
1201 mStackScroller.resetExposedGearView(animate, true /* force */);
Mady Mellor4b80b102016-01-22 08:03:58 -08001202 }
Daniel Sandler469e96e2012-05-04 15:56:19 -04001203 }
1204
Michael Jurka7f2668c2012-03-27 07:49:52 -07001205 @Override
Mady Mellor97c8df42016-03-22 18:09:39 -07001206 public void onGutsClosed(NotificationGuts guts) {
1207 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
1208 mNotificationGutsExposed = null;
1209 }
1210
1211 @Override
Winson Chung1e8d71b2014-05-16 17:05:22 -07001212 public void showRecentApps(boolean triggeredFromAltTab) {
1213 int msg = MSG_SHOW_RECENT_APPS;
1214 mHandler.removeMessages(msg);
1215 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, 0).sendToTarget();
1216 }
1217
1218 @Override
Winson Chungcdcd4872014-08-05 18:00:13 -07001219 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001220 int msg = MSG_HIDE_RECENT_APPS;
1221 mHandler.removeMessages(msg);
Winson Chungcdcd4872014-08-05 18:00:13 -07001222 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0,
1223 triggeredFromHomeKey ? 1 : 0).sendToTarget();
Winson Chung1e8d71b2014-05-16 17:05:22 -07001224 }
1225
1226 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001227 public void toggleRecentApps() {
Jorim Jaggi900fb482015-06-02 15:07:33 -07001228 toggleRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001229 }
1230
1231 @Override
Phil Weaver315c34e2016-02-19 15:12:29 -08001232 public void toggleSplitScreen() {
1233 toggleSplitScreenMode();
1234 }
1235
1236 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001237 public void preloadRecentApps() {
1238 int msg = MSG_PRELOAD_RECENT_APPS;
1239 mHandler.removeMessages(msg);
1240 mHandler.sendEmptyMessage(msg);
1241 }
1242
1243 @Override
1244 public void cancelPreloadRecentApps() {
1245 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
1246 mHandler.removeMessages(msg);
1247 mHandler.sendEmptyMessage(msg);
1248 }
1249
Clara Bayarrif2debb12015-07-10 14:47:17 +01001250 @Override
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001251 public void toggleKeyboardShortcutsMenu(int deviceId) {
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001252 int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
Clara Bayarrif2debb12015-07-10 14:47:17 +01001253 mHandler.removeMessages(msg);
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001254 mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
Clara Bayarrif2debb12015-07-10 14:47:17 +01001255 }
1256
Winson Chungb1f74992014-08-08 12:53:09 -07001257 /** Jumps to the next affiliated task in the group. */
1258 public void showNextAffiliatedTask() {
1259 int msg = MSG_SHOW_NEXT_AFFILIATED_TASK;
1260 mHandler.removeMessages(msg);
1261 mHandler.sendEmptyMessage(msg);
1262 }
1263
1264 /** Jumps to the previous affiliated task in the group. */
1265 public void showPreviousAffiliatedTask() {
1266 int msg = MSG_SHOW_PREV_AFFILIATED_TASK;
1267 mHandler.removeMessages(msg);
1268 mHandler.sendEmptyMessage(msg);
1269 }
1270
Michael Jurkaecc395a2012-03-30 05:31:46 -07001271 protected H createHandler() {
Michael Jurka7f2668c2012-03-27 07:49:52 -07001272 return new H();
1273 }
1274
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001275 protected void sendCloseSystemWindows(String reason) {
Michael Jurka56a57832012-05-14 13:24:43 -07001276 if (ActivityManagerNative.isSystemReady()) {
1277 try {
1278 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
1279 } catch (RemoteException e) {
1280 }
1281 }
1282 }
1283
Michael Jurkacb2522c2012-04-13 09:32:47 -07001284 protected abstract View getStatusBarView();
1285
Michael Jurka80343f62012-10-18 13:13:46 +02001286 protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
1287 // additional optimization when we have software system buttons - start loading the recent
1288 // tasks on touch down
1289 @Override
1290 public boolean onTouch(View v, MotionEvent event) {
1291 int action = event.getAction() & MotionEvent.ACTION_MASK;
1292 if (action == MotionEvent.ACTION_DOWN) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001293 preloadRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001294 } else if (action == MotionEvent.ACTION_CANCEL) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001295 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001296 } else if (action == MotionEvent.ACTION_UP) {
1297 if (!v.isPressed()) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001298 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001299 }
1300
1301 }
1302 return false;
1303 }
1304 };
1305
Phil Weaver315c34e2016-02-19 15:12:29 -08001306 /**
1307 * Toggle docking the app window
1308 *
1309 * @return {@code true} if the app window is docked after the toggle, {@code false} otherwise.
1310 */
1311 protected abstract boolean toggleSplitScreenMode();
1312
Winson Chung1e8d71b2014-05-16 17:05:22 -07001313 /** Proxy for RecentsComponent */
1314
1315 protected void showRecents(boolean triggeredFromAltTab) {
1316 if (mRecents != null) {
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001317 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001318 mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
1319 }
1320 }
1321
Winson Chungcdcd4872014-08-05 18:00:13 -07001322 protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001323 if (mRecents != null) {
Winson Chungcdcd4872014-08-05 18:00:13 -07001324 mRecents.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001325 }
1326 }
1327
1328 protected void toggleRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001329 if (mRecents != null) {
1330 mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
1331 }
1332 }
Michael Jurka80343f62012-10-18 13:13:46 +02001333
Winson Chung1e8d71b2014-05-16 17:05:22 -07001334 protected void preloadRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001335 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001336 mRecents.preloadRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001337 }
Michael Jurka80343f62012-10-18 13:13:46 +02001338 }
1339
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001340 protected void toggleKeyboardShortcuts(int deviceId) {
1341 getKeyboardShortcuts().toggleKeyboardShortcuts(deviceId);
Clara Bayarrif2debb12015-07-10 14:47:17 +01001342 }
1343
Winson Chung1e8d71b2014-05-16 17:05:22 -07001344 protected void cancelPreloadingRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001345 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001346 mRecents.cancelPreloadingRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001347 }
Michael Jurka80343f62012-10-18 13:13:46 +02001348 }
1349
Winson Chungb1f74992014-08-08 12:53:09 -07001350 protected void showRecentsNextAffiliatedTask() {
1351 if (mRecents != null) {
1352 mRecents.showNextAffiliatedTask();
1353 }
1354 }
1355
1356 protected void showRecentsPreviousAffiliatedTask() {
1357 if (mRecents != null) {
1358 mRecents.showPrevAffiliatedTask();
1359 }
1360 }
1361
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001362 /**
Selim Cinek684a4422015-04-15 16:18:39 -07001363 * If there is an active heads-up notification and it has a fullscreen intent, fire it now.
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001364 */
Selim Cinek684a4422015-04-15 16:18:39 -07001365 public abstract void maybeEscalateHeadsUp();
Chris Wrena4ef6202014-06-09 18:07:30 -04001366
Dan Sandlerfd16d562014-02-13 18:43:31 -08001367 /**
1368 * Save the current "public" (locked and secure) state of the lockscreen.
1369 */
1370 public void setLockscreenPublicMode(boolean publicMode) {
1371 mLockscreenPublicMode = publicMode;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001372 }
1373
Dan Sandlerfd16d562014-02-13 18:43:31 -08001374 public boolean isLockscreenPublicMode() {
1375 return mLockscreenPublicMode;
1376 }
1377
1378 /**
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001379 * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
1380 * "public" (secure & locked) mode?
1381 */
1382 public boolean userAllowsNotificationsInPublic(int userHandle) {
1383 if (userHandle == UserHandle.USER_ALL) {
1384 return true;
1385 }
1386
1387 if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
1388 final boolean allowed = 0 != Settings.Secure.getIntForUser(
1389 mContext.getContentResolver(),
1390 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
1391 mUsersAllowingNotifications.append(userHandle, allowed);
1392 return allowed;
1393 }
1394
1395 return mUsersAllowingNotifications.get(userHandle);
1396 }
1397
1398 /**
Dan Sandlerfd16d562014-02-13 18:43:31 -08001399 * Has the given user chosen to allow their private (full) notifications to be shown even
1400 * when the lockscreen is in "public" (secure & locked) mode?
1401 */
1402 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
1403 if (userHandle == UserHandle.USER_ALL) {
1404 return true;
1405 }
1406
1407 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001408 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
Dan Sandlerfd16d562014-02-13 18:43:31 -08001409 mContext.getContentResolver(),
1410 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001411 final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001412 final boolean allowed = allowedByUser && allowedByDpm;
1413 mUsersAllowingPrivateNotifications.append(userHandle, allowed);
Dan Sandlerfd16d562014-02-13 18:43:31 -08001414 return allowed;
1415 }
1416
1417 return mUsersAllowingPrivateNotifications.get(userHandle);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001418 }
1419
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001420 private boolean adminAllowsUnredactedNotifications(int userHandle) {
1421 if (userHandle == UserHandle.USER_ALL) {
1422 return true;
1423 }
1424 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
1425 userHandle);
1426 return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
1427 }
1428
Christoph Studerc8db24b2014-07-25 17:50:30 +02001429 /**
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001430 * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
1431 * If so, notifications should be hidden.
Christoph Studerc8db24b2014-07-25 17:50:30 +02001432 */
1433 @Override // NotificationData.Environment
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001434 public boolean shouldHideNotifications(int userid) {
1435 return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
1436 }
1437
1438 /**
1439 * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
1440 * package-specific override.
1441 */
1442 @Override // NotificationDate.Environment
1443 public boolean shouldHideNotifications(String key) {
1444 return isLockscreenPublicMode()
1445 && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
1446 }
1447
1448 /**
1449 * Returns true if we're on a secure lockscreen.
1450 */
1451 @Override // NotificationData.Environment
1452 public boolean onSecureLockScreen() {
1453 return isLockscreenPublicMode();
Christoph Studerc8db24b2014-07-25 17:50:30 +02001454 }
1455
Chris Wrena4ef6202014-06-09 18:07:30 -04001456 public void onNotificationClear(StatusBarNotification notification) {
1457 try {
1458 mBarService.onNotificationClear(
1459 notification.getPackageName(),
1460 notification.getTag(),
1461 notification.getId(),
1462 notification.getUserId());
1463 } catch (android.os.RemoteException ex) {
1464 // oh well
1465 }
1466 }
1467
Selim Cinek5f71bee2015-11-18 10:25:23 -08001468 /**
Selim Cinek5fbc6322016-01-15 17:17:58 -08001469 * Called when the notification panel layouts
Selim Cinek5f71bee2015-11-18 10:25:23 -08001470 */
Selim Cinek5fbc6322016-01-15 17:17:58 -08001471 public void onPanelLaidOut() {
Selim Cinek5f71bee2015-11-18 10:25:23 -08001472 if (mState == StatusBarState.KEYGUARD) {
1473 // Since the number of notifications is determined based on the height of the view, we
1474 // need to update them.
Selim Cinek5fbc6322016-01-15 17:17:58 -08001475 int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
1476 int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
1477 if (maxBefore != maxNotifications) {
1478 updateRowStates();
1479 }
Selim Cinek5f71bee2015-11-18 10:25:23 -08001480 }
1481 }
1482
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001483 protected void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {}
1484
Adrian Roos3aec6382016-02-05 14:19:01 -08001485 protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
1486
Selim Cinek570981d2015-12-01 11:37:01 -08001487 @Override
Selim Cinek31aada42015-12-18 17:51:15 -08001488 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
Selim Cinek570981d2015-12-01 11:37:01 -08001489 }
1490
Michael Jurka7f2668c2012-03-27 07:49:52 -07001491 protected class H extends Handler {
1492 public void handleMessage(Message m) {
1493 switch (m.what) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001494 case MSG_SHOW_RECENT_APPS:
1495 showRecents(m.arg1 > 0);
Michael Jurkacb2522c2012-04-13 09:32:47 -07001496 break;
Winson Chung1e8d71b2014-05-16 17:05:22 -07001497 case MSG_HIDE_RECENT_APPS:
Winson Chungcdcd4872014-08-05 18:00:13 -07001498 hideRecents(m.arg1 > 0, m.arg2 > 0);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001499 break;
1500 case MSG_TOGGLE_RECENTS_APPS:
1501 toggleRecents();
Michael Jurkacb2522c2012-04-13 09:32:47 -07001502 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001503 case MSG_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001504 preloadRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001505 break;
1506 case MSG_CANCEL_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001507 cancelPreloadingRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001508 break;
Winson Chungb1f74992014-08-08 12:53:09 -07001509 case MSG_SHOW_NEXT_AFFILIATED_TASK:
1510 showRecentsNextAffiliatedTask();
1511 break;
1512 case MSG_SHOW_PREV_AFFILIATED_TASK:
1513 showRecentsPreviousAffiliatedTask();
1514 break;
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001515 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001516 toggleKeyboardShortcuts(m.arg1);
Clara Bayarrif2debb12015-07-10 14:47:17 +01001517 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001518 }
1519 }
1520 }
1521
Daniel Sandler6a858c32012-03-12 14:38:58 -04001522 protected void workAroundBadLayerDrawableOpacity(View v) {
1523 }
1524
Selim Cinek8d490d42015-04-10 00:05:50 -07001525 protected boolean inflateViews(Entry entry, ViewGroup parent) {
Selim Cinekeef84282015-10-30 16:28:00 -07001526 PackageManager pmUser = getPackageManagerForUser(mContext,
Dan Sandlere9a4e902014-07-31 01:06:43 -04001527 entry.notification.getUser().getIdentifier());
1528
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001529 final StatusBarNotification sbn = entry.notification;
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001530 entry.cacheContentViews(mContext, null);
1531
1532 final RemoteViews contentView = entry.cachedContentView;
1533 final RemoteViews bigContentView = entry.cachedBigContentView;
1534 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
1535 final RemoteViews publicContentView = entry.cachedPublicContentView;
Chris Wren8fd39ec2014-02-27 17:43:26 -05001536
Chris Wren574a55e2013-07-15 18:48:37 -04001537 if (contentView == null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001538 Log.v(TAG, "no contentView for: " + sbn.getNotification());
Daniel Sandler6a858c32012-03-12 14:38:58 -04001539 return false;
1540 }
1541
Dan Sandlerf68448e2014-04-24 15:54:16 -04001542 if (DEBUG) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001543 Log.v(TAG, "publicContentView: " + publicContentView);
Dan Sandlerf68448e2014-04-24 15:54:16 -04001544 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001545
Christoph Studera7fe6312014-06-27 19:32:44 +02001546 ExpandableNotificationRow row;
1547
1548 // Stash away previous user expansion state so we can restore it at
1549 // the end.
1550 boolean hasUserChangedExpansion = false;
1551 boolean userExpanded = false;
1552 boolean userLocked = false;
1553
1554 if (entry.row != null) {
1555 row = entry.row;
1556 hasUserChangedExpansion = row.hasUserChangedExpansion();
1557 userExpanded = row.isUserExpanded();
1558 userLocked = row.isUserLocked();
Christoph Studer22f2ee52014-07-29 22:57:21 +02001559 entry.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +02001560 if (hasUserChangedExpansion) {
1561 row.setUserExpanded(userExpanded);
1562 }
1563 } else {
1564 // create the row view
1565 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
1566 Context.LAYOUT_INFLATER_SERVICE);
1567 row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
1568 parent, false);
Chris Wren78403d72014-07-28 10:23:24 +01001569 row.setExpansionLogger(this, entry.notification.getKey());
Selim Cinekb5605e52015-02-20 18:21:41 +01001570 row.setGroupManager(mGroupManager);
Selim Cinek31aada42015-12-18 17:51:15 -08001571 row.setHeadsUpManager(mHeadsUpManager);
Adrian Roosb88b1a12015-12-09 18:51:05 -08001572 row.setRemoteInputController(mRemoteInputController);
Selim Cinek570981d2015-12-01 11:37:01 -08001573 row.setOnExpandClickListener(this);
Mady Mellor3fd273e2016-03-15 21:08:14 -07001574
1575 // Get the app name
1576 final String pkg = sbn.getPackageName();
1577 String appname = pkg;
1578 try {
1579 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
1580 PackageManager.GET_UNINSTALLED_PACKAGES
1581 | PackageManager.GET_DISABLED_COMPONENTS);
1582 if (info != null) {
1583 appname = String.valueOf(pmUser.getApplicationLabel(info));
1584 }
1585 } catch (NameNotFoundException e) {
1586 // Do nothing
1587 }
1588 row.setAppName(appname);
Christoph Studera7fe6312014-06-27 19:32:44 +02001589 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001590
Daniel Sandler6a858c32012-03-12 14:38:58 -04001591 workAroundBadLayerDrawableOpacity(row);
Selim Cinek757d8792016-01-28 16:21:08 -08001592 View vetoButton = bindVetoButtonClickListener(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001593 vetoButton.setContentDescription(mContext.getString(
1594 R.string.accessibility_remove_notification));
1595
1596 // NB: the large icon is now handled entirely by the template
1597
1598 // bind the click event to the content area
Selim Cinek8d490d42015-04-10 00:05:50 -07001599 NotificationContentView contentContainer = row.getPrivateLayout();
1600 NotificationContentView contentContainerPublic = row.getPublicLayout();
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001601
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001602 row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
Adrian Roos497ab022015-02-10 20:49:33 +01001603 if (ENABLE_REMOTE_INPUT) {
1604 row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
1605 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001606
Chris Wren42d5dd42015-05-01 10:39:26 -04001607 mNotificationClicker.register(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001608
Dan Sandlera5e0f412014-01-23 15:11:54 -05001609 // set up the adaptive layout
Chris Wren574a55e2013-07-15 18:48:37 -04001610 View contentViewLocal = null;
1611 View bigContentViewLocal = null;
Selim Cinek8d490d42015-04-10 00:05:50 -07001612 View headsUpContentViewLocal = null;
Selim Cinek624c02db2015-12-14 21:00:02 -08001613 View publicViewLocal = null;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001614 try {
Dan Sandler68079d52015-07-22 10:45:30 -04001615 contentViewLocal = contentView.apply(
1616 sbn.getPackageContext(mContext),
1617 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001618 mOnClickHandler);
Chris Wren574a55e2013-07-15 18:48:37 -04001619 if (bigContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001620 bigContentViewLocal = bigContentView.apply(
1621 sbn.getPackageContext(mContext),
1622 contentContainer,
Selim Cinek8d490d42015-04-10 00:05:50 -07001623 mOnClickHandler);
1624 }
1625 if (headsUpContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001626 headsUpContentViewLocal = headsUpContentView.apply(
1627 sbn.getPackageContext(mContext),
1628 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001629 mOnClickHandler);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001630 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001631 if (publicContentView != null) {
1632 publicViewLocal = publicContentView.apply(
1633 sbn.getPackageContext(mContext),
1634 contentContainerPublic, mOnClickHandler);
1635 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001636 }
1637 catch (RuntimeException e) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001638 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
John Spurlockcd686b52013-06-05 10:13:46 -04001639 Log.e(TAG, "couldn't inflate view for notification " + ident, e);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001640 return false;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001641 }
1642
Chris Wren574a55e2013-07-15 18:48:37 -04001643 if (contentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001644 contentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001645 contentContainer.setContractedChild(contentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001646 }
Chris Wren574a55e2013-07-15 18:48:37 -04001647 if (bigContentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001648 bigContentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001649 contentContainer.setExpandedChild(bigContentViewLocal);
1650 }
1651 if (headsUpContentViewLocal != null) {
1652 headsUpContentViewLocal.setIsRootNamespace(true);
1653 contentContainer.setHeadsUpChild(headsUpContentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001654 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001655 if (publicViewLocal != null) {
1656 publicViewLocal.setIsRootNamespace(true);
1657 contentContainerPublic.setContractedChild(publicViewLocal);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001658 }
1659
Jorim Jaggia1eeade2014-09-08 22:34:39 +02001660 // Extract target SDK version.
1661 try {
1662 ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
1663 entry.targetSdk = info.targetSdkVersion;
1664 } catch (NameNotFoundException ex) {
1665 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
1666 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001667 entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001668
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001669 if (MULTIUSER_DEBUG) {
1670 TextView debug = (TextView) row.findViewById(R.id.debug_info);
1671 if (debug != null) {
1672 debug.setVisibility(View.VISIBLE);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001673 debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId());
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001674 }
1675 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001676 entry.row = row;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001677 entry.row.setOnActivatedListener(this);
Selim Cinek684a4422015-04-15 16:18:39 -07001678 entry.row.setExpandable(bigContentViewLocal != null);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001679
Christoph Studer13b895122014-08-26 15:42:12 +02001680 applyColorsAndBackgrounds(sbn, entry);
Jorim Jaggi46739852014-04-15 09:58:24 +02001681
Christoph Studera7fe6312014-06-27 19:32:44 +02001682 // Restore previous flags.
1683 if (hasUserChangedExpansion) {
1684 // Note: setUserExpanded() conveniently ignores calls with
1685 // userExpanded=true if !isExpandable().
1686 row.setUserExpanded(userExpanded);
1687 }
1688 row.setUserLocked(userLocked);
Selim Cinekda42d652015-12-04 15:51:16 -08001689 row.onNotificationUpdated(entry);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001690 return true;
1691 }
1692
Adrian Roos497ab022015-02-10 20:49:33 +01001693 /**
1694 * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
1695 * via first-class API.
1696 *
1697 * TODO: Remove once enough apps specify remote inputs on their own.
1698 */
1699 private void processForRemoteInput(Notification n) {
1700 if (!ENABLE_REMOTE_INPUT) return;
1701
1702 if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
1703 (n.actions == null || n.actions.length == 0)) {
1704 Notification.Action viableAction = null;
1705 Notification.WearableExtender we = new Notification.WearableExtender(n);
1706
1707 List<Notification.Action> actions = we.getActions();
1708 final int numActions = actions.size();
1709
1710 for (int i = 0; i < numActions; i++) {
1711 Notification.Action action = actions.get(i);
Adrian Roosa3539cb2015-12-16 16:47:02 -08001712 if (action == null) {
1713 continue;
1714 }
Adrian Roos497ab022015-02-10 20:49:33 +01001715 RemoteInput[] remoteInputs = action.getRemoteInputs();
Adrian Roosa3539cb2015-12-16 16:47:02 -08001716 if (remoteInputs == null) {
1717 continue;
1718 }
1719 for (RemoteInput ri : remoteInputs) {
Adrian Roos497ab022015-02-10 20:49:33 +01001720 if (ri.getAllowFreeFormInput()) {
1721 viableAction = action;
1722 break;
1723 }
1724 }
1725 if (viableAction != null) {
1726 break;
1727 }
1728 }
1729
1730 if (viableAction != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001731 Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
1732 rebuilder.setActions(viableAction);
1733 rebuilder.build(); // will rewrite n
Adrian Roos497ab022015-02-10 20:49:33 +01001734 }
1735 }
1736 }
1737
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001738 protected KeyboardShortcuts getKeyboardShortcuts() {
1739 if (mKeyboardShortcuts == null) {
Andrei Stingaceanu8861cb02016-01-20 16:48:30 +00001740 mKeyboardShortcuts = new KeyboardShortcuts(mContext);
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001741 }
1742
1743 return mKeyboardShortcuts;
1744 }
1745
Adrian Roos62692b22015-09-11 17:46:23 -07001746 public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
1747 if (!isDeviceProvisioned()) return;
1748
1749 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
1750 final boolean afterKeyguardGone = intent.isActivity()
1751 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
1752 mCurrentUserId);
1753 dismissKeyguardThenExecute(new OnDismissAction() {
1754 public boolean onDismiss() {
1755 new Thread() {
1756 @Override
1757 public void run() {
1758 try {
1759 if (keyguardShowing && !afterKeyguardGone) {
1760 ActivityManagerNative.getDefault()
1761 .keyguardWaitingForActivityDrawn();
1762 }
1763
1764 // The intent we are sending is for the application, which
1765 // won't have permission to immediately start an activity after
1766 // the user switches to home. We know it is safe to do at this
1767 // point, so make sure new activity switches are now allowed.
1768 ActivityManagerNative.getDefault().resumeAppSwitches();
1769 } catch (RemoteException e) {
1770 }
Adrian Roos62692b22015-09-11 17:46:23 -07001771 try {
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001772 intent.send(null, 0, null, null, null, null, getActivityOptions());
Adrian Roos62692b22015-09-11 17:46:23 -07001773 } catch (PendingIntent.CanceledException e) {
1774 // the stack trace isn't very helpful here.
1775 // Just log the exception message.
1776 Log.w(TAG, "Sending intent failed: " + e);
1777
1778 // TODO: Dismiss Keyguard.
1779 }
1780 if (intent.isActivity()) {
1781 mAssistManager.hideAssist();
1782 overrideActivityPendingAppTransition(keyguardShowing
1783 && !afterKeyguardGone);
1784 }
1785 }
1786 }.start();
1787
1788 // close the shade if it was open
1789 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
1790 true /* force */, true /* delayed */);
1791 visibilityChanged(false);
1792
1793 return true;
1794 }
1795 }, afterKeyguardGone);
1796 }
1797
Chris Wren42d5dd42015-05-01 10:39:26 -04001798 private final class NotificationClicker implements View.OnClickListener {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001799 public void onClick(final View v) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001800 if (!(v instanceof ExpandableNotificationRow)) {
1801 Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
1802 return;
1803 }
1804
1805 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
1806 final StatusBarNotification sbn = row.getStatusBarNotification();
1807 if (sbn == null) {
1808 Log.e(TAG, "NotificationClicker called on an unclickable notification,");
1809 return;
1810 }
1811
Mady Mellorf0625802016-02-11 18:03:48 -08001812 // Check if the notification is displaying the gear, if so slide notification back
1813 if (row.getSettingsRow() != null && row.getSettingsRow().isVisible()) {
1814 row.animateTranslateNotification(0);
1815 return;
1816 }
1817
Selim Cinekc6dd5212015-11-02 14:51:54 -08001818 Notification notification = sbn.getNotification();
1819 final PendingIntent intent = notification.contentIntent != null
1820 ? notification.contentIntent
1821 : notification.fullScreenIntent;
Chris Wren42d5dd42015-05-01 10:39:26 -04001822 final String notificationKey = sbn.getKey();
1823
Jorim Jaggi5eb67c22015-08-19 19:50:49 -07001824 // Mark notification for one frame.
1825 row.setJustClicked(true);
1826 DejankUtils.postAfterTraversal(new Runnable() {
1827 @Override
1828 public void run() {
1829 row.setJustClicked(false);
1830 }
1831 });
1832
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001833 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Chris Wren42d5dd42015-05-01 10:39:26 -04001834 final boolean afterKeyguardGone = intent.isActivity()
1835 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001836 mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +02001837 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001838 public boolean onDismiss() {
Chris Wren42d5dd42015-05-01 10:39:26 -04001839 if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
Christoph Studerc6a656c2015-01-22 15:02:49 +01001840 // Release the HUN notification to the shade.
1841 //
1842 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
1843 // become canceled shortly by NoMan, but we can't assume that.
Selim Cinek0fccc722015-07-29 17:04:36 -07001844 HeadsUpManager.setIsClickedNotification(row, true);
Chris Wren42d5dd42015-05-01 10:39:26 -04001845 mHeadsUpManager.releaseImmediately(notificationKey);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001846 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001847 new Thread() {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001848 @Override
1849 public void run() {
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001850 try {
1851 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001852 ActivityManagerNative.getDefault()
1853 .keyguardWaitingForActivityDrawn();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001854 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001855
1856 // The intent we are sending is for the application, which
1857 // won't have permission to immediately start an activity after
1858 // the user switches to home. We know it is safe to do at this
1859 // point, so make sure new activity switches are now allowed.
1860 ActivityManagerNative.getDefault().resumeAppSwitches();
1861 } catch (RemoteException e) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001862 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001863 if (intent != null) {
Ricky Wai7fa01712016-03-16 12:13:54 +00001864 // If we are launching a work activity and require to launch
1865 // separate work challenge, we defer the activity action and cancel
1866 // notification until work challenge is unlocked.
1867 if (intent.isActivity()) {
1868 final int userId = intent.getCreatorUserHandle()
1869 .getIdentifier();
1870 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
1871 && mKeyguardManager.isDeviceLocked(userId)) {
Ricky Waia8c37a12016-04-05 17:10:04 +01001872 if (startWorkChallengeIfNecessary(userId,
1873 intent.getIntentSender(), notificationKey)) {
1874 // Show work challenge, do not run pendingintent and
1875 // remove notification
1876 return;
1877 }
Ricky Wai7fa01712016-03-16 12:13:54 +00001878 }
1879 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001880 try {
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001881 intent.send(null, 0, null, null, null, null,
1882 getActivityOptions());
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001883 } catch (PendingIntent.CanceledException e) {
1884 // the stack trace isn't very helpful here.
1885 // Just log the exception message.
1886 Log.w(TAG, "Sending contentIntent failed: " + e);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001887
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001888 // TODO: Dismiss Keyguard.
1889 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001890 if (intent.isActivity()) {
Jorim Jaggib835dd72015-06-08 12:28:42 -07001891 mAssistManager.hideAssist();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001892 overrideActivityPendingAppTransition(keyguardShowing
1893 && !afterKeyguardGone);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001894 }
1895 }
1896
1897 try {
Chris Wren42d5dd42015-05-01 10:39:26 -04001898 mBarService.onNotificationClick(notificationKey);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001899 } catch (RemoteException ex) {
1900 // system process is dead if we're here.
1901 }
Adrian Roos7d7090d2014-05-21 13:10:23 +02001902 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001903 }.start();
Adrian Roos7d7090d2014-05-21 13:10:23 +02001904
1905 // close the shade if it was open
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +01001906 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001907 true /* force */, true /* delayed */);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001908 visibilityChanged(false);
1909
Jorim Jaggi8972c2a2015-06-05 16:05:54 -07001910 return true;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001911 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001912 }, afterKeyguardGone);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001913 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001914
Ricky Waia8c37a12016-04-05 17:10:04 +01001915 public boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
Ricky Wai7fa01712016-03-16 12:13:54 +00001916 String notificationKey) {
Ricky Waia8c37a12016-04-05 17:10:04 +01001917 final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
1918 null, userId);
1919 if (newIntent == null) {
1920 return false;
1921 }
Ricky Wai7fa01712016-03-16 12:13:54 +00001922 final Intent callBackIntent = new Intent(
1923 WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
1924 callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
1925 callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
1926 callBackIntent.setPackage(mContext.getPackageName());
1927
Ricky Wai7fa01712016-03-16 12:13:54 +00001928 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1929 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1930 newIntent.putExtra(Intent.EXTRA_INTENT, PendingIntent
1931 .getBroadcast(mContext, 0, callBackIntent, 0).getIntentSender());
1932 mContext.startActivity(newIntent);
Ricky Waia8c37a12016-04-05 17:10:04 +01001933 return true;
Ricky Wai7fa01712016-03-16 12:13:54 +00001934 }
1935
Chris Wren42d5dd42015-05-01 10:39:26 -04001936 public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
Selim Cinekc6dd5212015-11-02 14:51:54 -08001937 Notification notification = sbn.getNotification();
1938 if (notification.contentIntent != null || notification.fullScreenIntent != null) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001939 row.setOnClickListener(this);
1940 } else {
1941 row.setOnClickListener(null);
1942 }
1943 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001944 }
Chris Wrenf29c3b42013-11-27 16:30:30 -05001945
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001946 public void animateCollapsePanels(int flags, boolean force) {
1947 }
1948
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001949 public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
1950 }
1951
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001952 public void overrideActivityPendingAppTransition(boolean keyguardShowing) {
1953 if (keyguardShowing) {
1954 try {
1955 mWindowManagerService.overridePendingAppTransition(null, 0, 0, null);
1956 } catch (RemoteException e) {
1957 Log.w(TAG, "Error overriding app transition: " + e);
1958 }
1959 }
1960 }
1961
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001962 protected Bundle getActivityOptions() {
1963 // Anything launched from the notification shade should always go into the
1964 // fullscreen stack.
1965 ActivityOptions options = ActivityOptions.makeBasic();
1966 options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
1967 return options.toBundle();
1968 }
1969
Christoph Studere8e28652014-10-29 17:27:53 +01001970 protected void visibilityChanged(boolean visible) {
1971 if (mVisible != visible) {
1972 mVisible = visible;
1973 if (!visible) {
1974 dismissPopups();
1975 }
1976 }
1977 updateVisibleToUser();
1978 }
1979
1980 protected void updateVisibleToUser() {
1981 boolean oldVisibleToUser = mVisibleToUser;
Jorim Jaggi50ff3af2015-08-12 18:35:42 -07001982 mVisibleToUser = mVisible && mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +01001983
1984 if (oldVisibleToUser != mVisibleToUser) {
1985 handleVisibleToUserChanged(mVisibleToUser);
1986 }
1987 }
1988
Daniel Sandler6a858c32012-03-12 14:38:58 -04001989 /**
Christoph Studere8e28652014-10-29 17:27:53 +01001990 * The LEDs are turned off when the notification panel is shown, even just a little bit.
Dan Sandlercb012892016-03-01 00:45:06 -05001991 * See also NotificationStackScrollLayout.setIsExpanded() for another place where we
1992 * attempt to do this.
Daniel Sandler6a858c32012-03-12 14:38:58 -04001993 */
Christoph Studere8e28652014-10-29 17:27:53 +01001994 protected void handleVisibleToUserChanged(boolean visibleToUser) {
1995 try {
1996 if (visibleToUser) {
Selim Cinek6577cae2015-08-31 16:15:49 -07001997 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
1998 boolean clearNotificationEffects =
Dan Sandlercb012892016-03-01 00:45:06 -05001999 !isPanelFullyCollapsed() &&
2000 (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
Chris Wrenb659c4f2015-06-25 17:12:27 -04002001 int notificationLoad = mNotificationData.getActiveNotifications().size();
Selim Cinek6577cae2015-08-31 16:15:49 -07002002 if (pinnedHeadsUp && isPanelFullyCollapsed()) {
Chris Wrenb659c4f2015-06-25 17:12:27 -04002003 notificationLoad = 1;
2004 } else {
2005 MetricsLogger.histogram(mContext, "note_load", notificationLoad);
2006 }
2007 mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
Christoph Studere8e28652014-10-29 17:27:53 +01002008 } else {
2009 mBarService.onPanelHidden();
Dan Sandler4247a5c2014-07-23 15:58:08 -04002010 }
Christoph Studere8e28652014-10-29 17:27:53 +01002011 } catch (RemoteException ex) {
2012 // Won't fail unless the world has ended.
Daniel Sandler6a858c32012-03-12 14:38:58 -04002013 }
2014 }
2015
Chris Wren0c8275b2012-05-08 13:36:48 -04002016 /**
Chris Wren16895942015-06-23 11:22:20 -04002017 * Clear Buzz/Beep/Blink.
2018 */
2019 public void clearNotificationEffects() {
2020 try {
2021 mBarService.clearNotificationEffects();
2022 } catch (RemoteException e) {
2023 // Won't fail unless the world has ended.
2024 }
2025 }
2026
Yorke Leee4ea6ab2016-03-03 14:51:49 -08002027 public abstract boolean isPanelFullyCollapsed();
Chris Wren16895942015-06-23 11:22:20 -04002028
2029 /**
Chris Wren0c8275b2012-05-08 13:36:48 -04002030 * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
2031 * about the failure.
2032 *
2033 * WARNING: this will call back into us. Don't hold any locks.
2034 */
Christoph Studer71f18fd2014-05-20 17:02:04 +02002035 void handleNotificationError(StatusBarNotification n, String message) {
Christoph Studere71fefc2014-06-24 16:16:49 +02002036 removeNotification(n.getKey(), null);
Chris Wren0c8275b2012-05-08 13:36:48 -04002037 try {
Kenny Guy3a7c4a52014-03-03 18:24:03 +00002038 mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
2039 n.getInitialPid(), message, n.getUserId());
Chris Wren0c8275b2012-05-08 13:36:48 -04002040 } catch (RemoteException ex) {
2041 // The end is nigh.
2042 }
2043 }
2044
Christoph Studerd0694b62014-06-04 16:36:01 +02002045 protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
Christoph Studer37fe6932014-05-26 13:10:30 +02002046 NotificationData.Entry entry = mNotificationData.remove(key, ranking);
Chris Wren0c8275b2012-05-08 13:36:48 -04002047 if (entry == null) {
John Spurlockcd686b52013-06-05 10:13:46 -04002048 Log.w(TAG, "removeNotification for unknown key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -04002049 return null;
2050 }
Christoph Studer37fe6932014-05-26 13:10:30 +02002051 updateNotifications();
Chris Wren0c8275b2012-05-08 13:36:48 -04002052 return entry.notification;
2053 }
2054
Selim Cinek8d490d42015-04-10 00:05:50 -07002055 protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002056 if (DEBUG) {
Christoph Studera0506e72014-07-31 20:27:39 +02002057 Log.d(TAG, "createNotificationViews(notification=" + sbn);
Chris Wren0c8275b2012-05-08 13:36:48 -04002058 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01002059 final StatusBarIconView iconView = createIcon(sbn);
2060 if (iconView == null) {
2061 return null;
2062 }
2063
2064 // Construct the expanded view.
2065 NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
Selim Cinek8d490d42015-04-10 00:05:50 -07002066 if (!inflateViews(entry, mStackScroller)) {
Selim Cinek379ff8f2015-02-20 17:03:16 +01002067 handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
2068 return null;
2069 }
2070 return entry;
2071 }
2072
Xiaohui Chene90c2c52016-02-24 16:08:00 -08002073 public StatusBarIconView createIcon(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002074 // Construct the icon.
Christoph Studera0506e72014-07-31 20:27:39 +02002075 Notification n = sbn.getNotification();
Chris Wren0c8275b2012-05-08 13:36:48 -04002076 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Christoph Studera0506e72014-07-31 20:27:39 +02002077 sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
Chris Wren0c8275b2012-05-08 13:36:48 -04002078 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
2079
Dan Sandler33439812015-08-10 15:49:56 -04002080 final Icon smallIcon = n.getSmallIcon();
2081 if (smallIcon == null) {
2082 handleNotificationError(sbn,
2083 "No small icon in notification from " + sbn.getPackageName());
2084 return null;
2085 }
Dan Sandlerd63f9322015-05-06 15:18:49 -04002086 final StatusBarIcon ic = new StatusBarIcon(
Christoph Studera0506e72014-07-31 20:27:39 +02002087 sbn.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002088 sbn.getPackageName(),
Dan Sandler33439812015-08-10 15:49:56 -04002089 smallIcon,
Dan Sandler4e787062015-06-17 15:09:48 -04002090 n.iconLevel,
2091 n.number,
2092 n.tickerText);
Chris Wren0c8275b2012-05-08 13:36:48 -04002093 if (!iconView.set(ic)) {
Christoph Studera0506e72014-07-31 20:27:39 +02002094 handleNotificationError(sbn, "Couldn't create icon: " + ic);
Chris Wren0c8275b2012-05-08 13:36:48 -04002095 return null;
2096 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01002097 return iconView;
Chris Wrenf0048ce2013-08-07 16:43:43 -04002098 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002099
Christoph Studerd0694b62014-06-04 16:36:01 +02002100 protected void addNotificationViews(Entry entry, RankingMap ranking) {
Raju Yadav5f330262014-03-24 10:44:00 +01002101 if (entry == null) {
2102 return;
2103 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002104 // Add the expanded view and icon.
Christoph Studer37fe6932014-05-26 13:10:30 +02002105 mNotificationData.add(entry, ranking);
2106 updateNotifications();
Selim Cinek8efa6dd2014-05-19 16:27:37 +02002107 }
2108
Jorim Jaggi251957d2014-04-09 04:24:09 +02002109 /**
Selim Cinek5f71bee2015-11-18 10:25:23 -08002110 * @param recompute wheter the number should be recomputed
Jorim Jaggid4a57442014-04-10 02:45:55 +02002111 * @return The number of notifications we show on Keyguard.
2112 */
Selim Cinek5f71bee2015-11-18 10:25:23 -08002113 protected abstract int getMaxKeyguardNotifications(boolean recompute);
Jorim Jaggid4a57442014-04-10 02:45:55 +02002114
2115 /**
Jorim Jaggi251957d2014-04-09 04:24:09 +02002116 * Updates expanded, dimmed and locked states of notification rows.
2117 */
2118 protected void updateRowStates() {
Jorim Jaggif6411742014-08-05 17:10:43 +00002119 mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
2120
Christoph Studerc8db24b2014-07-25 17:50:30 +02002121 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
2122 final int N = activeNotifications.size();
2123
Jorim Jaggif6411742014-08-05 17:10:43 +00002124 int visibleNotifications = 0;
Jorim Jaggiecbab362014-04-23 16:13:15 +02002125 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
Selim Cinek5f71bee2015-11-18 10:25:23 -08002126 int maxNotifications = 0;
2127 if (onKeyguard) {
2128 maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
2129 }
Christoph Studer37fe6932014-05-26 13:10:30 +02002130 for (int i = 0; i < N; i++) {
Christoph Studerc8db24b2014-07-25 17:50:30 +02002131 NotificationData.Entry entry = activeNotifications.get(i);
Selim Cinek2a739342016-03-17 10:28:55 -07002132 boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
Jorim Jaggiecbab362014-04-23 16:13:15 +02002133 if (onKeyguard) {
Selim Cinek83bc7832015-10-22 13:26:54 -07002134 entry.row.setOnKeyguard(true);
Chris Wren3ddab0d2012-08-02 16:52:21 -04002135 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -07002136 entry.row.setOnKeyguard(false);
Selim Cinek2a739342016-03-17 10:28:55 -07002137 entry.row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
Chris Wren8fd12652012-05-09 21:25:57 -04002138 }
Selim Cinek2a739342016-03-17 10:28:55 -07002139 boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(entry.notification);
Selim Cinek83bc7832015-10-22 13:26:54 -07002140 boolean childWithVisibleSummary = childNotification
2141 && mGroupManager.getGroupSummary(entry.notification).getVisibility()
2142 == View.VISIBLE;
Jorim Jaggif6411742014-08-05 17:10:43 +00002143 boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
Selim Cinek2a739342016-03-17 10:28:55 -07002144 if (suppressedSummary || (isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
Selim Cinek5f71bee2015-11-18 10:25:23 -08002145 (onKeyguard && (visibleNotifications >= maxNotifications
Selim Cinek83bc7832015-10-22 13:26:54 -07002146 && !childWithVisibleSummary
2147 || !showOnKeyguard))) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002148 entry.row.setVisibility(View.GONE);
Selim Cinek2a739342016-03-17 10:28:55 -07002149 if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002150 mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
2151 }
2152 } else {
2153 boolean wasGone = entry.row.getVisibility() == View.GONE;
2154 entry.row.setVisibility(View.VISIBLE);
Selim Cinek83bc7832015-10-22 13:26:54 -07002155 if (!childNotification) {
Selim Cinekb5605e52015-02-20 18:21:41 +01002156 if (wasGone) {
2157 // notify the scroller of a child addition
Selim Cinek2a739342016-03-17 10:28:55 -07002158 mStackScroller.generateAddAnimation(entry.row,
2159 !showOnKeyguard /* fromMoreCard */);
Selim Cinekb5605e52015-02-20 18:21:41 +01002160 }
2161 visibleNotifications++;
Jorim Jaggif6411742014-08-05 17:10:43 +00002162 }
Jorim Jaggif6411742014-08-05 17:10:43 +00002163 }
Chris Wren8fd12652012-05-09 21:25:57 -04002164 }
Jorim Jaggif6411742014-08-05 17:10:43 +00002165
Selim Cinek2cd45df2015-06-09 18:00:07 -07002166 mStackScroller.updateOverflowContainerVisibility(onKeyguard
2167 && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0);
Jorim Jaggif6411742014-08-05 17:10:43 +00002168
Selim Cinek0cce5312015-05-20 22:13:55 -07002169 mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
2170 mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
Jorim Jaggif6411742014-08-05 17:10:43 +00002171 mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
2172 mStackScroller.getChildCount() - 3);
Jorim Jaggif6411742014-08-05 17:10:43 +00002173 }
2174
2175 private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
2176 return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
Chris Wren8fd12652012-05-09 21:25:57 -04002177 }
2178
John Spurlocke677d712014-02-13 12:52:19 -05002179 protected void setZenMode(int mode) {
John Spurlock110e5b12014-02-27 13:09:35 -05002180 if (!isDeviceProvisioned()) return;
John Spurlocke677d712014-02-13 12:52:19 -05002181 mZenMode = mode;
Christoph Studer37fe6932014-05-26 13:10:30 +02002182 updateNotifications();
John Spurlocke677d712014-02-13 12:52:19 -05002183 }
2184
Dan Sandler52e5701e2014-07-22 23:14:54 -04002185 // extended in PhoneStatusBar
2186 protected void setShowLockscreenNotifications(boolean show) {
2187 mShowLockscreenNotifications = show;
2188 }
2189
Adrian Roos3aec6382016-02-05 14:19:01 -08002190 protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
2191 mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
2192 }
2193
Dan Sandler52e5701e2014-07-22 23:14:54 -04002194 private void updateLockscreenNotificationSetting() {
2195 final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2196 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
2197 1,
2198 mCurrentUserId) != 0;
Adrian Roosbd3409c2014-08-12 18:21:09 +02002199 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
2200 null /* admin */, mCurrentUserId);
2201 final boolean allowedByDpm = (dpmFlags
2202 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
Adrian Roos3aec6382016-02-05 14:19:01 -08002203
2204 final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2205 Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
2206 0,
2207 mCurrentUserId) != 0;
2208
Adrian Roosbd3409c2014-08-12 18:21:09 +02002209 setShowLockscreenNotifications(show && allowedByDpm);
Adrian Roos3aec6382016-02-05 14:19:01 -08002210 setLockScreenAllowRemoteInput(remoteInput);
Dan Sandler52e5701e2014-07-22 23:14:54 -04002211 }
2212
Chris Wren0c8275b2012-05-08 13:36:48 -04002213 protected abstract void setAreThereNotifications();
Christoph Studer37fe6932014-05-26 13:10:30 +02002214 protected abstract void updateNotifications();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -07002215 public abstract boolean shouldDisableNavbarGestures();
Chris Wren0c8275b2012-05-08 13:36:48 -04002216
Christoph Studere71fefc2014-06-24 16:16:49 +02002217 public abstract void addNotification(StatusBarNotification notification,
Selim Cinek379ff8f2015-02-20 17:03:16 +01002218 RankingMap ranking, Entry oldEntry);
Christoph Studere71fefc2014-06-24 16:16:49 +02002219 protected abstract void updateNotificationRanking(RankingMap ranking);
2220 public abstract void removeNotification(String key, RankingMap ranking);
Christoph Studera7fe6312014-06-27 19:32:44 +02002221
Christoph Studere71fefc2014-06-24 16:16:49 +02002222 public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02002223 if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
Chris Wren0c8275b2012-05-08 13:36:48 -04002224
Chris Wrend04f6ce2014-06-11 17:37:28 -04002225 final String key = notification.getKey();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002226 Entry entry = mNotificationData.get(key);
2227 if (entry == null) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002228 return;
Selim Cinek2d79f632015-11-02 15:13:29 -08002229 } else if (mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
2230 mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
Chris Wren0c8275b2012-05-08 13:36:48 -04002231 }
2232
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002233 Notification n = notification.getNotification();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002234 mNotificationData.updateRanking(ranking);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002235
Selim Cineka6a6f032015-11-23 15:46:24 -08002236 boolean applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
Chris Wrenbdf33762015-12-04 15:50:51 -05002237 boolean shouldPeek = shouldPeek(entry, notification);
Selim Cinek684a4422015-04-15 16:18:39 -07002238 boolean alertAgain = alertAgain(entry, n);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002239 if (DEBUG) {
2240 Log.d(TAG, "applyInPlace=" + applyInPlace
Chris Wrenbdf33762015-12-04 15:50:51 -05002241 + " shouldPeek=" + shouldPeek
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002242 + " alertAgain=" + alertAgain);
2243 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002244
Dan Sandler24813b02016-01-14 15:49:36 -05002245 final StatusBarNotification oldNotification = entry.notification;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002246 entry.notification = notification;
Dan Sandler24813b02016-01-14 15:49:36 -05002247 mGroupManager.onEntryUpdated(entry, oldNotification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002248
2249 boolean updateSuccessful = false;
2250 if (applyInPlace) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002251 if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
2252 try {
2253 if (entry.icon != null) {
2254 // Update the icon
Dan Sandlerd63f9322015-05-06 15:18:49 -04002255 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002256 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002257 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002258 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002259 n.iconLevel,
2260 n.number,
2261 n.tickerText);
2262 entry.icon.setNotification(n);
2263 if (!entry.icon.set(ic)) {
2264 handleNotificationError(notification, "Couldn't update icon: " + ic);
2265 return;
2266 }
2267 }
Selim Cinek8d490d42015-04-10 00:05:50 -07002268 updateNotificationViews(entry, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002269 updateSuccessful = true;
2270 }
2271 catch (RuntimeException e) {
Selim Cinek684a4422015-04-15 16:18:39 -07002272 // It failed to apply cleanly.
Adrian Roose458aa82015-12-08 16:17:19 -08002273 Log.w(TAG, "Couldn't reapply views for package " +
2274 notification.getPackageName(), e);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002275 }
2276 }
2277 if (!updateSuccessful) {
2278 if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
Dan Sandlerd63f9322015-05-06 15:18:49 -04002279 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002280 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002281 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002282 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002283 n.iconLevel,
2284 n.number,
2285 n.tickerText);
2286 entry.icon.setNotification(n);
2287 entry.icon.set(ic);
Selim Cinek8d490d42015-04-10 00:05:50 -07002288 inflateViews(entry, mStackScroller);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002289 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002290 updateHeadsUp(key, entry, shouldPeek, alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002291 updateNotifications();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002292
2293 // Update the veto button accordingly (and as a result, whether this row is
2294 // swipe-dismissable)
Selim Cinek757d8792016-01-28 16:21:08 -08002295 bindVetoButtonClickListener(entry.row, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002296
dongwan0605.kim30637e42016-03-02 17:16:47 +09002297 if (!notification.isClearable()) {
2298 // The user may have performed a dismiss action on the notification, since it's
2299 // not clearable we should snap it back.
2300 mStackScroller.snapViewIfNeeded(entry.row);
2301 }
2302
Selim Cinek684a4422015-04-15 16:18:39 -07002303 if (DEBUG) {
2304 // Is this for you?
2305 boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
2306 Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
2307 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002308
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002309 setAreThereNotifications();
2310 }
2311
Chris Wrenbdf33762015-12-04 15:50:51 -05002312 protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
Selim Cinek29fa89b2015-04-17 10:39:11 -07002313 boolean alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002314
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002315 private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
2316 final RemoteViews contentView = entry.cachedContentView;
2317 final RemoteViews bigContentView = entry.cachedBigContentView;
2318 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
2319 final RemoteViews publicContentView = entry.cachedPublicContentView;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002320
Chris Wrene03f4e12013-08-08 16:48:48 -04002321 // Reapply the RemoteViews
Selim Cinek684a4422015-04-15 16:18:39 -07002322 contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
2323 if (bigContentView != null && entry.getExpandedContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002324 bigContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002325 entry.getExpandedContentView(),
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01002326 mOnClickHandler);
Chris Wrene03f4e12013-08-08 16:48:48 -04002327 }
Selim Cinek684a4422015-04-15 16:18:39 -07002328 View headsUpChild = entry.getHeadsUpContentView();
Selim Cinek8d490d42015-04-10 00:05:50 -07002329 if (headsUpContentView != null && headsUpChild != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002330 headsUpContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002331 headsUpChild, mOnClickHandler);
Selim Cinek8d490d42015-04-10 00:05:50 -07002332 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002333 if (publicContentView != null && entry.getPublicContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002334 publicContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002335 entry.getPublicContentView(), mOnClickHandler);
Dan Sandlera5e0f412014-01-23 15:11:54 -05002336 }
Chris Wrene03f4e12013-08-08 16:48:48 -04002337 // update the contentIntent
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002338 mNotificationClicker.register(entry.row, sbn);
Chris Wren42d5dd42015-05-01 10:39:26 -04002339
Selim Cinekda42d652015-12-04 15:51:16 -08002340 entry.row.onNotificationUpdated(entry);
Selim Cinek51ae05d2014-09-09 15:51:38 +02002341 entry.row.resetHeight();
Chris Wren0c8275b2012-05-08 13:36:48 -04002342 }
John Spurlock36231282012-06-23 17:11:27 -04002343
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002344 protected void updatePublicContentView(Entry entry,
2345 StatusBarNotification sbn) {
2346 final RemoteViews publicContentView = entry.cachedPublicContentView;
Selim Cineke4c068d2016-02-19 13:46:55 -08002347 View inflatedView = entry.getPublicContentView();
2348 if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002349 final boolean disabledByPolicy =
2350 !adminAllowsUnredactedNotifications(entry.notification.getUserId());
Selim Cineke4c068d2016-02-19 13:46:55 -08002351 String notificationHiddenText = mContext.getString(disabledByPolicy
2352 ? com.android.internal.R.string.notification_hidden_by_policy_text
2353 : com.android.internal.R.string.notification_hidden_text);
2354 TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
2355 if (titleView != null
2356 && !titleView.getText().toString().equals(notificationHiddenText)) {
2357 publicContentView.setTextViewText(android.R.id.title, notificationHiddenText);
2358 publicContentView.reapply(sbn.getPackageContext(mContext),
2359 inflatedView, mOnClickHandler);
2360 entry.row.onNotificationUpdated(entry);
2361 }
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002362 }
2363 }
2364
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002365 protected void notifyHeadsUpScreenOff() {
Selim Cinek684a4422015-04-15 16:18:39 -07002366 maybeEscalateHeadsUp();
Chris Wrene97f90b2013-08-07 17:39:35 -04002367 }
2368
Chris Wrend93d5ad2014-09-08 16:34:03 -04002369 private boolean alertAgain(Entry oldEntry, Notification newNotification) {
2370 return oldEntry == null || !oldEntry.hasInterrupted()
2371 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
Chris Wrend04f6ce2014-06-11 17:37:28 -04002372 }
2373
Chris Wrenbdf33762015-12-04 15:50:51 -05002374 protected boolean shouldPeek(Entry entry) {
2375 return shouldPeek(entry, entry.notification);
Chris Wren0c274b12015-07-17 10:34:53 -04002376 }
2377
Chris Wrenbdf33762015-12-04 15:50:51 -05002378 protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
Dan Sandlerdc34df52016-04-07 21:04:46 -04002379 if (isDeviceInVrMode()) {
2380 return false;
2381 }
2382
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002383 if (mNotificationData.shouldFilterOut(sbn)) {
Chris Wrenbdf33762015-12-04 15:50:51 -05002384 if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002385 return false;
2386 }
2387
Selim Cinekd5921912016-02-09 10:33:01 -08002388 boolean inUse = mPowerManager.isScreenOn()
2389 && (!mStatusBarKeyguardViewManager.isShowing()
2390 || mStatusBarKeyguardViewManager.isOccluded())
2391 && !mStatusBarKeyguardViewManager.isInputRestricted();
2392 try {
2393 inUse = inUse && !mDreamManager.isDreaming();
2394 } catch (RemoteException e) {
2395 Log.d(TAG, "failed to query dream manager", e);
2396 }
2397
2398 if (!inUse) {
2399 if (DEBUG) {
2400 Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
2401 }
2402 return false;
2403 }
2404
2405 if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
2406 if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
Chris Wrena6d4fb62014-11-20 14:46:23 -05002407 return false;
2408 }
2409
Chris Wrenbdf33762015-12-04 15:50:51 -05002410 if (entry.hasJustLaunchedFullScreenIntent()) {
2411 if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
2412 return false;
2413 }
2414
Julia Reynoldsf0f629f2016-02-25 09:34:04 -05002415 if (isSnoozedPackage(sbn)) {
2416 if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
2417 return false;
2418 }
2419
2420 if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_HIGH) {
2421 if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
2422 return false;
2423 }
2424
Selim Cinekd5921912016-02-09 10:33:01 -08002425 if (sbn.getNotification().fullScreenIntent != null) {
2426 if (mAccessibilityManager.isTouchExplorationEnabled()) {
2427 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
2428 return false;
2429 } else {
2430 return true;
2431 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002432 }
2433
Selim Cinekd5921912016-02-09 10:33:01 -08002434 return true;
Chris Wren157026f2013-06-28 16:54:01 -04002435 }
2436
Selim Cinek29fa89b2015-04-17 10:39:11 -07002437 protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
2438
John Spurlockcfc359a2013-09-05 10:42:03 -04002439 public void setInteracting(int barWindow, boolean interacting) {
John Spurlockad3e6cb2013-04-30 08:47:43 -04002440 // hook for subclasses
2441 }
John Spurlock5c454122013-06-17 07:35:46 -04002442
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002443 public void setBouncerShowing(boolean bouncerShowing) {
2444 mBouncerShowing = bouncerShowing;
2445 }
2446
2447 /**
2448 * @return Whether the security bouncer from Keyguard is showing.
2449 */
2450 public boolean isBouncerShowing() {
2451 return mBouncerShowing;
2452 }
2453
John Spurlock5c454122013-06-17 07:35:46 -04002454 public void destroy() {
John Spurlock5c454122013-06-17 07:35:46 -04002455 mContext.unregisterReceiver(mBroadcastReceiver);
Christoph Studere71fefc2014-06-24 16:16:49 +02002456 try {
2457 mNotificationListener.unregisterAsSystemService();
2458 } catch (RemoteException e) {
2459 // Ignore.
Christoph Studer37fe6932014-05-26 13:10:30 +02002460 }
John Spurlock5c454122013-06-17 07:35:46 -04002461 }
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002462
2463 /**
2464 * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
2465 * return PackageManager for mContext
2466 */
Selim Cinekeef84282015-10-30 16:28:00 -07002467 public static PackageManager getPackageManagerForUser(Context context, int userId) {
2468 Context contextForUser = context;
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002469 // UserHandle defines special userId as negative values, e.g. USER_ALL
2470 if (userId >= 0) {
2471 try {
2472 // Create a context for the correct user so if a package isn't installed
2473 // for user 0 we can still load information about the package.
2474 contextForUser =
Selim Cinekeef84282015-10-30 16:28:00 -07002475 context.createPackageContextAsUser(context.getPackageName(),
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002476 Context.CONTEXT_RESTRICTED,
2477 new UserHandle(userId));
2478 } catch (NameNotFoundException e) {
2479 // Shouldn't fail to find the package name for system ui.
2480 }
2481 }
2482 return contextForUser.getPackageManager();
2483 }
Chris Wren78403d72014-07-28 10:23:24 +01002484
2485 @Override
2486 public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
2487 try {
2488 mBarService.onNotificationExpansionChanged(key, userAction, expanded);
2489 } catch (RemoteException e) {
2490 // Ignore.
2491 }
2492 }
Jim Millerab954542014-10-10 18:21:49 -07002493
2494 public boolean isKeyguardSecure() {
Dan Sandlere163a642015-03-01 22:58:32 -05002495 if (mStatusBarKeyguardViewManager == null) {
2496 // startKeyguard() hasn't been called yet, so we don't know.
2497 // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
2498 // value onVisibilityChanged().
2499 Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
2500 new Throwable());
2501 return false;
2502 }
Jim Millerab954542014-10-10 18:21:49 -07002503 return mStatusBarKeyguardViewManager.isSecure();
2504 }
Adrian Roos4f43dc02015-06-17 16:43:38 -07002505
2506 @Override
2507 public void showAssistDisclosure() {
2508 if (mAssistManager != null) {
2509 mAssistManager.showDisclosure();
2510 }
2511 }
Jorim Jaggi165ce062015-07-06 16:18:11 -07002512
2513 @Override
2514 public void startAssist(Bundle args) {
2515 if (mAssistManager != null) {
2516 mAssistManager.startAssist(args);
2517 }
2518 }
Joe Onorato2314aab2010-04-08 16:41:23 -05002519}