blob: 1c5d28aaf27bcc908838b69bc965869b456c8ad4 [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;
Daniel Sandler6a858c32012-03-12 14:38:58 -040022import android.app.ActivityManagerNative;
Ricky Wai7fa01712016-03-16 12:13:54 +000023import android.app.KeyguardManager;
Chris Wren51c75102013-07-16 20:49:17 -040024import android.app.Notification;
Chris Wrencd8f4f72014-08-27 18:48:13 -040025import android.app.NotificationManager;
Daniel Sandler6a858c32012-03-12 14:38:58 -040026import android.app.PendingIntent;
Adrian Roos497ab022015-02-10 20:49:33 +010027import android.app.RemoteInput;
Adam Powell0fc5b2b2012-07-18 18:20:29 -070028import android.app.TaskStackBuilder;
Adrian Roosbd3409c2014-08-12 18:21:09 +020029import android.app.admin.DevicePolicyManager;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040030import android.content.BroadcastReceiver;
Christoph Studer60748e72014-05-22 16:51:41 +020031import android.content.ComponentName;
Joe Onorato808182d2010-07-09 18:52:06 -040032import android.content.Context;
Daniel Sandler6a858c32012-03-12 14:38:58 -040033import android.content.Intent;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040034import android.content.IntentFilter;
Ricky Wai7fa01712016-03-16 12:13:54 +000035import android.content.IntentSender;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040036import android.content.pm.ApplicationInfo;
Dan Sandlera5e0f412014-01-23 15:11:54 -050037import android.content.pm.PackageManager;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040038import android.content.pm.PackageManager.NameNotFoundException;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000039import android.content.pm.UserInfo;
John Spurlockde84f0e2013-06-12 12:41:00 -040040import android.content.res.Configuration;
Chris Wrencd8f4f72014-08-27 18:48:13 -040041import android.content.res.Resources;
Daniel Sandler26cda272012-05-22 15:44:08 -040042import android.database.ContentObserver;
Jorim Jaggi86905582016-02-09 21:36:09 -080043import android.graphics.Rect;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +010044import android.graphics.drawable.Drawable;
Dan Sandler33439812015-08-10 15:49:56 -040045import android.graphics.drawable.Icon;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +020046import android.os.AsyncTask;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040047import android.os.Build;
Jorim Jaggi165ce062015-07-06 16:18:11 -070048import android.os.Bundle;
Michael Jurka7f2668c2012-03-27 07:49:52 -070049import android.os.Handler;
Joe Onorato808182d2010-07-09 18:52:06 -040050import android.os.IBinder;
Michael Jurka7f2668c2012-03-27 07:49:52 -070051import android.os.Message;
Chris Wren157026f2013-06-28 16:54:01 -040052import android.os.PowerManager;
Joe Onorato808182d2010-07-09 18:52:06 -040053import android.os.RemoteException;
54import android.os.ServiceManager;
Adrian Roos497ab022015-02-10 20:49:33 +010055import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070056import android.os.UserHandle;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000057import android.os.UserManager;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040058import android.provider.Settings;
Chris Wren157026f2013-06-28 16:54:01 -040059import android.service.dreams.DreamService;
60import android.service.dreams.IDreamManager;
Christoph Studer60748e72014-05-22 16:51:41 +020061import android.service.notification.NotificationListenerService;
Christoph Studerd0694b62014-06-04 16:36:01 +020062import android.service.notification.NotificationListenerService.RankingMap;
John Spurlockde84f0e2013-06-12 12:41:00 -040063import android.service.notification.StatusBarNotification;
Chris Wren0c8275b2012-05-08 13:36:48 -040064import android.text.TextUtils;
Selim Cinek2d79f632015-11-02 15:13:29 -080065import android.util.ArraySet;
Joe Onorato808182d2010-07-09 18:52:06 -040066import android.util.Log;
Dan Sandlere163a642015-03-01 22:58:32 -050067import android.util.Slog;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000068import android.util.SparseArray;
Dan Sandlerfd16d562014-02-13 18:43:31 -080069import android.util.SparseBooleanArray;
Daniel Sandlerc638c1e2011-08-24 16:19:23 -070070import android.view.Display;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050071import android.view.IWindowManager;
Michael Jurka7f2668c2012-03-27 07:49:52 -070072import android.view.LayoutInflater;
73import android.view.MotionEvent;
Joe Onorato808182d2010-07-09 18:52:06 -040074import android.view.View;
Dan Sandler4247a5c2014-07-23 15:58:08 -040075import android.view.ViewAnimationUtils;
Daniel Sandler6a858c32012-03-12 14:38:58 -040076import android.view.ViewGroup;
Christoph Studer4da84cd2014-10-21 17:24:20 +020077import android.view.ViewParent;
Joe Onorato808182d2010-07-09 18:52:06 -040078import android.view.WindowManager;
Michael Jurka80343f62012-10-18 13:13:46 +020079import android.view.WindowManagerGlobal;
Selim Cineka8fefa52014-09-08 16:10:50 +020080import android.view.accessibility.AccessibilityManager;
Chris Wren0c8275b2012-05-08 13:36:48 -040081import android.widget.ImageView;
Michael Jurkaa600fd92012-06-25 15:57:05 -070082import android.widget.RemoteViews;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040083import android.widget.TextView;
Kenny Guydae30d52015-04-01 19:11:35 +010084import android.widget.Toast;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050085
Chris Wrenbd6b5fb2015-06-09 14:58:34 -040086import com.android.internal.logging.MetricsLogger;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050087import com.android.internal.logging.MetricsProto.MetricsEvent;
John Spurlockde84f0e2013-06-12 12:41:00 -040088import com.android.internal.statusbar.IStatusBarService;
89import com.android.internal.statusbar.StatusBarIcon;
Chris Wrencd8f4f72014-08-27 18:48:13 -040090import com.android.internal.widget.LockPatternUtils;
Adrian Roosd6aa6cb2015-04-16 19:31:29 -070091import com.android.keyguard.KeyguardUpdateMonitor;
Jorim Jaggi5eb67c22015-08-19 19:50:49 -070092import com.android.systemui.DejankUtils;
Winsonc0d70582016-01-29 10:24:39 -080093import com.android.systemui.Interpolators;
John Spurlockde84f0e2013-06-12 12:41:00 -040094import com.android.systemui.R;
John Spurlockd08de372013-06-24 13:06:08 -040095import com.android.systemui.RecentsComponent;
Dan Sandler4247a5c2014-07-23 15:58:08 -040096import com.android.systemui.SwipeHelper;
John Spurlockde84f0e2013-06-12 12:41:00 -040097import com.android.systemui.SystemUI;
Jorim Jaggib835dd72015-06-08 12:28:42 -070098import com.android.systemui.assist.AssistManager;
Jorim Jaggid61f2272014-12-19 20:35:35 +010099import com.android.systemui.recents.Recents;
Christoph Studer37fe6932014-05-26 13:10:30 +0200100import com.android.systemui.statusbar.NotificationData.Entry;
Selim Cinek92d892c2014-09-11 15:11:00 +0200101import com.android.systemui.statusbar.phone.NavigationBarView;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100102import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200103import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700104import com.android.systemui.statusbar.policy.HeadsUpManager;
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200105import com.android.systemui.statusbar.policy.PreviewInflater;
Adrian Roos497ab022015-02-10 20:49:33 +0100106import com.android.systemui.statusbar.policy.RemoteInputView;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100107import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Mady Mellor4b80b102016-01-22 08:03:58 -0800108import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.GearDisplayedListener;
Selim Cinekd84a5932015-12-15 11:45:36 -0800109import com.android.systemui.statusbar.stack.StackStateAnimator;
John Spurlockde84f0e2013-06-12 12:41:00 -0400110
Michael Jurkaa600fd92012-06-25 15:57:05 -0700111import java.util.ArrayList;
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200112import java.util.List;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700113import java.util.Locale;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400114
Julia Reynoldsf0f629f2016-02-25 09:34:04 -0500115import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100116import static com.android.keyguard.KeyguardHostView.OnDismissAction;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200117
Michael Jurka7f2668c2012-03-27 07:49:52 -0700118public abstract class BaseStatusBar extends SystemUI implements
Winson Chung9214eff2014-06-12 13:59:25 -0700119 CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
Selim Cinek570981d2015-12-01 11:37:01 -0800120 ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
Mady Mellor4b80b102016-01-22 08:03:58 -0800121 ExpandableNotificationRow.OnExpandClickListener, GearDisplayedListener {
Daniel Sandler198a0302012-08-17 16:04:31 -0400122 public static final String TAG = "StatusBar";
Jorim Jaggi86905582016-02-09 21:36:09 -0800123 public static final boolean DEBUG = false;
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400124 public static final boolean MULTIUSER_DEBUG = false;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400125
Adrian Roos497ab022015-02-10 20:49:33 +0100126 public static final boolean ENABLE_REMOTE_INPUT =
Adrian Roos9531c9b2015-11-03 17:43:01 -0800127 SystemProperties.getBoolean("debug.enable_remote_input", true);
Selim Cinek40412492015-12-08 18:03:22 -0800128 public static final boolean ENABLE_CHILD_NOTIFICATIONS
129 = SystemProperties.getBoolean("debug.child_notifs", true);
Adrian Roos497ab022015-02-10 20:49:33 +0100130
Winson Chung1e8d71b2014-05-16 17:05:22 -0700131 protected static final int MSG_SHOW_RECENT_APPS = 1019;
132 protected static final int MSG_HIDE_RECENT_APPS = 1020;
133 protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700134 protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
135 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
Winson Chungb1f74992014-08-08 12:53:09 -0700136 protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
137 protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +0000138 protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
Chris Wren0c8275b2012-05-08 13:36:48 -0400139
Chris Wren157026f2013-06-28 16:54:01 -0400140 protected static final boolean ENABLE_HEADS_UP = true;
Chris Wren22ae46e2014-02-26 18:08:09 -0500141 protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
Chris Wren0c8275b2012-05-08 13:36:48 -0400142
Ricky Wai7fa01712016-03-16 12:13:54 +0000143 private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
144
Winsond8b1d632016-01-04 17:51:18 -0800145 // Should match the values in PhoneWindowManager
Michael Jurka56a57832012-05-14 13:24:43 -0700146 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
Winsond8b1d632016-01-04 17:51:18 -0800147 public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
Michael Jurka56a57832012-05-14 13:24:43 -0700148
Chris Wrencd8f4f72014-08-27 18:48:13 -0400149 private static final String BANNER_ACTION_CANCEL =
150 "com.android.systemui.statusbar.banner_action_cancel";
151 private static final String BANNER_ACTION_SETUP =
152 "com.android.systemui.statusbar.banner_action_setup";
Ricky Wai7fa01712016-03-16 12:13:54 +0000153 private static final String WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION
154 = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
Chris Wrencd8f4f72014-08-27 18:48:13 -0400155
Joe Onorato808182d2010-07-09 18:52:06 -0400156 protected CommandQueue mCommandQueue;
157 protected IStatusBarService mBarService;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700158 protected H mHandler = createHandler();
159
Chris Wren0c8275b2012-05-08 13:36:48 -0400160 // all notifications
Christoph Studerc8db24b2014-07-25 17:50:30 +0200161 protected NotificationData mNotificationData;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100162 protected NotificationStackScrollLayout mStackScroller;
Chris Wren0c8275b2012-05-08 13:36:48 -0400163
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100164 protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
165
Adrian Roosb88b1a12015-12-09 18:51:05 -0800166 protected RemoteInputController mRemoteInputController;
167
Chris Wrena4ef6202014-06-09 18:07:30 -0400168 // for heads up notifications
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700169 protected HeadsUpManager mHeadsUpManager;
Chris Wren0c8275b2012-05-08 13:36:48 -0400170
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400171 protected int mCurrentUserId = 0;
Kenny Guy2a764942014-04-02 13:29:20 +0100172 final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400173
Daniel Sandler777dcde2013-09-30 10:21:45 -0400174 protected int mLayoutDirection = -1; // invalid
Selim Cineka8fefa52014-09-08 16:10:50 +0200175 protected AccessibilityManager mAccessibilityManager;
Selim Cinek92d892c2014-09-11 15:11:00 +0200176
177 // on-screen navigation buttons
178 protected NavigationBarView mNavigationBarView = null;
Christoph Studere8e28652014-10-29 17:27:53 +0100179
Jorim Jaggi50ff3af2015-08-12 18:35:42 -0700180 protected boolean mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +0100181
182 protected boolean mVisible;
Selim Cinek2d79f632015-11-02 15:13:29 -0800183 protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
Christoph Studere8e28652014-10-29 17:27:53 +0100184
185 // mScreenOnFromKeyguard && mVisible.
186 private boolean mVisibleToUser;
187
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700188 private Locale mLocale;
Dan Sandler539aad42014-08-04 00:43:39 -0400189 private float mFontScale;
190
Chris Wrenf6e83f42013-09-11 14:02:59 -0400191 protected boolean mUseHeadsUp = false;
Chris Wren22ae46e2014-02-26 18:08:09 -0500192 protected boolean mHeadsUpTicker = false;
Jason Monkf7019542014-07-31 12:42:25 -0400193 protected boolean mDisableNotificationAlerts = false;
Chris Wren157026f2013-06-28 16:54:01 -0400194
Adrian Roosbd3409c2014-08-12 18:21:09 +0200195 protected DevicePolicyManager mDevicePolicyManager;
Chris Wren157026f2013-06-28 16:54:01 -0400196 protected IDreamManager mDreamManager;
Julia Reynolds0971cb02016-01-26 17:00:22 -0500197 protected PowerManager mPowerManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200198 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Dan Sandlerfd16d562014-02-13 18:43:31 -0800199
200 // public mode, private notifications, etc
201 private boolean mLockscreenPublicMode = false;
202 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
Julia Reynolds26fa8a52016-02-24 08:31:22 -0500203 private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700204
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000205 private UserManager mUserManager;
Selim Cinek01af3342016-02-09 19:25:31 -0800206 private int mDensity;
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000207
Ricky Wai7fa01712016-03-16 12:13:54 +0000208 private KeyguardManager mKeyguardManager;
209 private LockPatternUtils mLockPatternUtils;
210
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500211 // UI-specific methods
Daniel Sandler6a858c32012-03-12 14:38:58 -0400212
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500213 /**
214 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
215 * and add them to the window manager.
216 */
217 protected abstract void createAndAddWindows();
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400218
Jeff Brown98365d72012-08-19 20:30:52 -0700219 protected WindowManager mWindowManager;
220 protected IWindowManager mWindowManagerService;
Christoph Studer60748e72014-05-22 16:51:41 +0200221
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700222 protected abstract void refreshLayout(int layoutDirection);
223
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500224 protected Display mDisplay;
Jeff Brown98365d72012-08-19 20:30:52 -0700225
Daniel Sandler26cda272012-05-22 15:44:08 -0400226 private boolean mDeviceProvisioned = false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400227
Jorim Jaggi75b25972015-10-21 14:51:10 +0200228 protected RecentsComponent mRecents;
John Spurlockd08de372013-06-24 13:06:08 -0400229
John Spurlocke677d712014-02-13 12:52:19 -0500230 protected int mZenMode;
231
Dan Sandler4247a5c2014-07-23 15:58:08 -0400232 // which notification is currently being longpress-examined by the user
Selim Cinek024ca592014-09-01 15:11:28 +0200233 private NotificationGuts mNotificationGutsExposed;
Mady Mellor4b80b102016-01-22 08:03:58 -0800234 private ExpandableNotificationRow mNotificationGearDisplayed;
Dan Sandler4247a5c2014-07-23 15:58:08 -0400235
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +0100236 private KeyboardShortcuts mKeyboardShortcuts;
237
Jorim Jaggiecbab362014-04-23 16:13:15 +0200238 /**
239 * The {@link StatusBarState} of the status bar.
240 */
241 protected int mState;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200242 protected boolean mBouncerShowing;
John Spurlock4b3bda22014-05-22 14:32:20 -0400243 protected boolean mShowLockscreenNotifications;
Adrian Roos3aec6382016-02-05 14:19:01 -0800244 protected boolean mAllowLockscreenRemoteInput;
Jorim Jaggiecbab362014-04-23 16:13:15 +0200245
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200246 protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
Dan Sandlereceda3d2014-07-21 15:35:01 -0400247 protected DismissView mDismissView;
Jorim Jaggia2052ea2014-08-05 16:22:30 +0200248 protected EmptyShadeView mEmptyShadeView;
Jorim Jaggi649b7082014-04-03 13:15:18 +0200249
Chris Wren42d5dd42015-05-01 10:39:26 -0400250 private NotificationClicker mNotificationClicker = new NotificationClicker();
251
Jorim Jaggib835dd72015-06-08 12:28:42 -0700252 protected AssistManager mAssistManager;
253
Christoph Studerc8db24b2014-07-25 17:50:30 +0200254 @Override // NotificationData.Environment
Daniel Sandler3ffdcc72012-09-23 14:31:48 -0400255 public boolean isDeviceProvisioned() {
Daniel Sandler26cda272012-05-22 15:44:08 -0400256 return mDeviceProvisioned;
257 }
258
John Spurlocke677d712014-02-13 12:52:19 -0500259 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
Daniel Sandler26cda272012-05-22 15:44:08 -0400260 @Override
261 public void onChange(boolean selfChange) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700262 final boolean provisioned = 0 != Settings.Global.getInt(
263 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
Daniel Sandler26cda272012-05-22 15:44:08 -0400264 if (provisioned != mDeviceProvisioned) {
265 mDeviceProvisioned = provisioned;
Christoph Studer37fe6932014-05-26 13:10:30 +0200266 updateNotifications();
Daniel Sandler26cda272012-05-22 15:44:08 -0400267 }
John Spurlocke677d712014-02-13 12:52:19 -0500268 final int mode = Settings.Global.getInt(mContext.getContentResolver(),
269 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
270 setZenMode(mode);
Dan Sandler52e5701e2014-07-22 23:14:54 -0400271
272 updateLockscreenNotificationSetting();
Daniel Sandler26cda272012-05-22 15:44:08 -0400273 }
274 };
275
Dan Sandlerfd16d562014-02-13 18:43:31 -0800276 private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
277 @Override
278 public void onChange(boolean selfChange) {
279 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
280 // so we just dump our cache ...
281 mUsersAllowingPrivateNotifications.clear();
282 // ... and refresh all the notifications
Christoph Studer37fe6932014-05-26 13:10:30 +0200283 updateNotifications();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800284 }
285 };
286
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700287 private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
288 @Override
Adrian Roos7d7090d2014-05-21 13:10:23 +0200289 public boolean onClickHandler(
290 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800291 if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
292 return true;
293 }
294
Daniel Sandler198a0302012-08-17 16:04:31 -0400295 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400296 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
Daniel Sandler198a0302012-08-17 16:04:31 -0400297 }
Christoph Studer4da84cd2014-10-21 17:24:20 +0200298 logActionClick(view);
Jorim Jaggi89f7f282014-10-17 19:54:15 +0200299 // The intent we are sending is for the application, which
300 // won't have permission to immediately start an activity after
301 // the user switches to home. We know it is safe to do at this
302 // point, so make sure new activity switches are now allowed.
303 try {
304 ActivityManagerNative.getDefault().resumeAppSwitches();
305 } catch (RemoteException e) {
306 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700307 final boolean isActivity = pendingIntent.isActivity();
308 if (isActivity) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200309 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200310 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
311 mContext, pendingIntent.getIntent(), mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +0200312 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200313 @Override
314 public boolean onDismiss() {
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200315 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200316 try {
317 ActivityManagerNative.getDefault()
318 .keyguardWaitingForActivityDrawn();
Jorim Jaggi91617a72015-06-25 15:01:29 -0700319 ActivityManagerNative.getDefault().resumeAppSwitches();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200320 } catch (RemoteException e) {
321 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200322 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700323
Adrian Roos7d7090d2014-05-21 13:10:23 +0200324 boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200325 overrideActivityPendingAppTransition(keyguardShowing && !afterKeyguardGone);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700326
Adrian Roos7d7090d2014-05-21 13:10:23 +0200327 // close the shade if it was open
328 if (handled) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100329 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
330 true /* force */);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200331 visibilityChanged(false);
Jorim Jaggi91617a72015-06-25 15:01:29 -0700332 mAssistManager.hideAssist();
Adrian Roos7d7090d2014-05-21 13:10:23 +0200333 }
Jorim Jaggi91617a72015-06-25 15:01:29 -0700334
Adrian Roos4314f6d2014-05-28 14:10:27 +0200335 // Wait for activity start.
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200336 return handled;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200337 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200338 }, afterKeyguardGone);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200339 return true;
340 } else {
341 return super.onClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700342 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200343 }
344
Christoph Studer4da84cd2014-10-21 17:24:20 +0200345 private void logActionClick(View view) {
346 ViewParent parent = view.getParent();
347 String key = getNotificationKeyForParent(parent);
348 if (key == null) {
349 Log.w(TAG, "Couldn't determine notification for click.");
350 return;
351 }
352 int index = -1;
353 // If this is a default template, determine the index of the button.
354 if (view.getId() == com.android.internal.R.id.action0 &&
355 parent != null && parent instanceof ViewGroup) {
356 ViewGroup actionGroup = (ViewGroup) parent;
357 index = actionGroup.indexOfChild(view);
358 }
359 try {
360 mBarService.onNotificationActionClick(key, index);
361 } catch (RemoteException e) {
362 // Ignore
363 }
364 }
365
366 private String getNotificationKeyForParent(ViewParent parent) {
367 while (parent != null) {
368 if (parent instanceof ExpandableNotificationRow) {
369 return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
370 }
371 parent = parent.getParent();
372 }
373 return null;
374 }
375
Adrian Roos7d7090d2014-05-21 13:10:23 +0200376 private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
377 Intent fillInIntent) {
378 return super.onClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700379 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800380
381 private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
382 Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
383 RemoteInput[] inputs = null;
384 if (tag instanceof RemoteInput[]) {
385 inputs = (RemoteInput[]) tag;
386 }
387
388 if (inputs == null) {
389 return false;
390 }
391
392 RemoteInput input = null;
393
394 for (RemoteInput i : inputs) {
395 if (i.getAllowFreeFormInput()) {
396 input = i;
397 }
398 }
399
400 if (input == null) {
401 return false;
402 }
403
404 ViewParent p = view.getParent();
405 RemoteInputView riv = null;
406 while (p != null) {
407 if (p instanceof View) {
408 View pv = (View) p;
409 if (pv.isRootNamespace()) {
410 riv = (RemoteInputView) pv.findViewWithTag(RemoteInputView.VIEW_TAG);
411 break;
412 }
413 }
414 p = p.getParent();
415 }
Adrian Roos3aec6382016-02-05 14:19:01 -0800416 ExpandableNotificationRow row = null;
417 while (p != null) {
418 if (p instanceof ExpandableNotificationRow) {
419 row = (ExpandableNotificationRow) p;
420 break;
421 }
422 p = p.getParent();
423 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800424
Adrian Roos3aec6382016-02-05 14:19:01 -0800425 if (riv == null || row == null) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800426 return false;
427 }
428
Adrian Roos3aec6382016-02-05 14:19:01 -0800429 row.setUserExpanded(true);
430
431 if (isLockscreenPublicMode() && !mAllowLockscreenRemoteInput) {
432 onLockedRemoteInput(row, view);
433 return true;
434 }
435
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800436 riv.setVisibility(View.VISIBLE);
437 int cx = view.getLeft() + view.getWidth() / 2;
438 int cy = view.getTop() + view.getHeight() / 2;
439 int w = riv.getWidth();
440 int h = riv.getHeight();
441 int r = Math.max(
442 Math.max(cx + cy, cx + (h - cy)),
443 Math.max((w - cx) + cy, (w - cx) + (h - cy)));
444 ViewAnimationUtils.createCircularReveal(riv, cx, cy, 0, r)
445 .start();
446
447 riv.setPendingIntent(pendingIntent);
448 riv.setRemoteInput(inputs, input);
449 riv.focus();
450
451 return true;
452 }
453
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700454 };
455
John Spurlock5c454122013-06-17 07:35:46 -0400456 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
457 @Override
458 public void onReceive(Context context, Intent intent) {
459 String action = intent.getAction();
460 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
461 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Kenny Guy2a764942014-04-02 13:29:20 +0100462 updateCurrentProfilesCache();
John Spurlock5c454122013-06-17 07:35:46 -0400463 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
Dan Sandler52e5701e2014-07-22 23:14:54 -0400464
465 updateLockscreenNotificationSetting();
466
John Spurlock5c454122013-06-17 07:35:46 -0400467 userSwitched(mCurrentUserId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000468 } else if (Intent.ACTION_USER_ADDED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +0100469 updateCurrentProfilesCache();
Kenny Guydae30d52015-04-01 19:11:35 +0100470 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
471 List<ActivityManager.RecentTaskInfo> recentTask = null;
472 try {
473 recentTask = ActivityManagerNative.getDefault().getRecentTasks(1,
474 ActivityManager.RECENT_WITH_EXCLUDED
475 | ActivityManager.RECENT_INCLUDE_PROFILES,
476 mCurrentUserId);
477 } catch (RemoteException e) {
478 // Abandon hope activity manager not running.
479 }
480 if (recentTask != null && recentTask.size() > 0) {
481 UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
482 if (user != null && user.isManagedProfile()) {
Kenny Guy63bf8ac2015-06-18 15:09:09 +0100483 Toast toast = Toast.makeText(mContext,
484 R.string.managed_profile_foreground_toast,
485 Toast.LENGTH_SHORT);
486 TextView text = (TextView) toast.getView().findViewById(
487 android.R.id.message);
488 text.setCompoundDrawablesRelativeWithIntrinsicBounds(
489 R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
490 int paddingPx = mContext.getResources().getDimensionPixelSize(
491 R.dimen.managed_profile_toast_padding);
492 text.setCompoundDrawablePadding(paddingPx);
Kenny Guy540f7d22015-06-08 20:24:23 +0100493 toast.show();
Kenny Guydae30d52015-04-01 19:11:35 +0100494 }
495 }
Chris Wrencd8f4f72014-08-27 18:48:13 -0400496 } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
497 NotificationManager noMan = (NotificationManager)
498 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500499 noMan.cancel(R.id.notification_hidden);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400500
501 Settings.Secure.putInt(mContext.getContentResolver(),
502 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
503 if (BANNER_ACTION_SETUP.equals(action)) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100504 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
505 true /* force */);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400506 mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
507 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
508
509 );
510 }
Ricky Wai7fa01712016-03-16 12:13:54 +0000511 } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
512 final IntentSender intentSender = (IntentSender) intent
513 .getParcelableExtra(Intent.EXTRA_INTENT);
514 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
515 try {
516 mContext.startIntentSender(intentSender, null, 0, 0, 0);
517 } catch (IntentSender.SendIntentException e) {
518 /* ignore */
519 }
520 try {
521 mBarService.onNotificationClick(notificationKey);
522 } catch (RemoteException e) {
523 /* ignore */
524 }
John Spurlock5c454122013-06-17 07:35:46 -0400525 }
526 }
527 };
528
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000529 private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
530 @Override
531 public void onReceive(Context context, Intent intent) {
532 String action = intent.getAction();
533 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
534 isCurrentProfile(getSendingUserId())) {
535 mUsersAllowingPrivateNotifications.clear();
536 updateLockscreenNotificationSetting();
537 updateNotifications();
538 }
539 }
540 };
541
Christoph Studer60748e72014-05-22 16:51:41 +0200542 private final NotificationListenerService mNotificationListener =
543 new NotificationListenerService() {
544 @Override
545 public void onListenerConnected() {
546 if (DEBUG) Log.d(TAG, "onListenerConnected");
547 final StatusBarNotification[] notifications = getActiveNotifications();
Christoph Studerd0694b62014-06-04 16:36:01 +0200548 final RankingMap currentRanking = getCurrentRanking();
Christoph Studer60748e72014-05-22 16:51:41 +0200549 mHandler.post(new Runnable() {
550 @Override
551 public void run() {
552 for (StatusBarNotification sbn : notifications) {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100553 addNotification(sbn, currentRanking, null /* oldEntry */);
Christoph Studer60748e72014-05-22 16:51:41 +0200554 }
555 }
556 });
557 }
558
559 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200560 public void onNotificationPosted(final StatusBarNotification sbn,
561 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200562 if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500563 if (sbn != null) {
564 mHandler.post(new Runnable() {
565 @Override
566 public void run() {
Adrian Roos497ab022015-02-10 20:49:33 +0100567 processForRemoteInput(sbn.getNotification());
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700568 String key = sbn.getKey();
569 boolean isUpdate = mNotificationData.get(key) != null;
Selim Cinekb5605e52015-02-20 18:21:41 +0100570 // In case we don't allow child notifications, we ignore children of
571 // notifications that have a summary, since we're not going to show them
572 // anyway. This is true also when the summary is canceled,
Chris Wren56919552015-02-24 15:56:34 -0500573 // because children are automatically canceled by NoMan in that case.
Selim Cinekb5605e52015-02-20 18:21:41 +0100574 if (!ENABLE_CHILD_NOTIFICATIONS
575 && mGroupManager.isChildInGroupWithSummary(sbn)) {
Chris Wren56919552015-02-24 15:56:34 -0500576 if (DEBUG) {
577 Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
578 }
579
580 // Remove existing notification to avoid stale data.
581 if (isUpdate) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700582 removeNotification(key, rankingMap);
Chris Wren56919552015-02-24 15:56:34 -0500583 } else {
584 mNotificationData.updateRanking(rankingMap);
585 }
586 return;
Christoph Studerd722f272014-09-02 11:49:19 +0200587 }
Christoph Studerd722f272014-09-02 11:49:19 +0200588 if (isUpdate) {
Chris Wren56919552015-02-24 15:56:34 -0500589 updateNotification(sbn, rankingMap);
Christoph Studerd722f272014-09-02 11:49:19 +0200590 } else {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100591 addNotification(sbn, rankingMap, null /* oldEntry */);
Christoph Studerd722f272014-09-02 11:49:19 +0200592 }
Christoph Studerd722f272014-09-02 11:49:19 +0200593 }
Chris Wren56919552015-02-24 15:56:34 -0500594 });
595 }
Christoph Studer60748e72014-05-22 16:51:41 +0200596 }
597
598 @Override
Chris Wren56919552015-02-24 15:56:34 -0500599 public void onNotificationRemoved(StatusBarNotification sbn,
Christoph Studerd0694b62014-06-04 16:36:01 +0200600 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200601 if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500602 if (sbn != null) {
603 final String key = sbn.getKey();
604 mHandler.post(new Runnable() {
605 @Override
606 public void run() {
607 removeNotification(key, rankingMap);
608 }
609 });
610 }
Christoph Studer37fe6932014-05-26 13:10:30 +0200611 }
612
613 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200614 public void onNotificationRankingUpdate(final RankingMap rankingMap) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200615 if (DEBUG) Log.d(TAG, "onRankingUpdate");
Chris Wren56919552015-02-24 15:56:34 -0500616 if (rankingMap != null) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200617 mHandler.post(new Runnable() {
618 @Override
619 public void run() {
Christoph Studere71fefc2014-06-24 16:16:49 +0200620 updateNotificationRanking(rankingMap);
Christoph Studer60748e72014-05-22 16:51:41 +0200621 }
622 });
Chris Wren56919552015-02-24 15:56:34 -0500623 } }
Christoph Studer5b638262014-07-07 11:21:49 +0200624
Christoph Studer60748e72014-05-22 16:51:41 +0200625 };
626
Kenny Guy2a764942014-04-02 13:29:20 +0100627 private void updateCurrentProfilesCache() {
628 synchronized (mCurrentProfiles) {
629 mCurrentProfiles.clear();
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000630 if (mUserManager != null) {
Kenny Guy2a764942014-04-02 13:29:20 +0100631 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
632 mCurrentProfiles.put(user.id, user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000633 }
634 }
635 }
636 }
637
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400638 public void start() {
Jeff Brown98365d72012-08-19 20:30:52 -0700639 mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
640 mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
641 mDisplay = mWindowManager.getDefaultDisplay();
Adrian Roosbd3409c2014-08-12 18:21:09 +0200642 mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
643 Context.DEVICE_POLICY_SERVICE);
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500644
Christoph Studerc8db24b2014-07-25 17:50:30 +0200645 mNotificationData = new NotificationData(this);
646
Selim Cineka8fefa52014-09-08 16:10:50 +0200647 mAccessibilityManager = (AccessibilityManager)
648 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
649
Chris Wren157026f2013-06-28 16:54:01 -0400650 mDreamManager = IDreamManager.Stub.asInterface(
651 ServiceManager.checkService(DreamService.DREAM_SERVICE));
Chris Wren157026f2013-06-28 16:54:01 -0400652 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
653
Daniel Sandler26cda272012-05-22 15:44:08 -0400654 mContext.getContentResolver().registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700655 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
John Spurlocke677d712014-02-13 12:52:19 -0500656 mSettingsObserver);
657 mContext.getContentResolver().registerContentObserver(
658 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
659 mSettingsObserver);
John Spurlock4b3bda22014-05-22 14:32:20 -0400660 mContext.getContentResolver().registerContentObserver(
Dan Sandler52e5701e2014-07-22 23:14:54 -0400661 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
662 mSettingsObserver,
663 UserHandle.USER_ALL);
Adrian Roos3aec6382016-02-05 14:19:01 -0800664 mContext.getContentResolver().registerContentObserver(
665 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), false,
666 mSettingsObserver,
667 UserHandle.USER_ALL);
Daniel Sandler26cda272012-05-22 15:44:08 -0400668
Dan Sandlerfd16d562014-02-13 18:43:31 -0800669 mContext.getContentResolver().registerContentObserver(
670 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
671 true,
672 mLockscreenSettingsObserver,
673 UserHandle.USER_ALL);
674
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500675 mBarService = IStatusBarService.Stub.asInterface(
676 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400677
Jorim Jaggid61f2272014-12-19 20:35:35 +0100678 mRecents = getComponent(Recents.class);
John Spurlockd08de372013-06-24 13:06:08 -0400679
Dan Sandler539aad42014-08-04 00:43:39 -0400680 final Configuration currentConfig = mContext.getResources().getConfiguration();
681 mLocale = currentConfig.locale;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700682 mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
Dan Sandler539aad42014-08-04 00:43:39 -0400683 mFontScale = currentConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800684 mDensity = currentConfig.densityDpi;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700685
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000686 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Ricky Wai7fa01712016-03-16 12:13:54 +0000687 mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
688 mLockPatternUtils = new LockPatternUtils(mContext);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000689
Joe Onorato2314aab2010-04-08 16:41:23 -0500690 // Connect in to the status bar manager service
Jason Monk07473ce2016-01-05 14:59:19 -0500691 mCommandQueue = new CommandQueue(this);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400692
Jorim Jaggi86905582016-02-09 21:36:09 -0800693 int[] switches = new int[9];
satokcd7cd292010-11-20 15:46:23 +0900694 ArrayList<IBinder> binders = new ArrayList<IBinder>();
Jason Monk07473ce2016-01-05 14:59:19 -0500695 ArrayList<String> iconSlots = new ArrayList<>();
696 ArrayList<StatusBarIcon> icons = new ArrayList<>();
Jorim Jaggi86905582016-02-09 21:36:09 -0800697 Rect fullscreenStackBounds = new Rect();
698 Rect dockedStackBounds = new Rect();
Joe Onorato2314aab2010-04-08 16:41:23 -0500699 try {
Jorim Jaggi86905582016-02-09 21:36:09 -0800700 mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
701 fullscreenStackBounds, dockedStackBounds);
Joe Onorato2314aab2010-04-08 16:41:23 -0500702 } catch (RemoteException ex) {
703 // If the system process isn't there we're doomed anyway.
704 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400705
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500706 createAndAddWindows();
Joe Onorato0cbda992010-05-02 16:28:15 -0700707
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100708 mSettingsObserver.onChange(false); // set up
Benjamin Franzcde0a2a2015-04-23 17:19:48 +0100709 disable(switches[0], switches[6], false /* animate */);
Jorim Jaggi86905582016-02-09 21:36:09 -0800710 setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
711 fullscreenStackBounds, dockedStackBounds);
Dianne Hackborn7d049322011-06-14 15:00:32 -0700712 topAppWindowChanged(switches[2] != 0);
satokcd7cd292010-11-20 15:46:23 +0900713 // StatusBarManagerService has a back up of IME token and it's restored here.
Michael Wright665366a2014-08-07 15:44:40 -0700714 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
Joe Onorato93056472010-09-10 10:30:46 -0400715
Joe Onorato0cbda992010-05-02 16:28:15 -0700716 // Set up the initial icon state
Jason Monk07473ce2016-01-05 14:59:19 -0500717 int N = iconSlots.size();
Joe Onorato0cbda992010-05-02 16:28:15 -0700718 int viewIndex = 0;
Jason Monk07473ce2016-01-05 14:59:19 -0500719 for (int i=0; i < N; i++) {
720 setIcon(iconSlots.get(i), icons.get(i));
Joe Onorato0cbda992010-05-02 16:28:15 -0700721 }
722
Christoph Studer71f18fd2014-05-20 17:02:04 +0200723 // Set up the initial notification state.
Christoph Studere71fefc2014-06-24 16:16:49 +0200724 try {
Christoph Studer4600f9b2014-07-22 22:44:43 +0200725 mNotificationListener.registerAsSystemService(mContext,
Christoph Studere71fefc2014-06-24 16:16:49 +0200726 new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
727 UserHandle.USER_ALL);
728 } catch (RemoteException e) {
729 Log.e(TAG, "Unable to register notification listener", e);
Joe Onorato75199e32010-05-29 17:22:51 -0400730 }
731
Christoph Studer60748e72014-05-22 16:51:41 +0200732
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500733 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400734 Log.d(TAG, String.format(
Daniel Sandler6a858c32012-03-12 14:38:58 -0400735 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
Jason Monk07473ce2016-01-05 14:59:19 -0500736 icons.size(),
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500737 switches[0],
738 switches[1],
739 switches[2],
740 switches[3]
741 ));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400742 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400743
Christopher Tate5e08af02012-09-21 17:17:22 -0700744 mCurrentUserId = ActivityManager.getCurrentUser();
Chris Wrena6d4fb62014-11-20 14:46:23 -0500745 setHeadsUpUser(mCurrentUserId);
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400746
747 IntentFilter filter = new IntentFilter();
748 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000749 filter.addAction(Intent.ACTION_USER_ADDED);
Kenny Guydae30d52015-04-01 19:11:35 +0100750 filter.addAction(Intent.ACTION_USER_PRESENT);
John Spurlock5c454122013-06-17 07:35:46 -0400751 mContext.registerReceiver(mBroadcastReceiver, filter);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000752
Ricky Wai7fa01712016-03-16 12:13:54 +0000753 IntentFilter internalFilter = new IntentFilter();
754 internalFilter.addAction(WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
755 internalFilter.addAction(BANNER_ACTION_CANCEL);
756 internalFilter.addAction(BANNER_ACTION_SETUP);
757 mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
758
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000759 IntentFilter allUsersFilter = new IntentFilter();
760 allUsersFilter.addAction(
761 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
762 mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
763 null, null);
Kenny Guy2a764942014-04-02 13:29:20 +0100764 updateCurrentProfilesCache();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400765 }
766
Chris Wrencd8f4f72014-08-27 18:48:13 -0400767 protected void notifyUserAboutHiddenNotifications() {
768 if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
769 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
770 Log.d(TAG, "user hasn't seen notification about hidden notifications");
Ricky Wai7fa01712016-03-16 12:13:54 +0000771 if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
Chris Wrencd8f4f72014-08-27 18:48:13 -0400772 Log.d(TAG, "insecure lockscreen, skipping notification");
773 Settings.Secure.putInt(mContext.getContentResolver(),
774 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
775 return;
776 }
777 Log.d(TAG, "disabling lockecreen notifications and alerting the user");
778 // disable lockscreen notifications until user acts on the banner.
779 Settings.Secure.putInt(mContext.getContentResolver(),
780 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
Adrian Roosaee70462014-09-03 16:27:39 +0200781 Settings.Secure.putInt(mContext.getContentResolver(),
782 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400783
784 final String packageName = mContext.getPackageName();
785 PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
786 new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
787 PendingIntent.FLAG_CANCEL_CURRENT);
788 PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
789 new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
790 PendingIntent.FLAG_CANCEL_CURRENT);
791
792 final Resources res = mContext.getResources();
793 final int colorRes = com.android.internal.R.color.system_notification_accent_color;
794 Notification.Builder note = new Notification.Builder(mContext)
795 .setSmallIcon(R.drawable.ic_android)
796 .setContentTitle(mContext.getString(R.string.hidden_notifications_title))
797 .setContentText(mContext.getString(R.string.hidden_notifications_text))
798 .setPriority(Notification.PRIORITY_HIGH)
799 .setOngoing(true)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700800 .setColor(mContext.getColor(colorRes))
Chris Wrencd8f4f72014-08-27 18:48:13 -0400801 .setContentIntent(setupIntent)
802 .addAction(R.drawable.ic_close,
803 mContext.getString(R.string.hidden_notifications_cancel),
804 cancelIntent)
805 .addAction(R.drawable.ic_settings,
806 mContext.getString(R.string.hidden_notifications_setup),
807 setupIntent);
808
809 NotificationManager noMan =
810 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500811 noMan.notify(R.id.notification_hidden, note.build());
Chris Wrencd8f4f72014-08-27 18:48:13 -0400812 }
813 }
814
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400815 public void userSwitched(int newUserId) {
Chris Wrena6d4fb62014-11-20 14:46:23 -0500816 setHeadsUpUser(newUserId);
817 }
818
Selim Cinek29fa89b2015-04-17 10:39:11 -0700819 protected abstract void setHeadsUpUser(int newUserId);
Chris Wrend04f6ce2014-06-11 17:37:28 -0400820
Christoph Studerc8db24b2014-07-25 17:50:30 +0200821 @Override // NotificationData.Environment
822 public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400823 final int thisUserId = mCurrentUserId;
824 final int notificationUserId = n.getUserId();
825 if (DEBUG && MULTIUSER_DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400826 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400827 n, thisUserId, notificationUserId));
828 }
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500829 return isCurrentProfile(notificationUserId);
Joe Onorato2314aab2010-04-08 16:41:23 -0500830 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400831
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700832 protected void setNotificationShown(StatusBarNotification n) {
Chris Wren26505582015-07-22 17:03:17 -0400833 setNotificationsShown(new String[]{n.getKey()});
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700834 }
835
836 protected void setNotificationsShown(String[] keys) {
Chris Wren26505582015-07-22 17:03:17 -0400837 try {
838 mNotificationListener.setNotificationsShown(keys);
839 } catch (RuntimeException e) {
840 Log.d(TAG, "failed setNotificationsShown: ", e);
841 }
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700842 }
843
Kenny Guy44fc65f2014-11-28 22:18:14 +0000844 protected boolean isCurrentProfile(int userId) {
845 synchronized (mCurrentProfiles) {
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500846 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
Kenny Guy44fc65f2014-11-28 22:18:14 +0000847 }
848 }
849
Christoph Studer2e731b52014-08-22 16:01:51 +0200850 @Override
851 public String getCurrentMediaNotificationKey() {
852 return null;
853 }
854
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100855 @Override
856 public NotificationGroupManager getGroupManager() {
857 return mGroupManager;
858 }
859
Adrian Roos7d7090d2014-05-21 13:10:23 +0200860 /**
861 * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
862 * @param action A dismiss action that is called if it's safe to start the activity.
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200863 * @param afterKeyguardGone Whether the action should be executed after the Keyguard is gone.
Adrian Roos7d7090d2014-05-21 13:10:23 +0200864 */
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200865 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200866 action.onDismiss();
867 }
868
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700869 @Override
870 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400871 final Locale locale = mContext.getResources().getConfiguration().locale;
872 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
Dan Sandler539aad42014-08-04 00:43:39 -0400873 final float fontScale = newConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800874 final int density = newConfig.densityDpi;
875 if (density != mDensity || mFontScale != fontScale) {
876 reInflateViews();
877 mDensity = density;
878 mFontScale = fontScale;
879 }
880 if (! locale.equals(mLocale) || ld != mLayoutDirection) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400881 if (DEBUG) {
882 Log.v(TAG, String.format(
883 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
884 locale, ld));
885 }
886 mLocale = locale;
887 mLayoutDirection = ld;
888 refreshLayout(ld);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700889 }
890 }
891
Selim Cinek01af3342016-02-09 19:25:31 -0800892 protected void reInflateViews() {
893 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
894 for (int i = 0; i < activeNotifications.size(); i++) {
895 Entry entry = activeNotifications.get(i);
896 boolean exposedGuts = entry.row.getGuts() == mNotificationGutsExposed;
897 entry.row.reInflateViews();
898 if (exposedGuts) {
899 mNotificationGutsExposed = entry.row.getGuts();
900 bindGuts(entry.row);
901 }
902 entry.cacheContentViews(mContext, null /* updatedNotification */);
903 inflateViews(entry, mStackScroller);
904 }
905 }
906
Selim Cinek757d8792016-01-28 16:21:08 -0800907 protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
Winson Chungc57ccf02011-10-13 15:04:59 -0700908 View vetoButton = row.findViewById(R.id.veto);
Selim Cinek757d8792016-01-28 16:21:08 -0800909 final String _pkg = n.getPackageName();
910 final String _tag = n.getTag();
911 final int _id = n.getId();
912 final int _userId = n.getUserId();
913 vetoButton.setOnClickListener(new View.OnClickListener() {
914 public void onClick(View v) {
915 // Accessibility feedback
916 v.announceForAccessibility(
917 mContext.getString(R.string.accessibility_notification_dismissed));
918 try {
919 mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700920
Selim Cinek757d8792016-01-28 16:21:08 -0800921 } catch (RemoteException ex) {
922 // system process is dead if we're here.
923 }
924 }
925 });
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700926 vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
Winson Chungc57ccf02011-10-13 15:04:59 -0700927 return vetoButton;
928 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400929
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400930
Christoph Studer13b895122014-08-26 15:42:12 +0200931 protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
Jorim Jaggi46739852014-04-15 09:58:24 +0200932 NotificationData.Entry entry) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400933
Selim Cinek684a4422015-04-15 16:18:39 -0700934 if (entry.getContentView().getId()
935 != com.android.internal.R.id.status_bar_latest_event_content) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400936 // Using custom RemoteViews
Jorim Jaggia1eeade2014-09-08 22:34:39 +0200937 if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700938 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
Selim Cinek697178b2014-07-02 19:40:30 +0200939 entry.row.setShowingLegacyBackground(true);
Jorim Jaggi36b15232014-06-10 17:24:20 +0200940 entry.legacy = true;
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400941 }
942 }
Christoph Studer13b895122014-08-26 15:42:12 +0200943
944 if (entry.icon != null) {
Jorim Jaggidd0107a2015-01-21 22:23:48 +0100945 entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
Christoph Studer13b895122014-08-26 15:42:12 +0200946 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400947 }
948
Dan Sandler16128f42014-05-21 12:48:22 -0400949 public boolean isMediaNotification(NotificationData.Entry entry) {
Dan Sandler842dd772014-05-15 09:36:47 -0400950 // TODO: confirm that there's a valid media key
Selim Cinek684a4422015-04-15 16:18:39 -0700951 return entry.getExpandedContentView() != null &&
952 entry.getExpandedContentView()
953 .findViewById(com.android.internal.R.id.media_actions) != null;
Dan Sandler842dd772014-05-15 09:36:47 -0400954 }
955
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200956 // The (i) button in the guts that links to the system notification settings for that app
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200957 private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
958 final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
Dan Sandlere9a4e902014-07-31 01:06:43 -0400959 intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
960 intent.putExtra(Settings.EXTRA_APP_UID, appUid);
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200961 startNotificationGutsIntent(intent, appUid);
962 }
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200963
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200964 private void startNotificationGutsIntent(final Intent intent, final int appUid) {
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200965 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
966 dismissKeyguardThenExecute(new OnDismissAction() {
967 @Override
968 public boolean onDismiss() {
969 AsyncTask.execute(new Runnable() {
970 public void run() {
971 try {
972 if (keyguardShowing) {
973 ActivityManagerNative.getDefault()
974 .keyguardWaitingForActivityDrawn();
975 }
976 TaskStackBuilder.create(mContext)
977 .addNextIntentWithParentStack(intent)
978 .startActivities(null,
979 new UserHandle(UserHandle.getUserId(appUid)));
980 overrideActivityPendingAppTransition(keyguardShowing);
981 } catch (RemoteException e) {
982 }
983 }
984 });
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100985 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200986 return true;
987 }
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200988 }, false /* afterKeyguardGone */);
Dan Sandler4247a5c2014-07-23 15:58:08 -0400989 }
990
Mady Mellorb53bc272016-02-11 18:28:23 -0800991 private void bindGuts(final ExpandableNotificationRow row) {
Selim Cinekab29aeb2015-02-20 18:18:32 +0100992 row.inflateGuts();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200993 final StatusBarNotification sbn = row.getStatusBarNotification();
Selim Cinekeef84282015-10-30 16:28:00 -0700994 PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200995 row.setTag(sbn.getPackageName());
Julia Reynoldsa07af882015-12-17 08:32:48 -0500996 final NotificationGuts guts = row.getGuts();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200997 final String pkg = sbn.getPackageName();
998 String appname = pkg;
999 Drawable pkgicon = null;
1000 int appUid = -1;
1001 try {
1002 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
1003 PackageManager.GET_UNINSTALLED_PACKAGES
1004 | PackageManager.GET_DISABLED_COMPONENTS);
1005 if (info != null) {
1006 appname = String.valueOf(pmUser.getApplicationLabel(info));
1007 pkgicon = pmUser.getApplicationIcon(info);
1008 appUid = info.uid;
1009 }
1010 } catch (NameNotFoundException e) {
1011 // app is gone, just show package name and generic icon
1012 pkgicon = pmUser.getDefaultActivityIcon();
1013 }
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001014
Julia Reynoldsbe018462016-03-01 12:22:48 -05001015 ((ImageView) row.findViewById(R.id.app_icon)).setImageDrawable(pkgicon);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001016 ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001017
Julia Reynolds56821922016-01-04 15:24:01 -05001018 final View settingsButton = guts.findViewById(R.id.more_settings);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001019 if (appUid >= 0) {
1020 final int appUidF = appUid;
1021 settingsButton.setOnClickListener(new View.OnClickListener() {
1022 public void onClick(View v) {
Chris Wrenf6e9228b2016-01-26 18:04:35 -05001023 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001024 startAppNotificationSettingsActivity(pkg, appUidF);
1025 }
1026 });
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001027 } else {
1028 settingsButton.setVisibility(View.GONE);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001029 }
1030
Julia Reynolds56821922016-01-04 15:24:01 -05001031 row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
1032 @Override
1033 public void onClick(View v) {
Julia Reynolds0714f622016-01-07 13:24:09 -05001034 guts.saveImportance(sbn);
Mady Mellorb53bc272016-02-11 18:28:23 -08001035
1036 int[] rowLocation = new int[2];
1037 int[] doneLocation = new int[2];
1038 row.getLocationOnScreen(rowLocation);
1039 v.getLocationOnScreen(doneLocation);
1040
1041 final int centerX = v.getWidth() / 2;
1042 final int centerY = v.getHeight() / 2;
1043 final int x = doneLocation[0] - rowLocation[0] + centerX;
1044 final int y = doneLocation[1] - rowLocation[1] + centerY;
1045 dismissPopups(x, y);
Julia Reynolds56821922016-01-04 15:24:01 -05001046 }
1047 });
1048
Julia Reynolds40779452016-02-23 13:43:32 -05001049 guts.bindImportance(pmUser, sbn, row, mNotificationData.getImportance(sbn.getKey()));
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001050 }
1051
Mady Mellor4b80b102016-01-22 08:03:58 -08001052 protected GearDisplayedListener getGearDisplayedListener() {
1053 return this;
1054 }
1055
Dan Sandler4247a5c2014-07-23 15:58:08 -04001056 protected SwipeHelper.LongPressListener getNotificationLongClicker() {
1057 return new SwipeHelper.LongPressListener() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001058 @Override
Selim Cinekd84a5932015-12-15 11:45:36 -08001059 public boolean onLongPress(View v, final int x, final int y) {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001060 if (!(v instanceof ExpandableNotificationRow)) {
1061 return false;
1062 }
Selim Cinekabdc5a02014-09-02 13:46:00 +02001063 if (v.getWindowToken() == null) {
1064 Log.e(TAG, "Trying to show notification guts, but not attached to window");
1065 return false;
1066 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001067
Mady Mellor4b80b102016-01-22 08:03:58 -08001068 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
Selim Cinekab29aeb2015-02-20 18:18:32 +01001069 bindGuts(row);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001070
Dan Sandler4247a5c2014-07-23 15:58:08 -04001071 // Assume we are a status_bar_notification_row
Selim Cinekab29aeb2015-02-20 18:18:32 +01001072 final NotificationGuts guts = row.getGuts();
Selim Cinekbdefcdf2014-09-11 12:41:47 +02001073 if (guts == null) {
1074 // This view has no guts. Examples are the more card or the dismiss all view
1075 return false;
1076 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001077
1078 // Already showing?
Selim Cinekabdc5a02014-09-02 13:46:00 +02001079 if (guts.getVisibility() == View.VISIBLE) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001080 dismissPopups(x, y);
Selim Cinekabdc5a02014-09-02 13:46:00 +02001081 return false;
1082 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001083
Chris Wrenf6e9228b2016-01-26 18:04:35 -05001084 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001085
Julia Reynolds40779452016-02-23 13:43:32 -05001086 // ensure that it's laid but not visible until actually laid out
Selim Cinekd84a5932015-12-15 11:45:36 -08001087 guts.setVisibility(View.INVISIBLE);
Julia Reynolds40779452016-02-23 13:43:32 -05001088 // Post to ensure the the guts are properly laid out.
Selim Cinekd84a5932015-12-15 11:45:36 -08001089 guts.post(new Runnable() {
1090 public void run() {
Mady Mellorb53bc272016-02-11 18:28:23 -08001091 dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001092 guts.setVisibility(View.VISIBLE);
1093 final double horz = Math.max(guts.getWidth() - x, x);
1094 final double vert = Math.max(guts.getHeight() - y, y);
1095 final float r = (float) Math.hypot(horz, vert);
1096 final Animator a
1097 = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
1098 a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc18010f2016-01-20 13:41:30 -08001099 a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Mady Mellor4b80b102016-01-22 08:03:58 -08001100 a.addListener(new AnimatorListenerAdapter() {
1101 @Override
1102 public void onAnimationEnd(Animator animation) {
1103 super.onAnimationEnd(animation);
1104 // Move the notification view back over the gear
1105 row.resetTranslation();
1106 }
1107 });
Selim Cinekd84a5932015-12-15 11:45:36 -08001108 a.start();
1109 guts.setExposed(true);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001110 row.closeRemoteInput();
Selim Cinekd84a5932015-12-15 11:45:36 -08001111 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
1112 mNotificationGutsExposed = guts;
1113 }
1114 });
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001115 return true;
1116 }
1117 };
1118 }
1119
Mady Mellor4b80b102016-01-22 08:03:58 -08001120 @Override
1121 public void onGearDisplayed(ExpandableNotificationRow row) {
Mady Mellora41587b2016-02-11 18:43:06 -08001122 MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
1123 row.getStatusBarNotification().getPackageName());
Mady Mellor4b80b102016-01-22 08:03:58 -08001124 mNotificationGearDisplayed = row;
1125 }
1126
Daniel Sandler469e96e2012-05-04 15:56:19 -04001127 public void dismissPopups() {
Mady Mellorb53bc272016-02-11 18:28:23 -08001128 dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001129 }
1130
1131 private void dismissPopups(int x, int y) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001132 dismissPopups(x, y, true /* resetGear */);
1133 }
1134
1135 public void dismissPopups(int x, int y, boolean resetGear) {
Dan Sandler4247a5c2014-07-23 15:58:08 -04001136 if (mNotificationGutsExposed != null) {
Selim Cinek024ca592014-09-01 15:11:28 +02001137 final NotificationGuts v = mNotificationGutsExposed;
Dan Sandler4247a5c2014-07-23 15:58:08 -04001138 mNotificationGutsExposed = null;
1139
Selim Cinekedb893b2014-09-02 12:51:31 +02001140 if (v.getWindowToken() == null) return;
Selim Cinekd84a5932015-12-15 11:45:36 -08001141 if (x == -1 || y == -1) {
1142 x = (v.getLeft() + v.getRight()) / 2;
1143 y = (v.getTop() + v.getHeight() / 2);
1144 }
1145 final double horz = Math.max(v.getWidth() - x, x);
1146 final double vert = Math.max(v.getHeight() - y, y);
1147 final float r = (float) Math.hypot(horz, vert);
Dan Sandler4247a5c2014-07-23 15:58:08 -04001148 final Animator a = ViewAnimationUtils.createCircularReveal(v,
Selim Cinekd84a5932015-12-15 11:45:36 -08001149 x, y, r, 0);
1150 a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc18010f2016-01-20 13:41:30 -08001151 a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
Dan Sandler4247a5c2014-07-23 15:58:08 -04001152 a.addListener(new AnimatorListenerAdapter() {
1153 @Override
1154 public void onAnimationEnd(Animator animation) {
1155 super.onAnimationEnd(animation);
1156 v.setVisibility(View.GONE);
1157 }
1158 });
1159 a.start();
Selim Cinekd84a5932015-12-15 11:45:36 -08001160 v.setExposed(false);
1161 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
Daniel Sandler469e96e2012-05-04 15:56:19 -04001162 }
Mady Mellorb53bc272016-02-11 18:28:23 -08001163 if (resetGear && mNotificationGearDisplayed != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001164 mNotificationGearDisplayed.resetTranslation();
1165 mNotificationGearDisplayed = null;
1166 }
Daniel Sandler469e96e2012-05-04 15:56:19 -04001167 }
1168
Michael Jurka7f2668c2012-03-27 07:49:52 -07001169 @Override
Winson Chung1e8d71b2014-05-16 17:05:22 -07001170 public void showRecentApps(boolean triggeredFromAltTab) {
1171 int msg = MSG_SHOW_RECENT_APPS;
1172 mHandler.removeMessages(msg);
1173 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, 0).sendToTarget();
1174 }
1175
1176 @Override
Winson Chungcdcd4872014-08-05 18:00:13 -07001177 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001178 int msg = MSG_HIDE_RECENT_APPS;
1179 mHandler.removeMessages(msg);
Winson Chungcdcd4872014-08-05 18:00:13 -07001180 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0,
1181 triggeredFromHomeKey ? 1 : 0).sendToTarget();
Winson Chung1e8d71b2014-05-16 17:05:22 -07001182 }
1183
1184 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001185 public void toggleRecentApps() {
Jorim Jaggi900fb482015-06-02 15:07:33 -07001186 toggleRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001187 }
1188
1189 @Override
Phil Weaver315c34e2016-02-19 15:12:29 -08001190 public void toggleSplitScreen() {
1191 toggleSplitScreenMode();
1192 }
1193
1194 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001195 public void preloadRecentApps() {
1196 int msg = MSG_PRELOAD_RECENT_APPS;
1197 mHandler.removeMessages(msg);
1198 mHandler.sendEmptyMessage(msg);
1199 }
1200
1201 @Override
1202 public void cancelPreloadRecentApps() {
1203 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
1204 mHandler.removeMessages(msg);
1205 mHandler.sendEmptyMessage(msg);
1206 }
1207
Clara Bayarrif2debb12015-07-10 14:47:17 +01001208 @Override
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001209 public void toggleKeyboardShortcutsMenu(int deviceId) {
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001210 int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
Clara Bayarrif2debb12015-07-10 14:47:17 +01001211 mHandler.removeMessages(msg);
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001212 mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
Clara Bayarrif2debb12015-07-10 14:47:17 +01001213 }
1214
Winson Chungb1f74992014-08-08 12:53:09 -07001215 /** Jumps to the next affiliated task in the group. */
1216 public void showNextAffiliatedTask() {
1217 int msg = MSG_SHOW_NEXT_AFFILIATED_TASK;
1218 mHandler.removeMessages(msg);
1219 mHandler.sendEmptyMessage(msg);
1220 }
1221
1222 /** Jumps to the previous affiliated task in the group. */
1223 public void showPreviousAffiliatedTask() {
1224 int msg = MSG_SHOW_PREV_AFFILIATED_TASK;
1225 mHandler.removeMessages(msg);
1226 mHandler.sendEmptyMessage(msg);
1227 }
1228
Michael Jurkaecc395a2012-03-30 05:31:46 -07001229 protected H createHandler() {
Michael Jurka7f2668c2012-03-27 07:49:52 -07001230 return new H();
1231 }
1232
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001233 protected void sendCloseSystemWindows(String reason) {
Michael Jurka56a57832012-05-14 13:24:43 -07001234 if (ActivityManagerNative.isSystemReady()) {
1235 try {
1236 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
1237 } catch (RemoteException e) {
1238 }
1239 }
1240 }
1241
Michael Jurkacb2522c2012-04-13 09:32:47 -07001242 protected abstract View getStatusBarView();
1243
Michael Jurka80343f62012-10-18 13:13:46 +02001244 protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
1245 // additional optimization when we have software system buttons - start loading the recent
1246 // tasks on touch down
1247 @Override
1248 public boolean onTouch(View v, MotionEvent event) {
1249 int action = event.getAction() & MotionEvent.ACTION_MASK;
1250 if (action == MotionEvent.ACTION_DOWN) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001251 preloadRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001252 } else if (action == MotionEvent.ACTION_CANCEL) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001253 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001254 } else if (action == MotionEvent.ACTION_UP) {
1255 if (!v.isPressed()) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001256 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001257 }
1258
1259 }
1260 return false;
1261 }
1262 };
1263
Phil Weaver315c34e2016-02-19 15:12:29 -08001264 /**
1265 * Toggle docking the app window
1266 *
1267 * @return {@code true} if the app window is docked after the toggle, {@code false} otherwise.
1268 */
1269 protected abstract boolean toggleSplitScreenMode();
1270
Winson Chung1e8d71b2014-05-16 17:05:22 -07001271 /** Proxy for RecentsComponent */
1272
1273 protected void showRecents(boolean triggeredFromAltTab) {
1274 if (mRecents != null) {
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001275 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001276 mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
1277 }
1278 }
1279
Winson Chungcdcd4872014-08-05 18:00:13 -07001280 protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001281 if (mRecents != null) {
Winson Chungcdcd4872014-08-05 18:00:13 -07001282 mRecents.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001283 }
1284 }
1285
1286 protected void toggleRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001287 if (mRecents != null) {
1288 mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
1289 }
1290 }
Michael Jurka80343f62012-10-18 13:13:46 +02001291
Winson Chung1e8d71b2014-05-16 17:05:22 -07001292 protected void preloadRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001293 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001294 mRecents.preloadRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001295 }
Michael Jurka80343f62012-10-18 13:13:46 +02001296 }
1297
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001298 protected void toggleKeyboardShortcuts(int deviceId) {
1299 getKeyboardShortcuts().toggleKeyboardShortcuts(deviceId);
Clara Bayarrif2debb12015-07-10 14:47:17 +01001300 }
1301
Winson Chung1e8d71b2014-05-16 17:05:22 -07001302 protected void cancelPreloadingRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001303 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001304 mRecents.cancelPreloadingRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001305 }
Michael Jurka80343f62012-10-18 13:13:46 +02001306 }
1307
Winson Chungb1f74992014-08-08 12:53:09 -07001308 protected void showRecentsNextAffiliatedTask() {
1309 if (mRecents != null) {
1310 mRecents.showNextAffiliatedTask();
1311 }
1312 }
1313
1314 protected void showRecentsPreviousAffiliatedTask() {
1315 if (mRecents != null) {
1316 mRecents.showPrevAffiliatedTask();
1317 }
1318 }
1319
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001320 /**
Selim Cinek684a4422015-04-15 16:18:39 -07001321 * If there is an active heads-up notification and it has a fullscreen intent, fire it now.
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001322 */
Selim Cinek684a4422015-04-15 16:18:39 -07001323 public abstract void maybeEscalateHeadsUp();
Chris Wrena4ef6202014-06-09 18:07:30 -04001324
Dan Sandlerfd16d562014-02-13 18:43:31 -08001325 /**
1326 * Save the current "public" (locked and secure) state of the lockscreen.
1327 */
1328 public void setLockscreenPublicMode(boolean publicMode) {
1329 mLockscreenPublicMode = publicMode;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001330 }
1331
Dan Sandlerfd16d562014-02-13 18:43:31 -08001332 public boolean isLockscreenPublicMode() {
1333 return mLockscreenPublicMode;
1334 }
1335
1336 /**
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001337 * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
1338 * "public" (secure & locked) mode?
1339 */
1340 public boolean userAllowsNotificationsInPublic(int userHandle) {
1341 if (userHandle == UserHandle.USER_ALL) {
1342 return true;
1343 }
1344
1345 if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
1346 final boolean allowed = 0 != Settings.Secure.getIntForUser(
1347 mContext.getContentResolver(),
1348 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
1349 mUsersAllowingNotifications.append(userHandle, allowed);
1350 return allowed;
1351 }
1352
1353 return mUsersAllowingNotifications.get(userHandle);
1354 }
1355
1356 /**
Dan Sandlerfd16d562014-02-13 18:43:31 -08001357 * Has the given user chosen to allow their private (full) notifications to be shown even
1358 * when the lockscreen is in "public" (secure & locked) mode?
1359 */
1360 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
1361 if (userHandle == UserHandle.USER_ALL) {
1362 return true;
1363 }
1364
1365 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001366 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
Dan Sandlerfd16d562014-02-13 18:43:31 -08001367 mContext.getContentResolver(),
1368 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001369 final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001370 final boolean allowed = allowedByUser && allowedByDpm;
1371 mUsersAllowingPrivateNotifications.append(userHandle, allowed);
Dan Sandlerfd16d562014-02-13 18:43:31 -08001372 return allowed;
1373 }
1374
1375 return mUsersAllowingPrivateNotifications.get(userHandle);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001376 }
1377
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001378 private boolean adminAllowsUnredactedNotifications(int userHandle) {
1379 if (userHandle == UserHandle.USER_ALL) {
1380 return true;
1381 }
1382 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
1383 userHandle);
1384 return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
1385 }
1386
Christoph Studerc8db24b2014-07-25 17:50:30 +02001387 /**
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001388 * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
1389 * If so, notifications should be hidden.
Christoph Studerc8db24b2014-07-25 17:50:30 +02001390 */
1391 @Override // NotificationData.Environment
Julia Reynolds26fa8a52016-02-24 08:31:22 -05001392 public boolean shouldHideNotifications(int userid) {
1393 return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
1394 }
1395
1396 /**
1397 * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
1398 * package-specific override.
1399 */
1400 @Override // NotificationDate.Environment
1401 public boolean shouldHideNotifications(String key) {
1402 return isLockscreenPublicMode()
1403 && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
1404 }
1405
1406 /**
1407 * Returns true if we're on a secure lockscreen.
1408 */
1409 @Override // NotificationData.Environment
1410 public boolean onSecureLockScreen() {
1411 return isLockscreenPublicMode();
Christoph Studerc8db24b2014-07-25 17:50:30 +02001412 }
1413
Chris Wrena4ef6202014-06-09 18:07:30 -04001414 public void onNotificationClear(StatusBarNotification notification) {
1415 try {
1416 mBarService.onNotificationClear(
1417 notification.getPackageName(),
1418 notification.getTag(),
1419 notification.getId(),
1420 notification.getUserId());
1421 } catch (android.os.RemoteException ex) {
1422 // oh well
1423 }
1424 }
1425
Selim Cinek5f71bee2015-11-18 10:25:23 -08001426 /**
Selim Cinek5fbc6322016-01-15 17:17:58 -08001427 * Called when the notification panel layouts
Selim Cinek5f71bee2015-11-18 10:25:23 -08001428 */
Selim Cinek5fbc6322016-01-15 17:17:58 -08001429 public void onPanelLaidOut() {
Selim Cinek5f71bee2015-11-18 10:25:23 -08001430 if (mState == StatusBarState.KEYGUARD) {
1431 // Since the number of notifications is determined based on the height of the view, we
1432 // need to update them.
Selim Cinek5fbc6322016-01-15 17:17:58 -08001433 int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
1434 int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
1435 if (maxBefore != maxNotifications) {
1436 updateRowStates();
1437 }
Selim Cinek5f71bee2015-11-18 10:25:23 -08001438 }
1439 }
1440
Adrian Roos3aec6382016-02-05 14:19:01 -08001441 protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
1442
Selim Cinek570981d2015-12-01 11:37:01 -08001443 @Override
Selim Cinek31aada42015-12-18 17:51:15 -08001444 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
Selim Cinek570981d2015-12-01 11:37:01 -08001445 }
1446
Michael Jurka7f2668c2012-03-27 07:49:52 -07001447 protected class H extends Handler {
1448 public void handleMessage(Message m) {
1449 switch (m.what) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001450 case MSG_SHOW_RECENT_APPS:
1451 showRecents(m.arg1 > 0);
Michael Jurkacb2522c2012-04-13 09:32:47 -07001452 break;
Winson Chung1e8d71b2014-05-16 17:05:22 -07001453 case MSG_HIDE_RECENT_APPS:
Winson Chungcdcd4872014-08-05 18:00:13 -07001454 hideRecents(m.arg1 > 0, m.arg2 > 0);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001455 break;
1456 case MSG_TOGGLE_RECENTS_APPS:
1457 toggleRecents();
Michael Jurkacb2522c2012-04-13 09:32:47 -07001458 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001459 case MSG_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001460 preloadRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001461 break;
1462 case MSG_CANCEL_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001463 cancelPreloadingRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001464 break;
Winson Chungb1f74992014-08-08 12:53:09 -07001465 case MSG_SHOW_NEXT_AFFILIATED_TASK:
1466 showRecentsNextAffiliatedTask();
1467 break;
1468 case MSG_SHOW_PREV_AFFILIATED_TASK:
1469 showRecentsPreviousAffiliatedTask();
1470 break;
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001471 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
Clara Bayarri4e850ff2016-03-02 11:12:32 -08001472 toggleKeyboardShortcuts(m.arg1);
Clara Bayarrif2debb12015-07-10 14:47:17 +01001473 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001474 }
1475 }
1476 }
1477
Daniel Sandler6a858c32012-03-12 14:38:58 -04001478 protected void workAroundBadLayerDrawableOpacity(View v) {
1479 }
1480
Selim Cinek8d490d42015-04-10 00:05:50 -07001481 protected boolean inflateViews(Entry entry, ViewGroup parent) {
Selim Cinekeef84282015-10-30 16:28:00 -07001482 PackageManager pmUser = getPackageManagerForUser(mContext,
Dan Sandlere9a4e902014-07-31 01:06:43 -04001483 entry.notification.getUser().getIdentifier());
1484
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001485 final StatusBarNotification sbn = entry.notification;
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001486 entry.cacheContentViews(mContext, null);
1487
1488 final RemoteViews contentView = entry.cachedContentView;
1489 final RemoteViews bigContentView = entry.cachedBigContentView;
1490 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
1491 final RemoteViews publicContentView = entry.cachedPublicContentView;
Chris Wren8fd39ec2014-02-27 17:43:26 -05001492
Chris Wren574a55e2013-07-15 18:48:37 -04001493 if (contentView == null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001494 Log.v(TAG, "no contentView for: " + sbn.getNotification());
Daniel Sandler6a858c32012-03-12 14:38:58 -04001495 return false;
1496 }
1497
Dan Sandlerf68448e2014-04-24 15:54:16 -04001498 if (DEBUG) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001499 Log.v(TAG, "publicContentView: " + publicContentView);
Dan Sandlerf68448e2014-04-24 15:54:16 -04001500 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001501
Christoph Studera7fe6312014-06-27 19:32:44 +02001502 ExpandableNotificationRow row;
1503
1504 // Stash away previous user expansion state so we can restore it at
1505 // the end.
1506 boolean hasUserChangedExpansion = false;
1507 boolean userExpanded = false;
1508 boolean userLocked = false;
1509
1510 if (entry.row != null) {
1511 row = entry.row;
1512 hasUserChangedExpansion = row.hasUserChangedExpansion();
1513 userExpanded = row.isUserExpanded();
1514 userLocked = row.isUserLocked();
Christoph Studer22f2ee52014-07-29 22:57:21 +02001515 entry.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +02001516 if (hasUserChangedExpansion) {
1517 row.setUserExpanded(userExpanded);
1518 }
1519 } else {
1520 // create the row view
1521 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
1522 Context.LAYOUT_INFLATER_SERVICE);
1523 row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
1524 parent, false);
Chris Wren78403d72014-07-28 10:23:24 +01001525 row.setExpansionLogger(this, entry.notification.getKey());
Selim Cinekb5605e52015-02-20 18:21:41 +01001526 row.setGroupManager(mGroupManager);
Selim Cinek31aada42015-12-18 17:51:15 -08001527 row.setHeadsUpManager(mHeadsUpManager);
Adrian Roosb88b1a12015-12-09 18:51:05 -08001528 row.setRemoteInputController(mRemoteInputController);
Selim Cinek570981d2015-12-01 11:37:01 -08001529 row.setOnExpandClickListener(this);
Mady Mellor3fd273e2016-03-15 21:08:14 -07001530
1531 // Get the app name
1532 final String pkg = sbn.getPackageName();
1533 String appname = pkg;
1534 try {
1535 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
1536 PackageManager.GET_UNINSTALLED_PACKAGES
1537 | PackageManager.GET_DISABLED_COMPONENTS);
1538 if (info != null) {
1539 appname = String.valueOf(pmUser.getApplicationLabel(info));
1540 }
1541 } catch (NameNotFoundException e) {
1542 // Do nothing
1543 }
1544 row.setAppName(appname);
Christoph Studera7fe6312014-06-27 19:32:44 +02001545 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001546
Daniel Sandler6a858c32012-03-12 14:38:58 -04001547 workAroundBadLayerDrawableOpacity(row);
Selim Cinek757d8792016-01-28 16:21:08 -08001548 View vetoButton = bindVetoButtonClickListener(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001549 vetoButton.setContentDescription(mContext.getString(
1550 R.string.accessibility_remove_notification));
1551
1552 // NB: the large icon is now handled entirely by the template
1553
1554 // bind the click event to the content area
Selim Cinek8d490d42015-04-10 00:05:50 -07001555 NotificationContentView contentContainer = row.getPrivateLayout();
1556 NotificationContentView contentContainerPublic = row.getPublicLayout();
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001557
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001558 row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
Adrian Roos497ab022015-02-10 20:49:33 +01001559 if (ENABLE_REMOTE_INPUT) {
1560 row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
1561 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001562
Chris Wren42d5dd42015-05-01 10:39:26 -04001563 mNotificationClicker.register(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001564
Dan Sandlera5e0f412014-01-23 15:11:54 -05001565 // set up the adaptive layout
Chris Wren574a55e2013-07-15 18:48:37 -04001566 View contentViewLocal = null;
1567 View bigContentViewLocal = null;
Selim Cinek8d490d42015-04-10 00:05:50 -07001568 View headsUpContentViewLocal = null;
Selim Cinek624c02db2015-12-14 21:00:02 -08001569 View publicViewLocal = null;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001570 try {
Dan Sandler68079d52015-07-22 10:45:30 -04001571 contentViewLocal = contentView.apply(
1572 sbn.getPackageContext(mContext),
1573 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001574 mOnClickHandler);
Chris Wren574a55e2013-07-15 18:48:37 -04001575 if (bigContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001576 bigContentViewLocal = bigContentView.apply(
1577 sbn.getPackageContext(mContext),
1578 contentContainer,
Selim Cinek8d490d42015-04-10 00:05:50 -07001579 mOnClickHandler);
1580 }
1581 if (headsUpContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001582 headsUpContentViewLocal = headsUpContentView.apply(
1583 sbn.getPackageContext(mContext),
1584 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001585 mOnClickHandler);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001586 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001587 if (publicContentView != null) {
1588 publicViewLocal = publicContentView.apply(
1589 sbn.getPackageContext(mContext),
1590 contentContainerPublic, mOnClickHandler);
1591 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001592 }
1593 catch (RuntimeException e) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001594 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
John Spurlockcd686b52013-06-05 10:13:46 -04001595 Log.e(TAG, "couldn't inflate view for notification " + ident, e);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001596 return false;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001597 }
1598
Chris Wren574a55e2013-07-15 18:48:37 -04001599 if (contentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001600 contentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001601 contentContainer.setContractedChild(contentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001602 }
Chris Wren574a55e2013-07-15 18:48:37 -04001603 if (bigContentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001604 bigContentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001605 contentContainer.setExpandedChild(bigContentViewLocal);
1606 }
1607 if (headsUpContentViewLocal != null) {
1608 headsUpContentViewLocal.setIsRootNamespace(true);
1609 contentContainer.setHeadsUpChild(headsUpContentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001610 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001611 if (publicViewLocal != null) {
1612 publicViewLocal.setIsRootNamespace(true);
1613 contentContainerPublic.setContractedChild(publicViewLocal);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001614 }
1615
Jorim Jaggia1eeade2014-09-08 22:34:39 +02001616 // Extract target SDK version.
1617 try {
1618 ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
1619 entry.targetSdk = info.targetSdkVersion;
1620 } catch (NameNotFoundException ex) {
1621 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
1622 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001623 entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001624
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001625 if (MULTIUSER_DEBUG) {
1626 TextView debug = (TextView) row.findViewById(R.id.debug_info);
1627 if (debug != null) {
1628 debug.setVisibility(View.VISIBLE);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001629 debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId());
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001630 }
1631 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001632 entry.row = row;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001633 entry.row.setOnActivatedListener(this);
Selim Cinek684a4422015-04-15 16:18:39 -07001634 entry.row.setExpandable(bigContentViewLocal != null);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001635
Christoph Studer13b895122014-08-26 15:42:12 +02001636 applyColorsAndBackgrounds(sbn, entry);
Jorim Jaggi46739852014-04-15 09:58:24 +02001637
Christoph Studera7fe6312014-06-27 19:32:44 +02001638 // Restore previous flags.
1639 if (hasUserChangedExpansion) {
1640 // Note: setUserExpanded() conveniently ignores calls with
1641 // userExpanded=true if !isExpandable().
1642 row.setUserExpanded(userExpanded);
1643 }
1644 row.setUserLocked(userLocked);
Selim Cinekda42d652015-12-04 15:51:16 -08001645 row.onNotificationUpdated(entry);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001646 return true;
1647 }
1648
Adrian Roos497ab022015-02-10 20:49:33 +01001649 /**
1650 * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
1651 * via first-class API.
1652 *
1653 * TODO: Remove once enough apps specify remote inputs on their own.
1654 */
1655 private void processForRemoteInput(Notification n) {
1656 if (!ENABLE_REMOTE_INPUT) return;
1657
1658 if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
1659 (n.actions == null || n.actions.length == 0)) {
1660 Notification.Action viableAction = null;
1661 Notification.WearableExtender we = new Notification.WearableExtender(n);
1662
1663 List<Notification.Action> actions = we.getActions();
1664 final int numActions = actions.size();
1665
1666 for (int i = 0; i < numActions; i++) {
1667 Notification.Action action = actions.get(i);
Adrian Roosa3539cb2015-12-16 16:47:02 -08001668 if (action == null) {
1669 continue;
1670 }
Adrian Roos497ab022015-02-10 20:49:33 +01001671 RemoteInput[] remoteInputs = action.getRemoteInputs();
Adrian Roosa3539cb2015-12-16 16:47:02 -08001672 if (remoteInputs == null) {
1673 continue;
1674 }
1675 for (RemoteInput ri : remoteInputs) {
Adrian Roos497ab022015-02-10 20:49:33 +01001676 if (ri.getAllowFreeFormInput()) {
1677 viableAction = action;
1678 break;
1679 }
1680 }
1681 if (viableAction != null) {
1682 break;
1683 }
1684 }
1685
1686 if (viableAction != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001687 Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
1688 rebuilder.setActions(viableAction);
1689 rebuilder.build(); // will rewrite n
Adrian Roos497ab022015-02-10 20:49:33 +01001690 }
1691 }
1692 }
1693
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001694 protected KeyboardShortcuts getKeyboardShortcuts() {
1695 if (mKeyboardShortcuts == null) {
Andrei Stingaceanu8861cb02016-01-20 16:48:30 +00001696 mKeyboardShortcuts = new KeyboardShortcuts(mContext);
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001697 }
1698
1699 return mKeyboardShortcuts;
1700 }
1701
Adrian Roos62692b22015-09-11 17:46:23 -07001702 public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
1703 if (!isDeviceProvisioned()) return;
1704
1705 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
1706 final boolean afterKeyguardGone = intent.isActivity()
1707 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
1708 mCurrentUserId);
1709 dismissKeyguardThenExecute(new OnDismissAction() {
1710 public boolean onDismiss() {
1711 new Thread() {
1712 @Override
1713 public void run() {
1714 try {
1715 if (keyguardShowing && !afterKeyguardGone) {
1716 ActivityManagerNative.getDefault()
1717 .keyguardWaitingForActivityDrawn();
1718 }
1719
1720 // The intent we are sending is for the application, which
1721 // won't have permission to immediately start an activity after
1722 // the user switches to home. We know it is safe to do at this
1723 // point, so make sure new activity switches are now allowed.
1724 ActivityManagerNative.getDefault().resumeAppSwitches();
1725 } catch (RemoteException e) {
1726 }
Adrian Roos62692b22015-09-11 17:46:23 -07001727 try {
1728 intent.send();
1729 } catch (PendingIntent.CanceledException e) {
1730 // the stack trace isn't very helpful here.
1731 // Just log the exception message.
1732 Log.w(TAG, "Sending intent failed: " + e);
1733
1734 // TODO: Dismiss Keyguard.
1735 }
1736 if (intent.isActivity()) {
1737 mAssistManager.hideAssist();
1738 overrideActivityPendingAppTransition(keyguardShowing
1739 && !afterKeyguardGone);
1740 }
1741 }
1742 }.start();
1743
1744 // close the shade if it was open
1745 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
1746 true /* force */, true /* delayed */);
1747 visibilityChanged(false);
1748
1749 return true;
1750 }
1751 }, afterKeyguardGone);
1752 }
1753
Chris Wren42d5dd42015-05-01 10:39:26 -04001754 private final class NotificationClicker implements View.OnClickListener {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001755 public void onClick(final View v) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001756 if (!(v instanceof ExpandableNotificationRow)) {
1757 Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
1758 return;
1759 }
1760
1761 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
1762 final StatusBarNotification sbn = row.getStatusBarNotification();
1763 if (sbn == null) {
1764 Log.e(TAG, "NotificationClicker called on an unclickable notification,");
1765 return;
1766 }
1767
Mady Mellorf0625802016-02-11 18:03:48 -08001768 // Check if the notification is displaying the gear, if so slide notification back
1769 if (row.getSettingsRow() != null && row.getSettingsRow().isVisible()) {
1770 row.animateTranslateNotification(0);
1771 return;
1772 }
1773
Selim Cinekc6dd5212015-11-02 14:51:54 -08001774 Notification notification = sbn.getNotification();
1775 final PendingIntent intent = notification.contentIntent != null
1776 ? notification.contentIntent
1777 : notification.fullScreenIntent;
Chris Wren42d5dd42015-05-01 10:39:26 -04001778 final String notificationKey = sbn.getKey();
1779
Jorim Jaggi5eb67c22015-08-19 19:50:49 -07001780 // Mark notification for one frame.
1781 row.setJustClicked(true);
1782 DejankUtils.postAfterTraversal(new Runnable() {
1783 @Override
1784 public void run() {
1785 row.setJustClicked(false);
1786 }
1787 });
1788
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001789 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Chris Wren42d5dd42015-05-01 10:39:26 -04001790 final boolean afterKeyguardGone = intent.isActivity()
1791 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001792 mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +02001793 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001794 public boolean onDismiss() {
Chris Wren42d5dd42015-05-01 10:39:26 -04001795 if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
Christoph Studerc6a656c2015-01-22 15:02:49 +01001796 // Release the HUN notification to the shade.
1797 //
1798 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
1799 // become canceled shortly by NoMan, but we can't assume that.
Selim Cinek0fccc722015-07-29 17:04:36 -07001800 HeadsUpManager.setIsClickedNotification(row, true);
Chris Wren42d5dd42015-05-01 10:39:26 -04001801 mHeadsUpManager.releaseImmediately(notificationKey);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001802 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001803 new Thread() {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001804 @Override
1805 public void run() {
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001806 try {
1807 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001808 ActivityManagerNative.getDefault()
1809 .keyguardWaitingForActivityDrawn();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001810 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001811
1812 // The intent we are sending is for the application, which
1813 // won't have permission to immediately start an activity after
1814 // the user switches to home. We know it is safe to do at this
1815 // point, so make sure new activity switches are now allowed.
1816 ActivityManagerNative.getDefault().resumeAppSwitches();
1817 } catch (RemoteException e) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001818 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001819 if (intent != null) {
Ricky Wai7fa01712016-03-16 12:13:54 +00001820 // If we are launching a work activity and require to launch
1821 // separate work challenge, we defer the activity action and cancel
1822 // notification until work challenge is unlocked.
1823 if (intent.isActivity()) {
1824 final int userId = intent.getCreatorUserHandle()
1825 .getIdentifier();
1826 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
1827 && mKeyguardManager.isDeviceLocked(userId)) {
1828 // Show work challenge, do not run pendingintent and
1829 // remove notification
1830 startWorkChallenge(userId, intent.getIntentSender(),
1831 notificationKey);
1832 return;
1833 }
1834 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001835 try {
Chris Wren42d5dd42015-05-01 10:39:26 -04001836 intent.send();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001837 } catch (PendingIntent.CanceledException e) {
1838 // the stack trace isn't very helpful here.
1839 // Just log the exception message.
1840 Log.w(TAG, "Sending contentIntent failed: " + e);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001841
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001842 // TODO: Dismiss Keyguard.
1843 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001844 if (intent.isActivity()) {
Jorim Jaggib835dd72015-06-08 12:28:42 -07001845 mAssistManager.hideAssist();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001846 overrideActivityPendingAppTransition(keyguardShowing
1847 && !afterKeyguardGone);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001848 }
1849 }
1850
1851 try {
Chris Wren42d5dd42015-05-01 10:39:26 -04001852 mBarService.onNotificationClick(notificationKey);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001853 } catch (RemoteException ex) {
1854 // system process is dead if we're here.
1855 }
Adrian Roos7d7090d2014-05-21 13:10:23 +02001856 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001857 }.start();
Adrian Roos7d7090d2014-05-21 13:10:23 +02001858
1859 // close the shade if it was open
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +01001860 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001861 true /* force */, true /* delayed */);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001862 visibilityChanged(false);
1863
Jorim Jaggi8972c2a2015-06-05 16:05:54 -07001864 return true;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001865 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001866 }, afterKeyguardGone);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001867 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001868
Ricky Wai7fa01712016-03-16 12:13:54 +00001869 public void startWorkChallenge(int userId, IntentSender intendSender,
1870 String notificationKey) {
1871 final Intent callBackIntent = new Intent(
1872 WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
1873 callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
1874 callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
1875 callBackIntent.setPackage(mContext.getPackageName());
1876
1877 final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
1878 null, userId);
1879 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1880 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1881 newIntent.putExtra(Intent.EXTRA_INTENT, PendingIntent
1882 .getBroadcast(mContext, 0, callBackIntent, 0).getIntentSender());
1883 mContext.startActivity(newIntent);
1884 }
1885
Chris Wren42d5dd42015-05-01 10:39:26 -04001886 public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
Selim Cinekc6dd5212015-11-02 14:51:54 -08001887 Notification notification = sbn.getNotification();
1888 if (notification.contentIntent != null || notification.fullScreenIntent != null) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001889 row.setOnClickListener(this);
1890 } else {
1891 row.setOnClickListener(null);
1892 }
1893 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001894 }
Chris Wrenf29c3b42013-11-27 16:30:30 -05001895
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001896 public void animateCollapsePanels(int flags, boolean force) {
1897 }
1898
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001899 public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
1900 }
1901
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001902 public void overrideActivityPendingAppTransition(boolean keyguardShowing) {
1903 if (keyguardShowing) {
1904 try {
1905 mWindowManagerService.overridePendingAppTransition(null, 0, 0, null);
1906 } catch (RemoteException e) {
1907 Log.w(TAG, "Error overriding app transition: " + e);
1908 }
1909 }
1910 }
1911
Christoph Studere8e28652014-10-29 17:27:53 +01001912 protected void visibilityChanged(boolean visible) {
1913 if (mVisible != visible) {
1914 mVisible = visible;
1915 if (!visible) {
1916 dismissPopups();
1917 }
1918 }
1919 updateVisibleToUser();
1920 }
1921
1922 protected void updateVisibleToUser() {
1923 boolean oldVisibleToUser = mVisibleToUser;
Jorim Jaggi50ff3af2015-08-12 18:35:42 -07001924 mVisibleToUser = mVisible && mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +01001925
1926 if (oldVisibleToUser != mVisibleToUser) {
1927 handleVisibleToUserChanged(mVisibleToUser);
1928 }
1929 }
1930
Daniel Sandler6a858c32012-03-12 14:38:58 -04001931 /**
Christoph Studere8e28652014-10-29 17:27:53 +01001932 * The LEDs are turned off when the notification panel is shown, even just a little bit.
Dan Sandlercb012892016-03-01 00:45:06 -05001933 * See also NotificationStackScrollLayout.setIsExpanded() for another place where we
1934 * attempt to do this.
Daniel Sandler6a858c32012-03-12 14:38:58 -04001935 */
Christoph Studere8e28652014-10-29 17:27:53 +01001936 protected void handleVisibleToUserChanged(boolean visibleToUser) {
1937 try {
1938 if (visibleToUser) {
Selim Cinek6577cae2015-08-31 16:15:49 -07001939 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
1940 boolean clearNotificationEffects =
Dan Sandlercb012892016-03-01 00:45:06 -05001941 !isPanelFullyCollapsed() &&
1942 (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
Chris Wrenb659c4f2015-06-25 17:12:27 -04001943 int notificationLoad = mNotificationData.getActiveNotifications().size();
Selim Cinek6577cae2015-08-31 16:15:49 -07001944 if (pinnedHeadsUp && isPanelFullyCollapsed()) {
Chris Wrenb659c4f2015-06-25 17:12:27 -04001945 notificationLoad = 1;
1946 } else {
1947 MetricsLogger.histogram(mContext, "note_load", notificationLoad);
1948 }
1949 mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
Christoph Studere8e28652014-10-29 17:27:53 +01001950 } else {
1951 mBarService.onPanelHidden();
Dan Sandler4247a5c2014-07-23 15:58:08 -04001952 }
Christoph Studere8e28652014-10-29 17:27:53 +01001953 } catch (RemoteException ex) {
1954 // Won't fail unless the world has ended.
Daniel Sandler6a858c32012-03-12 14:38:58 -04001955 }
1956 }
1957
Chris Wren0c8275b2012-05-08 13:36:48 -04001958 /**
Chris Wren16895942015-06-23 11:22:20 -04001959 * Clear Buzz/Beep/Blink.
1960 */
1961 public void clearNotificationEffects() {
1962 try {
1963 mBarService.clearNotificationEffects();
1964 } catch (RemoteException e) {
1965 // Won't fail unless the world has ended.
1966 }
1967 }
1968
Yorke Leee4ea6ab2016-03-03 14:51:49 -08001969 public abstract boolean isPanelFullyCollapsed();
Chris Wren16895942015-06-23 11:22:20 -04001970
1971 /**
Chris Wren0c8275b2012-05-08 13:36:48 -04001972 * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
1973 * about the failure.
1974 *
1975 * WARNING: this will call back into us. Don't hold any locks.
1976 */
Christoph Studer71f18fd2014-05-20 17:02:04 +02001977 void handleNotificationError(StatusBarNotification n, String message) {
Christoph Studere71fefc2014-06-24 16:16:49 +02001978 removeNotification(n.getKey(), null);
Chris Wren0c8275b2012-05-08 13:36:48 -04001979 try {
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001980 mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
1981 n.getInitialPid(), message, n.getUserId());
Chris Wren0c8275b2012-05-08 13:36:48 -04001982 } catch (RemoteException ex) {
1983 // The end is nigh.
1984 }
1985 }
1986
Christoph Studerd0694b62014-06-04 16:36:01 +02001987 protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
Christoph Studer37fe6932014-05-26 13:10:30 +02001988 NotificationData.Entry entry = mNotificationData.remove(key, ranking);
Chris Wren0c8275b2012-05-08 13:36:48 -04001989 if (entry == null) {
John Spurlockcd686b52013-06-05 10:13:46 -04001990 Log.w(TAG, "removeNotification for unknown key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -04001991 return null;
1992 }
Christoph Studer37fe6932014-05-26 13:10:30 +02001993 updateNotifications();
Chris Wren0c8275b2012-05-08 13:36:48 -04001994 return entry.notification;
1995 }
1996
Selim Cinek8d490d42015-04-10 00:05:50 -07001997 protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04001998 if (DEBUG) {
Christoph Studera0506e72014-07-31 20:27:39 +02001999 Log.d(TAG, "createNotificationViews(notification=" + sbn);
Chris Wren0c8275b2012-05-08 13:36:48 -04002000 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01002001 final StatusBarIconView iconView = createIcon(sbn);
2002 if (iconView == null) {
2003 return null;
2004 }
2005
2006 // Construct the expanded view.
2007 NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
Selim Cinek8d490d42015-04-10 00:05:50 -07002008 if (!inflateViews(entry, mStackScroller)) {
Selim Cinek379ff8f2015-02-20 17:03:16 +01002009 handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
2010 return null;
2011 }
2012 return entry;
2013 }
2014
Xiaohui Chene90c2c52016-02-24 16:08:00 -08002015 public StatusBarIconView createIcon(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002016 // Construct the icon.
Christoph Studera0506e72014-07-31 20:27:39 +02002017 Notification n = sbn.getNotification();
Chris Wren0c8275b2012-05-08 13:36:48 -04002018 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Christoph Studera0506e72014-07-31 20:27:39 +02002019 sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
Chris Wren0c8275b2012-05-08 13:36:48 -04002020 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
2021
Dan Sandler33439812015-08-10 15:49:56 -04002022 final Icon smallIcon = n.getSmallIcon();
2023 if (smallIcon == null) {
2024 handleNotificationError(sbn,
2025 "No small icon in notification from " + sbn.getPackageName());
2026 return null;
2027 }
Dan Sandlerd63f9322015-05-06 15:18:49 -04002028 final StatusBarIcon ic = new StatusBarIcon(
Christoph Studera0506e72014-07-31 20:27:39 +02002029 sbn.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002030 sbn.getPackageName(),
Dan Sandler33439812015-08-10 15:49:56 -04002031 smallIcon,
Dan Sandler4e787062015-06-17 15:09:48 -04002032 n.iconLevel,
2033 n.number,
2034 n.tickerText);
Chris Wren0c8275b2012-05-08 13:36:48 -04002035 if (!iconView.set(ic)) {
Christoph Studera0506e72014-07-31 20:27:39 +02002036 handleNotificationError(sbn, "Couldn't create icon: " + ic);
Chris Wren0c8275b2012-05-08 13:36:48 -04002037 return null;
2038 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01002039 return iconView;
Chris Wrenf0048ce2013-08-07 16:43:43 -04002040 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002041
Christoph Studerd0694b62014-06-04 16:36:01 +02002042 protected void addNotificationViews(Entry entry, RankingMap ranking) {
Raju Yadav5f330262014-03-24 10:44:00 +01002043 if (entry == null) {
2044 return;
2045 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002046 // Add the expanded view and icon.
Christoph Studer37fe6932014-05-26 13:10:30 +02002047 mNotificationData.add(entry, ranking);
2048 updateNotifications();
Selim Cinek8efa6dd2014-05-19 16:27:37 +02002049 }
2050
Jorim Jaggi251957d2014-04-09 04:24:09 +02002051 /**
Selim Cinek5f71bee2015-11-18 10:25:23 -08002052 * @param recompute wheter the number should be recomputed
Jorim Jaggid4a57442014-04-10 02:45:55 +02002053 * @return The number of notifications we show on Keyguard.
2054 */
Selim Cinek5f71bee2015-11-18 10:25:23 -08002055 protected abstract int getMaxKeyguardNotifications(boolean recompute);
Jorim Jaggid4a57442014-04-10 02:45:55 +02002056
2057 /**
Jorim Jaggi251957d2014-04-09 04:24:09 +02002058 * Updates expanded, dimmed and locked states of notification rows.
2059 */
2060 protected void updateRowStates() {
Jorim Jaggif6411742014-08-05 17:10:43 +00002061 mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
2062
Christoph Studerc8db24b2014-07-25 17:50:30 +02002063 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
2064 final int N = activeNotifications.size();
2065
Jorim Jaggif6411742014-08-05 17:10:43 +00002066 int visibleNotifications = 0;
Jorim Jaggiecbab362014-04-23 16:13:15 +02002067 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
Selim Cinek5f71bee2015-11-18 10:25:23 -08002068 int maxNotifications = 0;
2069 if (onKeyguard) {
2070 maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
2071 }
Christoph Studer37fe6932014-05-26 13:10:30 +02002072 for (int i = 0; i < N; i++) {
Christoph Studerc8db24b2014-07-25 17:50:30 +02002073 NotificationData.Entry entry = activeNotifications.get(i);
Selim Cinek2a739342016-03-17 10:28:55 -07002074 boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
Jorim Jaggiecbab362014-04-23 16:13:15 +02002075 if (onKeyguard) {
Selim Cinek83bc7832015-10-22 13:26:54 -07002076 entry.row.setOnKeyguard(true);
Chris Wren3ddab0d2012-08-02 16:52:21 -04002077 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -07002078 entry.row.setOnKeyguard(false);
Selim Cinek2a739342016-03-17 10:28:55 -07002079 entry.row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
Chris Wren8fd12652012-05-09 21:25:57 -04002080 }
Selim Cinek2a739342016-03-17 10:28:55 -07002081 boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(entry.notification);
Selim Cinek83bc7832015-10-22 13:26:54 -07002082 boolean childWithVisibleSummary = childNotification
2083 && mGroupManager.getGroupSummary(entry.notification).getVisibility()
2084 == View.VISIBLE;
Jorim Jaggif6411742014-08-05 17:10:43 +00002085 boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
Selim Cinek2a739342016-03-17 10:28:55 -07002086 if (suppressedSummary || (isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
Selim Cinek5f71bee2015-11-18 10:25:23 -08002087 (onKeyguard && (visibleNotifications >= maxNotifications
Selim Cinek83bc7832015-10-22 13:26:54 -07002088 && !childWithVisibleSummary
2089 || !showOnKeyguard))) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002090 entry.row.setVisibility(View.GONE);
Selim Cinek2a739342016-03-17 10:28:55 -07002091 if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
Jorim Jaggif6411742014-08-05 17:10:43 +00002092 mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
2093 }
2094 } else {
2095 boolean wasGone = entry.row.getVisibility() == View.GONE;
2096 entry.row.setVisibility(View.VISIBLE);
Selim Cinek83bc7832015-10-22 13:26:54 -07002097 if (!childNotification) {
Selim Cinekb5605e52015-02-20 18:21:41 +01002098 if (wasGone) {
2099 // notify the scroller of a child addition
Selim Cinek2a739342016-03-17 10:28:55 -07002100 mStackScroller.generateAddAnimation(entry.row,
2101 !showOnKeyguard /* fromMoreCard */);
Selim Cinekb5605e52015-02-20 18:21:41 +01002102 }
2103 visibleNotifications++;
Jorim Jaggif6411742014-08-05 17:10:43 +00002104 }
Jorim Jaggif6411742014-08-05 17:10:43 +00002105 }
Chris Wren8fd12652012-05-09 21:25:57 -04002106 }
Jorim Jaggif6411742014-08-05 17:10:43 +00002107
Selim Cinek2cd45df2015-06-09 18:00:07 -07002108 mStackScroller.updateOverflowContainerVisibility(onKeyguard
2109 && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0);
Jorim Jaggif6411742014-08-05 17:10:43 +00002110
Selim Cinek0cce5312015-05-20 22:13:55 -07002111 mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
2112 mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
Jorim Jaggif6411742014-08-05 17:10:43 +00002113 mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
2114 mStackScroller.getChildCount() - 3);
Jorim Jaggif6411742014-08-05 17:10:43 +00002115 }
2116
2117 private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
2118 return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
Chris Wren8fd12652012-05-09 21:25:57 -04002119 }
2120
John Spurlocke677d712014-02-13 12:52:19 -05002121 protected void setZenMode(int mode) {
John Spurlock110e5b12014-02-27 13:09:35 -05002122 if (!isDeviceProvisioned()) return;
John Spurlocke677d712014-02-13 12:52:19 -05002123 mZenMode = mode;
Christoph Studer37fe6932014-05-26 13:10:30 +02002124 updateNotifications();
John Spurlocke677d712014-02-13 12:52:19 -05002125 }
2126
Dan Sandler52e5701e2014-07-22 23:14:54 -04002127 // extended in PhoneStatusBar
2128 protected void setShowLockscreenNotifications(boolean show) {
2129 mShowLockscreenNotifications = show;
2130 }
2131
Adrian Roos3aec6382016-02-05 14:19:01 -08002132 protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
2133 mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
2134 }
2135
Dan Sandler52e5701e2014-07-22 23:14:54 -04002136 private void updateLockscreenNotificationSetting() {
2137 final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2138 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
2139 1,
2140 mCurrentUserId) != 0;
Adrian Roosbd3409c2014-08-12 18:21:09 +02002141 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
2142 null /* admin */, mCurrentUserId);
2143 final boolean allowedByDpm = (dpmFlags
2144 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
Adrian Roos3aec6382016-02-05 14:19:01 -08002145
2146 final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2147 Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
2148 0,
2149 mCurrentUserId) != 0;
2150
Adrian Roosbd3409c2014-08-12 18:21:09 +02002151 setShowLockscreenNotifications(show && allowedByDpm);
Adrian Roos3aec6382016-02-05 14:19:01 -08002152 setLockScreenAllowRemoteInput(remoteInput);
Dan Sandler52e5701e2014-07-22 23:14:54 -04002153 }
2154
Chris Wren0c8275b2012-05-08 13:36:48 -04002155 protected abstract void setAreThereNotifications();
Christoph Studer37fe6932014-05-26 13:10:30 +02002156 protected abstract void updateNotifications();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -07002157 public abstract boolean shouldDisableNavbarGestures();
Chris Wren0c8275b2012-05-08 13:36:48 -04002158
Christoph Studere71fefc2014-06-24 16:16:49 +02002159 public abstract void addNotification(StatusBarNotification notification,
Selim Cinek379ff8f2015-02-20 17:03:16 +01002160 RankingMap ranking, Entry oldEntry);
Christoph Studere71fefc2014-06-24 16:16:49 +02002161 protected abstract void updateNotificationRanking(RankingMap ranking);
2162 public abstract void removeNotification(String key, RankingMap ranking);
Christoph Studera7fe6312014-06-27 19:32:44 +02002163
Christoph Studere71fefc2014-06-24 16:16:49 +02002164 public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02002165 if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
Chris Wren0c8275b2012-05-08 13:36:48 -04002166
Chris Wrend04f6ce2014-06-11 17:37:28 -04002167 final String key = notification.getKey();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002168 Entry entry = mNotificationData.get(key);
2169 if (entry == null) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002170 return;
Selim Cinek2d79f632015-11-02 15:13:29 -08002171 } else if (mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
2172 mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
Chris Wren0c8275b2012-05-08 13:36:48 -04002173 }
2174
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002175 Notification n = notification.getNotification();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002176 mNotificationData.updateRanking(ranking);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002177
Selim Cineka6a6f032015-11-23 15:46:24 -08002178 boolean applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
Chris Wrenbdf33762015-12-04 15:50:51 -05002179 boolean shouldPeek = shouldPeek(entry, notification);
Selim Cinek684a4422015-04-15 16:18:39 -07002180 boolean alertAgain = alertAgain(entry, n);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002181 if (DEBUG) {
2182 Log.d(TAG, "applyInPlace=" + applyInPlace
Chris Wrenbdf33762015-12-04 15:50:51 -05002183 + " shouldPeek=" + shouldPeek
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002184 + " alertAgain=" + alertAgain);
2185 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002186
Dan Sandler24813b02016-01-14 15:49:36 -05002187 final StatusBarNotification oldNotification = entry.notification;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002188 entry.notification = notification;
Dan Sandler24813b02016-01-14 15:49:36 -05002189 mGroupManager.onEntryUpdated(entry, oldNotification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002190
2191 boolean updateSuccessful = false;
2192 if (applyInPlace) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002193 if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
2194 try {
2195 if (entry.icon != null) {
2196 // Update the icon
Dan Sandlerd63f9322015-05-06 15:18:49 -04002197 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002198 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002199 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002200 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002201 n.iconLevel,
2202 n.number,
2203 n.tickerText);
2204 entry.icon.setNotification(n);
2205 if (!entry.icon.set(ic)) {
2206 handleNotificationError(notification, "Couldn't update icon: " + ic);
2207 return;
2208 }
2209 }
Selim Cinek8d490d42015-04-10 00:05:50 -07002210 updateNotificationViews(entry, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002211 updateSuccessful = true;
2212 }
2213 catch (RuntimeException e) {
Selim Cinek684a4422015-04-15 16:18:39 -07002214 // It failed to apply cleanly.
Adrian Roose458aa82015-12-08 16:17:19 -08002215 Log.w(TAG, "Couldn't reapply views for package " +
2216 notification.getPackageName(), e);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002217 }
2218 }
2219 if (!updateSuccessful) {
2220 if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
Dan Sandlerd63f9322015-05-06 15:18:49 -04002221 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002222 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002223 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002224 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002225 n.iconLevel,
2226 n.number,
2227 n.tickerText);
2228 entry.icon.setNotification(n);
2229 entry.icon.set(ic);
Selim Cinek8d490d42015-04-10 00:05:50 -07002230 inflateViews(entry, mStackScroller);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002231 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002232 updateHeadsUp(key, entry, shouldPeek, alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002233 updateNotifications();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002234
2235 // Update the veto button accordingly (and as a result, whether this row is
2236 // swipe-dismissable)
Selim Cinek757d8792016-01-28 16:21:08 -08002237 bindVetoButtonClickListener(entry.row, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002238
dongwan0605.kim30637e42016-03-02 17:16:47 +09002239 if (!notification.isClearable()) {
2240 // The user may have performed a dismiss action on the notification, since it's
2241 // not clearable we should snap it back.
2242 mStackScroller.snapViewIfNeeded(entry.row);
2243 }
2244
Selim Cinek684a4422015-04-15 16:18:39 -07002245 if (DEBUG) {
2246 // Is this for you?
2247 boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
2248 Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
2249 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002250
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002251 setAreThereNotifications();
2252 }
2253
Chris Wrenbdf33762015-12-04 15:50:51 -05002254 protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
Selim Cinek29fa89b2015-04-17 10:39:11 -07002255 boolean alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002256
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002257 private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
2258 final RemoteViews contentView = entry.cachedContentView;
2259 final RemoteViews bigContentView = entry.cachedBigContentView;
2260 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
2261 final RemoteViews publicContentView = entry.cachedPublicContentView;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002262
Chris Wrene03f4e12013-08-08 16:48:48 -04002263 // Reapply the RemoteViews
Selim Cinek684a4422015-04-15 16:18:39 -07002264 contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
2265 if (bigContentView != null && entry.getExpandedContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002266 bigContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002267 entry.getExpandedContentView(),
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01002268 mOnClickHandler);
Chris Wrene03f4e12013-08-08 16:48:48 -04002269 }
Selim Cinek684a4422015-04-15 16:18:39 -07002270 View headsUpChild = entry.getHeadsUpContentView();
Selim Cinek8d490d42015-04-10 00:05:50 -07002271 if (headsUpContentView != null && headsUpChild != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002272 headsUpContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002273 headsUpChild, mOnClickHandler);
Selim Cinek8d490d42015-04-10 00:05:50 -07002274 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002275 if (publicContentView != null && entry.getPublicContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002276 publicContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002277 entry.getPublicContentView(), mOnClickHandler);
Dan Sandlera5e0f412014-01-23 15:11:54 -05002278 }
Chris Wrene03f4e12013-08-08 16:48:48 -04002279 // update the contentIntent
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002280 mNotificationClicker.register(entry.row, sbn);
Chris Wren42d5dd42015-05-01 10:39:26 -04002281
Selim Cinekda42d652015-12-04 15:51:16 -08002282 entry.row.onNotificationUpdated(entry);
Selim Cinek51ae05d2014-09-09 15:51:38 +02002283 entry.row.resetHeight();
Chris Wren0c8275b2012-05-08 13:36:48 -04002284 }
John Spurlock36231282012-06-23 17:11:27 -04002285
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002286 protected void updatePublicContentView(Entry entry,
2287 StatusBarNotification sbn) {
2288 final RemoteViews publicContentView = entry.cachedPublicContentView;
Selim Cineke4c068d2016-02-19 13:46:55 -08002289 View inflatedView = entry.getPublicContentView();
2290 if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002291 final boolean disabledByPolicy =
2292 !adminAllowsUnredactedNotifications(entry.notification.getUserId());
Selim Cineke4c068d2016-02-19 13:46:55 -08002293 String notificationHiddenText = mContext.getString(disabledByPolicy
2294 ? com.android.internal.R.string.notification_hidden_by_policy_text
2295 : com.android.internal.R.string.notification_hidden_text);
2296 TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
2297 if (titleView != null
2298 && !titleView.getText().toString().equals(notificationHiddenText)) {
2299 publicContentView.setTextViewText(android.R.id.title, notificationHiddenText);
2300 publicContentView.reapply(sbn.getPackageContext(mContext),
2301 inflatedView, mOnClickHandler);
2302 entry.row.onNotificationUpdated(entry);
2303 }
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002304 }
2305 }
2306
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002307 protected void notifyHeadsUpScreenOff() {
Selim Cinek684a4422015-04-15 16:18:39 -07002308 maybeEscalateHeadsUp();
Chris Wrene97f90b2013-08-07 17:39:35 -04002309 }
2310
Chris Wrend93d5ad2014-09-08 16:34:03 -04002311 private boolean alertAgain(Entry oldEntry, Notification newNotification) {
2312 return oldEntry == null || !oldEntry.hasInterrupted()
2313 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
Chris Wrend04f6ce2014-06-11 17:37:28 -04002314 }
2315
Chris Wrenbdf33762015-12-04 15:50:51 -05002316 protected boolean shouldPeek(Entry entry) {
2317 return shouldPeek(entry, entry.notification);
Chris Wren0c274b12015-07-17 10:34:53 -04002318 }
2319
Chris Wrenbdf33762015-12-04 15:50:51 -05002320 protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002321 if (mNotificationData.shouldFilterOut(sbn)) {
Chris Wrenbdf33762015-12-04 15:50:51 -05002322 if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002323 return false;
2324 }
2325
Selim Cinekd5921912016-02-09 10:33:01 -08002326 boolean inUse = mPowerManager.isScreenOn()
2327 && (!mStatusBarKeyguardViewManager.isShowing()
2328 || mStatusBarKeyguardViewManager.isOccluded())
2329 && !mStatusBarKeyguardViewManager.isInputRestricted();
2330 try {
2331 inUse = inUse && !mDreamManager.isDreaming();
2332 } catch (RemoteException e) {
2333 Log.d(TAG, "failed to query dream manager", e);
2334 }
2335
2336 if (!inUse) {
2337 if (DEBUG) {
2338 Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
2339 }
2340 return false;
2341 }
2342
2343 if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
2344 if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
Chris Wrena6d4fb62014-11-20 14:46:23 -05002345 return false;
2346 }
2347
Chris Wrenbdf33762015-12-04 15:50:51 -05002348 if (entry.hasJustLaunchedFullScreenIntent()) {
2349 if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
2350 return false;
2351 }
2352
Julia Reynoldsf0f629f2016-02-25 09:34:04 -05002353 if (isSnoozedPackage(sbn)) {
2354 if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
2355 return false;
2356 }
2357
2358 if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_HIGH) {
2359 if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
2360 return false;
2361 }
2362
Selim Cinekd5921912016-02-09 10:33:01 -08002363 if (sbn.getNotification().fullScreenIntent != null) {
2364 if (mAccessibilityManager.isTouchExplorationEnabled()) {
2365 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
2366 return false;
2367 } else {
2368 return true;
2369 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002370 }
2371
Selim Cinekd5921912016-02-09 10:33:01 -08002372 return true;
Chris Wren157026f2013-06-28 16:54:01 -04002373 }
2374
Selim Cinek29fa89b2015-04-17 10:39:11 -07002375 protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
2376
John Spurlockcfc359a2013-09-05 10:42:03 -04002377 public void setInteracting(int barWindow, boolean interacting) {
John Spurlockad3e6cb2013-04-30 08:47:43 -04002378 // hook for subclasses
2379 }
John Spurlock5c454122013-06-17 07:35:46 -04002380
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002381 public void setBouncerShowing(boolean bouncerShowing) {
2382 mBouncerShowing = bouncerShowing;
2383 }
2384
2385 /**
2386 * @return Whether the security bouncer from Keyguard is showing.
2387 */
2388 public boolean isBouncerShowing() {
2389 return mBouncerShowing;
2390 }
2391
John Spurlock5c454122013-06-17 07:35:46 -04002392 public void destroy() {
John Spurlock5c454122013-06-17 07:35:46 -04002393 mContext.unregisterReceiver(mBroadcastReceiver);
Christoph Studere71fefc2014-06-24 16:16:49 +02002394 try {
2395 mNotificationListener.unregisterAsSystemService();
2396 } catch (RemoteException e) {
2397 // Ignore.
Christoph Studer37fe6932014-05-26 13:10:30 +02002398 }
John Spurlock5c454122013-06-17 07:35:46 -04002399 }
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002400
2401 /**
2402 * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
2403 * return PackageManager for mContext
2404 */
Selim Cinekeef84282015-10-30 16:28:00 -07002405 public static PackageManager getPackageManagerForUser(Context context, int userId) {
2406 Context contextForUser = context;
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002407 // UserHandle defines special userId as negative values, e.g. USER_ALL
2408 if (userId >= 0) {
2409 try {
2410 // Create a context for the correct user so if a package isn't installed
2411 // for user 0 we can still load information about the package.
2412 contextForUser =
Selim Cinekeef84282015-10-30 16:28:00 -07002413 context.createPackageContextAsUser(context.getPackageName(),
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002414 Context.CONTEXT_RESTRICTED,
2415 new UserHandle(userId));
2416 } catch (NameNotFoundException e) {
2417 // Shouldn't fail to find the package name for system ui.
2418 }
2419 }
2420 return contextForUser.getPackageManager();
2421 }
Chris Wren78403d72014-07-28 10:23:24 +01002422
2423 @Override
2424 public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
2425 try {
2426 mBarService.onNotificationExpansionChanged(key, userAction, expanded);
2427 } catch (RemoteException e) {
2428 // Ignore.
2429 }
2430 }
Jim Millerab954542014-10-10 18:21:49 -07002431
2432 public boolean isKeyguardSecure() {
Dan Sandlere163a642015-03-01 22:58:32 -05002433 if (mStatusBarKeyguardViewManager == null) {
2434 // startKeyguard() hasn't been called yet, so we don't know.
2435 // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
2436 // value onVisibilityChanged().
2437 Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
2438 new Throwable());
2439 return false;
2440 }
Jim Millerab954542014-10-10 18:21:49 -07002441 return mStatusBarKeyguardViewManager.isSecure();
2442 }
Adrian Roos4f43dc02015-06-17 16:43:38 -07002443
2444 @Override
2445 public void showAssistDisclosure() {
2446 if (mAssistManager != null) {
2447 mAssistManager.showDisclosure();
2448 }
2449 }
Jorim Jaggi165ce062015-07-06 16:18:11 -07002450
2451 @Override
2452 public void startAssist(Bundle args) {
2453 if (mAssistManager != null) {
2454 mAssistManager.startAssist(args);
2455 }
2456 }
Joe Onorato2314aab2010-04-08 16:41:23 -05002457}