blob: 9d22b4a9f2802c2b1bf806cba7eee2ecfaf9f86b [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;
Daniel Sandler26cda272012-05-22 15:44:08 -040043import android.database.ContentObserver;
Jorim Jaggi86905582016-02-09 21:36:09 -080044import android.graphics.Rect;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +010045import android.graphics.drawable.Drawable;
Dan Sandler33439812015-08-10 15:49:56 -040046import android.graphics.drawable.Icon;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +020047import android.os.AsyncTask;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040048import android.os.Build;
Jorim Jaggi165ce062015-07-06 16:18:11 -070049import android.os.Bundle;
Michael Jurka7f2668c2012-03-27 07:49:52 -070050import android.os.Handler;
Joe Onorato808182d2010-07-09 18:52:06 -040051import android.os.IBinder;
Michael Jurka7f2668c2012-03-27 07:49:52 -070052import android.os.Message;
Chris Wren157026f2013-06-28 16:54:01 -040053import android.os.PowerManager;
Joe Onorato808182d2010-07-09 18:52:06 -040054import android.os.RemoteException;
55import android.os.ServiceManager;
Adrian Roos497ab022015-02-10 20:49:33 +010056import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070057import android.os.UserHandle;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000058import android.os.UserManager;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040059import android.provider.Settings;
Chris Wren157026f2013-06-28 16:54:01 -040060import android.service.dreams.DreamService;
61import android.service.dreams.IDreamManager;
Christoph Studer60748e72014-05-22 16:51:41 +020062import android.service.notification.NotificationListenerService;
Christoph Studerd0694b62014-06-04 16:36:01 +020063import android.service.notification.NotificationListenerService.RankingMap;
John Spurlockde84f0e2013-06-12 12:41:00 -040064import android.service.notification.StatusBarNotification;
Dan Sandlerdc34df52016-04-07 21:04:46 -040065import android.service.vr.IVrManager;
66import android.service.vr.IVrStateCallbacks;
Chris Wren0c8275b2012-05-08 13:36:48 -040067import android.text.TextUtils;
Selim Cinek2d79f632015-11-02 15:13:29 -080068import android.util.ArraySet;
Joe Onorato808182d2010-07-09 18:52:06 -040069import android.util.Log;
Dan Sandlere163a642015-03-01 22:58:32 -050070import android.util.Slog;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000071import android.util.SparseArray;
Dan Sandlerfd16d562014-02-13 18:43:31 -080072import android.util.SparseBooleanArray;
Daniel Sandlerc638c1e2011-08-24 16:19:23 -070073import android.view.Display;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050074import android.view.IWindowManager;
Michael Jurka7f2668c2012-03-27 07:49:52 -070075import android.view.LayoutInflater;
76import android.view.MotionEvent;
Joe Onorato808182d2010-07-09 18:52:06 -040077import android.view.View;
Dan Sandler4247a5c2014-07-23 15:58:08 -040078import android.view.ViewAnimationUtils;
Daniel Sandler6a858c32012-03-12 14:38:58 -040079import android.view.ViewGroup;
Christoph Studer4da84cd2014-10-21 17:24:20 +020080import android.view.ViewParent;
Joe Onorato808182d2010-07-09 18:52:06 -040081import android.view.WindowManager;
Michael Jurka80343f62012-10-18 13:13:46 +020082import android.view.WindowManagerGlobal;
Selim Cineka8fefa52014-09-08 16:10:50 +020083import android.view.accessibility.AccessibilityManager;
Chris Wren0c8275b2012-05-08 13:36:48 -040084import android.widget.ImageView;
Michael Jurkaa600fd92012-06-25 15:57:05 -070085import android.widget.RemoteViews;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040086import android.widget.TextView;
Kenny Guydae30d52015-04-01 19:11:35 +010087import android.widget.Toast;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050088
Chris Wrenbd6b5fb2015-06-09 14:58:34 -040089import com.android.internal.logging.MetricsLogger;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050090import com.android.internal.logging.MetricsProto.MetricsEvent;
Chris Wren117d5b42017-01-05 12:57:06 -050091import com.android.internal.messages.SystemMessageProto.SystemMessage;
John Spurlockde84f0e2013-06-12 12:41:00 -040092import com.android.internal.statusbar.IStatusBarService;
93import com.android.internal.statusbar.StatusBarIcon;
Chris Wrencd8f4f72014-08-27 18:48:13 -040094import com.android.internal.widget.LockPatternUtils;
Mady Mellor97c8df42016-03-22 18:09:39 -070095import com.android.keyguard.KeyguardHostView.OnDismissAction;
Selim Cinekfa760d42016-05-10 15:50:53 -040096import com.android.keyguard.KeyguardUpdateMonitor;
Jorim Jaggi5eb67c22015-08-19 19:50:49 -070097import com.android.systemui.DejankUtils;
Winsonc0d70582016-01-29 10:24:39 -080098import com.android.systemui.Interpolators;
John Spurlockde84f0e2013-06-12 12:41:00 -040099import com.android.systemui.R;
John Spurlockd08de372013-06-24 13:06:08 -0400100import com.android.systemui.RecentsComponent;
Dan Sandler4247a5c2014-07-23 15:58:08 -0400101import com.android.systemui.SwipeHelper;
John Spurlockde84f0e2013-06-12 12:41:00 -0400102import com.android.systemui.SystemUI;
Jorim Jaggib835dd72015-06-08 12:28:42 -0700103import com.android.systemui.assist.AssistManager;
Jorim Jaggid61f2272014-12-19 20:35:35 +0100104import com.android.systemui.recents.Recents;
Christoph Studer37fe6932014-05-26 13:10:30 +0200105import com.android.systemui.statusbar.NotificationData.Entry;
Mady Mellor97c8df42016-03-22 18:09:39 -0700106import com.android.systemui.statusbar.NotificationGuts.OnGutsClosedListener;
Selim Cinekadd95262016-12-06 14:34:47 -0800107import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinek92d892c2014-09-11 15:11:00 +0200108import com.android.systemui.statusbar.phone.NavigationBarView;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100109import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200110import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700111import com.android.systemui.statusbar.policy.HeadsUpManager;
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200112import com.android.systemui.statusbar.policy.PreviewInflater;
Adrian Roos497ab022015-02-10 20:49:33 +0100113import com.android.systemui.statusbar.policy.RemoteInputView;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100114import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekd84a5932015-12-15 11:45:36 -0800115import com.android.systemui.statusbar.stack.StackStateAnimator;
John Spurlockde84f0e2013-06-12 12:41:00 -0400116
Michael Jurkaa600fd92012-06-25 15:57:05 -0700117import java.util.ArrayList;
Julia Reynolds98a44862016-09-12 08:53:47 -0400118import java.util.Collections;
119import java.util.HashSet;
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200120import java.util.List;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700121import java.util.Locale;
Julia Reynolds98a44862016-09-12 08:53:47 -0400122import java.util.Set;
Selim Cinekadd95262016-12-06 14:34:47 -0800123import java.util.Stack;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400124
Julia Reynoldsf0f629f2016-02-25 09:34:04 -0500125import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200126
Michael Jurka7f2668c2012-03-27 07:49:52 -0700127public abstract class BaseStatusBar extends SystemUI implements
Winson Chung9214eff2014-06-12 13:59:25 -0700128 CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
Selim Cinek570981d2015-12-01 11:37:01 -0800129 ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
Selim Cinekadd95262016-12-06 14:34:47 -0800130 ExpandableNotificationRow.OnExpandClickListener, OnGutsClosedListener {
Daniel Sandler198a0302012-08-17 16:04:31 -0400131 public static final String TAG = "StatusBar";
Jorim Jaggi86905582016-02-09 21:36:09 -0800132 public static final boolean DEBUG = false;
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400133 public static final boolean MULTIUSER_DEBUG = false;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400134
Adrian Roos497ab022015-02-10 20:49:33 +0100135 public static final boolean ENABLE_REMOTE_INPUT =
Adrian Roos9531c9b2015-11-03 17:43:01 -0800136 SystemProperties.getBoolean("debug.enable_remote_input", true);
Selim Cinek40412492015-12-08 18:03:22 -0800137 public static final boolean ENABLE_CHILD_NOTIFICATIONS
138 = SystemProperties.getBoolean("debug.child_notifs", true);
Adrian Roosc0a579e2016-03-30 16:43:58 -0700139 public static final boolean FORCE_REMOTE_INPUT_HISTORY =
140 SystemProperties.getBoolean("debug.force_remoteinput_history", false);
Adrian Roosb27d7a52016-06-16 13:04:47 -0700141 private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
Adrian Roos497ab022015-02-10 20:49:33 +0100142
Winson Chung1e8d71b2014-05-16 17:05:22 -0700143 protected static final int MSG_SHOW_RECENT_APPS = 1019;
144 protected static final int MSG_HIDE_RECENT_APPS = 1020;
145 protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700146 protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
147 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
Winson Chungb1f74992014-08-08 12:53:09 -0700148 protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
149 protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +0000150 protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
Andrei Stingaceanu0bf096f2016-04-14 18:11:57 +0100151 protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
Chris Wren0c8275b2012-05-08 13:36:48 -0400152
Chris Wren157026f2013-06-28 16:54:01 -0400153 protected static final boolean ENABLE_HEADS_UP = true;
Chris Wren22ae46e2014-02-26 18:08:09 -0500154 protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
Chris Wren0c8275b2012-05-08 13:36:48 -0400155
Ricky Wai7fa01712016-03-16 12:13:54 +0000156 private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
157
Winsond8b1d632016-01-04 17:51:18 -0800158 // Should match the values in PhoneWindowManager
Michael Jurka56a57832012-05-14 13:24:43 -0700159 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
Winsond8b1d632016-01-04 17:51:18 -0800160 public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
Michael Jurka56a57832012-05-14 13:24:43 -0700161
Chris Wrencd8f4f72014-08-27 18:48:13 -0400162 private static final String BANNER_ACTION_CANCEL =
163 "com.android.systemui.statusbar.banner_action_cancel";
164 private static final String BANNER_ACTION_SETUP =
165 "com.android.systemui.statusbar.banner_action_setup";
Ricky Wai7fa01712016-03-16 12:13:54 +0000166 private static final String WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION
167 = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
Chris Wrencd8f4f72014-08-27 18:48:13 -0400168
Joe Onorato808182d2010-07-09 18:52:06 -0400169 protected CommandQueue mCommandQueue;
170 protected IStatusBarService mBarService;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700171 protected H mHandler = createHandler();
172
Chris Wren0c8275b2012-05-08 13:36:48 -0400173 // all notifications
Christoph Studerc8db24b2014-07-25 17:50:30 +0200174 protected NotificationData mNotificationData;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100175 protected NotificationStackScrollLayout mStackScroller;
Chris Wren0c8275b2012-05-08 13:36:48 -0400176
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100177 protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
178
Adrian Roosb88b1a12015-12-09 18:51:05 -0800179 protected RemoteInputController mRemoteInputController;
180
Chris Wrena4ef6202014-06-09 18:07:30 -0400181 // for heads up notifications
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700182 protected HeadsUpManager mHeadsUpManager;
Chris Wren0c8275b2012-05-08 13:36:48 -0400183
Selim Cinekadd95262016-12-06 14:34:47 -0800184 // handling reordering
185 protected VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager();
186
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400187 protected int mCurrentUserId = 0;
Kenny Guy2a764942014-04-02 13:29:20 +0100188 final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400189
Daniel Sandler777dcde2013-09-30 10:21:45 -0400190 protected int mLayoutDirection = -1; // invalid
Selim Cineka8fefa52014-09-08 16:10:50 +0200191 protected AccessibilityManager mAccessibilityManager;
Selim Cinek92d892c2014-09-11 15:11:00 +0200192
193 // on-screen navigation buttons
194 protected NavigationBarView mNavigationBarView = null;
Christoph Studere8e28652014-10-29 17:27:53 +0100195
Jorim Jaggi50ff3af2015-08-12 18:35:42 -0700196 protected boolean mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +0100197
198 protected boolean mVisible;
Selim Cinek2d79f632015-11-02 15:13:29 -0800199 protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
Adrian Roos18d099a2016-05-19 15:28:18 -0700200 protected ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>();
Christoph Studere8e28652014-10-29 17:27:53 +0100201
Adrian Roosc0a579e2016-03-30 16:43:58 -0700202 /**
203 * Notifications with keys in this set are not actually around anymore. We kept them around
204 * when they were canceled in response to a remote input interaction. This allows us to show
205 * what you replied and allows you to continue typing into it.
206 */
207 protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
208
Christoph Studere8e28652014-10-29 17:27:53 +0100209 // mScreenOnFromKeyguard && mVisible.
210 private boolean mVisibleToUser;
211
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700212 private Locale mLocale;
Dan Sandler539aad42014-08-04 00:43:39 -0400213 private float mFontScale;
214
Chris Wrenf6e83f42013-09-11 14:02:59 -0400215 protected boolean mUseHeadsUp = false;
Chris Wren22ae46e2014-02-26 18:08:09 -0500216 protected boolean mHeadsUpTicker = false;
Jason Monkf7019542014-07-31 12:42:25 -0400217 protected boolean mDisableNotificationAlerts = false;
Chris Wren157026f2013-06-28 16:54:01 -0400218
Adrian Roosbd3409c2014-08-12 18:21:09 +0200219 protected DevicePolicyManager mDevicePolicyManager;
Chris Wren157026f2013-06-28 16:54:01 -0400220 protected IDreamManager mDreamManager;
Julia Reynolds0971cb02016-01-26 17:00:22 -0500221 protected PowerManager mPowerManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200222 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Dan Sandlerfd16d562014-02-13 18:43:31 -0800223
224 // public mode, private notifications, etc
225 private boolean mLockscreenPublicMode = false;
226 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
Julia Reynolds26fa8a52016-02-24 08:31:22 -0500227 private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700228
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000229 private UserManager mUserManager;
Selim Cinek01af3342016-02-09 19:25:31 -0800230 private int mDensity;
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000231
Ricky Wai7fa01712016-03-16 12:13:54 +0000232 private KeyguardManager mKeyguardManager;
233 private LockPatternUtils mLockPatternUtils;
234
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500235 // UI-specific methods
Daniel Sandler6a858c32012-03-12 14:38:58 -0400236
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500237 /**
238 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
239 * and add them to the window manager.
240 */
241 protected abstract void createAndAddWindows();
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400242
Jeff Brown98365d72012-08-19 20:30:52 -0700243 protected WindowManager mWindowManager;
244 protected IWindowManager mWindowManagerService;
Christoph Studer60748e72014-05-22 16:51:41 +0200245
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700246 protected abstract void refreshLayout(int layoutDirection);
247
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500248 protected Display mDisplay;
Jeff Brown98365d72012-08-19 20:30:52 -0700249
Daniel Sandler26cda272012-05-22 15:44:08 -0400250 private boolean mDeviceProvisioned = false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400251
Jorim Jaggi75b25972015-10-21 14:51:10 +0200252 protected RecentsComponent mRecents;
John Spurlockd08de372013-06-24 13:06:08 -0400253
John Spurlocke677d712014-02-13 12:52:19 -0500254 protected int mZenMode;
255
Dan Sandler4247a5c2014-07-23 15:58:08 -0400256 // which notification is currently being longpress-examined by the user
Selim Cinek024ca592014-09-01 15:11:28 +0200257 private NotificationGuts mNotificationGutsExposed;
Dan Sandler4247a5c2014-07-23 15:58:08 -0400258
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +0100259 private KeyboardShortcuts mKeyboardShortcuts;
260
Jorim Jaggiecbab362014-04-23 16:13:15 +0200261 /**
262 * The {@link StatusBarState} of the status bar.
263 */
264 protected int mState;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200265 protected boolean mBouncerShowing;
John Spurlock4b3bda22014-05-22 14:32:20 -0400266 protected boolean mShowLockscreenNotifications;
Adrian Roos3aec6382016-02-05 14:19:01 -0800267 protected boolean mAllowLockscreenRemoteInput;
Jorim Jaggiecbab362014-04-23 16:13:15 +0200268
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200269 protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
Dan Sandlereceda3d2014-07-21 15:35:01 -0400270 protected DismissView mDismissView;
Jorim Jaggia2052ea2014-08-05 16:22:30 +0200271 protected EmptyShadeView mEmptyShadeView;
Jorim Jaggi649b7082014-04-03 13:15:18 +0200272
Chris Wren42d5dd42015-05-01 10:39:26 -0400273 private NotificationClicker mNotificationClicker = new NotificationClicker();
274
Jorim Jaggib835dd72015-06-08 12:28:42 -0700275 protected AssistManager mAssistManager;
276
Dan Sandlerdc34df52016-04-07 21:04:46 -0400277 protected boolean mVrMode;
278
Julia Reynolds98a44862016-09-12 08:53:47 -0400279 private Set<String> mNonBlockablePkgs;
280
Christoph Studerc8db24b2014-07-25 17:50:30 +0200281 @Override // NotificationData.Environment
Daniel Sandler3ffdcc72012-09-23 14:31:48 -0400282 public boolean isDeviceProvisioned() {
Daniel Sandler26cda272012-05-22 15:44:08 -0400283 return mDeviceProvisioned;
284 }
285
Dan Sandlerdc34df52016-04-07 21:04:46 -0400286 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
287 @Override
288 public void onVrStateChanged(boolean enabled) {
289 mVrMode = enabled;
290 }
291 };
292
293 public boolean isDeviceInVrMode() {
294 return mVrMode;
295 }
296
John Spurlocke677d712014-02-13 12:52:19 -0500297 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
Daniel Sandler26cda272012-05-22 15:44:08 -0400298 @Override
299 public void onChange(boolean selfChange) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700300 final boolean provisioned = 0 != Settings.Global.getInt(
301 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
Daniel Sandler26cda272012-05-22 15:44:08 -0400302 if (provisioned != mDeviceProvisioned) {
303 mDeviceProvisioned = provisioned;
Christoph Studer37fe6932014-05-26 13:10:30 +0200304 updateNotifications();
Daniel Sandler26cda272012-05-22 15:44:08 -0400305 }
John Spurlocke677d712014-02-13 12:52:19 -0500306 final int mode = Settings.Global.getInt(mContext.getContentResolver(),
307 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
308 setZenMode(mode);
Dan Sandler52e5701e2014-07-22 23:14:54 -0400309
310 updateLockscreenNotificationSetting();
Daniel Sandler26cda272012-05-22 15:44:08 -0400311 }
312 };
313
Dan Sandlerfd16d562014-02-13 18:43:31 -0800314 private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
315 @Override
316 public void onChange(boolean selfChange) {
Daniel U57454872016-03-29 20:28:21 +0100317 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
318 // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
Dan Sandlerfd16d562014-02-13 18:43:31 -0800319 mUsersAllowingPrivateNotifications.clear();
Daniel U57454872016-03-29 20:28:21 +0100320 mUsersAllowingNotifications.clear();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800321 // ... and refresh all the notifications
Christoph Studer37fe6932014-05-26 13:10:30 +0200322 updateNotifications();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800323 }
324 };
325
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700326 private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
327 @Override
Adrian Roos7d7090d2014-05-21 13:10:23 +0200328 public boolean onClickHandler(
329 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800330 if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
331 return true;
332 }
333
Daniel Sandler198a0302012-08-17 16:04:31 -0400334 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400335 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
Daniel Sandler198a0302012-08-17 16:04:31 -0400336 }
Christoph Studer4da84cd2014-10-21 17:24:20 +0200337 logActionClick(view);
Jorim Jaggi89f7f282014-10-17 19:54:15 +0200338 // The intent we are sending is for the application, which
339 // won't have permission to immediately start an activity after
340 // the user switches to home. We know it is safe to do at this
341 // point, so make sure new activity switches are now allowed.
342 try {
343 ActivityManagerNative.getDefault().resumeAppSwitches();
344 } catch (RemoteException e) {
345 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700346 final boolean isActivity = pendingIntent.isActivity();
347 if (isActivity) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200348 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200349 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
350 mContext, pendingIntent.getIntent(), mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +0200351 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200352 @Override
353 public boolean onDismiss() {
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200354 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200355 try {
356 ActivityManagerNative.getDefault()
357 .keyguardWaitingForActivityDrawn();
Jorim Jaggi91617a72015-06-25 15:01:29 -0700358 ActivityManagerNative.getDefault().resumeAppSwitches();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200359 } catch (RemoteException e) {
360 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200361 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700362
Adrian Roos7d7090d2014-05-21 13:10:23 +0200363 boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200364 overrideActivityPendingAppTransition(keyguardShowing && !afterKeyguardGone);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700365
Adrian Roos7d7090d2014-05-21 13:10:23 +0200366 // close the shade if it was open
367 if (handled) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100368 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
369 true /* force */);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200370 visibilityChanged(false);
Jorim Jaggi91617a72015-06-25 15:01:29 -0700371 mAssistManager.hideAssist();
Adrian Roos7d7090d2014-05-21 13:10:23 +0200372 }
Jorim Jaggi91617a72015-06-25 15:01:29 -0700373
Adrian Roos4314f6d2014-05-28 14:10:27 +0200374 // Wait for activity start.
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200375 return handled;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200376 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200377 }, afterKeyguardGone);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200378 return true;
379 } else {
Jorim Jaggie6e108e2016-03-28 13:38:45 -0700380 return superOnClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700381 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200382 }
383
Christoph Studer4da84cd2014-10-21 17:24:20 +0200384 private void logActionClick(View view) {
385 ViewParent parent = view.getParent();
386 String key = getNotificationKeyForParent(parent);
387 if (key == null) {
388 Log.w(TAG, "Couldn't determine notification for click.");
389 return;
390 }
391 int index = -1;
392 // If this is a default template, determine the index of the button.
393 if (view.getId() == com.android.internal.R.id.action0 &&
394 parent != null && parent instanceof ViewGroup) {
395 ViewGroup actionGroup = (ViewGroup) parent;
396 index = actionGroup.indexOfChild(view);
397 }
398 try {
399 mBarService.onNotificationActionClick(key, index);
400 } catch (RemoteException e) {
401 // Ignore
402 }
403 }
404
405 private String getNotificationKeyForParent(ViewParent parent) {
406 while (parent != null) {
407 if (parent instanceof ExpandableNotificationRow) {
408 return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
409 }
410 parent = parent.getParent();
411 }
412 return null;
413 }
414
Adrian Roos7d7090d2014-05-21 13:10:23 +0200415 private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
416 Intent fillInIntent) {
Jorim Jaggie6e108e2016-03-28 13:38:45 -0700417 return super.onClickHandler(view, pendingIntent, fillInIntent,
418 StackId.FULLSCREEN_WORKSPACE_STACK_ID);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700419 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800420
421 private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
422 Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
423 RemoteInput[] inputs = null;
424 if (tag instanceof RemoteInput[]) {
425 inputs = (RemoteInput[]) tag;
426 }
427
428 if (inputs == null) {
429 return false;
430 }
431
432 RemoteInput input = null;
433
434 for (RemoteInput i : inputs) {
435 if (i.getAllowFreeFormInput()) {
436 input = i;
437 }
438 }
439
440 if (input == null) {
441 return false;
442 }
443
444 ViewParent p = view.getParent();
445 RemoteInputView riv = null;
446 while (p != null) {
447 if (p instanceof View) {
448 View pv = (View) p;
449 if (pv.isRootNamespace()) {
450 riv = (RemoteInputView) pv.findViewWithTag(RemoteInputView.VIEW_TAG);
451 break;
452 }
453 }
454 p = p.getParent();
455 }
Adrian Roos3aec6382016-02-05 14:19:01 -0800456 ExpandableNotificationRow row = null;
457 while (p != null) {
458 if (p instanceof ExpandableNotificationRow) {
459 row = (ExpandableNotificationRow) p;
460 break;
461 }
462 p = p.getParent();
463 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800464
Adrian Roos3aec6382016-02-05 14:19:01 -0800465 if (riv == null || row == null) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800466 return false;
467 }
468
Adrian Roos3aec6382016-02-05 14:19:01 -0800469 row.setUserExpanded(true);
470
Ricky Waicd35def2016-05-03 11:07:07 +0100471 if (!mAllowLockscreenRemoteInput) {
472 if (isLockscreenPublicMode()) {
473 onLockedRemoteInput(row, view);
474 return true;
475 }
476 final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
477 if (mUserManager.getUserInfo(userId).isManagedProfile()
478 && mKeyguardManager.isDeviceLocked(userId)) {
479 onLockedWorkRemoteInput(userId, row, view);
480 return true;
481 }
Adrian Roos3aec6382016-02-05 14:19:01 -0800482 }
483
Adrian Roosaf06bf22016-07-15 12:26:49 -0700484 int width = view.getWidth();
485 if (view instanceof TextView) {
486 // Center the reveal on the text which might be off-center from the TextView
487 TextView tv = (TextView) view;
488 if (tv.getLayout() != null) {
489 int innerWidth = (int) tv.getLayout().getLineWidth(0);
490 innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
491 width = Math.min(width, innerWidth);
492 }
493 }
494 int cx = view.getLeft() + width / 2;
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800495 int cy = view.getTop() + view.getHeight() / 2;
496 int w = riv.getWidth();
497 int h = riv.getHeight();
498 int r = Math.max(
499 Math.max(cx + cy, cx + (h - cy)),
500 Math.max((w - cx) + cy, (w - cx) + (h - cy)));
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800501
Adrian Roosaf06bf22016-07-15 12:26:49 -0700502 riv.setRevealParameters(cx, cy, r);
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800503 riv.setPendingIntent(pendingIntent);
504 riv.setRemoteInput(inputs, input);
Adrian Roosaf06bf22016-07-15 12:26:49 -0700505 riv.focusAnimated();
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800506
507 return true;
508 }
509
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700510 };
511
John Spurlock5c454122013-06-17 07:35:46 -0400512 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
513 @Override
514 public void onReceive(Context context, Intent intent) {
515 String action = intent.getAction();
516 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
517 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Kenny Guy2a764942014-04-02 13:29:20 +0100518 updateCurrentProfilesCache();
John Spurlock5c454122013-06-17 07:35:46 -0400519 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
Dan Sandler52e5701e2014-07-22 23:14:54 -0400520
521 updateLockscreenNotificationSetting();
522
John Spurlock5c454122013-06-17 07:35:46 -0400523 userSwitched(mCurrentUserId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000524 } else if (Intent.ACTION_USER_ADDED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +0100525 updateCurrentProfilesCache();
Kenny Guydae30d52015-04-01 19:11:35 +0100526 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
527 List<ActivityManager.RecentTaskInfo> recentTask = null;
528 try {
529 recentTask = ActivityManagerNative.getDefault().getRecentTasks(1,
530 ActivityManager.RECENT_WITH_EXCLUDED
531 | ActivityManager.RECENT_INCLUDE_PROFILES,
Jeff Sharkey479212c2016-06-29 16:00:55 -0600532 mCurrentUserId).getList();
Kenny Guydae30d52015-04-01 19:11:35 +0100533 } catch (RemoteException e) {
534 // Abandon hope activity manager not running.
535 }
536 if (recentTask != null && recentTask.size() > 0) {
537 UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
538 if (user != null && user.isManagedProfile()) {
Kenny Guy63bf8ac2015-06-18 15:09:09 +0100539 Toast toast = Toast.makeText(mContext,
540 R.string.managed_profile_foreground_toast,
541 Toast.LENGTH_SHORT);
542 TextView text = (TextView) toast.getView().findViewById(
543 android.R.id.message);
544 text.setCompoundDrawablesRelativeWithIntrinsicBounds(
545 R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
546 int paddingPx = mContext.getResources().getDimensionPixelSize(
547 R.dimen.managed_profile_toast_padding);
548 text.setCompoundDrawablePadding(paddingPx);
Kenny Guy540f7d22015-06-08 20:24:23 +0100549 toast.show();
Kenny Guydae30d52015-04-01 19:11:35 +0100550 }
551 }
Chris Wrencd8f4f72014-08-27 18:48:13 -0400552 } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
553 NotificationManager noMan = (NotificationManager)
554 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren117d5b42017-01-05 12:57:06 -0500555 noMan.cancel(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400556
557 Settings.Secure.putInt(mContext.getContentResolver(),
558 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
559 if (BANNER_ACTION_SETUP.equals(action)) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100560 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
561 true /* force */);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400562 mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
563 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
564
565 );
566 }
Ricky Wai7fa01712016-03-16 12:13:54 +0000567 } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
Tony Mak646fe992016-04-21 16:43:08 +0100568 final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
Ricky Wai7fa01712016-03-16 12:13:54 +0000569 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
Ricky Waicd35def2016-05-03 11:07:07 +0100570 if (intentSender != null) {
571 try {
572 mContext.startIntentSender(intentSender, null, 0, 0, 0);
573 } catch (IntentSender.SendIntentException e) {
574 /* ignore */
575 }
Ricky Wai7fa01712016-03-16 12:13:54 +0000576 }
Ricky Waicd35def2016-05-03 11:07:07 +0100577 if (notificationKey != null) {
578 try {
579 mBarService.onNotificationClick(notificationKey);
580 } catch (RemoteException e) {
581 /* ignore */
582 }
Ricky Wai7fa01712016-03-16 12:13:54 +0000583 }
Ricky Waicd35def2016-05-03 11:07:07 +0100584 onWorkChallengeUnlocked();
John Spurlock5c454122013-06-17 07:35:46 -0400585 }
586 }
587 };
588
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000589 private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
590 @Override
591 public void onReceive(Context context, Intent intent) {
592 String action = intent.getAction();
593 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
594 isCurrentProfile(getSendingUserId())) {
595 mUsersAllowingPrivateNotifications.clear();
596 updateLockscreenNotificationSetting();
597 updateNotifications();
598 }
599 }
600 };
601
Christoph Studer60748e72014-05-22 16:51:41 +0200602 private final NotificationListenerService mNotificationListener =
603 new NotificationListenerService() {
604 @Override
605 public void onListenerConnected() {
606 if (DEBUG) Log.d(TAG, "onListenerConnected");
607 final StatusBarNotification[] notifications = getActiveNotifications();
Christoph Studerd0694b62014-06-04 16:36:01 +0200608 final RankingMap currentRanking = getCurrentRanking();
Christoph Studer60748e72014-05-22 16:51:41 +0200609 mHandler.post(new Runnable() {
610 @Override
611 public void run() {
612 for (StatusBarNotification sbn : notifications) {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100613 addNotification(sbn, currentRanking, null /* oldEntry */);
Christoph Studer60748e72014-05-22 16:51:41 +0200614 }
615 }
616 });
617 }
618
619 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200620 public void onNotificationPosted(final StatusBarNotification sbn,
621 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200622 if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500623 if (sbn != null) {
624 mHandler.post(new Runnable() {
625 @Override
626 public void run() {
Adrian Roos497ab022015-02-10 20:49:33 +0100627 processForRemoteInput(sbn.getNotification());
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700628 String key = sbn.getKey();
Adrian Roosc0a579e2016-03-30 16:43:58 -0700629 mKeysKeptForRemoteInput.remove(key);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700630 boolean isUpdate = mNotificationData.get(key) != null;
Selim Cinekb5605e52015-02-20 18:21:41 +0100631 // In case we don't allow child notifications, we ignore children of
632 // notifications that have a summary, since we're not going to show them
633 // anyway. This is true also when the summary is canceled,
Chris Wren56919552015-02-24 15:56:34 -0500634 // because children are automatically canceled by NoMan in that case.
Selim Cinekb5605e52015-02-20 18:21:41 +0100635 if (!ENABLE_CHILD_NOTIFICATIONS
636 && mGroupManager.isChildInGroupWithSummary(sbn)) {
Chris Wren56919552015-02-24 15:56:34 -0500637 if (DEBUG) {
638 Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
639 }
640
641 // Remove existing notification to avoid stale data.
642 if (isUpdate) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700643 removeNotification(key, rankingMap);
Chris Wren56919552015-02-24 15:56:34 -0500644 } else {
645 mNotificationData.updateRanking(rankingMap);
646 }
647 return;
Christoph Studerd722f272014-09-02 11:49:19 +0200648 }
Christoph Studerd722f272014-09-02 11:49:19 +0200649 if (isUpdate) {
Chris Wren56919552015-02-24 15:56:34 -0500650 updateNotification(sbn, rankingMap);
Christoph Studerd722f272014-09-02 11:49:19 +0200651 } else {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100652 addNotification(sbn, rankingMap, null /* oldEntry */);
Christoph Studerd722f272014-09-02 11:49:19 +0200653 }
Christoph Studerd722f272014-09-02 11:49:19 +0200654 }
Chris Wren56919552015-02-24 15:56:34 -0500655 });
656 }
Christoph Studer60748e72014-05-22 16:51:41 +0200657 }
658
659 @Override
Chris Wren56919552015-02-24 15:56:34 -0500660 public void onNotificationRemoved(StatusBarNotification sbn,
Christoph Studerd0694b62014-06-04 16:36:01 +0200661 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200662 if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500663 if (sbn != null) {
664 final String key = sbn.getKey();
665 mHandler.post(new Runnable() {
666 @Override
667 public void run() {
668 removeNotification(key, rankingMap);
669 }
670 });
671 }
Christoph Studer37fe6932014-05-26 13:10:30 +0200672 }
673
674 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200675 public void onNotificationRankingUpdate(final RankingMap rankingMap) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200676 if (DEBUG) Log.d(TAG, "onRankingUpdate");
Chris Wren56919552015-02-24 15:56:34 -0500677 if (rankingMap != null) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200678 mHandler.post(new Runnable() {
679 @Override
680 public void run() {
Christoph Studere71fefc2014-06-24 16:16:49 +0200681 updateNotificationRanking(rankingMap);
Christoph Studer60748e72014-05-22 16:51:41 +0200682 }
683 });
Chris Wren56919552015-02-24 15:56:34 -0500684 } }
Christoph Studer5b638262014-07-07 11:21:49 +0200685
Christoph Studer60748e72014-05-22 16:51:41 +0200686 };
687
Kenny Guy2a764942014-04-02 13:29:20 +0100688 private void updateCurrentProfilesCache() {
689 synchronized (mCurrentProfiles) {
690 mCurrentProfiles.clear();
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000691 if (mUserManager != null) {
Kenny Guy2a764942014-04-02 13:29:20 +0100692 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
693 mCurrentProfiles.put(user.id, user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000694 }
695 }
696 }
697 }
698
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400699 public void start() {
Jeff Brown98365d72012-08-19 20:30:52 -0700700 mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
701 mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
702 mDisplay = mWindowManager.getDefaultDisplay();
Adrian Roosbd3409c2014-08-12 18:21:09 +0200703 mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
704 Context.DEVICE_POLICY_SERVICE);
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500705
Christoph Studerc8db24b2014-07-25 17:50:30 +0200706 mNotificationData = new NotificationData(this);
707
Selim Cineka8fefa52014-09-08 16:10:50 +0200708 mAccessibilityManager = (AccessibilityManager)
709 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
710
Chris Wren157026f2013-06-28 16:54:01 -0400711 mDreamManager = IDreamManager.Stub.asInterface(
712 ServiceManager.checkService(DreamService.DREAM_SERVICE));
Chris Wren157026f2013-06-28 16:54:01 -0400713 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
714
Daniel Sandler26cda272012-05-22 15:44:08 -0400715 mContext.getContentResolver().registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700716 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
John Spurlocke677d712014-02-13 12:52:19 -0500717 mSettingsObserver);
718 mContext.getContentResolver().registerContentObserver(
719 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
720 mSettingsObserver);
John Spurlock4b3bda22014-05-22 14:32:20 -0400721 mContext.getContentResolver().registerContentObserver(
Dan Sandler52e5701e2014-07-22 23:14:54 -0400722 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
723 mSettingsObserver,
724 UserHandle.USER_ALL);
Adrian Roosb27d7a52016-06-16 13:04:47 -0700725 if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
726 mContext.getContentResolver().registerContentObserver(
727 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
728 false,
729 mSettingsObserver,
730 UserHandle.USER_ALL);
731 }
Daniel Sandler26cda272012-05-22 15:44:08 -0400732
Dan Sandlerfd16d562014-02-13 18:43:31 -0800733 mContext.getContentResolver().registerContentObserver(
734 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
735 true,
736 mLockscreenSettingsObserver,
737 UserHandle.USER_ALL);
738
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500739 mBarService = IStatusBarService.Stub.asInterface(
740 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400741
Jorim Jaggid61f2272014-12-19 20:35:35 +0100742 mRecents = getComponent(Recents.class);
John Spurlockd08de372013-06-24 13:06:08 -0400743
Dan Sandler539aad42014-08-04 00:43:39 -0400744 final Configuration currentConfig = mContext.getResources().getConfiguration();
745 mLocale = currentConfig.locale;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700746 mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
Dan Sandler539aad42014-08-04 00:43:39 -0400747 mFontScale = currentConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800748 mDensity = currentConfig.densityDpi;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700749
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000750 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Ricky Wai7fa01712016-03-16 12:13:54 +0000751 mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
752 mLockPatternUtils = new LockPatternUtils(mContext);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000753
Joe Onorato2314aab2010-04-08 16:41:23 -0500754 // Connect in to the status bar manager service
Jason Monk07473ce2016-01-05 14:59:19 -0500755 mCommandQueue = new CommandQueue(this);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400756
Jorim Jaggi86905582016-02-09 21:36:09 -0800757 int[] switches = new int[9];
satokcd7cd292010-11-20 15:46:23 +0900758 ArrayList<IBinder> binders = new ArrayList<IBinder>();
Jason Monk07473ce2016-01-05 14:59:19 -0500759 ArrayList<String> iconSlots = new ArrayList<>();
760 ArrayList<StatusBarIcon> icons = new ArrayList<>();
Jorim Jaggi86905582016-02-09 21:36:09 -0800761 Rect fullscreenStackBounds = new Rect();
762 Rect dockedStackBounds = new Rect();
Joe Onorato2314aab2010-04-08 16:41:23 -0500763 try {
Jorim Jaggi86905582016-02-09 21:36:09 -0800764 mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
765 fullscreenStackBounds, dockedStackBounds);
Joe Onorato2314aab2010-04-08 16:41:23 -0500766 } catch (RemoteException ex) {
767 // If the system process isn't there we're doomed anyway.
768 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400769
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500770 createAndAddWindows();
Joe Onorato0cbda992010-05-02 16:28:15 -0700771
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100772 mSettingsObserver.onChange(false); // set up
Benjamin Franzcde0a2a2015-04-23 17:19:48 +0100773 disable(switches[0], switches[6], false /* animate */);
Jorim Jaggi86905582016-02-09 21:36:09 -0800774 setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
775 fullscreenStackBounds, dockedStackBounds);
Dianne Hackborn7d049322011-06-14 15:00:32 -0700776 topAppWindowChanged(switches[2] != 0);
satokcd7cd292010-11-20 15:46:23 +0900777 // StatusBarManagerService has a back up of IME token and it's restored here.
Michael Wright665366a2014-08-07 15:44:40 -0700778 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
Joe Onorato93056472010-09-10 10:30:46 -0400779
Joe Onorato0cbda992010-05-02 16:28:15 -0700780 // Set up the initial icon state
Jason Monk07473ce2016-01-05 14:59:19 -0500781 int N = iconSlots.size();
Joe Onorato0cbda992010-05-02 16:28:15 -0700782 int viewIndex = 0;
Jason Monk07473ce2016-01-05 14:59:19 -0500783 for (int i=0; i < N; i++) {
784 setIcon(iconSlots.get(i), icons.get(i));
Joe Onorato0cbda992010-05-02 16:28:15 -0700785 }
786
Christoph Studer71f18fd2014-05-20 17:02:04 +0200787 // Set up the initial notification state.
Christoph Studere71fefc2014-06-24 16:16:49 +0200788 try {
Christoph Studer4600f9b2014-07-22 22:44:43 +0200789 mNotificationListener.registerAsSystemService(mContext,
Christoph Studere71fefc2014-06-24 16:16:49 +0200790 new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
791 UserHandle.USER_ALL);
792 } catch (RemoteException e) {
793 Log.e(TAG, "Unable to register notification listener", e);
Joe Onorato75199e32010-05-29 17:22:51 -0400794 }
795
Christoph Studer60748e72014-05-22 16:51:41 +0200796
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500797 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400798 Log.d(TAG, String.format(
Daniel Sandler6a858c32012-03-12 14:38:58 -0400799 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
Jason Monk07473ce2016-01-05 14:59:19 -0500800 icons.size(),
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500801 switches[0],
802 switches[1],
803 switches[2],
804 switches[3]
805 ));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400806 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400807
Christopher Tate5e08af02012-09-21 17:17:22 -0700808 mCurrentUserId = ActivityManager.getCurrentUser();
Chris Wrena6d4fb62014-11-20 14:46:23 -0500809 setHeadsUpUser(mCurrentUserId);
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400810
811 IntentFilter filter = new IntentFilter();
812 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000813 filter.addAction(Intent.ACTION_USER_ADDED);
Kenny Guydae30d52015-04-01 19:11:35 +0100814 filter.addAction(Intent.ACTION_USER_PRESENT);
John Spurlock5c454122013-06-17 07:35:46 -0400815 mContext.registerReceiver(mBroadcastReceiver, filter);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000816
Ricky Wai7fa01712016-03-16 12:13:54 +0000817 IntentFilter internalFilter = new IntentFilter();
818 internalFilter.addAction(WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
819 internalFilter.addAction(BANNER_ACTION_CANCEL);
820 internalFilter.addAction(BANNER_ACTION_SETUP);
821 mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
822
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000823 IntentFilter allUsersFilter = new IntentFilter();
824 allUsersFilter.addAction(
825 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
826 mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
827 null, null);
Kenny Guy2a764942014-04-02 13:29:20 +0100828 updateCurrentProfilesCache();
Dan Sandlerdc34df52016-04-07 21:04:46 -0400829
830 IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
831 try {
832 vrManager.registerListener(mVrStateCallbacks);
833 } catch (RemoteException e) {
834 Slog.e(TAG, "Failed to register VR mode state listener: " + e);
835 }
836
Dan Sandler028a60f2016-10-04 15:01:22 -0400837 mNonBlockablePkgs = new ArraySet<String>();
Julia Reynolds98a44862016-09-12 08:53:47 -0400838 Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
839 com.android.internal.R.array.config_nonBlockableNotificationPackages));
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400840 }
841
Chris Wrencd8f4f72014-08-27 18:48:13 -0400842 protected void notifyUserAboutHiddenNotifications() {
843 if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
844 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
845 Log.d(TAG, "user hasn't seen notification about hidden notifications");
Ricky Wai7fa01712016-03-16 12:13:54 +0000846 if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
Chris Wrencd8f4f72014-08-27 18:48:13 -0400847 Log.d(TAG, "insecure lockscreen, skipping notification");
848 Settings.Secure.putInt(mContext.getContentResolver(),
849 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
850 return;
851 }
852 Log.d(TAG, "disabling lockecreen notifications and alerting the user");
853 // disable lockscreen notifications until user acts on the banner.
854 Settings.Secure.putInt(mContext.getContentResolver(),
855 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
Adrian Roosaee70462014-09-03 16:27:39 +0200856 Settings.Secure.putInt(mContext.getContentResolver(),
857 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400858
859 final String packageName = mContext.getPackageName();
860 PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
861 new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
862 PendingIntent.FLAG_CANCEL_CURRENT);
863 PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
864 new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
865 PendingIntent.FLAG_CANCEL_CURRENT);
866
Chris Wrencd8f4f72014-08-27 18:48:13 -0400867 final int colorRes = com.android.internal.R.color.system_notification_accent_color;
868 Notification.Builder note = new Notification.Builder(mContext)
869 .setSmallIcon(R.drawable.ic_android)
870 .setContentTitle(mContext.getString(R.string.hidden_notifications_title))
871 .setContentText(mContext.getString(R.string.hidden_notifications_text))
872 .setPriority(Notification.PRIORITY_HIGH)
873 .setOngoing(true)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700874 .setColor(mContext.getColor(colorRes))
Chris Wrencd8f4f72014-08-27 18:48:13 -0400875 .setContentIntent(setupIntent)
876 .addAction(R.drawable.ic_close,
877 mContext.getString(R.string.hidden_notifications_cancel),
878 cancelIntent)
879 .addAction(R.drawable.ic_settings,
880 mContext.getString(R.string.hidden_notifications_setup),
881 setupIntent);
Adrian Roose25c18d2016-06-17 15:59:49 -0700882 overrideNotificationAppName(mContext, note);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400883
884 NotificationManager noMan =
885 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren117d5b42017-01-05 12:57:06 -0500886 noMan.notify(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS, note.build());
Chris Wrencd8f4f72014-08-27 18:48:13 -0400887 }
888 }
889
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400890 public void userSwitched(int newUserId) {
Chris Wrena6d4fb62014-11-20 14:46:23 -0500891 setHeadsUpUser(newUserId);
892 }
893
Selim Cinek29fa89b2015-04-17 10:39:11 -0700894 protected abstract void setHeadsUpUser(int newUserId);
Chris Wrend04f6ce2014-06-11 17:37:28 -0400895
Christoph Studerc8db24b2014-07-25 17:50:30 +0200896 @Override // NotificationData.Environment
897 public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400898 final int thisUserId = mCurrentUserId;
899 final int notificationUserId = n.getUserId();
900 if (DEBUG && MULTIUSER_DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400901 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400902 n, thisUserId, notificationUserId));
903 }
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500904 return isCurrentProfile(notificationUserId);
Joe Onorato2314aab2010-04-08 16:41:23 -0500905 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400906
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700907 protected void setNotificationShown(StatusBarNotification n) {
Chris Wren26505582015-07-22 17:03:17 -0400908 setNotificationsShown(new String[]{n.getKey()});
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700909 }
910
911 protected void setNotificationsShown(String[] keys) {
Chris Wren26505582015-07-22 17:03:17 -0400912 try {
913 mNotificationListener.setNotificationsShown(keys);
914 } catch (RuntimeException e) {
915 Log.d(TAG, "failed setNotificationsShown: ", e);
916 }
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700917 }
918
Kenny Guy44fc65f2014-11-28 22:18:14 +0000919 protected boolean isCurrentProfile(int userId) {
920 synchronized (mCurrentProfiles) {
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500921 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
Kenny Guy44fc65f2014-11-28 22:18:14 +0000922 }
923 }
924
Christoph Studer2e731b52014-08-22 16:01:51 +0200925 @Override
926 public String getCurrentMediaNotificationKey() {
927 return null;
928 }
929
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100930 @Override
931 public NotificationGroupManager getGroupManager() {
932 return mGroupManager;
933 }
934
Adrian Roos7d7090d2014-05-21 13:10:23 +0200935 /**
936 * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
937 * @param action A dismiss action that is called if it's safe to start the activity.
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200938 * @param afterKeyguardGone Whether the action should be executed after the Keyguard is gone.
Adrian Roos7d7090d2014-05-21 13:10:23 +0200939 */
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200940 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200941 action.onDismiss();
942 }
943
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700944 @Override
945 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400946 final Locale locale = mContext.getResources().getConfiguration().locale;
947 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
Dan Sandler539aad42014-08-04 00:43:39 -0400948 final float fontScale = newConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800949 final int density = newConfig.densityDpi;
950 if (density != mDensity || mFontScale != fontScale) {
Selim Cinek3e7592d2016-04-11 09:35:54 +0800951 onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -0800952 mDensity = density;
953 mFontScale = fontScale;
954 }
955 if (! locale.equals(mLocale) || ld != mLayoutDirection) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400956 if (DEBUG) {
957 Log.v(TAG, String.format(
958 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
959 locale, ld));
960 }
961 mLocale = locale;
962 mLayoutDirection = ld;
963 refreshLayout(ld);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700964 }
965 }
966
Selim Cinek3e7592d2016-04-11 09:35:54 +0800967 protected void onDensityOrFontScaleChanged() {
Selim Cinek01af3342016-02-09 19:25:31 -0800968 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
969 for (int i = 0; i < activeNotifications.size(); i++) {
970 Entry entry = activeNotifications.get(i);
971 boolean exposedGuts = entry.row.getGuts() == mNotificationGutsExposed;
972 entry.row.reInflateViews();
973 if (exposedGuts) {
974 mNotificationGutsExposed = entry.row.getGuts();
975 bindGuts(entry.row);
976 }
Selim Cinek01af3342016-02-09 19:25:31 -0800977 inflateViews(entry, mStackScroller);
978 }
979 }
980
Selim Cinek9e624e72016-07-20 13:46:49 -0700981 protected void bindDismissListener(final ExpandableNotificationRow row) {
982 row.setOnDismissListener(new View.OnClickListener() {
Selim Cinek757d8792016-01-28 16:21:08 -0800983 public void onClick(View v) {
984 // Accessibility feedback
985 v.announceForAccessibility(
986 mContext.getString(R.string.accessibility_notification_dismissed));
Selim Cinek5e018202016-12-15 14:44:36 -0800987 performRemoveNotification(row.getStatusBarNotification());
Selim Cinek757d8792016-01-28 16:21:08 -0800988 }
989 });
Winson Chungc57ccf02011-10-13 15:04:59 -0700990 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400991
Selim Cinek5e018202016-12-15 14:44:36 -0800992 protected void performRemoveNotification(StatusBarNotification n) {
Selim Cinek36b02232016-05-11 23:07:05 -0400993 final String pkg = n.getPackageName();
994 final String tag = n.getTag();
995 final int id = n.getId();
996 final int userId = n.getUserId();
997 try {
998 mBarService.onNotificationClear(pkg, tag, id, userId);
999 if (FORCE_REMOTE_INPUT_HISTORY
1000 && mKeysKeptForRemoteInput.contains(n.getKey())) {
1001 mKeysKeptForRemoteInput.remove(n.getKey());
Selim Cinek36b02232016-05-11 23:07:05 -04001002 }
Selim Cinek5e018202016-12-15 14:44:36 -08001003 removeNotification(n.getKey(), null);
Selim Cinek36b02232016-05-11 23:07:05 -04001004
1005 } catch (RemoteException ex) {
1006 // system process is dead if we're here.
1007 }
1008 }
1009
Daniel Sandler96fd7c12012-03-30 16:37:36 -04001010
Christoph Studer13b895122014-08-26 15:42:12 +02001011 protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
Jorim Jaggi46739852014-04-15 09:58:24 +02001012 NotificationData.Entry entry) {
Dan Sandlerfe266a32014-05-15 22:28:06 -04001013
Selim Cinek684a4422015-04-15 16:18:39 -07001014 if (entry.getContentView().getId()
1015 != com.android.internal.R.id.status_bar_latest_event_content) {
Dan Sandlerfe266a32014-05-15 22:28:06 -04001016 // Using custom RemoteViews
Jorim Jaggia1eeade2014-09-08 22:34:39 +02001017 if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
Dianne Hackborn955d8d62014-10-07 20:17:19 -07001018 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
Selim Cinek697178b2014-07-02 19:40:30 +02001019 entry.row.setShowingLegacyBackground(true);
Jorim Jaggi36b15232014-06-10 17:24:20 +02001020 entry.legacy = true;
Daniel Sandler96fd7c12012-03-30 16:37:36 -04001021 }
1022 }
Christoph Studer13b895122014-08-26 15:42:12 +02001023
1024 if (entry.icon != null) {
Jorim Jaggidd0107a2015-01-21 22:23:48 +01001025 entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
Christoph Studer13b895122014-08-26 15:42:12 +02001026 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -04001027 }
1028
Dan Sandler16128f42014-05-21 12:48:22 -04001029 public boolean isMediaNotification(NotificationData.Entry entry) {
Dan Sandler842dd772014-05-15 09:36:47 -04001030 // TODO: confirm that there's a valid media key
Selim Cinek684a4422015-04-15 16:18:39 -07001031 return entry.getExpandedContentView() != null &&
1032 entry.getExpandedContentView()
1033 .findViewById(com.android.internal.R.id.media_actions) != null;
Dan Sandler842dd772014-05-15 09:36:47 -04001034 }
1035
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001036 // The (i) button in the guts that links to the system notification settings for that app
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001037 private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
1038 final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
Dan Sandlere9a4e902014-07-31 01:06:43 -04001039 intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
1040 intent.putExtra(Settings.EXTRA_APP_UID, appUid);
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001041 startNotificationGutsIntent(intent, appUid);
1042 }
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001043
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001044 private void startNotificationGutsIntent(final Intent intent, final int appUid) {
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001045 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
1046 dismissKeyguardThenExecute(new OnDismissAction() {
1047 @Override
1048 public boolean onDismiss() {
1049 AsyncTask.execute(new Runnable() {
1050 public void run() {
1051 try {
1052 if (keyguardShowing) {
1053 ActivityManagerNative.getDefault()
1054 .keyguardWaitingForActivityDrawn();
1055 }
1056 TaskStackBuilder.create(mContext)
1057 .addNextIntentWithParentStack(intent)
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001058 .startActivities(getActivityOptions(),
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001059 new UserHandle(UserHandle.getUserId(appUid)));
1060 overrideActivityPendingAppTransition(keyguardShowing);
1061 } catch (RemoteException e) {
1062 }
1063 }
1064 });
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +01001065 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
Jorim Jaggifb28c0e2014-08-22 16:28:42 +02001066 return true;
1067 }
Jorim Jaggi746f7fa2014-08-27 17:52:46 +02001068 }, false /* afterKeyguardGone */);
Dan Sandler4247a5c2014-07-23 15:58:08 -04001069 }
1070
Mady Mellorb53bc272016-02-11 18:28:23 -08001071 private void bindGuts(final ExpandableNotificationRow row) {
Selim Cinekab29aeb2015-02-20 18:18:32 +01001072 row.inflateGuts();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001073 final StatusBarNotification sbn = row.getStatusBarNotification();
Selim Cinekeef84282015-10-30 16:28:00 -07001074 PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001075 row.setTag(sbn.getPackageName());
Julia Reynoldsa07af882015-12-17 08:32:48 -05001076 final NotificationGuts guts = row.getGuts();
Mady Mellor97c8df42016-03-22 18:09:39 -07001077 guts.setClosedListener(this);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001078 final String pkg = sbn.getPackageName();
1079 String appname = pkg;
1080 Drawable pkgicon = null;
1081 int appUid = -1;
1082 try {
1083 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
1084 PackageManager.GET_UNINSTALLED_PACKAGES
1085 | PackageManager.GET_DISABLED_COMPONENTS);
1086 if (info != null) {
1087 appname = String.valueOf(pmUser.getApplicationLabel(info));
1088 pkgicon = pmUser.getApplicationIcon(info);
1089 appUid = info.uid;
1090 }
1091 } catch (NameNotFoundException e) {
1092 // app is gone, just show package name and generic icon
1093 pkgicon = pmUser.getDefaultActivityIcon();
1094 }
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001095
Min Yun175559a2016-06-17 11:59:24 -07001096 ((ImageView) guts.findViewById(R.id.app_icon)).setImageDrawable(pkgicon);
1097 ((TextView) guts.findViewById(R.id.pkgname)).setText(appname);
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001098
Min Yunde383c72016-06-24 11:05:03 -07001099 final TextView settingsButton = (TextView) guts.findViewById(R.id.more_settings);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001100 if (appUid >= 0) {
1101 final int appUidF = appUid;
1102 settingsButton.setOnClickListener(new View.OnClickListener() {
1103 public void onClick(View v) {
Chris Wrenf6e9228b2016-01-26 18:04:35 -05001104 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
Mady Mellor97c8df42016-03-22 18:09:39 -07001105 guts.resetFalsingCheck();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001106 startAppNotificationSettingsActivity(pkg, appUidF);
1107 }
1108 });
Min Yunde383c72016-06-24 11:05:03 -07001109 settingsButton.setText(R.string.notification_more_settings);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001110 } else {
1111 settingsButton.setVisibility(View.GONE);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001112 }
1113
Julia Reynolds98a44862016-09-12 08:53:47 -04001114 guts.bindImportance(pmUser, sbn, mNonBlockablePkgs,
1115 mNotificationData.getImportance(sbn.getKey()));
Min Yun175559a2016-06-17 11:59:24 -07001116
Min Yunde383c72016-06-24 11:05:03 -07001117 final TextView doneButton = (TextView) guts.findViewById(R.id.done);
1118 doneButton.setText(R.string.notification_done);
1119 doneButton.setOnClickListener(new View.OnClickListener() {
Julia Reynolds56821922016-01-04 15:24:01 -05001120 @Override
1121 public void onClick(View v) {
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001122 // If the user has security enabled, show challenge if the setting is changed.
1123 if (guts.hasImportanceChanged() && isLockscreenPublicMode() &&
1124 (mState == StatusBarState.KEYGUARD
1125 || mState == StatusBarState.SHADE_LOCKED)) {
1126 OnDismissAction dismissAction = new OnDismissAction() {
1127 @Override
1128 public boolean onDismiss() {
1129 saveImportanceCloseControls(sbn, row, guts, v);
1130 return true;
1131 }
1132 };
1133 onLockedNotificationImportanceChange(dismissAction);
1134 } else {
1135 saveImportanceCloseControls(sbn, row, guts, v);
1136 }
Julia Reynolds56821922016-01-04 15:24:01 -05001137 }
1138 });
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001139 }
1140
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001141 private void saveImportanceCloseControls(StatusBarNotification sbn,
1142 ExpandableNotificationRow row, NotificationGuts guts, View done) {
Mady Mellor97c8df42016-03-22 18:09:39 -07001143 guts.resetFalsingCheck();
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001144 guts.saveImportance(sbn);
1145
1146 int[] rowLocation = new int[2];
1147 int[] doneLocation = new int[2];
1148 row.getLocationOnScreen(rowLocation);
1149 done.getLocationOnScreen(doneLocation);
1150
1151 final int centerX = done.getWidth() / 2;
1152 final int centerY = done.getHeight() / 2;
1153 final int x = doneLocation[0] - rowLocation[0] + centerX;
1154 final int y = doneLocation[1] - rowLocation[1] + centerY;
1155 dismissPopups(x, y);
1156 }
1157
Dan Sandler4247a5c2014-07-23 15:58:08 -04001158 protected SwipeHelper.LongPressListener getNotificationLongClicker() {
1159 return new SwipeHelper.LongPressListener() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001160 @Override
Selim Cinekd84a5932015-12-15 11:45:36 -08001161 public boolean onLongPress(View v, final int x, final int y) {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001162 if (!(v instanceof ExpandableNotificationRow)) {
1163 return false;
1164 }
Selim Cinekabdc5a02014-09-02 13:46:00 +02001165 if (v.getWindowToken() == null) {
1166 Log.e(TAG, "Trying to show notification guts, but not attached to window");
1167 return false;
1168 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001169
Mady Mellor4b80b102016-01-22 08:03:58 -08001170 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
Selim Cinekab29aeb2015-02-20 18:18:32 +01001171 bindGuts(row);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001172
Dan Sandler4247a5c2014-07-23 15:58:08 -04001173 // Assume we are a status_bar_notification_row
Selim Cinekab29aeb2015-02-20 18:18:32 +01001174 final NotificationGuts guts = row.getGuts();
Selim Cinekbdefcdf2014-09-11 12:41:47 +02001175 if (guts == null) {
1176 // This view has no guts. Examples are the more card or the dismiss all view
1177 return false;
1178 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001179
1180 // Already showing?
Selim Cinekabdc5a02014-09-02 13:46:00 +02001181 if (guts.getVisibility() == View.VISIBLE) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001182 dismissPopups(x, y);
Selim Cinekabdc5a02014-09-02 13:46:00 +02001183 return false;
1184 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001185
Chris Wrenf6e9228b2016-01-26 18:04:35 -05001186 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001187
Julia Reynolds40779452016-02-23 13:43:32 -05001188 // ensure that it's laid but not visible until actually laid out
Selim Cinekd84a5932015-12-15 11:45:36 -08001189 guts.setVisibility(View.INVISIBLE);
Julia Reynolds40779452016-02-23 13:43:32 -05001190 // Post to ensure the the guts are properly laid out.
Selim Cinekd84a5932015-12-15 11:45:36 -08001191 guts.post(new Runnable() {
1192 public void run() {
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001193 dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */,
1194 false /* animate */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001195 guts.setVisibility(View.VISIBLE);
1196 final double horz = Math.max(guts.getWidth() - x, x);
1197 final double vert = Math.max(guts.getHeight() - y, y);
1198 final float r = (float) Math.hypot(horz, vert);
1199 final Animator a
1200 = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
1201 a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc18010f2016-01-20 13:41:30 -08001202 a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Mady Mellor4b80b102016-01-22 08:03:58 -08001203 a.addListener(new AnimatorListenerAdapter() {
1204 @Override
1205 public void onAnimationEnd(Animator animation) {
1206 super.onAnimationEnd(animation);
1207 // Move the notification view back over the gear
1208 row.resetTranslation();
1209 }
1210 });
Selim Cinekd84a5932015-12-15 11:45:36 -08001211 a.start();
Mady Mellor97c8df42016-03-22 18:09:39 -07001212 guts.setExposed(true /* exposed */,
1213 mState == StatusBarState.KEYGUARD /* needsFalsingProtection */);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001214 row.closeRemoteInput();
Selim Cinekd84a5932015-12-15 11:45:36 -08001215 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
1216 mNotificationGutsExposed = guts;
1217 }
1218 });
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001219 return true;
1220 }
1221 };
1222 }
1223
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001224 /**
1225 * Returns the exposed NotificationGuts or null if none are exposed.
1226 */
1227 public NotificationGuts getExposedGuts() {
1228 return mNotificationGutsExposed;
Mady Mellor4b80b102016-01-22 08:03:58 -08001229 }
1230
Daniel Sandler469e96e2012-05-04 15:56:19 -04001231 public void dismissPopups() {
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001232 dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */, false /* animate */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001233 }
1234
1235 private void dismissPopups(int x, int y) {
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001236 dismissPopups(x, y, true /* resetGear */, false /* animate */);
Mady Mellorb53bc272016-02-11 18:28:23 -08001237 }
1238
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001239 public void dismissPopups(int x, int y, boolean resetGear, boolean animate) {
Dan Sandler4247a5c2014-07-23 15:58:08 -04001240 if (mNotificationGutsExposed != null) {
Mady Mellor97c8df42016-03-22 18:09:39 -07001241 mNotificationGutsExposed.closeControls(x, y, true /* notify */);
Daniel Sandler469e96e2012-05-04 15:56:19 -04001242 }
Mady Mellor7a9b2a62016-03-23 07:41:47 -07001243 if (resetGear) {
1244 mStackScroller.resetExposedGearView(animate, true /* force */);
Mady Mellor4b80b102016-01-22 08:03:58 -08001245 }
Daniel Sandler469e96e2012-05-04 15:56:19 -04001246 }
1247
Michael Jurka7f2668c2012-03-27 07:49:52 -07001248 @Override
Mady Mellor97c8df42016-03-22 18:09:39 -07001249 public void onGutsClosed(NotificationGuts guts) {
1250 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
1251 mNotificationGutsExposed = null;
1252 }
1253
1254 @Override
Jorim Jaggi681fc7b2016-04-14 22:02:39 -07001255 public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001256 int msg = MSG_SHOW_RECENT_APPS;
1257 mHandler.removeMessages(msg);
Jorim Jaggi681fc7b2016-04-14 22:02:39 -07001258 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, fromHome ? 1 : 0).sendToTarget();
Winson Chung1e8d71b2014-05-16 17:05:22 -07001259 }
1260
1261 @Override
Winson Chungcdcd4872014-08-05 18:00:13 -07001262 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001263 int msg = MSG_HIDE_RECENT_APPS;
1264 mHandler.removeMessages(msg);
Winson Chungcdcd4872014-08-05 18:00:13 -07001265 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0,
1266 triggeredFromHomeKey ? 1 : 0).sendToTarget();
Winson Chung1e8d71b2014-05-16 17:05:22 -07001267 }
1268
1269 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001270 public void toggleRecentApps() {
Jorim Jaggi900fb482015-06-02 15:07:33 -07001271 toggleRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001272 }
1273
1274 @Override
Phil Weaver315c34e2016-02-19 15:12:29 -08001275 public void toggleSplitScreen() {
Jorim Jaggi29379ec2016-04-11 23:43:42 -07001276 toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
Phil Weaver315c34e2016-02-19 15:12:29 -08001277 }
1278
1279 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001280 public void preloadRecentApps() {
1281 int msg = MSG_PRELOAD_RECENT_APPS;
1282 mHandler.removeMessages(msg);
1283 mHandler.sendEmptyMessage(msg);
1284 }
1285
1286 @Override
1287 public void cancelPreloadRecentApps() {
1288 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
1289 mHandler.removeMessages(msg);
1290 mHandler.sendEmptyMessage(msg);
1291 }
1292
Clara Bayarrif2debb12015-07-10 14:47:17 +01001293 @Override
Andrei Stingaceanu0bf096f2016-04-14 18:11:57 +01001294 public void dismissKeyboardShortcutsMenu() {
1295 int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
1296 mHandler.removeMessages(msg);
1297 mHandler.sendEmptyMessage(msg);
1298 }
1299
1300 @Override
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001301 public void toggleKeyboardShortcutsMenu(int deviceId) {
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001302 int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
Clara Bayarrif2debb12015-07-10 14:47:17 +01001303 mHandler.removeMessages(msg);
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001304 mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
Clara Bayarrif2debb12015-07-10 14:47:17 +01001305 }
1306
Winson Chungb1f74992014-08-08 12:53:09 -07001307 /** Jumps to the next affiliated task in the group. */
1308 public void showNextAffiliatedTask() {
1309 int msg = MSG_SHOW_NEXT_AFFILIATED_TASK;
1310 mHandler.removeMessages(msg);
1311 mHandler.sendEmptyMessage(msg);
1312 }
1313
1314 /** Jumps to the previous affiliated task in the group. */
1315 public void showPreviousAffiliatedTask() {
1316 int msg = MSG_SHOW_PREV_AFFILIATED_TASK;
1317 mHandler.removeMessages(msg);
1318 mHandler.sendEmptyMessage(msg);
1319 }
1320
Michael Jurkaecc395a2012-03-30 05:31:46 -07001321 protected H createHandler() {
Michael Jurka7f2668c2012-03-27 07:49:52 -07001322 return new H();
1323 }
1324
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001325 protected void sendCloseSystemWindows(String reason) {
Michael Jurka56a57832012-05-14 13:24:43 -07001326 if (ActivityManagerNative.isSystemReady()) {
1327 try {
1328 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
1329 } catch (RemoteException e) {
1330 }
1331 }
1332 }
1333
Michael Jurkacb2522c2012-04-13 09:32:47 -07001334 protected abstract View getStatusBarView();
1335
Michael Jurka80343f62012-10-18 13:13:46 +02001336 protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
1337 // additional optimization when we have software system buttons - start loading the recent
1338 // tasks on touch down
1339 @Override
1340 public boolean onTouch(View v, MotionEvent event) {
1341 int action = event.getAction() & MotionEvent.ACTION_MASK;
1342 if (action == MotionEvent.ACTION_DOWN) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001343 preloadRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001344 } else if (action == MotionEvent.ACTION_CANCEL) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001345 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001346 } else if (action == MotionEvent.ACTION_UP) {
1347 if (!v.isPressed()) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001348 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001349 }
1350
1351 }
1352 return false;
1353 }
1354 };
1355
Phil Weaver315c34e2016-02-19 15:12:29 -08001356 /**
1357 * Toggle docking the app window
1358 *
Jorim Jaggi29379ec2016-04-11 23:43:42 -07001359 * @param metricsDockAction the action to log when docking is successful, or -1 to not log
1360 * anything on successful docking
1361 * @param metricsUndockAction the action to log when undocking, or -1 to not log anything when
1362 * undocking
Phil Weaver315c34e2016-02-19 15:12:29 -08001363 */
Jorim Jaggi29379ec2016-04-11 23:43:42 -07001364 protected abstract void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction);
Phil Weaver315c34e2016-02-19 15:12:29 -08001365
Winson Chung1e8d71b2014-05-16 17:05:22 -07001366 /** Proxy for RecentsComponent */
1367
Jorim Jaggi681fc7b2016-04-14 22:02:39 -07001368 protected void showRecents(boolean triggeredFromAltTab, boolean fromHome) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001369 if (mRecents != null) {
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001370 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001371 mRecents.showRecents(triggeredFromAltTab, fromHome);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001372 }
1373 }
1374
Winson Chungcdcd4872014-08-05 18:00:13 -07001375 protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001376 if (mRecents != null) {
Winson Chungcdcd4872014-08-05 18:00:13 -07001377 mRecents.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001378 }
1379 }
1380
1381 protected void toggleRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001382 if (mRecents != null) {
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001383 mRecents.toggleRecents(mDisplay);
John Spurlockd08de372013-06-24 13:06:08 -04001384 }
1385 }
Michael Jurka80343f62012-10-18 13:13:46 +02001386
Winson Chung1e8d71b2014-05-16 17:05:22 -07001387 protected void preloadRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001388 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001389 mRecents.preloadRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001390 }
Michael Jurka80343f62012-10-18 13:13:46 +02001391 }
1392
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001393 protected void toggleKeyboardShortcuts(int deviceId) {
Andrei Stingaceanuf86bc972016-04-12 15:29:25 +01001394 KeyboardShortcuts.toggle(mContext, deviceId);
Clara Bayarrif2debb12015-07-10 14:47:17 +01001395 }
1396
Andrei Stingaceanu0bf096f2016-04-14 18:11:57 +01001397 protected void dismissKeyboardShortcuts() {
1398 KeyboardShortcuts.dismiss();
1399 }
1400
Winson Chung1e8d71b2014-05-16 17:05:22 -07001401 protected void cancelPreloadingRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001402 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001403 mRecents.cancelPreloadingRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001404 }
Michael Jurka80343f62012-10-18 13:13:46 +02001405 }
1406
Winson Chungb1f74992014-08-08 12:53:09 -07001407 protected void showRecentsNextAffiliatedTask() {
1408 if (mRecents != null) {
1409 mRecents.showNextAffiliatedTask();
1410 }
1411 }
1412
1413 protected void showRecentsPreviousAffiliatedTask() {
1414 if (mRecents != null) {
1415 mRecents.showPrevAffiliatedTask();
1416 }
1417 }
1418
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001419 /**
Selim Cinek684a4422015-04-15 16:18:39 -07001420 * If there is an active heads-up notification and it has a fullscreen intent, fire it now.
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001421 */
Selim Cinek684a4422015-04-15 16:18:39 -07001422 public abstract void maybeEscalateHeadsUp();
Chris Wrena4ef6202014-06-09 18:07:30 -04001423
Dan Sandlerfd16d562014-02-13 18:43:31 -08001424 /**
1425 * Save the current "public" (locked and secure) state of the lockscreen.
1426 */
1427 public void setLockscreenPublicMode(boolean publicMode) {
1428 mLockscreenPublicMode = publicMode;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001429 }
1430
Dan Sandlerfd16d562014-02-13 18:43:31 -08001431 public boolean isLockscreenPublicMode() {
1432 return mLockscreenPublicMode;
1433 }
1434
Ricky Waicd35def2016-05-03 11:07:07 +01001435 protected void onWorkChallengeUnlocked() {}
1436
Dan Sandlerfd16d562014-02-13 18:43:31 -08001437 /**
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001438 * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
1439 * "public" (secure & locked) mode?
1440 */
1441 public boolean userAllowsNotificationsInPublic(int userHandle) {
1442 if (userHandle == UserHandle.USER_ALL) {
1443 return true;
1444 }
1445
1446 if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
1447 final boolean allowed = 0 != Settings.Secure.getIntForUser(
1448 mContext.getContentResolver(),
1449 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
1450 mUsersAllowingNotifications.append(userHandle, allowed);
1451 return allowed;
1452 }
1453
1454 return mUsersAllowingNotifications.get(userHandle);
1455 }
1456
1457 /**
Dan Sandlerfd16d562014-02-13 18:43:31 -08001458 * Has the given user chosen to allow their private (full) notifications to be shown even
1459 * when the lockscreen is in "public" (secure & locked) mode?
1460 */
1461 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
1462 if (userHandle == UserHandle.USER_ALL) {
1463 return true;
1464 }
1465
1466 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001467 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
Dan Sandlerfd16d562014-02-13 18:43:31 -08001468 mContext.getContentResolver(),
1469 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001470 final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001471 final boolean allowed = allowedByUser && allowedByDpm;
1472 mUsersAllowingPrivateNotifications.append(userHandle, allowed);
Dan Sandlerfd16d562014-02-13 18:43:31 -08001473 return allowed;
1474 }
1475
1476 return mUsersAllowingPrivateNotifications.get(userHandle);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001477 }
1478
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001479 private boolean adminAllowsUnredactedNotifications(int userHandle) {
1480 if (userHandle == UserHandle.USER_ALL) {
1481 return true;
1482 }
1483 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
1484 userHandle);
1485 return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
1486 }
1487
Christoph Studerc8db24b2014-07-25 17:50:30 +02001488 /**
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001489 * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
1490 * If so, notifications should be hidden.
Christoph Studerc8db24b2014-07-25 17:50:30 +02001491 */
1492 @Override // NotificationData.Environment
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001493 public boolean shouldHideNotifications(int userid) {
1494 return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
1495 }
1496
1497 /**
1498 * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
1499 * package-specific override.
1500 */
1501 @Override // NotificationDate.Environment
1502 public boolean shouldHideNotifications(String key) {
1503 return isLockscreenPublicMode()
1504 && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
1505 }
1506
1507 /**
1508 * Returns true if we're on a secure lockscreen.
1509 */
1510 @Override // NotificationData.Environment
1511 public boolean onSecureLockScreen() {
1512 return isLockscreenPublicMode();
Christoph Studerc8db24b2014-07-25 17:50:30 +02001513 }
1514
Chris Wrena4ef6202014-06-09 18:07:30 -04001515 public void onNotificationClear(StatusBarNotification notification) {
1516 try {
1517 mBarService.onNotificationClear(
1518 notification.getPackageName(),
1519 notification.getTag(),
1520 notification.getId(),
1521 notification.getUserId());
1522 } catch (android.os.RemoteException ex) {
1523 // oh well
1524 }
1525 }
1526
Selim Cinek5f71bee2015-11-18 10:25:23 -08001527 /**
Selim Cinek5fbc6322016-01-15 17:17:58 -08001528 * Called when the notification panel layouts
Selim Cinek5f71bee2015-11-18 10:25:23 -08001529 */
Selim Cinek5fbc6322016-01-15 17:17:58 -08001530 public void onPanelLaidOut() {
Selim Cinek5f71bee2015-11-18 10:25:23 -08001531 if (mState == StatusBarState.KEYGUARD) {
1532 // Since the number of notifications is determined based on the height of the view, we
1533 // need to update them.
Selim Cinek5fbc6322016-01-15 17:17:58 -08001534 int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
1535 int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
1536 if (maxBefore != maxNotifications) {
1537 updateRowStates();
1538 }
Selim Cinek5f71bee2015-11-18 10:25:23 -08001539 }
1540 }
1541
Mady Mellor8e8a69e2016-03-14 12:30:10 -07001542 protected void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {}
1543
Adrian Roos3aec6382016-02-05 14:19:01 -08001544 protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
1545
Ricky Waicd35def2016-05-03 11:07:07 +01001546 protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
1547 View clicked) {}
1548
Selim Cinek570981d2015-12-01 11:37:01 -08001549 @Override
Selim Cinek31aada42015-12-18 17:51:15 -08001550 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
Selim Cinek570981d2015-12-01 11:37:01 -08001551 }
1552
Michael Jurka7f2668c2012-03-27 07:49:52 -07001553 protected class H extends Handler {
1554 public void handleMessage(Message m) {
1555 switch (m.what) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001556 case MSG_SHOW_RECENT_APPS:
Jorim Jaggi681fc7b2016-04-14 22:02:39 -07001557 showRecents(m.arg1 > 0, m.arg2 != 0);
Michael Jurkacb2522c2012-04-13 09:32:47 -07001558 break;
Winson Chung1e8d71b2014-05-16 17:05:22 -07001559 case MSG_HIDE_RECENT_APPS:
Winson Chungcdcd4872014-08-05 18:00:13 -07001560 hideRecents(m.arg1 > 0, m.arg2 > 0);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001561 break;
1562 case MSG_TOGGLE_RECENTS_APPS:
1563 toggleRecents();
Michael Jurkacb2522c2012-04-13 09:32:47 -07001564 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001565 case MSG_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001566 preloadRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001567 break;
1568 case MSG_CANCEL_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001569 cancelPreloadingRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001570 break;
Winson Chungb1f74992014-08-08 12:53:09 -07001571 case MSG_SHOW_NEXT_AFFILIATED_TASK:
1572 showRecentsNextAffiliatedTask();
1573 break;
1574 case MSG_SHOW_PREV_AFFILIATED_TASK:
1575 showRecentsPreviousAffiliatedTask();
1576 break;
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001577 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001578 toggleKeyboardShortcuts(m.arg1);
Clara Bayarrif2debb12015-07-10 14:47:17 +01001579 break;
Andrei Stingaceanu0bf096f2016-04-14 18:11:57 +01001580 case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
1581 dismissKeyboardShortcuts();
1582 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001583 }
1584 }
1585 }
1586
Daniel Sandler6a858c32012-03-12 14:38:58 -04001587 protected void workAroundBadLayerDrawableOpacity(View v) {
1588 }
1589
Selim Cinek8d490d42015-04-10 00:05:50 -07001590 protected boolean inflateViews(Entry entry, ViewGroup parent) {
Selim Cinekeef84282015-10-30 16:28:00 -07001591 PackageManager pmUser = getPackageManagerForUser(mContext,
Dan Sandlere9a4e902014-07-31 01:06:43 -04001592 entry.notification.getUser().getIdentifier());
1593
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001594 final StatusBarNotification sbn = entry.notification;
Adrian Roos95f8bea2016-07-27 15:49:03 -07001595 try {
1596 entry.cacheContentViews(mContext, null);
1597 } catch (RuntimeException e) {
1598 Log.e(TAG, "Unable to get notification remote views", e);
1599 return false;
1600 }
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001601
1602 final RemoteViews contentView = entry.cachedContentView;
1603 final RemoteViews bigContentView = entry.cachedBigContentView;
1604 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
1605 final RemoteViews publicContentView = entry.cachedPublicContentView;
Chris Wren8fd39ec2014-02-27 17:43:26 -05001606
Chris Wren574a55e2013-07-15 18:48:37 -04001607 if (contentView == null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001608 Log.v(TAG, "no contentView for: " + sbn.getNotification());
Daniel Sandler6a858c32012-03-12 14:38:58 -04001609 return false;
1610 }
1611
Dan Sandlerf68448e2014-04-24 15:54:16 -04001612 if (DEBUG) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001613 Log.v(TAG, "publicContentView: " + publicContentView);
Dan Sandlerf68448e2014-04-24 15:54:16 -04001614 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001615
Christoph Studera7fe6312014-06-27 19:32:44 +02001616 ExpandableNotificationRow row;
1617
1618 // Stash away previous user expansion state so we can restore it at
1619 // the end.
1620 boolean hasUserChangedExpansion = false;
1621 boolean userExpanded = false;
1622 boolean userLocked = false;
1623
1624 if (entry.row != null) {
1625 row = entry.row;
1626 hasUserChangedExpansion = row.hasUserChangedExpansion();
1627 userExpanded = row.isUserExpanded();
1628 userLocked = row.isUserLocked();
Christoph Studer22f2ee52014-07-29 22:57:21 +02001629 entry.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +02001630 if (hasUserChangedExpansion) {
1631 row.setUserExpanded(userExpanded);
1632 }
1633 } else {
1634 // create the row view
1635 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
1636 Context.LAYOUT_INFLATER_SERVICE);
1637 row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
1638 parent, false);
Chris Wren78403d72014-07-28 10:23:24 +01001639 row.setExpansionLogger(this, entry.notification.getKey());
Selim Cinekb5605e52015-02-20 18:21:41 +01001640 row.setGroupManager(mGroupManager);
Selim Cinek31aada42015-12-18 17:51:15 -08001641 row.setHeadsUpManager(mHeadsUpManager);
Adrian Roosb88b1a12015-12-09 18:51:05 -08001642 row.setRemoteInputController(mRemoteInputController);
Selim Cinek570981d2015-12-01 11:37:01 -08001643 row.setOnExpandClickListener(this);
Mady Mellor3fd273e2016-03-15 21:08:14 -07001644
Dan Sandler732bd6c2016-04-12 14:20:32 -04001645 // Get the app name.
1646 // Note that Notification.Builder#bindHeaderAppName has similar logic
1647 // but since this field is used in the guts, it must be accurate.
1648 // Therefore we will only show the application label, or, failing that, the
1649 // package name. No substitutions.
Mady Mellor3fd273e2016-03-15 21:08:14 -07001650 final String pkg = sbn.getPackageName();
1651 String appname = pkg;
1652 try {
1653 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
1654 PackageManager.GET_UNINSTALLED_PACKAGES
1655 | PackageManager.GET_DISABLED_COMPONENTS);
1656 if (info != null) {
1657 appname = String.valueOf(pmUser.getApplicationLabel(info));
1658 }
1659 } catch (NameNotFoundException e) {
1660 // Do nothing
1661 }
1662 row.setAppName(appname);
Christoph Studera7fe6312014-06-27 19:32:44 +02001663 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001664
Daniel Sandler6a858c32012-03-12 14:38:58 -04001665 workAroundBadLayerDrawableOpacity(row);
Selim Cinek9e624e72016-07-20 13:46:49 -07001666 bindDismissListener(row);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001667
1668 // NB: the large icon is now handled entirely by the template
1669
1670 // bind the click event to the content area
Selim Cinek8d490d42015-04-10 00:05:50 -07001671 NotificationContentView contentContainer = row.getPrivateLayout();
1672 NotificationContentView contentContainerPublic = row.getPublicLayout();
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001673
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001674 row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
Adrian Roos497ab022015-02-10 20:49:33 +01001675 if (ENABLE_REMOTE_INPUT) {
1676 row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
1677 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001678
Chris Wren42d5dd42015-05-01 10:39:26 -04001679 mNotificationClicker.register(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001680
Dan Sandlera5e0f412014-01-23 15:11:54 -05001681 // set up the adaptive layout
Chris Wren574a55e2013-07-15 18:48:37 -04001682 View contentViewLocal = null;
1683 View bigContentViewLocal = null;
Selim Cinek8d490d42015-04-10 00:05:50 -07001684 View headsUpContentViewLocal = null;
Selim Cinek624c02db2015-12-14 21:00:02 -08001685 View publicViewLocal = null;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001686 try {
Dan Sandler68079d52015-07-22 10:45:30 -04001687 contentViewLocal = contentView.apply(
1688 sbn.getPackageContext(mContext),
1689 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001690 mOnClickHandler);
Chris Wren574a55e2013-07-15 18:48:37 -04001691 if (bigContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001692 bigContentViewLocal = bigContentView.apply(
1693 sbn.getPackageContext(mContext),
1694 contentContainer,
Selim Cinek8d490d42015-04-10 00:05:50 -07001695 mOnClickHandler);
1696 }
1697 if (headsUpContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001698 headsUpContentViewLocal = headsUpContentView.apply(
1699 sbn.getPackageContext(mContext),
1700 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001701 mOnClickHandler);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001702 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001703 if (publicContentView != null) {
1704 publicViewLocal = publicContentView.apply(
1705 sbn.getPackageContext(mContext),
1706 contentContainerPublic, mOnClickHandler);
1707 }
dooyoung.hwang78c41142016-10-04 18:55:31 +09001708
1709 if (contentViewLocal != null) {
1710 contentViewLocal.setIsRootNamespace(true);
1711 contentContainer.setContractedChild(contentViewLocal);
1712 }
1713 if (bigContentViewLocal != null) {
1714 bigContentViewLocal.setIsRootNamespace(true);
1715 contentContainer.setExpandedChild(bigContentViewLocal);
1716 }
1717 if (headsUpContentViewLocal != null) {
1718 headsUpContentViewLocal.setIsRootNamespace(true);
1719 contentContainer.setHeadsUpChild(headsUpContentViewLocal);
1720 }
1721 if (publicViewLocal != null) {
1722 publicViewLocal.setIsRootNamespace(true);
1723 contentContainerPublic.setContractedChild(publicViewLocal);
1724 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001725 }
1726 catch (RuntimeException e) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001727 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
John Spurlockcd686b52013-06-05 10:13:46 -04001728 Log.e(TAG, "couldn't inflate view for notification " + ident, e);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001729 return false;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001730 }
1731
Jorim Jaggia1eeade2014-09-08 22:34:39 +02001732 // Extract target SDK version.
1733 try {
1734 ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
1735 entry.targetSdk = info.targetSdkVersion;
1736 } catch (NameNotFoundException ex) {
1737 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
1738 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001739 entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001740
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001741 if (MULTIUSER_DEBUG) {
1742 TextView debug = (TextView) row.findViewById(R.id.debug_info);
1743 if (debug != null) {
1744 debug.setVisibility(View.VISIBLE);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001745 debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId());
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001746 }
1747 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001748 entry.row = row;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001749 entry.row.setOnActivatedListener(this);
Selim Cinek684a4422015-04-15 16:18:39 -07001750 entry.row.setExpandable(bigContentViewLocal != null);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001751
Christoph Studer13b895122014-08-26 15:42:12 +02001752 applyColorsAndBackgrounds(sbn, entry);
Jorim Jaggi46739852014-04-15 09:58:24 +02001753
Christoph Studera7fe6312014-06-27 19:32:44 +02001754 // Restore previous flags.
1755 if (hasUserChangedExpansion) {
1756 // Note: setUserExpanded() conveniently ignores calls with
1757 // userExpanded=true if !isExpandable().
1758 row.setUserExpanded(userExpanded);
1759 }
1760 row.setUserLocked(userLocked);
Selim Cinekda42d652015-12-04 15:51:16 -08001761 row.onNotificationUpdated(entry);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001762 return true;
1763 }
1764
Adrian Roos497ab022015-02-10 20:49:33 +01001765 /**
1766 * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
1767 * via first-class API.
1768 *
1769 * TODO: Remove once enough apps specify remote inputs on their own.
1770 */
1771 private void processForRemoteInput(Notification n) {
1772 if (!ENABLE_REMOTE_INPUT) return;
1773
1774 if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
1775 (n.actions == null || n.actions.length == 0)) {
1776 Notification.Action viableAction = null;
1777 Notification.WearableExtender we = new Notification.WearableExtender(n);
1778
1779 List<Notification.Action> actions = we.getActions();
1780 final int numActions = actions.size();
1781
1782 for (int i = 0; i < numActions; i++) {
1783 Notification.Action action = actions.get(i);
Adrian Roosa3539cb2015-12-16 16:47:02 -08001784 if (action == null) {
1785 continue;
1786 }
Adrian Roos497ab022015-02-10 20:49:33 +01001787 RemoteInput[] remoteInputs = action.getRemoteInputs();
Adrian Roosa3539cb2015-12-16 16:47:02 -08001788 if (remoteInputs == null) {
1789 continue;
1790 }
1791 for (RemoteInput ri : remoteInputs) {
Adrian Roos497ab022015-02-10 20:49:33 +01001792 if (ri.getAllowFreeFormInput()) {
1793 viableAction = action;
1794 break;
1795 }
1796 }
1797 if (viableAction != null) {
1798 break;
1799 }
1800 }
1801
1802 if (viableAction != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001803 Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
1804 rebuilder.setActions(viableAction);
1805 rebuilder.build(); // will rewrite n
Adrian Roos497ab022015-02-10 20:49:33 +01001806 }
1807 }
1808 }
1809
Adrian Roos62692b22015-09-11 17:46:23 -07001810 public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
1811 if (!isDeviceProvisioned()) return;
1812
1813 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
1814 final boolean afterKeyguardGone = intent.isActivity()
1815 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
1816 mCurrentUserId);
1817 dismissKeyguardThenExecute(new OnDismissAction() {
1818 public boolean onDismiss() {
1819 new Thread() {
1820 @Override
1821 public void run() {
1822 try {
1823 if (keyguardShowing && !afterKeyguardGone) {
1824 ActivityManagerNative.getDefault()
1825 .keyguardWaitingForActivityDrawn();
1826 }
1827
1828 // The intent we are sending is for the application, which
1829 // won't have permission to immediately start an activity after
1830 // the user switches to home. We know it is safe to do at this
1831 // point, so make sure new activity switches are now allowed.
1832 ActivityManagerNative.getDefault().resumeAppSwitches();
1833 } catch (RemoteException e) {
1834 }
Adrian Roos62692b22015-09-11 17:46:23 -07001835 try {
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001836 intent.send(null, 0, null, null, null, null, getActivityOptions());
Adrian Roos62692b22015-09-11 17:46:23 -07001837 } catch (PendingIntent.CanceledException e) {
1838 // the stack trace isn't very helpful here.
1839 // Just log the exception message.
1840 Log.w(TAG, "Sending intent failed: " + e);
1841
1842 // TODO: Dismiss Keyguard.
1843 }
1844 if (intent.isActivity()) {
1845 mAssistManager.hideAssist();
1846 overrideActivityPendingAppTransition(keyguardShowing
1847 && !afterKeyguardGone);
1848 }
1849 }
1850 }.start();
1851
1852 // close the shade if it was open
1853 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
1854 true /* force */, true /* delayed */);
1855 visibilityChanged(false);
1856
1857 return true;
1858 }
1859 }, afterKeyguardGone);
1860 }
1861
Selim Cinek36b02232016-05-11 23:07:05 -04001862 public void addPostCollapseAction(Runnable r) {
1863 }
1864
1865 public boolean isCollapsing() {
1866 return false;
1867 }
1868
Chris Wren42d5dd42015-05-01 10:39:26 -04001869 private final class NotificationClicker implements View.OnClickListener {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001870 public void onClick(final View v) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001871 if (!(v instanceof ExpandableNotificationRow)) {
1872 Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
1873 return;
1874 }
1875
1876 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
1877 final StatusBarNotification sbn = row.getStatusBarNotification();
1878 if (sbn == null) {
1879 Log.e(TAG, "NotificationClicker called on an unclickable notification,");
1880 return;
1881 }
1882
Mady Mellorf0625802016-02-11 18:03:48 -08001883 // Check if the notification is displaying the gear, if so slide notification back
1884 if (row.getSettingsRow() != null && row.getSettingsRow().isVisible()) {
1885 row.animateTranslateNotification(0);
1886 return;
1887 }
1888
Selim Cinekc6dd5212015-11-02 14:51:54 -08001889 Notification notification = sbn.getNotification();
1890 final PendingIntent intent = notification.contentIntent != null
1891 ? notification.contentIntent
1892 : notification.fullScreenIntent;
Chris Wren42d5dd42015-05-01 10:39:26 -04001893 final String notificationKey = sbn.getKey();
1894
Jorim Jaggi5eb67c22015-08-19 19:50:49 -07001895 // Mark notification for one frame.
1896 row.setJustClicked(true);
1897 DejankUtils.postAfterTraversal(new Runnable() {
1898 @Override
1899 public void run() {
1900 row.setJustClicked(false);
1901 }
1902 });
1903
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001904 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Chris Wren42d5dd42015-05-01 10:39:26 -04001905 final boolean afterKeyguardGone = intent.isActivity()
1906 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001907 mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +02001908 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001909 public boolean onDismiss() {
Chris Wren42d5dd42015-05-01 10:39:26 -04001910 if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
Christoph Studerc6a656c2015-01-22 15:02:49 +01001911 // Release the HUN notification to the shade.
Selim Cinekf55f1bc2016-05-27 11:19:11 -07001912
1913 if (isPanelFullyCollapsed()) {
1914 HeadsUpManager.setIsClickedNotification(row, true);
1915 }
Christoph Studerc6a656c2015-01-22 15:02:49 +01001916 //
1917 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
1918 // become canceled shortly by NoMan, but we can't assume that.
Chris Wren42d5dd42015-05-01 10:39:26 -04001919 mHeadsUpManager.releaseImmediately(notificationKey);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001920 }
Selim Cinek36b02232016-05-11 23:07:05 -04001921 StatusBarNotification parentToCancel = null;
1922 if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
1923 StatusBarNotification summarySbn = mGroupManager.getLogicalGroupSummary(sbn)
1924 .getStatusBarNotification();
1925 if (shouldAutoCancel(summarySbn)) {
1926 parentToCancel = summarySbn;
1927 }
1928 }
1929 final StatusBarNotification parentToCancelFinal = parentToCancel;
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001930 new Thread() {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001931 @Override
1932 public void run() {
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001933 try {
1934 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001935 ActivityManagerNative.getDefault()
1936 .keyguardWaitingForActivityDrawn();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001937 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001938
1939 // The intent we are sending is for the application, which
1940 // won't have permission to immediately start an activity after
1941 // the user switches to home. We know it is safe to do at this
1942 // point, so make sure new activity switches are now allowed.
1943 ActivityManagerNative.getDefault().resumeAppSwitches();
1944 } catch (RemoteException e) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001945 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001946 if (intent != null) {
Ricky Wai7fa01712016-03-16 12:13:54 +00001947 // If we are launching a work activity and require to launch
1948 // separate work challenge, we defer the activity action and cancel
1949 // notification until work challenge is unlocked.
1950 if (intent.isActivity()) {
1951 final int userId = intent.getCreatorUserHandle()
1952 .getIdentifier();
1953 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
1954 && mKeyguardManager.isDeviceLocked(userId)) {
Rubin Xu89927b32016-07-28 14:34:26 +01001955 boolean canBypass = false;
1956 try {
1957 canBypass = ActivityManagerNative.getDefault()
1958 .canBypassWorkChallenge(intent);
1959 } catch (RemoteException e) {
1960 }
1961 // For direct-boot aware activities, they can be shown when
1962 // the device is still locked without triggering the work
1963 // challenge.
1964 if ((!canBypass) && startWorkChallengeIfNecessary(userId,
1965 intent.getIntentSender(), notificationKey)) {
1966 // Show work challenge, do not run PendingIntent and
Ricky Waia8c37a12016-04-05 17:10:04 +01001967 // remove notification
1968 return;
1969 }
Ricky Wai7fa01712016-03-16 12:13:54 +00001970 }
1971 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001972 try {
Jorim Jaggie6e108e2016-03-28 13:38:45 -07001973 intent.send(null, 0, null, null, null, null,
1974 getActivityOptions());
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001975 } catch (PendingIntent.CanceledException e) {
1976 // the stack trace isn't very helpful here.
1977 // Just log the exception message.
1978 Log.w(TAG, "Sending contentIntent failed: " + e);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001979
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001980 // TODO: Dismiss Keyguard.
1981 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001982 if (intent.isActivity()) {
Jorim Jaggib835dd72015-06-08 12:28:42 -07001983 mAssistManager.hideAssist();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001984 overrideActivityPendingAppTransition(keyguardShowing
1985 && !afterKeyguardGone);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001986 }
1987 }
1988
1989 try {
Chris Wren42d5dd42015-05-01 10:39:26 -04001990 mBarService.onNotificationClick(notificationKey);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001991 } catch (RemoteException ex) {
1992 // system process is dead if we're here.
1993 }
Selim Cinek36b02232016-05-11 23:07:05 -04001994 if (parentToCancelFinal != null) {
1995 // We have to post it to the UI thread for synchronization
1996 mHandler.post(new Runnable() {
1997 @Override
1998 public void run() {
1999 Runnable removeRunnable = new Runnable() {
2000 @Override
2001 public void run() {
Selim Cinek5e018202016-12-15 14:44:36 -08002002 performRemoveNotification(parentToCancelFinal);
Selim Cinek36b02232016-05-11 23:07:05 -04002003 }
2004 };
2005 if (isCollapsing()) {
2006 // To avoid lags we're only performing the remove
2007 // after the shade was collapsed
2008 addPostCollapseAction(removeRunnable);
2009 } else {
2010 removeRunnable.run();
2011 }
2012 }
2013 });
2014 }
Adrian Roos7d7090d2014-05-21 13:10:23 +02002015 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02002016 }.start();
Adrian Roos7d7090d2014-05-21 13:10:23 +02002017
2018 // close the shade if it was open
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +01002019 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
Jorim Jaggi27c9b742015-04-09 10:34:49 -07002020 true /* force */, true /* delayed */);
Adrian Roos7d7090d2014-05-21 13:10:23 +02002021 visibilityChanged(false);
2022
Jorim Jaggi8972c2a2015-06-05 16:05:54 -07002023 return true;
Daniel Sandler6a858c32012-03-12 14:38:58 -04002024 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02002025 }, afterKeyguardGone);
Daniel Sandler6a858c32012-03-12 14:38:58 -04002026 }
Chris Wren42d5dd42015-05-01 10:39:26 -04002027
Selim Cinek36b02232016-05-11 23:07:05 -04002028 private boolean shouldAutoCancel(StatusBarNotification sbn) {
2029 int flags = sbn.getNotification().flags;
2030 if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
2031 return false;
2032 }
2033 if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2034 return false;
2035 }
2036 return true;
2037 }
2038
Chris Wren42d5dd42015-05-01 10:39:26 -04002039 public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
Selim Cinekc6dd5212015-11-02 14:51:54 -08002040 Notification notification = sbn.getNotification();
2041 if (notification.contentIntent != null || notification.fullScreenIntent != null) {
Chris Wren42d5dd42015-05-01 10:39:26 -04002042 row.setOnClickListener(this);
2043 } else {
2044 row.setOnClickListener(null);
2045 }
2046 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04002047 }
Chris Wrenf29c3b42013-11-27 16:30:30 -05002048
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02002049 public void animateCollapsePanels(int flags, boolean force) {
2050 }
2051
Jorim Jaggi27c9b742015-04-09 10:34:49 -07002052 public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
2053 }
2054
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02002055 public void overrideActivityPendingAppTransition(boolean keyguardShowing) {
2056 if (keyguardShowing) {
2057 try {
2058 mWindowManagerService.overridePendingAppTransition(null, 0, 0, null);
2059 } catch (RemoteException e) {
2060 Log.w(TAG, "Error overriding app transition: " + e);
2061 }
2062 }
2063 }
2064
Ricky Waicd35def2016-05-03 11:07:07 +01002065 protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
2066 String notificationKey) {
2067 final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
2068 null, userId);
2069 if (newIntent == null) {
2070 return false;
2071 }
2072 final Intent callBackIntent = new Intent(
2073 WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
2074 callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
2075 callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
2076 callBackIntent.setPackage(mContext.getPackageName());
2077
2078 PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
2079 mContext,
2080 0,
2081 callBackIntent,
2082 PendingIntent.FLAG_CANCEL_CURRENT |
2083 PendingIntent.FLAG_ONE_SHOT |
2084 PendingIntent.FLAG_IMMUTABLE);
2085 newIntent.putExtra(
2086 Intent.EXTRA_INTENT,
2087 callBackPendingIntent.getIntentSender());
2088 try {
2089 ActivityManagerNative.getDefault().startConfirmDeviceCredentialIntent(newIntent);
2090 } catch (RemoteException ex) {
2091 // ignore
2092 }
2093 return true;
2094 }
2095
Jorim Jaggie6e108e2016-03-28 13:38:45 -07002096 protected Bundle getActivityOptions() {
2097 // Anything launched from the notification shade should always go into the
2098 // fullscreen stack.
2099 ActivityOptions options = ActivityOptions.makeBasic();
2100 options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
2101 return options.toBundle();
2102 }
2103
Christoph Studere8e28652014-10-29 17:27:53 +01002104 protected void visibilityChanged(boolean visible) {
2105 if (mVisible != visible) {
2106 mVisible = visible;
2107 if (!visible) {
2108 dismissPopups();
2109 }
2110 }
2111 updateVisibleToUser();
2112 }
2113
2114 protected void updateVisibleToUser() {
2115 boolean oldVisibleToUser = mVisibleToUser;
Jorim Jaggi50ff3af2015-08-12 18:35:42 -07002116 mVisibleToUser = mVisible && mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +01002117
2118 if (oldVisibleToUser != mVisibleToUser) {
2119 handleVisibleToUserChanged(mVisibleToUser);
2120 }
2121 }
2122
Daniel Sandler6a858c32012-03-12 14:38:58 -04002123 /**
Christoph Studere8e28652014-10-29 17:27:53 +01002124 * The LEDs are turned off when the notification panel is shown, even just a little bit.
Adrian Roos18d099a2016-05-19 15:28:18 -07002125 * See also PhoneStatusBar.setPanelExpanded for another place where we attempt to do this.
Daniel Sandler6a858c32012-03-12 14:38:58 -04002126 */
Christoph Studere8e28652014-10-29 17:27:53 +01002127 protected void handleVisibleToUserChanged(boolean visibleToUser) {
2128 try {
2129 if (visibleToUser) {
Selim Cinek6577cae2015-08-31 16:15:49 -07002130 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
2131 boolean clearNotificationEffects =
Dan Sandlercb012892016-03-01 00:45:06 -05002132 !isPanelFullyCollapsed() &&
2133 (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
Chris Wrenb659c4f2015-06-25 17:12:27 -04002134 int notificationLoad = mNotificationData.getActiveNotifications().size();
Selim Cinek6577cae2015-08-31 16:15:49 -07002135 if (pinnedHeadsUp && isPanelFullyCollapsed()) {
Chris Wrenb659c4f2015-06-25 17:12:27 -04002136 notificationLoad = 1;
2137 } else {
2138 MetricsLogger.histogram(mContext, "note_load", notificationLoad);
2139 }
2140 mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
Christoph Studere8e28652014-10-29 17:27:53 +01002141 } else {
2142 mBarService.onPanelHidden();
Dan Sandler4247a5c2014-07-23 15:58:08 -04002143 }
Christoph Studere8e28652014-10-29 17:27:53 +01002144 } catch (RemoteException ex) {
2145 // Won't fail unless the world has ended.
Daniel Sandler6a858c32012-03-12 14:38:58 -04002146 }
2147 }
2148
Chris Wren0c8275b2012-05-08 13:36:48 -04002149 /**
Chris Wren16895942015-06-23 11:22:20 -04002150 * Clear Buzz/Beep/Blink.
2151 */
2152 public void clearNotificationEffects() {
2153 try {
2154 mBarService.clearNotificationEffects();
2155 } catch (RemoteException e) {
2156 // Won't fail unless the world has ended.
2157 }
2158 }
2159
Yorke Leee4ea6ab2016-03-03 14:51:49 -08002160 public abstract boolean isPanelFullyCollapsed();
Chris Wren16895942015-06-23 11:22:20 -04002161
2162 /**
Chris Wren0c8275b2012-05-08 13:36:48 -04002163 * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
2164 * about the failure.
2165 *
2166 * WARNING: this will call back into us. Don't hold any locks.
2167 */
Christoph Studer71f18fd2014-05-20 17:02:04 +02002168 void handleNotificationError(StatusBarNotification n, String message) {
Christoph Studere71fefc2014-06-24 16:16:49 +02002169 removeNotification(n.getKey(), null);
Chris Wren0c8275b2012-05-08 13:36:48 -04002170 try {
Kenny Guy3a7c4a52014-03-03 18:24:03 +00002171 mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
2172 n.getInitialPid(), message, n.getUserId());
Chris Wren0c8275b2012-05-08 13:36:48 -04002173 } catch (RemoteException ex) {
2174 // The end is nigh.
2175 }
2176 }
2177
Christoph Studerd0694b62014-06-04 16:36:01 +02002178 protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
Christoph Studer37fe6932014-05-26 13:10:30 +02002179 NotificationData.Entry entry = mNotificationData.remove(key, ranking);
Chris Wren0c8275b2012-05-08 13:36:48 -04002180 if (entry == null) {
John Spurlockcd686b52013-06-05 10:13:46 -04002181 Log.w(TAG, "removeNotification for unknown key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -04002182 return null;
2183 }
Christoph Studer37fe6932014-05-26 13:10:30 +02002184 updateNotifications();
Chris Wren0c8275b2012-05-08 13:36:48 -04002185 return entry.notification;
2186 }
2187
Selim Cinek8d490d42015-04-10 00:05:50 -07002188 protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002189 if (DEBUG) {
Christoph Studera0506e72014-07-31 20:27:39 +02002190 Log.d(TAG, "createNotificationViews(notification=" + sbn);
Chris Wren0c8275b2012-05-08 13:36:48 -04002191 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01002192 final StatusBarIconView iconView = createIcon(sbn);
2193 if (iconView == null) {
2194 return null;
2195 }
2196
2197 // Construct the expanded view.
2198 NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
Selim Cinek8d490d42015-04-10 00:05:50 -07002199 if (!inflateViews(entry, mStackScroller)) {
Selim Cinek379ff8f2015-02-20 17:03:16 +01002200 handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
2201 return null;
2202 }
2203 return entry;
2204 }
2205
Xiaohui Chene90c2c52016-02-24 16:08:00 -08002206 public StatusBarIconView createIcon(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002207 // Construct the icon.
Christoph Studera0506e72014-07-31 20:27:39 +02002208 Notification n = sbn.getNotification();
Chris Wren0c8275b2012-05-08 13:36:48 -04002209 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Christoph Studera0506e72014-07-31 20:27:39 +02002210 sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
Chris Wren0c8275b2012-05-08 13:36:48 -04002211 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
2212
Dan Sandler33439812015-08-10 15:49:56 -04002213 final Icon smallIcon = n.getSmallIcon();
2214 if (smallIcon == null) {
2215 handleNotificationError(sbn,
2216 "No small icon in notification from " + sbn.getPackageName());
2217 return null;
2218 }
Dan Sandlerd63f9322015-05-06 15:18:49 -04002219 final StatusBarIcon ic = new StatusBarIcon(
Christoph Studera0506e72014-07-31 20:27:39 +02002220 sbn.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002221 sbn.getPackageName(),
Dan Sandler33439812015-08-10 15:49:56 -04002222 smallIcon,
Dan Sandler4e787062015-06-17 15:09:48 -04002223 n.iconLevel,
2224 n.number,
Adrian Rooseba05822016-04-22 17:09:27 -07002225 StatusBarIconView.contentDescForNotification(mContext, n));
Chris Wren0c8275b2012-05-08 13:36:48 -04002226 if (!iconView.set(ic)) {
Christoph Studera0506e72014-07-31 20:27:39 +02002227 handleNotificationError(sbn, "Couldn't create icon: " + ic);
Chris Wren0c8275b2012-05-08 13:36:48 -04002228 return null;
2229 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01002230 return iconView;
Chris Wrenf0048ce2013-08-07 16:43:43 -04002231 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002232
Christoph Studerd0694b62014-06-04 16:36:01 +02002233 protected void addNotificationViews(Entry entry, RankingMap ranking) {
Raju Yadav5f330262014-03-24 10:44:00 +01002234 if (entry == null) {
2235 return;
2236 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002237 // Add the expanded view and icon.
Christoph Studer37fe6932014-05-26 13:10:30 +02002238 mNotificationData.add(entry, ranking);
2239 updateNotifications();
Selim Cinek8efa6dd2014-05-19 16:27:37 +02002240 }
2241
Jorim Jaggi251957d2014-04-09 04:24:09 +02002242 /**
Selim Cinek5f71bee2015-11-18 10:25:23 -08002243 * @param recompute wheter the number should be recomputed
Jorim Jaggid4a57442014-04-10 02:45:55 +02002244 * @return The number of notifications we show on Keyguard.
2245 */
Selim Cinek5f71bee2015-11-18 10:25:23 -08002246 protected abstract int getMaxKeyguardNotifications(boolean recompute);
Jorim Jaggid4a57442014-04-10 02:45:55 +02002247
2248 /**
Jorim Jaggi251957d2014-04-09 04:24:09 +02002249 * Updates expanded, dimmed and locked states of notification rows.
2250 */
2251 protected void updateRowStates() {
Jorim Jaggif6411742014-08-05 17:10:43 +00002252 mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
Selim Cinekadd95262016-12-06 14:34:47 -08002253 final int N = mStackScroller.getChildCount();
Jorim Jaggif6411742014-08-05 17:10:43 +00002254
Christoph Studerc8db24b2014-07-25 17:50:30 +02002255
Jorim Jaggif6411742014-08-05 17:10:43 +00002256 int visibleNotifications = 0;
Jorim Jaggiecbab362014-04-23 16:13:15 +02002257 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
Selim Cinek5f71bee2015-11-18 10:25:23 -08002258 int maxNotifications = 0;
2259 if (onKeyguard) {
2260 maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
2261 }
Selim Cinekadd95262016-12-06 14:34:47 -08002262 Stack<ExpandableNotificationRow> stack = new Stack<>();
2263 for (int i = N - 1; i >= 0; i--) {
2264 View child = mStackScroller.getChildAt(i);
2265 if (!(child instanceof ExpandableNotificationRow)) {
2266 continue;
2267 }
2268 stack.push((ExpandableNotificationRow) child);
2269 }
2270 while(!stack.isEmpty()) {
2271 ExpandableNotificationRow row = stack.pop();
2272 NotificationData.Entry entry = row.getEntry();
Selim Cinek2a739342016-03-17 10:28:55 -07002273 boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
Jorim Jaggiecbab362014-04-23 16:13:15 +02002274 if (onKeyguard) {
Selim Cinekadd95262016-12-06 14:34:47 -08002275 row.setOnKeyguard(true);
Chris Wren3ddab0d2012-08-02 16:52:21 -04002276 } else {
Selim Cinekadd95262016-12-06 14:34:47 -08002277 row.setOnKeyguard(false);
2278 row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
Chris Wren8fd12652012-05-09 21:25:57 -04002279 }
Selim Cinek3f19f602016-05-02 18:01:56 -07002280 boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
2281 entry.notification) && !entry.row.isRemoved();
Selim Cinek83bc7832015-10-22 13:26:54 -07002282 boolean childWithVisibleSummary = childNotification
2283 && mGroupManager.getGroupSummary(entry.notification).getVisibility()
2284 == View.VISIBLE;
Jorim Jaggif6411742014-08-05 17:10:43 +00002285 boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
Selim Cinek2a739342016-03-17 10:28:55 -07002286 if (suppressedSummary || (isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
Selim Cinek06416b92016-05-09 16:36:10 -04002287 (onKeyguard && !childWithVisibleSummary
2288 && (visibleNotifications >= maxNotifications || !showOnKeyguard))) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002289 entry.row.setVisibility(View.GONE);
Selim Cinek2a739342016-03-17 10:28:55 -07002290 if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002291 mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
2292 }
2293 } else {
2294 boolean wasGone = entry.row.getVisibility() == View.GONE;
Selim Cinekab24dc92016-12-21 18:23:11 +01002295 if (wasGone) {
2296 entry.row.setVisibility(View.VISIBLE);
2297 }
Selim Cinekfa760d42016-05-10 15:50:53 -04002298 if (!childNotification && !entry.row.isRemoved()) {
Selim Cinekb5605e52015-02-20 18:21:41 +01002299 if (wasGone) {
2300 // notify the scroller of a child addition
Selim Cinek2a739342016-03-17 10:28:55 -07002301 mStackScroller.generateAddAnimation(entry.row,
2302 !showOnKeyguard /* fromMoreCard */);
Selim Cinekb5605e52015-02-20 18:21:41 +01002303 }
2304 visibleNotifications++;
Jorim Jaggif6411742014-08-05 17:10:43 +00002305 }
Jorim Jaggif6411742014-08-05 17:10:43 +00002306 }
Selim Cinekadd95262016-12-06 14:34:47 -08002307 if (row.isSummaryWithChildren()) {
2308 List<ExpandableNotificationRow> notificationChildren =
2309 row.getNotificationChildren();
2310 int size = notificationChildren.size();
2311 for (int i = size - 1; i >= 0; i--) {
2312 stack.push(notificationChildren.get(i));
2313 }
2314 }
Chris Wren8fd12652012-05-09 21:25:57 -04002315 }
Jorim Jaggif6411742014-08-05 17:10:43 +00002316
Selim Cinek2cd45df2015-06-09 18:00:07 -07002317 mStackScroller.updateOverflowContainerVisibility(onKeyguard
2318 && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0);
Jorim Jaggif6411742014-08-05 17:10:43 +00002319
Selim Cinek0cce5312015-05-20 22:13:55 -07002320 mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
2321 mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
Jorim Jaggif6411742014-08-05 17:10:43 +00002322 mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
2323 mStackScroller.getChildCount() - 3);
Jorim Jaggif6411742014-08-05 17:10:43 +00002324 }
2325
Selim Cinekfa760d42016-05-10 15:50:53 -04002326 public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002327 return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
Chris Wren8fd12652012-05-09 21:25:57 -04002328 }
2329
John Spurlocke677d712014-02-13 12:52:19 -05002330 protected void setZenMode(int mode) {
John Spurlock110e5b12014-02-27 13:09:35 -05002331 if (!isDeviceProvisioned()) return;
John Spurlocke677d712014-02-13 12:52:19 -05002332 mZenMode = mode;
Christoph Studer37fe6932014-05-26 13:10:30 +02002333 updateNotifications();
John Spurlocke677d712014-02-13 12:52:19 -05002334 }
2335
Dan Sandler52e5701e2014-07-22 23:14:54 -04002336 // extended in PhoneStatusBar
2337 protected void setShowLockscreenNotifications(boolean show) {
2338 mShowLockscreenNotifications = show;
2339 }
2340
Adrian Roos3aec6382016-02-05 14:19:01 -08002341 protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
2342 mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
2343 }
2344
Dan Sandler52e5701e2014-07-22 23:14:54 -04002345 private void updateLockscreenNotificationSetting() {
2346 final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2347 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
2348 1,
2349 mCurrentUserId) != 0;
Adrian Roosbd3409c2014-08-12 18:21:09 +02002350 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
2351 null /* admin */, mCurrentUserId);
2352 final boolean allowedByDpm = (dpmFlags
2353 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
Adrian Roos3aec6382016-02-05 14:19:01 -08002354
Adrian Roosbd3409c2014-08-12 18:21:09 +02002355 setShowLockscreenNotifications(show && allowedByDpm);
Adrian Roosb27d7a52016-06-16 13:04:47 -07002356
2357 if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
2358 final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2359 Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
2360 0,
2361 mCurrentUserId) != 0;
2362 final boolean remoteInputDpm =
2363 (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
2364
2365 setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
2366 } else {
2367 setLockScreenAllowRemoteInput(false);
2368 }
Dan Sandler52e5701e2014-07-22 23:14:54 -04002369 }
2370
Chris Wren0c8275b2012-05-08 13:36:48 -04002371 protected abstract void setAreThereNotifications();
Christoph Studer37fe6932014-05-26 13:10:30 +02002372 protected abstract void updateNotifications();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -07002373 public abstract boolean shouldDisableNavbarGestures();
Chris Wren0c8275b2012-05-08 13:36:48 -04002374
Christoph Studere71fefc2014-06-24 16:16:49 +02002375 public abstract void addNotification(StatusBarNotification notification,
Selim Cinek379ff8f2015-02-20 17:03:16 +01002376 RankingMap ranking, Entry oldEntry);
Christoph Studere71fefc2014-06-24 16:16:49 +02002377 protected abstract void updateNotificationRanking(RankingMap ranking);
2378 public abstract void removeNotification(String key, RankingMap ranking);
Christoph Studera7fe6312014-06-27 19:32:44 +02002379
Christoph Studere71fefc2014-06-24 16:16:49 +02002380 public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02002381 if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
Chris Wren0c8275b2012-05-08 13:36:48 -04002382
Chris Wrend04f6ce2014-06-11 17:37:28 -04002383 final String key = notification.getKey();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002384 Entry entry = mNotificationData.get(key);
2385 if (entry == null) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002386 return;
Adrian Roos18d099a2016-05-19 15:28:18 -07002387 } else {
Selim Cinek2d79f632015-11-02 15:13:29 -08002388 mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
Adrian Roos18d099a2016-05-19 15:28:18 -07002389 mRemoteInputEntriesToRemoveOnCollapse.remove(entry);
Chris Wren0c8275b2012-05-08 13:36:48 -04002390 }
2391
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002392 Notification n = notification.getNotification();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002393 mNotificationData.updateRanking(ranking);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002394
Adrian Roos95f8bea2016-07-27 15:49:03 -07002395 boolean applyInPlace;
2396 try {
2397 applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
2398 } catch (RuntimeException e) {
2399 Log.e(TAG, "Unable to get notification remote views", e);
2400 applyInPlace = false;
2401 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002402 boolean shouldPeek = shouldPeek(entry, notification);
Selim Cinek684a4422015-04-15 16:18:39 -07002403 boolean alertAgain = alertAgain(entry, n);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002404 if (DEBUG) {
2405 Log.d(TAG, "applyInPlace=" + applyInPlace
Chris Wrenbdf33762015-12-04 15:50:51 -05002406 + " shouldPeek=" + shouldPeek
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002407 + " alertAgain=" + alertAgain);
2408 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002409
Dan Sandler24813b02016-01-14 15:49:36 -05002410 final StatusBarNotification oldNotification = entry.notification;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002411 entry.notification = notification;
Dan Sandler24813b02016-01-14 15:49:36 -05002412 mGroupManager.onEntryUpdated(entry, oldNotification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002413
2414 boolean updateSuccessful = false;
2415 if (applyInPlace) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002416 if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
2417 try {
2418 if (entry.icon != null) {
2419 // Update the icon
Dan Sandlerd63f9322015-05-06 15:18:49 -04002420 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002421 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002422 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002423 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002424 n.iconLevel,
2425 n.number,
Adrian Rooseba05822016-04-22 17:09:27 -07002426 StatusBarIconView.contentDescForNotification(mContext, n));
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002427 entry.icon.setNotification(n);
2428 if (!entry.icon.set(ic)) {
2429 handleNotificationError(notification, "Couldn't update icon: " + ic);
2430 return;
2431 }
2432 }
Selim Cinek8d490d42015-04-10 00:05:50 -07002433 updateNotificationViews(entry, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002434 updateSuccessful = true;
2435 }
2436 catch (RuntimeException e) {
Selim Cinek684a4422015-04-15 16:18:39 -07002437 // It failed to apply cleanly.
Adrian Roose458aa82015-12-08 16:17:19 -08002438 Log.w(TAG, "Couldn't reapply views for package " +
2439 notification.getPackageName(), e);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002440 }
2441 }
2442 if (!updateSuccessful) {
2443 if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
Dan Sandlerd63f9322015-05-06 15:18:49 -04002444 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002445 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002446 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002447 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002448 n.iconLevel,
2449 n.number,
Adrian Rooseba05822016-04-22 17:09:27 -07002450 StatusBarIconView.contentDescForNotification(mContext, n));
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002451 entry.icon.setNotification(n);
2452 entry.icon.set(ic);
Adrian Roos95f8bea2016-07-27 15:49:03 -07002453 if (!inflateViews(entry, mStackScroller)) {
2454 handleNotificationError(notification, "Couldn't update remote views for: "
2455 + notification);
2456 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002457 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002458 updateHeadsUp(key, entry, shouldPeek, alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002459 updateNotifications();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002460
dongwan0605.kim30637e42016-03-02 17:16:47 +09002461 if (!notification.isClearable()) {
2462 // The user may have performed a dismiss action on the notification, since it's
2463 // not clearable we should snap it back.
2464 mStackScroller.snapViewIfNeeded(entry.row);
2465 }
2466
Selim Cinek684a4422015-04-15 16:18:39 -07002467 if (DEBUG) {
2468 // Is this for you?
2469 boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
2470 Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
2471 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002472
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002473 setAreThereNotifications();
2474 }
2475
Chris Wrenbdf33762015-12-04 15:50:51 -05002476 protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
Selim Cinek29fa89b2015-04-17 10:39:11 -07002477 boolean alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002478
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002479 private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
2480 final RemoteViews contentView = entry.cachedContentView;
2481 final RemoteViews bigContentView = entry.cachedBigContentView;
2482 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
2483 final RemoteViews publicContentView = entry.cachedPublicContentView;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002484
Chris Wrene03f4e12013-08-08 16:48:48 -04002485 // Reapply the RemoteViews
Selim Cinek684a4422015-04-15 16:18:39 -07002486 contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
2487 if (bigContentView != null && entry.getExpandedContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002488 bigContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002489 entry.getExpandedContentView(),
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01002490 mOnClickHandler);
Chris Wrene03f4e12013-08-08 16:48:48 -04002491 }
Selim Cinek684a4422015-04-15 16:18:39 -07002492 View headsUpChild = entry.getHeadsUpContentView();
Selim Cinek8d490d42015-04-10 00:05:50 -07002493 if (headsUpContentView != null && headsUpChild != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002494 headsUpContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002495 headsUpChild, mOnClickHandler);
Selim Cinek8d490d42015-04-10 00:05:50 -07002496 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002497 if (publicContentView != null && entry.getPublicContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002498 publicContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002499 entry.getPublicContentView(), mOnClickHandler);
Dan Sandlera5e0f412014-01-23 15:11:54 -05002500 }
Chris Wrene03f4e12013-08-08 16:48:48 -04002501 // update the contentIntent
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002502 mNotificationClicker.register(entry.row, sbn);
Chris Wren42d5dd42015-05-01 10:39:26 -04002503
Selim Cinekda42d652015-12-04 15:51:16 -08002504 entry.row.onNotificationUpdated(entry);
Selim Cinek51ae05d2014-09-09 15:51:38 +02002505 entry.row.resetHeight();
Chris Wren0c8275b2012-05-08 13:36:48 -04002506 }
John Spurlock36231282012-06-23 17:11:27 -04002507
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002508 protected void updatePublicContentView(Entry entry,
2509 StatusBarNotification sbn) {
2510 final RemoteViews publicContentView = entry.cachedPublicContentView;
Selim Cineke4c068d2016-02-19 13:46:55 -08002511 View inflatedView = entry.getPublicContentView();
2512 if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002513 final boolean disabledByPolicy =
2514 !adminAllowsUnredactedNotifications(entry.notification.getUserId());
Selim Cineke4c068d2016-02-19 13:46:55 -08002515 String notificationHiddenText = mContext.getString(disabledByPolicy
2516 ? com.android.internal.R.string.notification_hidden_by_policy_text
2517 : com.android.internal.R.string.notification_hidden_text);
2518 TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
2519 if (titleView != null
2520 && !titleView.getText().toString().equals(notificationHiddenText)) {
2521 publicContentView.setTextViewText(android.R.id.title, notificationHiddenText);
2522 publicContentView.reapply(sbn.getPackageContext(mContext),
2523 inflatedView, mOnClickHandler);
2524 entry.row.onNotificationUpdated(entry);
2525 }
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002526 }
2527 }
2528
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002529 protected void notifyHeadsUpScreenOff() {
Selim Cinek684a4422015-04-15 16:18:39 -07002530 maybeEscalateHeadsUp();
Chris Wrene97f90b2013-08-07 17:39:35 -04002531 }
2532
Chris Wrend93d5ad2014-09-08 16:34:03 -04002533 private boolean alertAgain(Entry oldEntry, Notification newNotification) {
2534 return oldEntry == null || !oldEntry.hasInterrupted()
2535 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
Chris Wrend04f6ce2014-06-11 17:37:28 -04002536 }
2537
Chris Wrenbdf33762015-12-04 15:50:51 -05002538 protected boolean shouldPeek(Entry entry) {
2539 return shouldPeek(entry, entry.notification);
Chris Wren0c274b12015-07-17 10:34:53 -04002540 }
2541
Chris Wrenbdf33762015-12-04 15:50:51 -05002542 protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
Adrian Roosf6967e062016-06-21 16:12:48 -07002543 if (!mUseHeadsUp || isDeviceInVrMode()) {
Dan Sandlerdc34df52016-04-07 21:04:46 -04002544 return false;
2545 }
2546
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002547 if (mNotificationData.shouldFilterOut(sbn)) {
Chris Wrenbdf33762015-12-04 15:50:51 -05002548 if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002549 return false;
2550 }
2551
Selim Cinekab24dc92016-12-21 18:23:11 +01002552 boolean inUse = mPowerManager.isScreenOn();
Selim Cinekd5921912016-02-09 10:33:01 -08002553 try {
2554 inUse = inUse && !mDreamManager.isDreaming();
2555 } catch (RemoteException e) {
2556 Log.d(TAG, "failed to query dream manager", e);
2557 }
2558
2559 if (!inUse) {
2560 if (DEBUG) {
2561 Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
2562 }
2563 return false;
2564 }
2565
2566 if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
2567 if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
Chris Wrena6d4fb62014-11-20 14:46:23 -05002568 return false;
2569 }
2570
Chris Wrenbdf33762015-12-04 15:50:51 -05002571 if (entry.hasJustLaunchedFullScreenIntent()) {
2572 if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
2573 return false;
2574 }
2575
Julia Reynoldsf0f629f2016-02-25 09:34:04 -05002576 if (isSnoozedPackage(sbn)) {
2577 if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
2578 return false;
2579 }
2580
2581 if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_HIGH) {
2582 if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
2583 return false;
2584 }
2585
Selim Cinekd5921912016-02-09 10:33:01 -08002586 if (sbn.getNotification().fullScreenIntent != null) {
2587 if (mAccessibilityManager.isTouchExplorationEnabled()) {
2588 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
2589 return false;
2590 } else {
Selim Cinekab24dc92016-12-21 18:23:11 +01002591 // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
2592 return !mStatusBarKeyguardViewManager.isShowing()
2593 || mStatusBarKeyguardViewManager.isOccluded();
Selim Cinekd5921912016-02-09 10:33:01 -08002594 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002595 }
2596
Selim Cinekd5921912016-02-09 10:33:01 -08002597 return true;
Chris Wren157026f2013-06-28 16:54:01 -04002598 }
2599
Selim Cinek29fa89b2015-04-17 10:39:11 -07002600 protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
2601
John Spurlockcfc359a2013-09-05 10:42:03 -04002602 public void setInteracting(int barWindow, boolean interacting) {
John Spurlockad3e6cb2013-04-30 08:47:43 -04002603 // hook for subclasses
2604 }
John Spurlock5c454122013-06-17 07:35:46 -04002605
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002606 public void setBouncerShowing(boolean bouncerShowing) {
2607 mBouncerShowing = bouncerShowing;
2608 }
2609
2610 /**
2611 * @return Whether the security bouncer from Keyguard is showing.
2612 */
2613 public boolean isBouncerShowing() {
2614 return mBouncerShowing;
2615 }
2616
John Spurlock5c454122013-06-17 07:35:46 -04002617 public void destroy() {
John Spurlock5c454122013-06-17 07:35:46 -04002618 mContext.unregisterReceiver(mBroadcastReceiver);
Christoph Studere71fefc2014-06-24 16:16:49 +02002619 try {
2620 mNotificationListener.unregisterAsSystemService();
2621 } catch (RemoteException e) {
2622 // Ignore.
Christoph Studer37fe6932014-05-26 13:10:30 +02002623 }
John Spurlock5c454122013-06-17 07:35:46 -04002624 }
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002625
2626 /**
2627 * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
2628 * return PackageManager for mContext
2629 */
Selim Cinekeef84282015-10-30 16:28:00 -07002630 public static PackageManager getPackageManagerForUser(Context context, int userId) {
2631 Context contextForUser = context;
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002632 // UserHandle defines special userId as negative values, e.g. USER_ALL
2633 if (userId >= 0) {
2634 try {
2635 // Create a context for the correct user so if a package isn't installed
2636 // for user 0 we can still load information about the package.
2637 contextForUser =
Selim Cinekeef84282015-10-30 16:28:00 -07002638 context.createPackageContextAsUser(context.getPackageName(),
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002639 Context.CONTEXT_RESTRICTED,
2640 new UserHandle(userId));
2641 } catch (NameNotFoundException e) {
2642 // Shouldn't fail to find the package name for system ui.
2643 }
2644 }
2645 return contextForUser.getPackageManager();
2646 }
Chris Wren78403d72014-07-28 10:23:24 +01002647
2648 @Override
2649 public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
2650 try {
2651 mBarService.onNotificationExpansionChanged(key, userAction, expanded);
2652 } catch (RemoteException e) {
2653 // Ignore.
2654 }
2655 }
Jim Millerab954542014-10-10 18:21:49 -07002656
2657 public boolean isKeyguardSecure() {
Dan Sandlere163a642015-03-01 22:58:32 -05002658 if (mStatusBarKeyguardViewManager == null) {
2659 // startKeyguard() hasn't been called yet, so we don't know.
2660 // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
2661 // value onVisibilityChanged().
2662 Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
2663 new Throwable());
2664 return false;
2665 }
Jim Millerab954542014-10-10 18:21:49 -07002666 return mStatusBarKeyguardViewManager.isSecure();
2667 }
Adrian Roos4f43dc02015-06-17 16:43:38 -07002668
2669 @Override
2670 public void showAssistDisclosure() {
2671 if (mAssistManager != null) {
2672 mAssistManager.showDisclosure();
2673 }
2674 }
Jorim Jaggi165ce062015-07-06 16:18:11 -07002675
2676 @Override
2677 public void startAssist(Bundle args) {
2678 if (mAssistManager != null) {
2679 mAssistManager.startAssist(args);
2680 }
2681 }
Joe Onorato2314aab2010-04-08 16:41:23 -05002682}