blob: 178838ea939d0c277d0d52a75247a1b28e73a3d3 [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;
Chris Wren51c75102013-07-16 20:49:17 -040023import android.app.Notification;
Chris Wrencd8f4f72014-08-27 18:48:13 -040024import android.app.NotificationManager;
Daniel Sandler6a858c32012-03-12 14:38:58 -040025import android.app.PendingIntent;
Adrian Roos497ab022015-02-10 20:49:33 +010026import android.app.RemoteInput;
Adam Powell0fc5b2b2012-07-18 18:20:29 -070027import android.app.TaskStackBuilder;
Adrian Roosbd3409c2014-08-12 18:21:09 +020028import android.app.admin.DevicePolicyManager;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040029import android.content.BroadcastReceiver;
Christoph Studer60748e72014-05-22 16:51:41 +020030import android.content.ComponentName;
Joe Onorato808182d2010-07-09 18:52:06 -040031import android.content.Context;
Daniel Sandler6a858c32012-03-12 14:38:58 -040032import android.content.Intent;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040033import android.content.IntentFilter;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040034import android.content.pm.ApplicationInfo;
Dan Sandlera5e0f412014-01-23 15:11:54 -050035import android.content.pm.PackageManager;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040036import android.content.pm.PackageManager.NameNotFoundException;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000037import android.content.pm.UserInfo;
John Spurlockde84f0e2013-06-12 12:41:00 -040038import android.content.res.Configuration;
Chris Wrencd8f4f72014-08-27 18:48:13 -040039import android.content.res.Resources;
Daniel Sandler26cda272012-05-22 15:44:08 -040040import android.database.ContentObserver;
Jorim Jaggi86905582016-02-09 21:36:09 -080041import android.graphics.Rect;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +010042import android.graphics.drawable.Drawable;
Dan Sandler33439812015-08-10 15:49:56 -040043import android.graphics.drawable.Icon;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +020044import android.os.AsyncTask;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040045import android.os.Build;
Jorim Jaggi165ce062015-07-06 16:18:11 -070046import android.os.Bundle;
Michael Jurka7f2668c2012-03-27 07:49:52 -070047import android.os.Handler;
Joe Onorato808182d2010-07-09 18:52:06 -040048import android.os.IBinder;
Michael Jurka7f2668c2012-03-27 07:49:52 -070049import android.os.Message;
Chris Wren157026f2013-06-28 16:54:01 -040050import android.os.PowerManager;
Joe Onorato808182d2010-07-09 18:52:06 -040051import android.os.RemoteException;
52import android.os.ServiceManager;
Adrian Roos497ab022015-02-10 20:49:33 +010053import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070054import android.os.UserHandle;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000055import android.os.UserManager;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040056import android.provider.Settings;
Chris Wren157026f2013-06-28 16:54:01 -040057import android.service.dreams.DreamService;
58import android.service.dreams.IDreamManager;
Christoph Studer60748e72014-05-22 16:51:41 +020059import android.service.notification.NotificationListenerService;
Christoph Studerd0694b62014-06-04 16:36:01 +020060import android.service.notification.NotificationListenerService.RankingMap;
John Spurlockde84f0e2013-06-12 12:41:00 -040061import android.service.notification.StatusBarNotification;
Chris Wren0c8275b2012-05-08 13:36:48 -040062import android.text.TextUtils;
Selim Cinek2d79f632015-11-02 15:13:29 -080063import android.util.ArraySet;
Joe Onorato808182d2010-07-09 18:52:06 -040064import android.util.Log;
Dan Sandlere163a642015-03-01 22:58:32 -050065import android.util.Slog;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000066import android.util.SparseArray;
Dan Sandlerfd16d562014-02-13 18:43:31 -080067import android.util.SparseBooleanArray;
Daniel Sandlerc638c1e2011-08-24 16:19:23 -070068import android.view.Display;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050069import android.view.IWindowManager;
Michael Jurka7f2668c2012-03-27 07:49:52 -070070import android.view.LayoutInflater;
71import android.view.MotionEvent;
Joe Onorato808182d2010-07-09 18:52:06 -040072import android.view.View;
Dan Sandler4247a5c2014-07-23 15:58:08 -040073import android.view.ViewAnimationUtils;
Daniel Sandler6a858c32012-03-12 14:38:58 -040074import android.view.ViewGroup;
Christoph Studer4da84cd2014-10-21 17:24:20 +020075import android.view.ViewParent;
Joe Onorato808182d2010-07-09 18:52:06 -040076import android.view.WindowManager;
Michael Jurka80343f62012-10-18 13:13:46 +020077import android.view.WindowManagerGlobal;
Selim Cineka8fefa52014-09-08 16:10:50 +020078import android.view.accessibility.AccessibilityManager;
Chris Wren0c8275b2012-05-08 13:36:48 -040079import android.widget.ImageView;
Michael Jurkaa600fd92012-06-25 15:57:05 -070080import android.widget.RemoteViews;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040081import android.widget.TextView;
Kenny Guydae30d52015-04-01 19:11:35 +010082import android.widget.Toast;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050083
Chris Wrenbd6b5fb2015-06-09 14:58:34 -040084import com.android.internal.logging.MetricsLogger;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050085import com.android.internal.logging.MetricsProto.MetricsEvent;
John Spurlockde84f0e2013-06-12 12:41:00 -040086import com.android.internal.statusbar.IStatusBarService;
87import com.android.internal.statusbar.StatusBarIcon;
Chris Wrencd8f4f72014-08-27 18:48:13 -040088import com.android.internal.widget.LockPatternUtils;
Adrian Roosd6aa6cb2015-04-16 19:31:29 -070089import com.android.keyguard.KeyguardUpdateMonitor;
Jorim Jaggi5eb67c22015-08-19 19:50:49 -070090import com.android.systemui.DejankUtils;
Winsonc0d70582016-01-29 10:24:39 -080091import com.android.systemui.Interpolators;
John Spurlockde84f0e2013-06-12 12:41:00 -040092import com.android.systemui.R;
John Spurlockd08de372013-06-24 13:06:08 -040093import com.android.systemui.RecentsComponent;
Dan Sandler4247a5c2014-07-23 15:58:08 -040094import com.android.systemui.SwipeHelper;
John Spurlockde84f0e2013-06-12 12:41:00 -040095import com.android.systemui.SystemUI;
Jorim Jaggib835dd72015-06-08 12:28:42 -070096import com.android.systemui.assist.AssistManager;
Jorim Jaggid61f2272014-12-19 20:35:35 +010097import com.android.systemui.recents.Recents;
Christoph Studer37fe6932014-05-26 13:10:30 +020098import com.android.systemui.statusbar.NotificationData.Entry;
Selim Cinek92d892c2014-09-11 15:11:00 +020099import com.android.systemui.statusbar.phone.NavigationBarView;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100100import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200101import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700102import com.android.systemui.statusbar.policy.HeadsUpManager;
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200103import com.android.systemui.statusbar.policy.PreviewInflater;
Adrian Roos497ab022015-02-10 20:49:33 +0100104import com.android.systemui.statusbar.policy.RemoteInputView;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100105import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Mady Mellor4b80b102016-01-22 08:03:58 -0800106import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.GearDisplayedListener;
Selim Cinekd84a5932015-12-15 11:45:36 -0800107import com.android.systemui.statusbar.stack.StackStateAnimator;
John Spurlockde84f0e2013-06-12 12:41:00 -0400108
Michael Jurkaa600fd92012-06-25 15:57:05 -0700109import java.util.ArrayList;
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200110import java.util.List;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700111import java.util.Locale;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400112
Julia Reynoldsf0f629f2016-02-25 09:34:04 -0500113import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100114import static com.android.keyguard.KeyguardHostView.OnDismissAction;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200115
Michael Jurka7f2668c2012-03-27 07:49:52 -0700116public abstract class BaseStatusBar extends SystemUI implements
Winson Chung9214eff2014-06-12 13:59:25 -0700117 CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
Selim Cinek570981d2015-12-01 11:37:01 -0800118 ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
Mady Mellor4b80b102016-01-22 08:03:58 -0800119 ExpandableNotificationRow.OnExpandClickListener, GearDisplayedListener {
Daniel Sandler198a0302012-08-17 16:04:31 -0400120 public static final String TAG = "StatusBar";
Jorim Jaggi86905582016-02-09 21:36:09 -0800121 public static final boolean DEBUG = false;
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400122 public static final boolean MULTIUSER_DEBUG = false;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400123
Adrian Roos497ab022015-02-10 20:49:33 +0100124 public static final boolean ENABLE_REMOTE_INPUT =
Adrian Roos9531c9b2015-11-03 17:43:01 -0800125 SystemProperties.getBoolean("debug.enable_remote_input", true);
Selim Cinek40412492015-12-08 18:03:22 -0800126 public static final boolean ENABLE_CHILD_NOTIFICATIONS
127 = SystemProperties.getBoolean("debug.child_notifs", true);
Adrian Roos497ab022015-02-10 20:49:33 +0100128
Winson Chung1e8d71b2014-05-16 17:05:22 -0700129 protected static final int MSG_SHOW_RECENT_APPS = 1019;
130 protected static final int MSG_HIDE_RECENT_APPS = 1020;
131 protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700132 protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
133 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
Winson Chungb1f74992014-08-08 12:53:09 -0700134 protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
135 protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +0000136 protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
Chris Wren0c8275b2012-05-08 13:36:48 -0400137
Chris Wren157026f2013-06-28 16:54:01 -0400138 protected static final boolean ENABLE_HEADS_UP = true;
Chris Wren22ae46e2014-02-26 18:08:09 -0500139 protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
Chris Wren0c8275b2012-05-08 13:36:48 -0400140
Winsond8b1d632016-01-04 17:51:18 -0800141 // Should match the values in PhoneWindowManager
Michael Jurka56a57832012-05-14 13:24:43 -0700142 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
Winsond8b1d632016-01-04 17:51:18 -0800143 public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
Michael Jurka56a57832012-05-14 13:24:43 -0700144
Chris Wrencd8f4f72014-08-27 18:48:13 -0400145 private static final String BANNER_ACTION_CANCEL =
146 "com.android.systemui.statusbar.banner_action_cancel";
147 private static final String BANNER_ACTION_SETUP =
148 "com.android.systemui.statusbar.banner_action_setup";
149
Joe Onorato808182d2010-07-09 18:52:06 -0400150 protected CommandQueue mCommandQueue;
151 protected IStatusBarService mBarService;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700152 protected H mHandler = createHandler();
153
Chris Wren0c8275b2012-05-08 13:36:48 -0400154 // all notifications
Christoph Studerc8db24b2014-07-25 17:50:30 +0200155 protected NotificationData mNotificationData;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100156 protected NotificationStackScrollLayout mStackScroller;
Chris Wren0c8275b2012-05-08 13:36:48 -0400157
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100158 protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
159
Adrian Roosb88b1a12015-12-09 18:51:05 -0800160 protected RemoteInputController mRemoteInputController;
161
Chris Wrena4ef6202014-06-09 18:07:30 -0400162 // for heads up notifications
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700163 protected HeadsUpManager mHeadsUpManager;
Chris Wren0c8275b2012-05-08 13:36:48 -0400164
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400165 protected int mCurrentUserId = 0;
Kenny Guy2a764942014-04-02 13:29:20 +0100166 final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400167
Daniel Sandler777dcde2013-09-30 10:21:45 -0400168 protected int mLayoutDirection = -1; // invalid
Selim Cineka8fefa52014-09-08 16:10:50 +0200169 protected AccessibilityManager mAccessibilityManager;
Selim Cinek92d892c2014-09-11 15:11:00 +0200170
171 // on-screen navigation buttons
172 protected NavigationBarView mNavigationBarView = null;
Christoph Studere8e28652014-10-29 17:27:53 +0100173
Jorim Jaggi50ff3af2015-08-12 18:35:42 -0700174 protected boolean mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +0100175
176 protected boolean mVisible;
Selim Cinek2d79f632015-11-02 15:13:29 -0800177 protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
Christoph Studere8e28652014-10-29 17:27:53 +0100178
179 // mScreenOnFromKeyguard && mVisible.
180 private boolean mVisibleToUser;
181
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700182 private Locale mLocale;
Dan Sandler539aad42014-08-04 00:43:39 -0400183 private float mFontScale;
184
Chris Wrenf6e83f42013-09-11 14:02:59 -0400185 protected boolean mUseHeadsUp = false;
Chris Wren22ae46e2014-02-26 18:08:09 -0500186 protected boolean mHeadsUpTicker = false;
Jason Monkf7019542014-07-31 12:42:25 -0400187 protected boolean mDisableNotificationAlerts = false;
Chris Wren157026f2013-06-28 16:54:01 -0400188
Adrian Roosbd3409c2014-08-12 18:21:09 +0200189 protected DevicePolicyManager mDevicePolicyManager;
Chris Wren157026f2013-06-28 16:54:01 -0400190 protected IDreamManager mDreamManager;
Julia Reynolds0971cb02016-01-26 17:00:22 -0500191 protected PowerManager mPowerManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200192 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Dan Sandlerfd16d562014-02-13 18:43:31 -0800193
194 // public mode, private notifications, etc
195 private boolean mLockscreenPublicMode = false;
196 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700197
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000198 private UserManager mUserManager;
Selim Cinek01af3342016-02-09 19:25:31 -0800199 private int mDensity;
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000200
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500201 // UI-specific methods
Daniel Sandler6a858c32012-03-12 14:38:58 -0400202
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500203 /**
204 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
205 * and add them to the window manager.
206 */
207 protected abstract void createAndAddWindows();
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400208
Jeff Brown98365d72012-08-19 20:30:52 -0700209 protected WindowManager mWindowManager;
210 protected IWindowManager mWindowManagerService;
Christoph Studer60748e72014-05-22 16:51:41 +0200211
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700212 protected abstract void refreshLayout(int layoutDirection);
213
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500214 protected Display mDisplay;
Jeff Brown98365d72012-08-19 20:30:52 -0700215
Daniel Sandler26cda272012-05-22 15:44:08 -0400216 private boolean mDeviceProvisioned = false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400217
Jorim Jaggi75b25972015-10-21 14:51:10 +0200218 protected RecentsComponent mRecents;
John Spurlockd08de372013-06-24 13:06:08 -0400219
John Spurlocke677d712014-02-13 12:52:19 -0500220 protected int mZenMode;
221
Dan Sandler4247a5c2014-07-23 15:58:08 -0400222 // which notification is currently being longpress-examined by the user
Selim Cinek024ca592014-09-01 15:11:28 +0200223 private NotificationGuts mNotificationGutsExposed;
Mady Mellor4b80b102016-01-22 08:03:58 -0800224 private ExpandableNotificationRow mNotificationGearDisplayed;
Dan Sandler4247a5c2014-07-23 15:58:08 -0400225
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +0100226 private KeyboardShortcuts mKeyboardShortcuts;
227
Jorim Jaggiecbab362014-04-23 16:13:15 +0200228 /**
229 * The {@link StatusBarState} of the status bar.
230 */
231 protected int mState;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200232 protected boolean mBouncerShowing;
John Spurlock4b3bda22014-05-22 14:32:20 -0400233 protected boolean mShowLockscreenNotifications;
Adrian Roos3aec6382016-02-05 14:19:01 -0800234 protected boolean mAllowLockscreenRemoteInput;
Jorim Jaggiecbab362014-04-23 16:13:15 +0200235
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200236 protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
Dan Sandlereceda3d2014-07-21 15:35:01 -0400237 protected DismissView mDismissView;
Jorim Jaggia2052ea2014-08-05 16:22:30 +0200238 protected EmptyShadeView mEmptyShadeView;
Jorim Jaggi649b7082014-04-03 13:15:18 +0200239
Chris Wren42d5dd42015-05-01 10:39:26 -0400240 private NotificationClicker mNotificationClicker = new NotificationClicker();
241
Jorim Jaggib835dd72015-06-08 12:28:42 -0700242 protected AssistManager mAssistManager;
243
Christoph Studerc8db24b2014-07-25 17:50:30 +0200244 @Override // NotificationData.Environment
Daniel Sandler3ffdcc72012-09-23 14:31:48 -0400245 public boolean isDeviceProvisioned() {
Daniel Sandler26cda272012-05-22 15:44:08 -0400246 return mDeviceProvisioned;
247 }
248
John Spurlocke677d712014-02-13 12:52:19 -0500249 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
Daniel Sandler26cda272012-05-22 15:44:08 -0400250 @Override
251 public void onChange(boolean selfChange) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700252 final boolean provisioned = 0 != Settings.Global.getInt(
253 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
Daniel Sandler26cda272012-05-22 15:44:08 -0400254 if (provisioned != mDeviceProvisioned) {
255 mDeviceProvisioned = provisioned;
Christoph Studer37fe6932014-05-26 13:10:30 +0200256 updateNotifications();
Daniel Sandler26cda272012-05-22 15:44:08 -0400257 }
John Spurlocke677d712014-02-13 12:52:19 -0500258 final int mode = Settings.Global.getInt(mContext.getContentResolver(),
259 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
260 setZenMode(mode);
Dan Sandler52e5701e2014-07-22 23:14:54 -0400261
262 updateLockscreenNotificationSetting();
Daniel Sandler26cda272012-05-22 15:44:08 -0400263 }
264 };
265
Dan Sandlerfd16d562014-02-13 18:43:31 -0800266 private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
267 @Override
268 public void onChange(boolean selfChange) {
269 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
270 // so we just dump our cache ...
271 mUsersAllowingPrivateNotifications.clear();
272 // ... and refresh all the notifications
Christoph Studer37fe6932014-05-26 13:10:30 +0200273 updateNotifications();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800274 }
275 };
276
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700277 private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
278 @Override
Adrian Roos7d7090d2014-05-21 13:10:23 +0200279 public boolean onClickHandler(
280 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800281 if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
282 return true;
283 }
284
Daniel Sandler198a0302012-08-17 16:04:31 -0400285 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400286 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
Daniel Sandler198a0302012-08-17 16:04:31 -0400287 }
Christoph Studer4da84cd2014-10-21 17:24:20 +0200288 logActionClick(view);
Jorim Jaggi89f7f282014-10-17 19:54:15 +0200289 // The intent we are sending is for the application, which
290 // won't have permission to immediately start an activity after
291 // the user switches to home. We know it is safe to do at this
292 // point, so make sure new activity switches are now allowed.
293 try {
294 ActivityManagerNative.getDefault().resumeAppSwitches();
295 } catch (RemoteException e) {
296 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700297 final boolean isActivity = pendingIntent.isActivity();
298 if (isActivity) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200299 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200300 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
301 mContext, pendingIntent.getIntent(), mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +0200302 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200303 @Override
304 public boolean onDismiss() {
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200305 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200306 try {
307 ActivityManagerNative.getDefault()
308 .keyguardWaitingForActivityDrawn();
Jorim Jaggi91617a72015-06-25 15:01:29 -0700309 ActivityManagerNative.getDefault().resumeAppSwitches();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200310 } catch (RemoteException e) {
311 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200312 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700313
Adrian Roos7d7090d2014-05-21 13:10:23 +0200314 boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200315 overrideActivityPendingAppTransition(keyguardShowing && !afterKeyguardGone);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700316
Adrian Roos7d7090d2014-05-21 13:10:23 +0200317 // close the shade if it was open
318 if (handled) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100319 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
320 true /* force */);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200321 visibilityChanged(false);
Jorim Jaggi91617a72015-06-25 15:01:29 -0700322 mAssistManager.hideAssist();
Adrian Roos7d7090d2014-05-21 13:10:23 +0200323 }
Jorim Jaggi91617a72015-06-25 15:01:29 -0700324
Adrian Roos4314f6d2014-05-28 14:10:27 +0200325 // Wait for activity start.
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200326 return handled;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200327 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200328 }, afterKeyguardGone);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200329 return true;
330 } else {
331 return super.onClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700332 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200333 }
334
Christoph Studer4da84cd2014-10-21 17:24:20 +0200335 private void logActionClick(View view) {
336 ViewParent parent = view.getParent();
337 String key = getNotificationKeyForParent(parent);
338 if (key == null) {
339 Log.w(TAG, "Couldn't determine notification for click.");
340 return;
341 }
342 int index = -1;
343 // If this is a default template, determine the index of the button.
344 if (view.getId() == com.android.internal.R.id.action0 &&
345 parent != null && parent instanceof ViewGroup) {
346 ViewGroup actionGroup = (ViewGroup) parent;
347 index = actionGroup.indexOfChild(view);
348 }
349 try {
350 mBarService.onNotificationActionClick(key, index);
351 } catch (RemoteException e) {
352 // Ignore
353 }
354 }
355
356 private String getNotificationKeyForParent(ViewParent parent) {
357 while (parent != null) {
358 if (parent instanceof ExpandableNotificationRow) {
359 return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
360 }
361 parent = parent.getParent();
362 }
363 return null;
364 }
365
Adrian Roos7d7090d2014-05-21 13:10:23 +0200366 private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
367 Intent fillInIntent) {
368 return super.onClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700369 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800370
371 private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
372 Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
373 RemoteInput[] inputs = null;
374 if (tag instanceof RemoteInput[]) {
375 inputs = (RemoteInput[]) tag;
376 }
377
378 if (inputs == null) {
379 return false;
380 }
381
382 RemoteInput input = null;
383
384 for (RemoteInput i : inputs) {
385 if (i.getAllowFreeFormInput()) {
386 input = i;
387 }
388 }
389
390 if (input == null) {
391 return false;
392 }
393
394 ViewParent p = view.getParent();
395 RemoteInputView riv = null;
396 while (p != null) {
397 if (p instanceof View) {
398 View pv = (View) p;
399 if (pv.isRootNamespace()) {
400 riv = (RemoteInputView) pv.findViewWithTag(RemoteInputView.VIEW_TAG);
401 break;
402 }
403 }
404 p = p.getParent();
405 }
Adrian Roos3aec6382016-02-05 14:19:01 -0800406 ExpandableNotificationRow row = null;
407 while (p != null) {
408 if (p instanceof ExpandableNotificationRow) {
409 row = (ExpandableNotificationRow) p;
410 break;
411 }
412 p = p.getParent();
413 }
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800414
Adrian Roos3aec6382016-02-05 14:19:01 -0800415 if (riv == null || row == null) {
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800416 return false;
417 }
418
Adrian Roos3aec6382016-02-05 14:19:01 -0800419 row.setUserExpanded(true);
420
421 if (isLockscreenPublicMode() && !mAllowLockscreenRemoteInput) {
422 onLockedRemoteInput(row, view);
423 return true;
424 }
425
Adrian Roosfe84e1f2015-11-04 15:55:39 -0800426 riv.setVisibility(View.VISIBLE);
427 int cx = view.getLeft() + view.getWidth() / 2;
428 int cy = view.getTop() + view.getHeight() / 2;
429 int w = riv.getWidth();
430 int h = riv.getHeight();
431 int r = Math.max(
432 Math.max(cx + cy, cx + (h - cy)),
433 Math.max((w - cx) + cy, (w - cx) + (h - cy)));
434 ViewAnimationUtils.createCircularReveal(riv, cx, cy, 0, r)
435 .start();
436
437 riv.setPendingIntent(pendingIntent);
438 riv.setRemoteInput(inputs, input);
439 riv.focus();
440
441 return true;
442 }
443
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700444 };
445
John Spurlock5c454122013-06-17 07:35:46 -0400446 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
447 @Override
448 public void onReceive(Context context, Intent intent) {
449 String action = intent.getAction();
450 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
451 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Kenny Guy2a764942014-04-02 13:29:20 +0100452 updateCurrentProfilesCache();
John Spurlock5c454122013-06-17 07:35:46 -0400453 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
Dan Sandler52e5701e2014-07-22 23:14:54 -0400454
455 updateLockscreenNotificationSetting();
456
John Spurlock5c454122013-06-17 07:35:46 -0400457 userSwitched(mCurrentUserId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000458 } else if (Intent.ACTION_USER_ADDED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +0100459 updateCurrentProfilesCache();
Kenny Guydae30d52015-04-01 19:11:35 +0100460 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
461 List<ActivityManager.RecentTaskInfo> recentTask = null;
462 try {
463 recentTask = ActivityManagerNative.getDefault().getRecentTasks(1,
464 ActivityManager.RECENT_WITH_EXCLUDED
465 | ActivityManager.RECENT_INCLUDE_PROFILES,
466 mCurrentUserId);
467 } catch (RemoteException e) {
468 // Abandon hope activity manager not running.
469 }
470 if (recentTask != null && recentTask.size() > 0) {
471 UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
472 if (user != null && user.isManagedProfile()) {
Kenny Guy63bf8ac2015-06-18 15:09:09 +0100473 Toast toast = Toast.makeText(mContext,
474 R.string.managed_profile_foreground_toast,
475 Toast.LENGTH_SHORT);
476 TextView text = (TextView) toast.getView().findViewById(
477 android.R.id.message);
478 text.setCompoundDrawablesRelativeWithIntrinsicBounds(
479 R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
480 int paddingPx = mContext.getResources().getDimensionPixelSize(
481 R.dimen.managed_profile_toast_padding);
482 text.setCompoundDrawablePadding(paddingPx);
Kenny Guy540f7d22015-06-08 20:24:23 +0100483 toast.show();
Kenny Guydae30d52015-04-01 19:11:35 +0100484 }
485 }
Chris Wrencd8f4f72014-08-27 18:48:13 -0400486 } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
487 NotificationManager noMan = (NotificationManager)
488 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500489 noMan.cancel(R.id.notification_hidden);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400490
491 Settings.Secure.putInt(mContext.getContentResolver(),
492 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
493 if (BANNER_ACTION_SETUP.equals(action)) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100494 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
495 true /* force */);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400496 mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
497 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
498
499 );
500 }
John Spurlock5c454122013-06-17 07:35:46 -0400501 }
502 }
503 };
504
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000505 private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
506 @Override
507 public void onReceive(Context context, Intent intent) {
508 String action = intent.getAction();
509 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
510 isCurrentProfile(getSendingUserId())) {
511 mUsersAllowingPrivateNotifications.clear();
512 updateLockscreenNotificationSetting();
513 updateNotifications();
514 }
515 }
516 };
517
Christoph Studer60748e72014-05-22 16:51:41 +0200518 private final NotificationListenerService mNotificationListener =
519 new NotificationListenerService() {
520 @Override
521 public void onListenerConnected() {
522 if (DEBUG) Log.d(TAG, "onListenerConnected");
523 final StatusBarNotification[] notifications = getActiveNotifications();
Christoph Studerd0694b62014-06-04 16:36:01 +0200524 final RankingMap currentRanking = getCurrentRanking();
Christoph Studer60748e72014-05-22 16:51:41 +0200525 mHandler.post(new Runnable() {
526 @Override
527 public void run() {
528 for (StatusBarNotification sbn : notifications) {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100529 addNotification(sbn, currentRanking, null /* oldEntry */);
Christoph Studer60748e72014-05-22 16:51:41 +0200530 }
531 }
532 });
533 }
534
535 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200536 public void onNotificationPosted(final StatusBarNotification sbn,
537 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200538 if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500539 if (sbn != null) {
540 mHandler.post(new Runnable() {
541 @Override
542 public void run() {
Adrian Roos497ab022015-02-10 20:49:33 +0100543 processForRemoteInput(sbn.getNotification());
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700544 String key = sbn.getKey();
545 boolean isUpdate = mNotificationData.get(key) != null;
Selim Cinekb5605e52015-02-20 18:21:41 +0100546 // In case we don't allow child notifications, we ignore children of
547 // notifications that have a summary, since we're not going to show them
548 // anyway. This is true also when the summary is canceled,
Chris Wren56919552015-02-24 15:56:34 -0500549 // because children are automatically canceled by NoMan in that case.
Selim Cinekb5605e52015-02-20 18:21:41 +0100550 if (!ENABLE_CHILD_NOTIFICATIONS
551 && mGroupManager.isChildInGroupWithSummary(sbn)) {
Chris Wren56919552015-02-24 15:56:34 -0500552 if (DEBUG) {
553 Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
554 }
555
556 // Remove existing notification to avoid stale data.
557 if (isUpdate) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700558 removeNotification(key, rankingMap);
Chris Wren56919552015-02-24 15:56:34 -0500559 } else {
560 mNotificationData.updateRanking(rankingMap);
561 }
562 return;
Christoph Studerd722f272014-09-02 11:49:19 +0200563 }
Christoph Studerd722f272014-09-02 11:49:19 +0200564 if (isUpdate) {
Chris Wren56919552015-02-24 15:56:34 -0500565 updateNotification(sbn, rankingMap);
Christoph Studerd722f272014-09-02 11:49:19 +0200566 } else {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100567 addNotification(sbn, rankingMap, null /* oldEntry */);
Christoph Studerd722f272014-09-02 11:49:19 +0200568 }
Christoph Studerd722f272014-09-02 11:49:19 +0200569 }
Chris Wren56919552015-02-24 15:56:34 -0500570 });
571 }
Christoph Studer60748e72014-05-22 16:51:41 +0200572 }
573
574 @Override
Chris Wren56919552015-02-24 15:56:34 -0500575 public void onNotificationRemoved(StatusBarNotification sbn,
Christoph Studerd0694b62014-06-04 16:36:01 +0200576 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200577 if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500578 if (sbn != null) {
579 final String key = sbn.getKey();
580 mHandler.post(new Runnable() {
581 @Override
582 public void run() {
583 removeNotification(key, rankingMap);
584 }
585 });
586 }
Christoph Studer37fe6932014-05-26 13:10:30 +0200587 }
588
589 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200590 public void onNotificationRankingUpdate(final RankingMap rankingMap) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200591 if (DEBUG) Log.d(TAG, "onRankingUpdate");
Chris Wren56919552015-02-24 15:56:34 -0500592 if (rankingMap != null) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200593 mHandler.post(new Runnable() {
594 @Override
595 public void run() {
Christoph Studere71fefc2014-06-24 16:16:49 +0200596 updateNotificationRanking(rankingMap);
Christoph Studer60748e72014-05-22 16:51:41 +0200597 }
598 });
Chris Wren56919552015-02-24 15:56:34 -0500599 } }
Christoph Studer5b638262014-07-07 11:21:49 +0200600
Christoph Studer60748e72014-05-22 16:51:41 +0200601 };
602
Kenny Guy2a764942014-04-02 13:29:20 +0100603 private void updateCurrentProfilesCache() {
604 synchronized (mCurrentProfiles) {
605 mCurrentProfiles.clear();
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000606 if (mUserManager != null) {
Kenny Guy2a764942014-04-02 13:29:20 +0100607 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
608 mCurrentProfiles.put(user.id, user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000609 }
610 }
611 }
612 }
613
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400614 public void start() {
Jeff Brown98365d72012-08-19 20:30:52 -0700615 mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
616 mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
617 mDisplay = mWindowManager.getDefaultDisplay();
Adrian Roosbd3409c2014-08-12 18:21:09 +0200618 mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
619 Context.DEVICE_POLICY_SERVICE);
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500620
Christoph Studerc8db24b2014-07-25 17:50:30 +0200621 mNotificationData = new NotificationData(this);
622
Selim Cineka8fefa52014-09-08 16:10:50 +0200623 mAccessibilityManager = (AccessibilityManager)
624 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
625
Chris Wren157026f2013-06-28 16:54:01 -0400626 mDreamManager = IDreamManager.Stub.asInterface(
627 ServiceManager.checkService(DreamService.DREAM_SERVICE));
Chris Wren157026f2013-06-28 16:54:01 -0400628 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
629
Daniel Sandler26cda272012-05-22 15:44:08 -0400630 mContext.getContentResolver().registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700631 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
John Spurlocke677d712014-02-13 12:52:19 -0500632 mSettingsObserver);
633 mContext.getContentResolver().registerContentObserver(
634 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
635 mSettingsObserver);
John Spurlock4b3bda22014-05-22 14:32:20 -0400636 mContext.getContentResolver().registerContentObserver(
Dan Sandler52e5701e2014-07-22 23:14:54 -0400637 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
638 mSettingsObserver,
639 UserHandle.USER_ALL);
Adrian Roos3aec6382016-02-05 14:19:01 -0800640 mContext.getContentResolver().registerContentObserver(
641 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), false,
642 mSettingsObserver,
643 UserHandle.USER_ALL);
Daniel Sandler26cda272012-05-22 15:44:08 -0400644
Dan Sandlerfd16d562014-02-13 18:43:31 -0800645 mContext.getContentResolver().registerContentObserver(
646 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
647 true,
648 mLockscreenSettingsObserver,
649 UserHandle.USER_ALL);
650
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500651 mBarService = IStatusBarService.Stub.asInterface(
652 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400653
Jorim Jaggid61f2272014-12-19 20:35:35 +0100654 mRecents = getComponent(Recents.class);
John Spurlockd08de372013-06-24 13:06:08 -0400655
Dan Sandler539aad42014-08-04 00:43:39 -0400656 final Configuration currentConfig = mContext.getResources().getConfiguration();
657 mLocale = currentConfig.locale;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700658 mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
Dan Sandler539aad42014-08-04 00:43:39 -0400659 mFontScale = currentConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800660 mDensity = currentConfig.densityDpi;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700661
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000662 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
663
Joe Onorato2314aab2010-04-08 16:41:23 -0500664 // Connect in to the status bar manager service
Jason Monk07473ce2016-01-05 14:59:19 -0500665 mCommandQueue = new CommandQueue(this);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400666
Jorim Jaggi86905582016-02-09 21:36:09 -0800667 int[] switches = new int[9];
satokcd7cd292010-11-20 15:46:23 +0900668 ArrayList<IBinder> binders = new ArrayList<IBinder>();
Jason Monk07473ce2016-01-05 14:59:19 -0500669 ArrayList<String> iconSlots = new ArrayList<>();
670 ArrayList<StatusBarIcon> icons = new ArrayList<>();
Jorim Jaggi86905582016-02-09 21:36:09 -0800671 Rect fullscreenStackBounds = new Rect();
672 Rect dockedStackBounds = new Rect();
Joe Onorato2314aab2010-04-08 16:41:23 -0500673 try {
Jorim Jaggi86905582016-02-09 21:36:09 -0800674 mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
675 fullscreenStackBounds, dockedStackBounds);
Joe Onorato2314aab2010-04-08 16:41:23 -0500676 } catch (RemoteException ex) {
677 // If the system process isn't there we're doomed anyway.
678 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400679
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500680 createAndAddWindows();
Joe Onorato0cbda992010-05-02 16:28:15 -0700681
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100682 mSettingsObserver.onChange(false); // set up
Benjamin Franzcde0a2a2015-04-23 17:19:48 +0100683 disable(switches[0], switches[6], false /* animate */);
Jorim Jaggi86905582016-02-09 21:36:09 -0800684 setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
685 fullscreenStackBounds, dockedStackBounds);
Dianne Hackborn7d049322011-06-14 15:00:32 -0700686 topAppWindowChanged(switches[2] != 0);
satokcd7cd292010-11-20 15:46:23 +0900687 // StatusBarManagerService has a back up of IME token and it's restored here.
Michael Wright665366a2014-08-07 15:44:40 -0700688 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
Joe Onorato93056472010-09-10 10:30:46 -0400689
Joe Onorato0cbda992010-05-02 16:28:15 -0700690 // Set up the initial icon state
Jason Monk07473ce2016-01-05 14:59:19 -0500691 int N = iconSlots.size();
Joe Onorato0cbda992010-05-02 16:28:15 -0700692 int viewIndex = 0;
Jason Monk07473ce2016-01-05 14:59:19 -0500693 for (int i=0; i < N; i++) {
694 setIcon(iconSlots.get(i), icons.get(i));
Joe Onorato0cbda992010-05-02 16:28:15 -0700695 }
696
Christoph Studer71f18fd2014-05-20 17:02:04 +0200697 // Set up the initial notification state.
Christoph Studere71fefc2014-06-24 16:16:49 +0200698 try {
Christoph Studer4600f9b2014-07-22 22:44:43 +0200699 mNotificationListener.registerAsSystemService(mContext,
Christoph Studere71fefc2014-06-24 16:16:49 +0200700 new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
701 UserHandle.USER_ALL);
702 } catch (RemoteException e) {
703 Log.e(TAG, "Unable to register notification listener", e);
Joe Onorato75199e32010-05-29 17:22:51 -0400704 }
705
Christoph Studer60748e72014-05-22 16:51:41 +0200706
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500707 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400708 Log.d(TAG, String.format(
Daniel Sandler6a858c32012-03-12 14:38:58 -0400709 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
Jason Monk07473ce2016-01-05 14:59:19 -0500710 icons.size(),
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500711 switches[0],
712 switches[1],
713 switches[2],
714 switches[3]
715 ));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400716 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400717
Christopher Tate5e08af02012-09-21 17:17:22 -0700718 mCurrentUserId = ActivityManager.getCurrentUser();
Chris Wrena6d4fb62014-11-20 14:46:23 -0500719 setHeadsUpUser(mCurrentUserId);
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400720
721 IntentFilter filter = new IntentFilter();
722 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000723 filter.addAction(Intent.ACTION_USER_ADDED);
Kenny Guydae30d52015-04-01 19:11:35 +0100724 filter.addAction(Intent.ACTION_USER_PRESENT);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400725 filter.addAction(BANNER_ACTION_CANCEL);
726 filter.addAction(BANNER_ACTION_SETUP);
John Spurlock5c454122013-06-17 07:35:46 -0400727 mContext.registerReceiver(mBroadcastReceiver, filter);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000728
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000729 IntentFilter allUsersFilter = new IntentFilter();
730 allUsersFilter.addAction(
731 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
732 mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
733 null, null);
Kenny Guy2a764942014-04-02 13:29:20 +0100734 updateCurrentProfilesCache();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400735 }
736
Chris Wrencd8f4f72014-08-27 18:48:13 -0400737 protected void notifyUserAboutHiddenNotifications() {
738 if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
739 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
740 Log.d(TAG, "user hasn't seen notification about hidden notifications");
741 final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
Adrian Roosd6aa6cb2015-04-16 19:31:29 -0700742 if (!lockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
Chris Wrencd8f4f72014-08-27 18:48:13 -0400743 Log.d(TAG, "insecure lockscreen, skipping notification");
744 Settings.Secure.putInt(mContext.getContentResolver(),
745 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
746 return;
747 }
748 Log.d(TAG, "disabling lockecreen notifications and alerting the user");
749 // disable lockscreen notifications until user acts on the banner.
750 Settings.Secure.putInt(mContext.getContentResolver(),
751 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
Adrian Roosaee70462014-09-03 16:27:39 +0200752 Settings.Secure.putInt(mContext.getContentResolver(),
753 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400754
755 final String packageName = mContext.getPackageName();
756 PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
757 new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
758 PendingIntent.FLAG_CANCEL_CURRENT);
759 PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
760 new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
761 PendingIntent.FLAG_CANCEL_CURRENT);
762
763 final Resources res = mContext.getResources();
764 final int colorRes = com.android.internal.R.color.system_notification_accent_color;
765 Notification.Builder note = new Notification.Builder(mContext)
766 .setSmallIcon(R.drawable.ic_android)
767 .setContentTitle(mContext.getString(R.string.hidden_notifications_title))
768 .setContentText(mContext.getString(R.string.hidden_notifications_text))
769 .setPriority(Notification.PRIORITY_HIGH)
770 .setOngoing(true)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700771 .setColor(mContext.getColor(colorRes))
Chris Wrencd8f4f72014-08-27 18:48:13 -0400772 .setContentIntent(setupIntent)
773 .addAction(R.drawable.ic_close,
774 mContext.getString(R.string.hidden_notifications_cancel),
775 cancelIntent)
776 .addAction(R.drawable.ic_settings,
777 mContext.getString(R.string.hidden_notifications_setup),
778 setupIntent);
779
780 NotificationManager noMan =
781 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500782 noMan.notify(R.id.notification_hidden, note.build());
Chris Wrencd8f4f72014-08-27 18:48:13 -0400783 }
784 }
785
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400786 public void userSwitched(int newUserId) {
Chris Wrena6d4fb62014-11-20 14:46:23 -0500787 setHeadsUpUser(newUserId);
788 }
789
Selim Cinek29fa89b2015-04-17 10:39:11 -0700790 protected abstract void setHeadsUpUser(int newUserId);
Chris Wrend04f6ce2014-06-11 17:37:28 -0400791
Christoph Studerc8db24b2014-07-25 17:50:30 +0200792 @Override // NotificationData.Environment
793 public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400794 final int thisUserId = mCurrentUserId;
795 final int notificationUserId = n.getUserId();
796 if (DEBUG && MULTIUSER_DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400797 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400798 n, thisUserId, notificationUserId));
799 }
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500800 return isCurrentProfile(notificationUserId);
Joe Onorato2314aab2010-04-08 16:41:23 -0500801 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400802
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700803 protected void setNotificationShown(StatusBarNotification n) {
Chris Wren26505582015-07-22 17:03:17 -0400804 setNotificationsShown(new String[]{n.getKey()});
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700805 }
806
807 protected void setNotificationsShown(String[] keys) {
Chris Wren26505582015-07-22 17:03:17 -0400808 try {
809 mNotificationListener.setNotificationsShown(keys);
810 } catch (RuntimeException e) {
811 Log.d(TAG, "failed setNotificationsShown: ", e);
812 }
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700813 }
814
Kenny Guy44fc65f2014-11-28 22:18:14 +0000815 protected boolean isCurrentProfile(int userId) {
816 synchronized (mCurrentProfiles) {
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500817 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
Kenny Guy44fc65f2014-11-28 22:18:14 +0000818 }
819 }
820
Christoph Studer2e731b52014-08-22 16:01:51 +0200821 @Override
822 public String getCurrentMediaNotificationKey() {
823 return null;
824 }
825
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100826 @Override
827 public NotificationGroupManager getGroupManager() {
828 return mGroupManager;
829 }
830
Adrian Roos7d7090d2014-05-21 13:10:23 +0200831 /**
832 * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
833 * @param action A dismiss action that is called if it's safe to start the activity.
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200834 * @param afterKeyguardGone Whether the action should be executed after the Keyguard is gone.
Adrian Roos7d7090d2014-05-21 13:10:23 +0200835 */
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200836 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200837 action.onDismiss();
838 }
839
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700840 @Override
841 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400842 final Locale locale = mContext.getResources().getConfiguration().locale;
843 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
Dan Sandler539aad42014-08-04 00:43:39 -0400844 final float fontScale = newConfig.fontScale;
Selim Cinek01af3342016-02-09 19:25:31 -0800845 final int density = newConfig.densityDpi;
846 if (density != mDensity || mFontScale != fontScale) {
847 reInflateViews();
848 mDensity = density;
849 mFontScale = fontScale;
850 }
851 if (! locale.equals(mLocale) || ld != mLayoutDirection) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400852 if (DEBUG) {
853 Log.v(TAG, String.format(
854 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
855 locale, ld));
856 }
857 mLocale = locale;
858 mLayoutDirection = ld;
859 refreshLayout(ld);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700860 }
861 }
862
Selim Cinek01af3342016-02-09 19:25:31 -0800863 protected void reInflateViews() {
864 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
865 for (int i = 0; i < activeNotifications.size(); i++) {
866 Entry entry = activeNotifications.get(i);
867 boolean exposedGuts = entry.row.getGuts() == mNotificationGutsExposed;
868 entry.row.reInflateViews();
869 if (exposedGuts) {
870 mNotificationGutsExposed = entry.row.getGuts();
871 bindGuts(entry.row);
872 }
873 entry.cacheContentViews(mContext, null /* updatedNotification */);
874 inflateViews(entry, mStackScroller);
875 }
876 }
877
Selim Cinek757d8792016-01-28 16:21:08 -0800878 protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
Winson Chungc57ccf02011-10-13 15:04:59 -0700879 View vetoButton = row.findViewById(R.id.veto);
Selim Cinek757d8792016-01-28 16:21:08 -0800880 final String _pkg = n.getPackageName();
881 final String _tag = n.getTag();
882 final int _id = n.getId();
883 final int _userId = n.getUserId();
884 vetoButton.setOnClickListener(new View.OnClickListener() {
885 public void onClick(View v) {
886 // Accessibility feedback
887 v.announceForAccessibility(
888 mContext.getString(R.string.accessibility_notification_dismissed));
889 try {
890 mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700891
Selim Cinek757d8792016-01-28 16:21:08 -0800892 } catch (RemoteException ex) {
893 // system process is dead if we're here.
894 }
895 }
896 });
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700897 vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
Winson Chungc57ccf02011-10-13 15:04:59 -0700898 return vetoButton;
899 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400900
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400901
Christoph Studer13b895122014-08-26 15:42:12 +0200902 protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
Jorim Jaggi46739852014-04-15 09:58:24 +0200903 NotificationData.Entry entry) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400904
Selim Cinek684a4422015-04-15 16:18:39 -0700905 if (entry.getContentView().getId()
906 != com.android.internal.R.id.status_bar_latest_event_content) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400907 // Using custom RemoteViews
Jorim Jaggia1eeade2014-09-08 22:34:39 +0200908 if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700909 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
Selim Cinek697178b2014-07-02 19:40:30 +0200910 entry.row.setShowingLegacyBackground(true);
Jorim Jaggi36b15232014-06-10 17:24:20 +0200911 entry.legacy = true;
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400912 }
913 }
Christoph Studer13b895122014-08-26 15:42:12 +0200914
915 if (entry.icon != null) {
Jorim Jaggidd0107a2015-01-21 22:23:48 +0100916 entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
Christoph Studer13b895122014-08-26 15:42:12 +0200917 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400918 }
919
Dan Sandler16128f42014-05-21 12:48:22 -0400920 public boolean isMediaNotification(NotificationData.Entry entry) {
Dan Sandler842dd772014-05-15 09:36:47 -0400921 // TODO: confirm that there's a valid media key
Selim Cinek684a4422015-04-15 16:18:39 -0700922 return entry.getExpandedContentView() != null &&
923 entry.getExpandedContentView()
924 .findViewById(com.android.internal.R.id.media_actions) != null;
Dan Sandler842dd772014-05-15 09:36:47 -0400925 }
926
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200927 // The (i) button in the guts that links to the system notification settings for that app
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200928 private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
929 final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
Dan Sandlere9a4e902014-07-31 01:06:43 -0400930 intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
931 intent.putExtra(Settings.EXTRA_APP_UID, appUid);
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200932 startNotificationGutsIntent(intent, appUid);
933 }
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200934
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200935 private void startNotificationGutsIntent(final Intent intent, final int appUid) {
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200936 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
937 dismissKeyguardThenExecute(new OnDismissAction() {
938 @Override
939 public boolean onDismiss() {
940 AsyncTask.execute(new Runnable() {
941 public void run() {
942 try {
943 if (keyguardShowing) {
944 ActivityManagerNative.getDefault()
945 .keyguardWaitingForActivityDrawn();
946 }
947 TaskStackBuilder.create(mContext)
948 .addNextIntentWithParentStack(intent)
949 .startActivities(null,
950 new UserHandle(UserHandle.getUserId(appUid)));
951 overrideActivityPendingAppTransition(keyguardShowing);
952 } catch (RemoteException e) {
953 }
954 }
955 });
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100956 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200957 return true;
958 }
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200959 }, false /* afterKeyguardGone */);
Dan Sandler4247a5c2014-07-23 15:58:08 -0400960 }
961
Mady Mellorb53bc272016-02-11 18:28:23 -0800962 private void bindGuts(final ExpandableNotificationRow row) {
Selim Cinekab29aeb2015-02-20 18:18:32 +0100963 row.inflateGuts();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200964 final StatusBarNotification sbn = row.getStatusBarNotification();
Selim Cinekeef84282015-10-30 16:28:00 -0700965 PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200966 row.setTag(sbn.getPackageName());
Julia Reynoldsa07af882015-12-17 08:32:48 -0500967 final NotificationGuts guts = row.getGuts();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200968 final String pkg = sbn.getPackageName();
969 String appname = pkg;
970 Drawable pkgicon = null;
971 int appUid = -1;
972 try {
973 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
974 PackageManager.GET_UNINSTALLED_PACKAGES
975 | PackageManager.GET_DISABLED_COMPONENTS);
976 if (info != null) {
977 appname = String.valueOf(pmUser.getApplicationLabel(info));
978 pkgicon = pmUser.getApplicationIcon(info);
979 appUid = info.uid;
980 }
981 } catch (NameNotFoundException e) {
982 // app is gone, just show package name and generic icon
983 pkgicon = pmUser.getDefaultActivityIcon();
984 }
Julia Reynoldsead00aa2015-12-07 08:23:48 -0500985
Julia Reynoldsbe018462016-03-01 12:22:48 -0500986 ((ImageView) row.findViewById(R.id.app_icon)).setImageDrawable(pkgicon);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200987 ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
Julia Reynoldsead00aa2015-12-07 08:23:48 -0500988
Julia Reynolds56821922016-01-04 15:24:01 -0500989 final View settingsButton = guts.findViewById(R.id.more_settings);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200990 if (appUid >= 0) {
991 final int appUidF = appUid;
992 settingsButton.setOnClickListener(new View.OnClickListener() {
993 public void onClick(View v) {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500994 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200995 startAppNotificationSettingsActivity(pkg, appUidF);
996 }
997 });
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200998 } else {
999 settingsButton.setVisibility(View.GONE);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001000 }
1001
Julia Reynolds56821922016-01-04 15:24:01 -05001002 row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
1003 @Override
1004 public void onClick(View v) {
Julia Reynolds0714f622016-01-07 13:24:09 -05001005 guts.saveImportance(sbn);
Mady Mellorb53bc272016-02-11 18:28:23 -08001006
1007 int[] rowLocation = new int[2];
1008 int[] doneLocation = new int[2];
1009 row.getLocationOnScreen(rowLocation);
1010 v.getLocationOnScreen(doneLocation);
1011
1012 final int centerX = v.getWidth() / 2;
1013 final int centerY = v.getHeight() / 2;
1014 final int x = doneLocation[0] - rowLocation[0] + centerX;
1015 final int y = doneLocation[1] - rowLocation[1] + centerY;
1016 dismissPopups(x, y);
Julia Reynolds56821922016-01-04 15:24:01 -05001017 }
1018 });
1019
Julia Reynolds40779452016-02-23 13:43:32 -05001020 guts.bindImportance(pmUser, sbn, row, mNotificationData.getImportance(sbn.getKey()));
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001021 }
1022
Mady Mellor4b80b102016-01-22 08:03:58 -08001023 protected GearDisplayedListener getGearDisplayedListener() {
1024 return this;
1025 }
1026
Dan Sandler4247a5c2014-07-23 15:58:08 -04001027 protected SwipeHelper.LongPressListener getNotificationLongClicker() {
1028 return new SwipeHelper.LongPressListener() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001029 @Override
Selim Cinekd84a5932015-12-15 11:45:36 -08001030 public boolean onLongPress(View v, final int x, final int y) {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001031 if (!(v instanceof ExpandableNotificationRow)) {
1032 return false;
1033 }
Selim Cinekabdc5a02014-09-02 13:46:00 +02001034 if (v.getWindowToken() == null) {
1035 Log.e(TAG, "Trying to show notification guts, but not attached to window");
1036 return false;
1037 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001038
Mady Mellor4b80b102016-01-22 08:03:58 -08001039 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
Selim Cinekab29aeb2015-02-20 18:18:32 +01001040 bindGuts(row);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001041
Dan Sandler4247a5c2014-07-23 15:58:08 -04001042 // Assume we are a status_bar_notification_row
Selim Cinekab29aeb2015-02-20 18:18:32 +01001043 final NotificationGuts guts = row.getGuts();
Selim Cinekbdefcdf2014-09-11 12:41:47 +02001044 if (guts == null) {
1045 // This view has no guts. Examples are the more card or the dismiss all view
1046 return false;
1047 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001048
1049 // Already showing?
Selim Cinekabdc5a02014-09-02 13:46:00 +02001050 if (guts.getVisibility() == View.VISIBLE) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001051 dismissPopups(x, y);
Selim Cinekabdc5a02014-09-02 13:46:00 +02001052 return false;
1053 }
Dan Sandler4247a5c2014-07-23 15:58:08 -04001054
Chris Wrenf6e9228b2016-01-26 18:04:35 -05001055 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001056
Julia Reynolds40779452016-02-23 13:43:32 -05001057 // ensure that it's laid but not visible until actually laid out
Selim Cinekd84a5932015-12-15 11:45:36 -08001058 guts.setVisibility(View.INVISIBLE);
Julia Reynolds40779452016-02-23 13:43:32 -05001059 // Post to ensure the the guts are properly laid out.
Selim Cinekd84a5932015-12-15 11:45:36 -08001060 guts.post(new Runnable() {
1061 public void run() {
Mady Mellorb53bc272016-02-11 18:28:23 -08001062 dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001063 guts.setVisibility(View.VISIBLE);
1064 final double horz = Math.max(guts.getWidth() - x, x);
1065 final double vert = Math.max(guts.getHeight() - y, y);
1066 final float r = (float) Math.hypot(horz, vert);
1067 final Animator a
1068 = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
1069 a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc18010f2016-01-20 13:41:30 -08001070 a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Mady Mellor4b80b102016-01-22 08:03:58 -08001071 a.addListener(new AnimatorListenerAdapter() {
1072 @Override
1073 public void onAnimationEnd(Animator animation) {
1074 super.onAnimationEnd(animation);
1075 // Move the notification view back over the gear
1076 row.resetTranslation();
1077 }
1078 });
Selim Cinekd84a5932015-12-15 11:45:36 -08001079 a.start();
1080 guts.setExposed(true);
1081 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
1082 mNotificationGutsExposed = guts;
1083 }
1084 });
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001085 return true;
1086 }
1087 };
1088 }
1089
Mady Mellor4b80b102016-01-22 08:03:58 -08001090 @Override
1091 public void onGearDisplayed(ExpandableNotificationRow row) {
1092 mNotificationGearDisplayed = row;
1093 }
1094
Daniel Sandler469e96e2012-05-04 15:56:19 -04001095 public void dismissPopups() {
Mady Mellorb53bc272016-02-11 18:28:23 -08001096 dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */);
Selim Cinekd84a5932015-12-15 11:45:36 -08001097 }
1098
1099 private void dismissPopups(int x, int y) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001100 dismissPopups(x, y, true /* resetGear */);
1101 }
1102
1103 public void dismissPopups(int x, int y, boolean resetGear) {
Dan Sandler4247a5c2014-07-23 15:58:08 -04001104 if (mNotificationGutsExposed != null) {
Selim Cinek024ca592014-09-01 15:11:28 +02001105 final NotificationGuts v = mNotificationGutsExposed;
Dan Sandler4247a5c2014-07-23 15:58:08 -04001106 mNotificationGutsExposed = null;
1107
Selim Cinekedb893b2014-09-02 12:51:31 +02001108 if (v.getWindowToken() == null) return;
Selim Cinekd84a5932015-12-15 11:45:36 -08001109 if (x == -1 || y == -1) {
1110 x = (v.getLeft() + v.getRight()) / 2;
1111 y = (v.getTop() + v.getHeight() / 2);
1112 }
1113 final double horz = Math.max(v.getWidth() - x, x);
1114 final double vert = Math.max(v.getHeight() - y, y);
1115 final float r = (float) Math.hypot(horz, vert);
Dan Sandler4247a5c2014-07-23 15:58:08 -04001116 final Animator a = ViewAnimationUtils.createCircularReveal(v,
Selim Cinekd84a5932015-12-15 11:45:36 -08001117 x, y, r, 0);
1118 a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc18010f2016-01-20 13:41:30 -08001119 a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
Dan Sandler4247a5c2014-07-23 15:58:08 -04001120 a.addListener(new AnimatorListenerAdapter() {
1121 @Override
1122 public void onAnimationEnd(Animator animation) {
1123 super.onAnimationEnd(animation);
1124 v.setVisibility(View.GONE);
1125 }
1126 });
1127 a.start();
Selim Cinekd84a5932015-12-15 11:45:36 -08001128 v.setExposed(false);
1129 mStackScroller.onHeightChanged(null, true /* needsAnimation */);
Daniel Sandler469e96e2012-05-04 15:56:19 -04001130 }
Mady Mellorb53bc272016-02-11 18:28:23 -08001131 if (resetGear && mNotificationGearDisplayed != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001132 mNotificationGearDisplayed.resetTranslation();
1133 mNotificationGearDisplayed = null;
1134 }
Daniel Sandler469e96e2012-05-04 15:56:19 -04001135 }
1136
Michael Jurka7f2668c2012-03-27 07:49:52 -07001137 @Override
Winson Chung1e8d71b2014-05-16 17:05:22 -07001138 public void showRecentApps(boolean triggeredFromAltTab) {
1139 int msg = MSG_SHOW_RECENT_APPS;
1140 mHandler.removeMessages(msg);
1141 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, 0).sendToTarget();
1142 }
1143
1144 @Override
Winson Chungcdcd4872014-08-05 18:00:13 -07001145 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001146 int msg = MSG_HIDE_RECENT_APPS;
1147 mHandler.removeMessages(msg);
Winson Chungcdcd4872014-08-05 18:00:13 -07001148 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0,
1149 triggeredFromHomeKey ? 1 : 0).sendToTarget();
Winson Chung1e8d71b2014-05-16 17:05:22 -07001150 }
1151
1152 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001153 public void toggleRecentApps() {
Jorim Jaggi900fb482015-06-02 15:07:33 -07001154 toggleRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001155 }
1156
1157 @Override
Phil Weaver315c34e2016-02-19 15:12:29 -08001158 public void toggleSplitScreen() {
1159 toggleSplitScreenMode();
1160 }
1161
1162 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001163 public void preloadRecentApps() {
1164 int msg = MSG_PRELOAD_RECENT_APPS;
1165 mHandler.removeMessages(msg);
1166 mHandler.sendEmptyMessage(msg);
1167 }
1168
1169 @Override
1170 public void cancelPreloadRecentApps() {
1171 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
1172 mHandler.removeMessages(msg);
1173 mHandler.sendEmptyMessage(msg);
1174 }
1175
Clara Bayarrif2debb12015-07-10 14:47:17 +01001176 @Override
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001177 public void toggleKeyboardShortcutsMenu() {
1178 int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
Clara Bayarrif2debb12015-07-10 14:47:17 +01001179 mHandler.removeMessages(msg);
1180 mHandler.sendEmptyMessage(msg);
1181 }
1182
Winson Chungb1f74992014-08-08 12:53:09 -07001183 /** Jumps to the next affiliated task in the group. */
1184 public void showNextAffiliatedTask() {
1185 int msg = MSG_SHOW_NEXT_AFFILIATED_TASK;
1186 mHandler.removeMessages(msg);
1187 mHandler.sendEmptyMessage(msg);
1188 }
1189
1190 /** Jumps to the previous affiliated task in the group. */
1191 public void showPreviousAffiliatedTask() {
1192 int msg = MSG_SHOW_PREV_AFFILIATED_TASK;
1193 mHandler.removeMessages(msg);
1194 mHandler.sendEmptyMessage(msg);
1195 }
1196
Michael Jurkaecc395a2012-03-30 05:31:46 -07001197 protected H createHandler() {
Michael Jurka7f2668c2012-03-27 07:49:52 -07001198 return new H();
1199 }
1200
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001201 protected void sendCloseSystemWindows(String reason) {
Michael Jurka56a57832012-05-14 13:24:43 -07001202 if (ActivityManagerNative.isSystemReady()) {
1203 try {
1204 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
1205 } catch (RemoteException e) {
1206 }
1207 }
1208 }
1209
Michael Jurkacb2522c2012-04-13 09:32:47 -07001210 protected abstract View getStatusBarView();
1211
Michael Jurka80343f62012-10-18 13:13:46 +02001212 protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
1213 // additional optimization when we have software system buttons - start loading the recent
1214 // tasks on touch down
1215 @Override
1216 public boolean onTouch(View v, MotionEvent event) {
1217 int action = event.getAction() & MotionEvent.ACTION_MASK;
1218 if (action == MotionEvent.ACTION_DOWN) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001219 preloadRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001220 } else if (action == MotionEvent.ACTION_CANCEL) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001221 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001222 } else if (action == MotionEvent.ACTION_UP) {
1223 if (!v.isPressed()) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001224 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001225 }
1226
1227 }
1228 return false;
1229 }
1230 };
1231
Phil Weaver315c34e2016-02-19 15:12:29 -08001232 /**
1233 * Toggle docking the app window
1234 *
1235 * @return {@code true} if the app window is docked after the toggle, {@code false} otherwise.
1236 */
1237 protected abstract boolean toggleSplitScreenMode();
1238
Winson Chung1e8d71b2014-05-16 17:05:22 -07001239 /** Proxy for RecentsComponent */
1240
1241 protected void showRecents(boolean triggeredFromAltTab) {
1242 if (mRecents != null) {
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001243 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001244 mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
1245 }
1246 }
1247
Winson Chungcdcd4872014-08-05 18:00:13 -07001248 protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001249 if (mRecents != null) {
Winson Chungcdcd4872014-08-05 18:00:13 -07001250 mRecents.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001251 }
1252 }
1253
1254 protected void toggleRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001255 if (mRecents != null) {
1256 mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
1257 }
1258 }
Michael Jurka80343f62012-10-18 13:13:46 +02001259
Winson Chung1e8d71b2014-05-16 17:05:22 -07001260 protected void preloadRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001261 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001262 mRecents.preloadRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001263 }
Michael Jurka80343f62012-10-18 13:13:46 +02001264 }
1265
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001266 protected void toggleKeyboardShortcuts() {
Andrei Stingaceanu8861cb02016-01-20 16:48:30 +00001267 getKeyboardShortcuts().toggleKeyboardShortcuts();
Clara Bayarrif2debb12015-07-10 14:47:17 +01001268 }
1269
Winson Chung1e8d71b2014-05-16 17:05:22 -07001270 protected void cancelPreloadingRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001271 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001272 mRecents.cancelPreloadingRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001273 }
Michael Jurka80343f62012-10-18 13:13:46 +02001274 }
1275
Winson Chungb1f74992014-08-08 12:53:09 -07001276 protected void showRecentsNextAffiliatedTask() {
1277 if (mRecents != null) {
1278 mRecents.showNextAffiliatedTask();
1279 }
1280 }
1281
1282 protected void showRecentsPreviousAffiliatedTask() {
1283 if (mRecents != null) {
1284 mRecents.showPrevAffiliatedTask();
1285 }
1286 }
1287
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001288 /**
Selim Cinek684a4422015-04-15 16:18:39 -07001289 * If there is an active heads-up notification and it has a fullscreen intent, fire it now.
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001290 */
Selim Cinek684a4422015-04-15 16:18:39 -07001291 public abstract void maybeEscalateHeadsUp();
Chris Wrena4ef6202014-06-09 18:07:30 -04001292
Dan Sandlerfd16d562014-02-13 18:43:31 -08001293 /**
1294 * Save the current "public" (locked and secure) state of the lockscreen.
1295 */
1296 public void setLockscreenPublicMode(boolean publicMode) {
1297 mLockscreenPublicMode = publicMode;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001298 }
1299
Dan Sandlerfd16d562014-02-13 18:43:31 -08001300 public boolean isLockscreenPublicMode() {
1301 return mLockscreenPublicMode;
1302 }
1303
1304 /**
1305 * Has the given user chosen to allow their private (full) notifications to be shown even
1306 * when the lockscreen is in "public" (secure & locked) mode?
1307 */
1308 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
1309 if (userHandle == UserHandle.USER_ALL) {
1310 return true;
1311 }
1312
1313 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001314 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
Dan Sandlerfd16d562014-02-13 18:43:31 -08001315 mContext.getContentResolver(),
1316 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001317 final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001318 final boolean allowed = allowedByUser && allowedByDpm;
1319 mUsersAllowingPrivateNotifications.append(userHandle, allowed);
Dan Sandlerfd16d562014-02-13 18:43:31 -08001320 return allowed;
1321 }
1322
1323 return mUsersAllowingPrivateNotifications.get(userHandle);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001324 }
1325
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00001326 private boolean adminAllowsUnredactedNotifications(int userHandle) {
1327 if (userHandle == UserHandle.USER_ALL) {
1328 return true;
1329 }
1330 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
1331 userHandle);
1332 return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
1333 }
1334
Christoph Studerc8db24b2014-07-25 17:50:30 +02001335 /**
1336 * Returns true if we're on a secure lockscreen and the user wants to hide "sensitive"
1337 * notification data. If so, private notifications should show their (possibly
1338 * auto-generated) publicVersion, and secret notifications should be totally invisible.
1339 */
1340 @Override // NotificationData.Environment
1341 public boolean shouldHideSensitiveContents(int userid) {
1342 return isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(userid);
1343 }
1344
Chris Wrena4ef6202014-06-09 18:07:30 -04001345 public void onNotificationClear(StatusBarNotification notification) {
1346 try {
1347 mBarService.onNotificationClear(
1348 notification.getPackageName(),
1349 notification.getTag(),
1350 notification.getId(),
1351 notification.getUserId());
1352 } catch (android.os.RemoteException ex) {
1353 // oh well
1354 }
1355 }
1356
Selim Cinek5f71bee2015-11-18 10:25:23 -08001357 /**
Selim Cinek5fbc6322016-01-15 17:17:58 -08001358 * Called when the notification panel layouts
Selim Cinek5f71bee2015-11-18 10:25:23 -08001359 */
Selim Cinek5fbc6322016-01-15 17:17:58 -08001360 public void onPanelLaidOut() {
Selim Cinek5f71bee2015-11-18 10:25:23 -08001361 if (mState == StatusBarState.KEYGUARD) {
1362 // Since the number of notifications is determined based on the height of the view, we
1363 // need to update them.
Selim Cinek5fbc6322016-01-15 17:17:58 -08001364 int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
1365 int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
1366 if (maxBefore != maxNotifications) {
1367 updateRowStates();
1368 }
Selim Cinek5f71bee2015-11-18 10:25:23 -08001369 }
1370 }
1371
Adrian Roos3aec6382016-02-05 14:19:01 -08001372 protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
1373
Selim Cinek570981d2015-12-01 11:37:01 -08001374 @Override
Selim Cinek31aada42015-12-18 17:51:15 -08001375 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
Selim Cinek570981d2015-12-01 11:37:01 -08001376 }
1377
Michael Jurka7f2668c2012-03-27 07:49:52 -07001378 protected class H extends Handler {
1379 public void handleMessage(Message m) {
1380 switch (m.what) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001381 case MSG_SHOW_RECENT_APPS:
1382 showRecents(m.arg1 > 0);
Michael Jurkacb2522c2012-04-13 09:32:47 -07001383 break;
Winson Chung1e8d71b2014-05-16 17:05:22 -07001384 case MSG_HIDE_RECENT_APPS:
Winson Chungcdcd4872014-08-05 18:00:13 -07001385 hideRecents(m.arg1 > 0, m.arg2 > 0);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001386 break;
1387 case MSG_TOGGLE_RECENTS_APPS:
1388 toggleRecents();
Michael Jurkacb2522c2012-04-13 09:32:47 -07001389 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001390 case MSG_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001391 preloadRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001392 break;
1393 case MSG_CANCEL_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001394 cancelPreloadingRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001395 break;
Winson Chungb1f74992014-08-08 12:53:09 -07001396 case MSG_SHOW_NEXT_AFFILIATED_TASK:
1397 showRecentsNextAffiliatedTask();
1398 break;
1399 case MSG_SHOW_PREV_AFFILIATED_TASK:
1400 showRecentsPreviousAffiliatedTask();
1401 break;
Andrei Stingaceanuc22ab792016-01-07 12:39:38 +00001402 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
1403 toggleKeyboardShortcuts();
Clara Bayarrif2debb12015-07-10 14:47:17 +01001404 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001405 }
1406 }
1407 }
1408
Daniel Sandler6a858c32012-03-12 14:38:58 -04001409 protected void workAroundBadLayerDrawableOpacity(View v) {
1410 }
1411
Selim Cinek8d490d42015-04-10 00:05:50 -07001412 protected boolean inflateViews(Entry entry, ViewGroup parent) {
Selim Cinekeef84282015-10-30 16:28:00 -07001413 PackageManager pmUser = getPackageManagerForUser(mContext,
Dan Sandlere9a4e902014-07-31 01:06:43 -04001414 entry.notification.getUser().getIdentifier());
1415
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001416 final StatusBarNotification sbn = entry.notification;
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001417 entry.cacheContentViews(mContext, null);
1418
1419 final RemoteViews contentView = entry.cachedContentView;
1420 final RemoteViews bigContentView = entry.cachedBigContentView;
1421 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
1422 final RemoteViews publicContentView = entry.cachedPublicContentView;
Chris Wren8fd39ec2014-02-27 17:43:26 -05001423
Chris Wren574a55e2013-07-15 18:48:37 -04001424 if (contentView == null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001425 Log.v(TAG, "no contentView for: " + sbn.getNotification());
Daniel Sandler6a858c32012-03-12 14:38:58 -04001426 return false;
1427 }
1428
Dan Sandlerf68448e2014-04-24 15:54:16 -04001429 if (DEBUG) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001430 Log.v(TAG, "publicContentView: " + publicContentView);
Dan Sandlerf68448e2014-04-24 15:54:16 -04001431 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001432
Christoph Studera7fe6312014-06-27 19:32:44 +02001433 ExpandableNotificationRow row;
1434
1435 // Stash away previous user expansion state so we can restore it at
1436 // the end.
1437 boolean hasUserChangedExpansion = false;
1438 boolean userExpanded = false;
1439 boolean userLocked = false;
1440
1441 if (entry.row != null) {
1442 row = entry.row;
1443 hasUserChangedExpansion = row.hasUserChangedExpansion();
1444 userExpanded = row.isUserExpanded();
1445 userLocked = row.isUserLocked();
Christoph Studer22f2ee52014-07-29 22:57:21 +02001446 entry.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +02001447 if (hasUserChangedExpansion) {
1448 row.setUserExpanded(userExpanded);
1449 }
1450 } else {
1451 // create the row view
1452 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
1453 Context.LAYOUT_INFLATER_SERVICE);
1454 row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
1455 parent, false);
Chris Wren78403d72014-07-28 10:23:24 +01001456 row.setExpansionLogger(this, entry.notification.getKey());
Selim Cinekb5605e52015-02-20 18:21:41 +01001457 row.setGroupManager(mGroupManager);
Selim Cinek31aada42015-12-18 17:51:15 -08001458 row.setHeadsUpManager(mHeadsUpManager);
Adrian Roosb88b1a12015-12-09 18:51:05 -08001459 row.setRemoteInputController(mRemoteInputController);
Selim Cinek570981d2015-12-01 11:37:01 -08001460 row.setOnExpandClickListener(this);
Christoph Studera7fe6312014-06-27 19:32:44 +02001461 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001462
Daniel Sandler6a858c32012-03-12 14:38:58 -04001463 workAroundBadLayerDrawableOpacity(row);
Selim Cinek757d8792016-01-28 16:21:08 -08001464 View vetoButton = bindVetoButtonClickListener(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001465 vetoButton.setContentDescription(mContext.getString(
1466 R.string.accessibility_remove_notification));
1467
1468 // NB: the large icon is now handled entirely by the template
1469
1470 // bind the click event to the content area
Selim Cinek8d490d42015-04-10 00:05:50 -07001471 NotificationContentView contentContainer = row.getPrivateLayout();
1472 NotificationContentView contentContainerPublic = row.getPublicLayout();
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001473
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001474 row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
Adrian Roos497ab022015-02-10 20:49:33 +01001475 if (ENABLE_REMOTE_INPUT) {
1476 row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
1477 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001478
Chris Wren42d5dd42015-05-01 10:39:26 -04001479 mNotificationClicker.register(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001480
Dan Sandlera5e0f412014-01-23 15:11:54 -05001481 // set up the adaptive layout
Chris Wren574a55e2013-07-15 18:48:37 -04001482 View contentViewLocal = null;
1483 View bigContentViewLocal = null;
Selim Cinek8d490d42015-04-10 00:05:50 -07001484 View headsUpContentViewLocal = null;
Selim Cinek624c02db2015-12-14 21:00:02 -08001485 View publicViewLocal = null;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001486 try {
Dan Sandler68079d52015-07-22 10:45:30 -04001487 contentViewLocal = contentView.apply(
1488 sbn.getPackageContext(mContext),
1489 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001490 mOnClickHandler);
Chris Wren574a55e2013-07-15 18:48:37 -04001491 if (bigContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001492 bigContentViewLocal = bigContentView.apply(
1493 sbn.getPackageContext(mContext),
1494 contentContainer,
Selim Cinek8d490d42015-04-10 00:05:50 -07001495 mOnClickHandler);
1496 }
1497 if (headsUpContentView != null) {
Dan Sandler68079d52015-07-22 10:45:30 -04001498 headsUpContentViewLocal = headsUpContentView.apply(
1499 sbn.getPackageContext(mContext),
1500 contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001501 mOnClickHandler);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001502 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001503 if (publicContentView != null) {
1504 publicViewLocal = publicContentView.apply(
1505 sbn.getPackageContext(mContext),
1506 contentContainerPublic, mOnClickHandler);
1507 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001508 }
1509 catch (RuntimeException e) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001510 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
John Spurlockcd686b52013-06-05 10:13:46 -04001511 Log.e(TAG, "couldn't inflate view for notification " + ident, e);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001512 return false;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001513 }
1514
Chris Wren574a55e2013-07-15 18:48:37 -04001515 if (contentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001516 contentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001517 contentContainer.setContractedChild(contentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001518 }
Chris Wren574a55e2013-07-15 18:48:37 -04001519 if (bigContentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001520 bigContentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001521 contentContainer.setExpandedChild(bigContentViewLocal);
1522 }
1523 if (headsUpContentViewLocal != null) {
1524 headsUpContentViewLocal.setIsRootNamespace(true);
1525 contentContainer.setHeadsUpChild(headsUpContentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001526 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001527 if (publicViewLocal != null) {
1528 publicViewLocal.setIsRootNamespace(true);
1529 contentContainerPublic.setContractedChild(publicViewLocal);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001530 }
1531
Jorim Jaggia1eeade2014-09-08 22:34:39 +02001532 // Extract target SDK version.
1533 try {
1534 ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
1535 entry.targetSdk = info.targetSdkVersion;
1536 } catch (NameNotFoundException ex) {
1537 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
1538 }
Selim Cinek624c02db2015-12-14 21:00:02 -08001539 entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001540
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001541 if (MULTIUSER_DEBUG) {
1542 TextView debug = (TextView) row.findViewById(R.id.debug_info);
1543 if (debug != null) {
1544 debug.setVisibility(View.VISIBLE);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001545 debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId());
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001546 }
1547 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001548 entry.row = row;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001549 entry.row.setOnActivatedListener(this);
Selim Cinek684a4422015-04-15 16:18:39 -07001550 entry.row.setExpandable(bigContentViewLocal != null);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001551
Christoph Studer13b895122014-08-26 15:42:12 +02001552 applyColorsAndBackgrounds(sbn, entry);
Jorim Jaggi46739852014-04-15 09:58:24 +02001553
Christoph Studera7fe6312014-06-27 19:32:44 +02001554 // Restore previous flags.
1555 if (hasUserChangedExpansion) {
1556 // Note: setUserExpanded() conveniently ignores calls with
1557 // userExpanded=true if !isExpandable().
1558 row.setUserExpanded(userExpanded);
1559 }
1560 row.setUserLocked(userLocked);
Selim Cinekda42d652015-12-04 15:51:16 -08001561 row.onNotificationUpdated(entry);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001562 return true;
1563 }
1564
Adrian Roos497ab022015-02-10 20:49:33 +01001565 /**
1566 * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
1567 * via first-class API.
1568 *
1569 * TODO: Remove once enough apps specify remote inputs on their own.
1570 */
1571 private void processForRemoteInput(Notification n) {
1572 if (!ENABLE_REMOTE_INPUT) return;
1573
1574 if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
1575 (n.actions == null || n.actions.length == 0)) {
1576 Notification.Action viableAction = null;
1577 Notification.WearableExtender we = new Notification.WearableExtender(n);
1578
1579 List<Notification.Action> actions = we.getActions();
1580 final int numActions = actions.size();
1581
1582 for (int i = 0; i < numActions; i++) {
1583 Notification.Action action = actions.get(i);
Adrian Roosa3539cb2015-12-16 16:47:02 -08001584 if (action == null) {
1585 continue;
1586 }
Adrian Roos497ab022015-02-10 20:49:33 +01001587 RemoteInput[] remoteInputs = action.getRemoteInputs();
Adrian Roosa3539cb2015-12-16 16:47:02 -08001588 if (remoteInputs == null) {
1589 continue;
1590 }
1591 for (RemoteInput ri : remoteInputs) {
Adrian Roos497ab022015-02-10 20:49:33 +01001592 if (ri.getAllowFreeFormInput()) {
1593 viableAction = action;
1594 break;
1595 }
1596 }
1597 if (viableAction != null) {
1598 break;
1599 }
1600 }
1601
1602 if (viableAction != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04001603 Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
1604 rebuilder.setActions(viableAction);
1605 rebuilder.build(); // will rewrite n
Adrian Roos497ab022015-02-10 20:49:33 +01001606 }
1607 }
1608 }
1609
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001610 protected KeyboardShortcuts getKeyboardShortcuts() {
1611 if (mKeyboardShortcuts == null) {
Andrei Stingaceanu8861cb02016-01-20 16:48:30 +00001612 mKeyboardShortcuts = new KeyboardShortcuts(mContext);
Andrei Stingaceanu9d9294c2015-08-24 17:19:06 +01001613 }
1614
1615 return mKeyboardShortcuts;
1616 }
1617
Adrian Roos62692b22015-09-11 17:46:23 -07001618 public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
1619 if (!isDeviceProvisioned()) return;
1620
1621 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
1622 final boolean afterKeyguardGone = intent.isActivity()
1623 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
1624 mCurrentUserId);
1625 dismissKeyguardThenExecute(new OnDismissAction() {
1626 public boolean onDismiss() {
1627 new Thread() {
1628 @Override
1629 public void run() {
1630 try {
1631 if (keyguardShowing && !afterKeyguardGone) {
1632 ActivityManagerNative.getDefault()
1633 .keyguardWaitingForActivityDrawn();
1634 }
1635
1636 // The intent we are sending is for the application, which
1637 // won't have permission to immediately start an activity after
1638 // the user switches to home. We know it is safe to do at this
1639 // point, so make sure new activity switches are now allowed.
1640 ActivityManagerNative.getDefault().resumeAppSwitches();
1641 } catch (RemoteException e) {
1642 }
1643
1644 try {
1645 intent.send();
1646 } catch (PendingIntent.CanceledException e) {
1647 // the stack trace isn't very helpful here.
1648 // Just log the exception message.
1649 Log.w(TAG, "Sending intent failed: " + e);
1650
1651 // TODO: Dismiss Keyguard.
1652 }
1653 if (intent.isActivity()) {
1654 mAssistManager.hideAssist();
1655 overrideActivityPendingAppTransition(keyguardShowing
1656 && !afterKeyguardGone);
1657 }
1658 }
1659 }.start();
1660
1661 // close the shade if it was open
1662 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
1663 true /* force */, true /* delayed */);
1664 visibilityChanged(false);
1665
1666 return true;
1667 }
1668 }, afterKeyguardGone);
1669 }
1670
Chris Wren42d5dd42015-05-01 10:39:26 -04001671 private final class NotificationClicker implements View.OnClickListener {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001672 public void onClick(final View v) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001673 if (!(v instanceof ExpandableNotificationRow)) {
1674 Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
1675 return;
1676 }
1677
1678 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
1679 final StatusBarNotification sbn = row.getStatusBarNotification();
1680 if (sbn == null) {
1681 Log.e(TAG, "NotificationClicker called on an unclickable notification,");
1682 return;
1683 }
1684
Mady Mellorf0625802016-02-11 18:03:48 -08001685 // Check if the notification is displaying the gear, if so slide notification back
1686 if (row.getSettingsRow() != null && row.getSettingsRow().isVisible()) {
1687 row.animateTranslateNotification(0);
1688 return;
1689 }
1690
Selim Cinekc6dd5212015-11-02 14:51:54 -08001691 Notification notification = sbn.getNotification();
1692 final PendingIntent intent = notification.contentIntent != null
1693 ? notification.contentIntent
1694 : notification.fullScreenIntent;
Chris Wren42d5dd42015-05-01 10:39:26 -04001695 final String notificationKey = sbn.getKey();
1696
Jorim Jaggi5eb67c22015-08-19 19:50:49 -07001697 // Mark notification for one frame.
1698 row.setJustClicked(true);
1699 DejankUtils.postAfterTraversal(new Runnable() {
1700 @Override
1701 public void run() {
1702 row.setJustClicked(false);
1703 }
1704 });
1705
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001706 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Chris Wren42d5dd42015-05-01 10:39:26 -04001707 final boolean afterKeyguardGone = intent.isActivity()
1708 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001709 mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +02001710 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001711 public boolean onDismiss() {
Chris Wren42d5dd42015-05-01 10:39:26 -04001712 if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
Christoph Studerc6a656c2015-01-22 15:02:49 +01001713 // Release the HUN notification to the shade.
1714 //
1715 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
1716 // become canceled shortly by NoMan, but we can't assume that.
Selim Cinek0fccc722015-07-29 17:04:36 -07001717 HeadsUpManager.setIsClickedNotification(row, true);
Chris Wren42d5dd42015-05-01 10:39:26 -04001718 mHeadsUpManager.releaseImmediately(notificationKey);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001719 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001720 new Thread() {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001721 @Override
1722 public void run() {
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001723 try {
1724 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001725 ActivityManagerNative.getDefault()
1726 .keyguardWaitingForActivityDrawn();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001727 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001728
1729 // The intent we are sending is for the application, which
1730 // won't have permission to immediately start an activity after
1731 // the user switches to home. We know it is safe to do at this
1732 // point, so make sure new activity switches are now allowed.
1733 ActivityManagerNative.getDefault().resumeAppSwitches();
1734 } catch (RemoteException e) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001735 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001736
Chris Wren42d5dd42015-05-01 10:39:26 -04001737 if (intent != null) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001738 try {
Chris Wren42d5dd42015-05-01 10:39:26 -04001739 intent.send();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001740 } catch (PendingIntent.CanceledException e) {
1741 // the stack trace isn't very helpful here.
1742 // Just log the exception message.
1743 Log.w(TAG, "Sending contentIntent failed: " + e);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001744
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001745 // TODO: Dismiss Keyguard.
1746 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001747 if (intent.isActivity()) {
Jorim Jaggib835dd72015-06-08 12:28:42 -07001748 mAssistManager.hideAssist();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001749 overrideActivityPendingAppTransition(keyguardShowing
1750 && !afterKeyguardGone);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001751 }
1752 }
1753
1754 try {
Chris Wren42d5dd42015-05-01 10:39:26 -04001755 mBarService.onNotificationClick(notificationKey);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001756 } catch (RemoteException ex) {
1757 // system process is dead if we're here.
1758 }
Adrian Roos7d7090d2014-05-21 13:10:23 +02001759 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001760 }.start();
Adrian Roos7d7090d2014-05-21 13:10:23 +02001761
1762 // close the shade if it was open
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +01001763 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001764 true /* force */, true /* delayed */);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001765 visibilityChanged(false);
1766
Jorim Jaggi8972c2a2015-06-05 16:05:54 -07001767 return true;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001768 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001769 }, afterKeyguardGone);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001770 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001771
1772 public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
Selim Cinekc6dd5212015-11-02 14:51:54 -08001773 Notification notification = sbn.getNotification();
1774 if (notification.contentIntent != null || notification.fullScreenIntent != null) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001775 row.setOnClickListener(this);
1776 } else {
1777 row.setOnClickListener(null);
1778 }
1779 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001780 }
Chris Wrenf29c3b42013-11-27 16:30:30 -05001781
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001782 public void animateCollapsePanels(int flags, boolean force) {
1783 }
1784
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001785 public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
1786 }
1787
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001788 public void overrideActivityPendingAppTransition(boolean keyguardShowing) {
1789 if (keyguardShowing) {
1790 try {
1791 mWindowManagerService.overridePendingAppTransition(null, 0, 0, null);
1792 } catch (RemoteException e) {
1793 Log.w(TAG, "Error overriding app transition: " + e);
1794 }
1795 }
1796 }
1797
Christoph Studere8e28652014-10-29 17:27:53 +01001798 protected void visibilityChanged(boolean visible) {
1799 if (mVisible != visible) {
1800 mVisible = visible;
1801 if (!visible) {
1802 dismissPopups();
1803 }
1804 }
1805 updateVisibleToUser();
1806 }
1807
1808 protected void updateVisibleToUser() {
1809 boolean oldVisibleToUser = mVisibleToUser;
Jorim Jaggi50ff3af2015-08-12 18:35:42 -07001810 mVisibleToUser = mVisible && mDeviceInteractive;
Christoph Studere8e28652014-10-29 17:27:53 +01001811
1812 if (oldVisibleToUser != mVisibleToUser) {
1813 handleVisibleToUserChanged(mVisibleToUser);
1814 }
1815 }
1816
Daniel Sandler6a858c32012-03-12 14:38:58 -04001817 /**
Christoph Studere8e28652014-10-29 17:27:53 +01001818 * The LEDs are turned off when the notification panel is shown, even just a little bit.
Daniel Sandler6a858c32012-03-12 14:38:58 -04001819 */
Christoph Studere8e28652014-10-29 17:27:53 +01001820 protected void handleVisibleToUserChanged(boolean visibleToUser) {
1821 try {
1822 if (visibleToUser) {
Selim Cinek6577cae2015-08-31 16:15:49 -07001823 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
1824 boolean clearNotificationEffects =
1825 ((mShowLockscreenNotifications && mState == StatusBarState.KEYGUARD) ||
1826 (!pinnedHeadsUp && (mState == StatusBarState.SHADE
1827 || mState == StatusBarState.SHADE_LOCKED)));
Chris Wrenb659c4f2015-06-25 17:12:27 -04001828 int notificationLoad = mNotificationData.getActiveNotifications().size();
Selim Cinek6577cae2015-08-31 16:15:49 -07001829 if (pinnedHeadsUp && isPanelFullyCollapsed()) {
Chris Wrenb659c4f2015-06-25 17:12:27 -04001830 notificationLoad = 1;
1831 } else {
1832 MetricsLogger.histogram(mContext, "note_load", notificationLoad);
1833 }
1834 mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
Christoph Studere8e28652014-10-29 17:27:53 +01001835 } else {
1836 mBarService.onPanelHidden();
Dan Sandler4247a5c2014-07-23 15:58:08 -04001837 }
Christoph Studere8e28652014-10-29 17:27:53 +01001838 } catch (RemoteException ex) {
1839 // Won't fail unless the world has ended.
Daniel Sandler6a858c32012-03-12 14:38:58 -04001840 }
1841 }
1842
Chris Wren0c8275b2012-05-08 13:36:48 -04001843 /**
Chris Wren16895942015-06-23 11:22:20 -04001844 * Clear Buzz/Beep/Blink.
1845 */
1846 public void clearNotificationEffects() {
1847 try {
1848 mBarService.clearNotificationEffects();
1849 } catch (RemoteException e) {
1850 // Won't fail unless the world has ended.
1851 }
1852 }
1853
1854 protected abstract boolean isPanelFullyCollapsed();
1855
1856 /**
Chris Wren0c8275b2012-05-08 13:36:48 -04001857 * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
1858 * about the failure.
1859 *
1860 * WARNING: this will call back into us. Don't hold any locks.
1861 */
Christoph Studer71f18fd2014-05-20 17:02:04 +02001862 void handleNotificationError(StatusBarNotification n, String message) {
Christoph Studere71fefc2014-06-24 16:16:49 +02001863 removeNotification(n.getKey(), null);
Chris Wren0c8275b2012-05-08 13:36:48 -04001864 try {
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001865 mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
1866 n.getInitialPid(), message, n.getUserId());
Chris Wren0c8275b2012-05-08 13:36:48 -04001867 } catch (RemoteException ex) {
1868 // The end is nigh.
1869 }
1870 }
1871
Christoph Studerd0694b62014-06-04 16:36:01 +02001872 protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
Christoph Studer37fe6932014-05-26 13:10:30 +02001873 NotificationData.Entry entry = mNotificationData.remove(key, ranking);
Chris Wren0c8275b2012-05-08 13:36:48 -04001874 if (entry == null) {
John Spurlockcd686b52013-06-05 10:13:46 -04001875 Log.w(TAG, "removeNotification for unknown key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -04001876 return null;
1877 }
Christoph Studer37fe6932014-05-26 13:10:30 +02001878 updateNotifications();
Chris Wren0c8275b2012-05-08 13:36:48 -04001879 return entry.notification;
1880 }
1881
Selim Cinek8d490d42015-04-10 00:05:50 -07001882 protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04001883 if (DEBUG) {
Christoph Studera0506e72014-07-31 20:27:39 +02001884 Log.d(TAG, "createNotificationViews(notification=" + sbn);
Chris Wren0c8275b2012-05-08 13:36:48 -04001885 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01001886 final StatusBarIconView iconView = createIcon(sbn);
1887 if (iconView == null) {
1888 return null;
1889 }
1890
1891 // Construct the expanded view.
1892 NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
Selim Cinek8d490d42015-04-10 00:05:50 -07001893 if (!inflateViews(entry, mStackScroller)) {
Selim Cinek379ff8f2015-02-20 17:03:16 +01001894 handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
1895 return null;
1896 }
1897 return entry;
1898 }
1899
Xiaohui Chene90c2c52016-02-24 16:08:00 -08001900 public StatusBarIconView createIcon(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04001901 // Construct the icon.
Christoph Studera0506e72014-07-31 20:27:39 +02001902 Notification n = sbn.getNotification();
Chris Wren0c8275b2012-05-08 13:36:48 -04001903 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Christoph Studera0506e72014-07-31 20:27:39 +02001904 sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
Chris Wren0c8275b2012-05-08 13:36:48 -04001905 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
1906
Dan Sandler33439812015-08-10 15:49:56 -04001907 final Icon smallIcon = n.getSmallIcon();
1908 if (smallIcon == null) {
1909 handleNotificationError(sbn,
1910 "No small icon in notification from " + sbn.getPackageName());
1911 return null;
1912 }
Dan Sandlerd63f9322015-05-06 15:18:49 -04001913 final StatusBarIcon ic = new StatusBarIcon(
Christoph Studera0506e72014-07-31 20:27:39 +02001914 sbn.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04001915 sbn.getPackageName(),
Dan Sandler33439812015-08-10 15:49:56 -04001916 smallIcon,
Dan Sandler4e787062015-06-17 15:09:48 -04001917 n.iconLevel,
1918 n.number,
1919 n.tickerText);
Chris Wren0c8275b2012-05-08 13:36:48 -04001920 if (!iconView.set(ic)) {
Christoph Studera0506e72014-07-31 20:27:39 +02001921 handleNotificationError(sbn, "Couldn't create icon: " + ic);
Chris Wren0c8275b2012-05-08 13:36:48 -04001922 return null;
1923 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01001924 return iconView;
Chris Wrenf0048ce2013-08-07 16:43:43 -04001925 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001926
Christoph Studerd0694b62014-06-04 16:36:01 +02001927 protected void addNotificationViews(Entry entry, RankingMap ranking) {
Raju Yadav5f330262014-03-24 10:44:00 +01001928 if (entry == null) {
1929 return;
1930 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001931 // Add the expanded view and icon.
Christoph Studer37fe6932014-05-26 13:10:30 +02001932 mNotificationData.add(entry, ranking);
1933 updateNotifications();
Selim Cinek8efa6dd2014-05-19 16:27:37 +02001934 }
1935
Jorim Jaggi251957d2014-04-09 04:24:09 +02001936 /**
Selim Cinek5f71bee2015-11-18 10:25:23 -08001937 * @param recompute wheter the number should be recomputed
Jorim Jaggid4a57442014-04-10 02:45:55 +02001938 * @return The number of notifications we show on Keyguard.
1939 */
Selim Cinek5f71bee2015-11-18 10:25:23 -08001940 protected abstract int getMaxKeyguardNotifications(boolean recompute);
Jorim Jaggid4a57442014-04-10 02:45:55 +02001941
1942 /**
Jorim Jaggi251957d2014-04-09 04:24:09 +02001943 * Updates expanded, dimmed and locked states of notification rows.
1944 */
1945 protected void updateRowStates() {
Jorim Jaggif6411742014-08-05 17:10:43 +00001946 mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
1947
Christoph Studerc8db24b2014-07-25 17:50:30 +02001948 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1949 final int N = activeNotifications.size();
1950
Jorim Jaggif6411742014-08-05 17:10:43 +00001951 int visibleNotifications = 0;
Jorim Jaggiecbab362014-04-23 16:13:15 +02001952 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
Selim Cinek5f71bee2015-11-18 10:25:23 -08001953 int maxNotifications = 0;
1954 if (onKeyguard) {
1955 maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
1956 }
Christoph Studer37fe6932014-05-26 13:10:30 +02001957 for (int i = 0; i < N; i++) {
Christoph Studerc8db24b2014-07-25 17:50:30 +02001958 NotificationData.Entry entry = activeNotifications.get(i);
Jorim Jaggiecbab362014-04-23 16:13:15 +02001959 if (onKeyguard) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001960 entry.row.setOnKeyguard(true);
Chris Wren3ddab0d2012-08-02 16:52:21 -04001961 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -07001962 entry.row.setOnKeyguard(false);
1963 boolean top = (i == 0);
1964 entry.row.setSystemExpanded(top);
Chris Wren8fd12652012-05-09 21:25:57 -04001965 }
Selim Cinek83bc7832015-10-22 13:26:54 -07001966 boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
1967 boolean childWithVisibleSummary = childNotification
1968 && mGroupManager.getGroupSummary(entry.notification).getVisibility()
1969 == View.VISIBLE;
Jorim Jaggif6411742014-08-05 17:10:43 +00001970 boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
Jorim Jaggi9261b3b2014-09-08 14:02:07 +02001971 if ((isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
Selim Cinek5f71bee2015-11-18 10:25:23 -08001972 (onKeyguard && (visibleNotifications >= maxNotifications
Selim Cinek83bc7832015-10-22 13:26:54 -07001973 && !childWithVisibleSummary
1974 || !showOnKeyguard))) {
Jorim Jaggif6411742014-08-05 17:10:43 +00001975 entry.row.setVisibility(View.GONE);
Selim Cinek83bc7832015-10-22 13:26:54 -07001976 if (onKeyguard && showOnKeyguard && !childNotification) {
Jorim Jaggif6411742014-08-05 17:10:43 +00001977 mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
1978 }
1979 } else {
1980 boolean wasGone = entry.row.getVisibility() == View.GONE;
1981 entry.row.setVisibility(View.VISIBLE);
Selim Cinek83bc7832015-10-22 13:26:54 -07001982 if (!childNotification) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001983 if (wasGone) {
1984 // notify the scroller of a child addition
1985 mStackScroller.generateAddAnimation(entry.row, true /* fromMoreCard */);
1986 }
1987 visibleNotifications++;
Jorim Jaggif6411742014-08-05 17:10:43 +00001988 }
Jorim Jaggif6411742014-08-05 17:10:43 +00001989 }
Chris Wren8fd12652012-05-09 21:25:57 -04001990 }
Jorim Jaggif6411742014-08-05 17:10:43 +00001991
Selim Cinek2cd45df2015-06-09 18:00:07 -07001992 mStackScroller.updateOverflowContainerVisibility(onKeyguard
1993 && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0);
Jorim Jaggif6411742014-08-05 17:10:43 +00001994
Selim Cinek0cce5312015-05-20 22:13:55 -07001995 mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
1996 mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
Jorim Jaggif6411742014-08-05 17:10:43 +00001997 mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
1998 mStackScroller.getChildCount() - 3);
Jorim Jaggif6411742014-08-05 17:10:43 +00001999 }
2000
2001 private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
2002 return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
Chris Wren8fd12652012-05-09 21:25:57 -04002003 }
2004
John Spurlocke677d712014-02-13 12:52:19 -05002005 protected void setZenMode(int mode) {
John Spurlock110e5b12014-02-27 13:09:35 -05002006 if (!isDeviceProvisioned()) return;
John Spurlocke677d712014-02-13 12:52:19 -05002007 mZenMode = mode;
Christoph Studer37fe6932014-05-26 13:10:30 +02002008 updateNotifications();
John Spurlocke677d712014-02-13 12:52:19 -05002009 }
2010
Dan Sandler52e5701e2014-07-22 23:14:54 -04002011 // extended in PhoneStatusBar
2012 protected void setShowLockscreenNotifications(boolean show) {
2013 mShowLockscreenNotifications = show;
2014 }
2015
Adrian Roos3aec6382016-02-05 14:19:01 -08002016 protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
2017 mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
2018 }
2019
Dan Sandler52e5701e2014-07-22 23:14:54 -04002020 private void updateLockscreenNotificationSetting() {
2021 final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2022 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
2023 1,
2024 mCurrentUserId) != 0;
Adrian Roosbd3409c2014-08-12 18:21:09 +02002025 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
2026 null /* admin */, mCurrentUserId);
2027 final boolean allowedByDpm = (dpmFlags
2028 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
Adrian Roos3aec6382016-02-05 14:19:01 -08002029
2030 final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2031 Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
2032 0,
2033 mCurrentUserId) != 0;
2034
Adrian Roosbd3409c2014-08-12 18:21:09 +02002035 setShowLockscreenNotifications(show && allowedByDpm);
Adrian Roos3aec6382016-02-05 14:19:01 -08002036 setLockScreenAllowRemoteInput(remoteInput);
Dan Sandler52e5701e2014-07-22 23:14:54 -04002037 }
2038
Chris Wren0c8275b2012-05-08 13:36:48 -04002039 protected abstract void setAreThereNotifications();
Christoph Studer37fe6932014-05-26 13:10:30 +02002040 protected abstract void updateNotifications();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -07002041 public abstract boolean shouldDisableNavbarGestures();
Chris Wren0c8275b2012-05-08 13:36:48 -04002042
Christoph Studere71fefc2014-06-24 16:16:49 +02002043 public abstract void addNotification(StatusBarNotification notification,
Selim Cinek379ff8f2015-02-20 17:03:16 +01002044 RankingMap ranking, Entry oldEntry);
Christoph Studere71fefc2014-06-24 16:16:49 +02002045 protected abstract void updateNotificationRanking(RankingMap ranking);
2046 public abstract void removeNotification(String key, RankingMap ranking);
Christoph Studera7fe6312014-06-27 19:32:44 +02002047
Christoph Studere71fefc2014-06-24 16:16:49 +02002048 public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02002049 if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
Chris Wren0c8275b2012-05-08 13:36:48 -04002050
Chris Wrend04f6ce2014-06-11 17:37:28 -04002051 final String key = notification.getKey();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002052 Entry entry = mNotificationData.get(key);
2053 if (entry == null) {
Chris Wren0c8275b2012-05-08 13:36:48 -04002054 return;
Selim Cinek2d79f632015-11-02 15:13:29 -08002055 } else if (mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
2056 mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
Chris Wren0c8275b2012-05-08 13:36:48 -04002057 }
2058
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002059 Notification n = notification.getNotification();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002060 mNotificationData.updateRanking(ranking);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002061
Selim Cineka6a6f032015-11-23 15:46:24 -08002062 boolean applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
Chris Wrenbdf33762015-12-04 15:50:51 -05002063 boolean shouldPeek = shouldPeek(entry, notification);
Selim Cinek684a4422015-04-15 16:18:39 -07002064 boolean alertAgain = alertAgain(entry, n);
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002065 if (DEBUG) {
2066 Log.d(TAG, "applyInPlace=" + applyInPlace
Chris Wrenbdf33762015-12-04 15:50:51 -05002067 + " shouldPeek=" + shouldPeek
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002068 + " alertAgain=" + alertAgain);
2069 }
Chris Wren0c8275b2012-05-08 13:36:48 -04002070
Dan Sandler24813b02016-01-14 15:49:36 -05002071 final StatusBarNotification oldNotification = entry.notification;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002072 entry.notification = notification;
Dan Sandler24813b02016-01-14 15:49:36 -05002073 mGroupManager.onEntryUpdated(entry, oldNotification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002074
2075 boolean updateSuccessful = false;
2076 if (applyInPlace) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002077 if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
2078 try {
2079 if (entry.icon != null) {
2080 // Update the icon
Dan Sandlerd63f9322015-05-06 15:18:49 -04002081 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002082 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002083 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002084 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002085 n.iconLevel,
2086 n.number,
2087 n.tickerText);
2088 entry.icon.setNotification(n);
2089 if (!entry.icon.set(ic)) {
2090 handleNotificationError(notification, "Couldn't update icon: " + ic);
2091 return;
2092 }
2093 }
Selim Cinek8d490d42015-04-10 00:05:50 -07002094 updateNotificationViews(entry, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002095 updateSuccessful = true;
2096 }
2097 catch (RuntimeException e) {
Selim Cinek684a4422015-04-15 16:18:39 -07002098 // It failed to apply cleanly.
Adrian Roose458aa82015-12-08 16:17:19 -08002099 Log.w(TAG, "Couldn't reapply views for package " +
2100 notification.getPackageName(), e);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002101 }
2102 }
2103 if (!updateSuccessful) {
2104 if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
Dan Sandlerd63f9322015-05-06 15:18:49 -04002105 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002106 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04002107 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04002108 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002109 n.iconLevel,
2110 n.number,
2111 n.tickerText);
2112 entry.icon.setNotification(n);
2113 entry.icon.set(ic);
Selim Cinek8d490d42015-04-10 00:05:50 -07002114 inflateViews(entry, mStackScroller);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002115 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002116 updateHeadsUp(key, entry, shouldPeek, alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002117 updateNotifications();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002118
2119 // Update the veto button accordingly (and as a result, whether this row is
2120 // swipe-dismissable)
Selim Cinek757d8792016-01-28 16:21:08 -08002121 bindVetoButtonClickListener(entry.row, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002122
Selim Cinek684a4422015-04-15 16:18:39 -07002123 if (DEBUG) {
2124 // Is this for you?
2125 boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
2126 Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
2127 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002128
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002129 setAreThereNotifications();
2130 }
2131
Chris Wrenbdf33762015-12-04 15:50:51 -05002132 protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
Selim Cinek29fa89b2015-04-17 10:39:11 -07002133 boolean alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002134
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002135 private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
2136 final RemoteViews contentView = entry.cachedContentView;
2137 final RemoteViews bigContentView = entry.cachedBigContentView;
2138 final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
2139 final RemoteViews publicContentView = entry.cachedPublicContentView;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002140
Chris Wrene03f4e12013-08-08 16:48:48 -04002141 // Reapply the RemoteViews
Selim Cinek684a4422015-04-15 16:18:39 -07002142 contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
2143 if (bigContentView != null && entry.getExpandedContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002144 bigContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002145 entry.getExpandedContentView(),
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01002146 mOnClickHandler);
Chris Wrene03f4e12013-08-08 16:48:48 -04002147 }
Selim Cinek684a4422015-04-15 16:18:39 -07002148 View headsUpChild = entry.getHeadsUpContentView();
Selim Cinek8d490d42015-04-10 00:05:50 -07002149 if (headsUpContentView != null && headsUpChild != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002150 headsUpContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002151 headsUpChild, mOnClickHandler);
Selim Cinek8d490d42015-04-10 00:05:50 -07002152 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002153 if (publicContentView != null && entry.getPublicContentView() != null) {
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002154 publicContentView.reapply(sbn.getPackageContext(mContext),
Dan Sandler68079d52015-07-22 10:45:30 -04002155 entry.getPublicContentView(), mOnClickHandler);
Dan Sandlera5e0f412014-01-23 15:11:54 -05002156 }
Chris Wrene03f4e12013-08-08 16:48:48 -04002157 // update the contentIntent
Julia Reynoldsd9228f12015-10-20 10:37:27 -04002158 mNotificationClicker.register(entry.row, sbn);
Chris Wren42d5dd42015-05-01 10:39:26 -04002159
Selim Cinekda42d652015-12-04 15:51:16 -08002160 entry.row.onNotificationUpdated(entry);
Selim Cinek51ae05d2014-09-09 15:51:38 +02002161 entry.row.resetHeight();
Chris Wren0c8275b2012-05-08 13:36:48 -04002162 }
John Spurlock36231282012-06-23 17:11:27 -04002163
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002164 protected void updatePublicContentView(Entry entry,
2165 StatusBarNotification sbn) {
2166 final RemoteViews publicContentView = entry.cachedPublicContentView;
Selim Cineke4c068d2016-02-19 13:46:55 -08002167 View inflatedView = entry.getPublicContentView();
2168 if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002169 final boolean disabledByPolicy =
2170 !adminAllowsUnredactedNotifications(entry.notification.getUserId());
Selim Cineke4c068d2016-02-19 13:46:55 -08002171 String notificationHiddenText = mContext.getString(disabledByPolicy
2172 ? com.android.internal.R.string.notification_hidden_by_policy_text
2173 : com.android.internal.R.string.notification_hidden_text);
2174 TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
2175 if (titleView != null
2176 && !titleView.getText().toString().equals(notificationHiddenText)) {
2177 publicContentView.setTextViewText(android.R.id.title, notificationHiddenText);
2178 publicContentView.reapply(sbn.getPackageContext(mContext),
2179 inflatedView, mOnClickHandler);
2180 entry.row.onNotificationUpdated(entry);
2181 }
Sudheer Shankaf5b850e2016-01-25 19:58:59 +00002182 }
2183 }
2184
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002185 protected void notifyHeadsUpScreenOff() {
Selim Cinek684a4422015-04-15 16:18:39 -07002186 maybeEscalateHeadsUp();
Chris Wrene97f90b2013-08-07 17:39:35 -04002187 }
2188
Chris Wrend93d5ad2014-09-08 16:34:03 -04002189 private boolean alertAgain(Entry oldEntry, Notification newNotification) {
2190 return oldEntry == null || !oldEntry.hasInterrupted()
2191 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
Chris Wrend04f6ce2014-06-11 17:37:28 -04002192 }
2193
Chris Wrenbdf33762015-12-04 15:50:51 -05002194 protected boolean shouldPeek(Entry entry) {
2195 return shouldPeek(entry, entry.notification);
Chris Wren0c274b12015-07-17 10:34:53 -04002196 }
2197
Chris Wrenbdf33762015-12-04 15:50:51 -05002198 protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002199 if (mNotificationData.shouldFilterOut(sbn)) {
Chris Wrenbdf33762015-12-04 15:50:51 -05002200 if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
Christoph Studer2f9dbba2014-09-03 17:35:54 +02002201 return false;
2202 }
2203
Selim Cinekd5921912016-02-09 10:33:01 -08002204 boolean inUse = mPowerManager.isScreenOn()
2205 && (!mStatusBarKeyguardViewManager.isShowing()
2206 || mStatusBarKeyguardViewManager.isOccluded())
2207 && !mStatusBarKeyguardViewManager.isInputRestricted();
2208 try {
2209 inUse = inUse && !mDreamManager.isDreaming();
2210 } catch (RemoteException e) {
2211 Log.d(TAG, "failed to query dream manager", e);
2212 }
2213
2214 if (!inUse) {
2215 if (DEBUG) {
2216 Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
2217 }
2218 return false;
2219 }
2220
2221 if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
2222 if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
Chris Wrena6d4fb62014-11-20 14:46:23 -05002223 return false;
2224 }
2225
Chris Wrenbdf33762015-12-04 15:50:51 -05002226 if (entry.hasJustLaunchedFullScreenIntent()) {
2227 if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
2228 return false;
2229 }
2230
Julia Reynoldsf0f629f2016-02-25 09:34:04 -05002231 if (isSnoozedPackage(sbn)) {
2232 if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
2233 return false;
2234 }
2235
2236 if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_HIGH) {
2237 if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
2238 return false;
2239 }
2240
Selim Cinekd5921912016-02-09 10:33:01 -08002241 if (sbn.getNotification().fullScreenIntent != null) {
2242 if (mAccessibilityManager.isTouchExplorationEnabled()) {
2243 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
2244 return false;
2245 } else {
2246 return true;
2247 }
Chris Wrenbdf33762015-12-04 15:50:51 -05002248 }
2249
Selim Cinekd5921912016-02-09 10:33:01 -08002250 return true;
Chris Wren157026f2013-06-28 16:54:01 -04002251 }
2252
Selim Cinek29fa89b2015-04-17 10:39:11 -07002253 protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
2254
John Spurlockcfc359a2013-09-05 10:42:03 -04002255 public void setInteracting(int barWindow, boolean interacting) {
John Spurlockad3e6cb2013-04-30 08:47:43 -04002256 // hook for subclasses
2257 }
John Spurlock5c454122013-06-17 07:35:46 -04002258
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002259 public void setBouncerShowing(boolean bouncerShowing) {
2260 mBouncerShowing = bouncerShowing;
2261 }
2262
2263 /**
2264 * @return Whether the security bouncer from Keyguard is showing.
2265 */
2266 public boolean isBouncerShowing() {
2267 return mBouncerShowing;
2268 }
2269
John Spurlock5c454122013-06-17 07:35:46 -04002270 public void destroy() {
John Spurlock5c454122013-06-17 07:35:46 -04002271 mContext.unregisterReceiver(mBroadcastReceiver);
Christoph Studere71fefc2014-06-24 16:16:49 +02002272 try {
2273 mNotificationListener.unregisterAsSystemService();
2274 } catch (RemoteException e) {
2275 // Ignore.
Christoph Studer37fe6932014-05-26 13:10:30 +02002276 }
John Spurlock5c454122013-06-17 07:35:46 -04002277 }
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002278
2279 /**
2280 * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
2281 * return PackageManager for mContext
2282 */
Selim Cinekeef84282015-10-30 16:28:00 -07002283 public static PackageManager getPackageManagerForUser(Context context, int userId) {
2284 Context contextForUser = context;
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002285 // UserHandle defines special userId as negative values, e.g. USER_ALL
2286 if (userId >= 0) {
2287 try {
2288 // Create a context for the correct user so if a package isn't installed
2289 // for user 0 we can still load information about the package.
2290 contextForUser =
Selim Cinekeef84282015-10-30 16:28:00 -07002291 context.createPackageContextAsUser(context.getPackageName(),
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002292 Context.CONTEXT_RESTRICTED,
2293 new UserHandle(userId));
2294 } catch (NameNotFoundException e) {
2295 // Shouldn't fail to find the package name for system ui.
2296 }
2297 }
2298 return contextForUser.getPackageManager();
2299 }
Chris Wren78403d72014-07-28 10:23:24 +01002300
2301 @Override
2302 public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
2303 try {
2304 mBarService.onNotificationExpansionChanged(key, userAction, expanded);
2305 } catch (RemoteException e) {
2306 // Ignore.
2307 }
2308 }
Jim Millerab954542014-10-10 18:21:49 -07002309
2310 public boolean isKeyguardSecure() {
Dan Sandlere163a642015-03-01 22:58:32 -05002311 if (mStatusBarKeyguardViewManager == null) {
2312 // startKeyguard() hasn't been called yet, so we don't know.
2313 // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
2314 // value onVisibilityChanged().
2315 Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
2316 new Throwable());
2317 return false;
2318 }
Jim Millerab954542014-10-10 18:21:49 -07002319 return mStatusBarKeyguardViewManager.isSecure();
2320 }
Adrian Roos4f43dc02015-06-17 16:43:38 -07002321
2322 @Override
2323 public void showAssistDisclosure() {
2324 if (mAssistManager != null) {
2325 mAssistManager.showDisclosure();
2326 }
2327 }
Jorim Jaggi165ce062015-07-06 16:18:11 -07002328
2329 @Override
2330 public void startAssist(Bundle args) {
2331 if (mAssistManager != null) {
2332 mAssistManager.startAssist(args);
2333 }
2334 }
Joe Onorato2314aab2010-04-08 16:41:23 -05002335}