blob: 295fdc81e775bd8579353de1c9fc474b15478655 [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;
21import android.animation.TimeInterpolator;
Christopher Tate5e08af02012-09-21 17:17:22 -070022import android.app.ActivityManager;
Daniel Sandler6a858c32012-03-12 14:38:58 -040023import android.app.ActivityManagerNative;
Chris Wren51c75102013-07-16 20:49:17 -040024import android.app.Notification;
Chris Wrencd8f4f72014-08-27 18:48:13 -040025import android.app.NotificationManager;
Daniel Sandler6a858c32012-03-12 14:38:58 -040026import android.app.PendingIntent;
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;
Dan Sandlerf4db75c2014-09-03 18:02:31 +020037import android.content.pm.ResolveInfo;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000038import android.content.pm.UserInfo;
John Spurlockde84f0e2013-06-12 12:41:00 -040039import android.content.res.Configuration;
Chris Wrencd8f4f72014-08-27 18:48:13 -040040import android.content.res.Resources;
Daniel Sandler26cda272012-05-22 15:44:08 -040041import android.database.ContentObserver;
Jorim Jaggia1eeade2014-09-08 22:34:39 +020042import android.graphics.PorterDuff;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +010043import android.graphics.drawable.Drawable;
Dan Sandler4e787062015-06-17 15:09:48 -040044import android.graphics.drawable.Icon;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +020045import android.os.AsyncTask;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040046import android.os.Build;
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;
Joe Onorato808182d2010-07-09 18:52:06 -040063import android.util.Log;
Dan Sandlere163a642015-03-01 22:58:32 -050064import android.util.Slog;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000065import android.util.SparseArray;
Dan Sandlerfd16d562014-02-13 18:43:31 -080066import android.util.SparseBooleanArray;
Daniel Sandlerc638c1e2011-08-24 16:19:23 -070067import android.view.Display;
Kenny Guy540f7d22015-06-08 20:24:23 +010068import android.view.Gravity;
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;
Dan Sandler4247a5c2014-07-23 15:58:08 -040079import android.view.animation.AnimationUtils;
Dan Sandler18bb4f92014-07-14 16:48:27 -040080import android.widget.DateTimeView;
Chris Wren0c8275b2012-05-08 13:36:48 -040081import android.widget.ImageView;
Michael Jurkaa600fd92012-06-25 15:57:05 -070082import android.widget.RemoteViews;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040083import android.widget.TextView;
Kenny Guydae30d52015-04-01 19:11:35 +010084import android.widget.Toast;
Joe Onorato808182d2010-07-09 18:52:06 -040085
Chris Wrenbd6b5fb2015-06-09 14:58:34 -040086import com.android.internal.logging.MetricsLogger;
John Spurlockde84f0e2013-06-12 12:41:00 -040087import com.android.internal.statusbar.IStatusBarService;
88import com.android.internal.statusbar.StatusBarIcon;
89import com.android.internal.statusbar.StatusBarIconList;
Dan Sandler26e81cf2014-05-06 10:01:27 -040090import com.android.internal.util.NotificationColorUtil;
Chris Wrencd8f4f72014-08-27 18:48:13 -040091import com.android.internal.widget.LockPatternUtils;
Adrian Roosd6aa6cb2015-04-16 19:31:29 -070092import com.android.keyguard.KeyguardUpdateMonitor;
John Spurlockde84f0e2013-06-12 12:41:00 -040093import com.android.systemui.R;
John Spurlockd08de372013-06-24 13:06:08 -040094import com.android.systemui.RecentsComponent;
Dan Sandler4247a5c2014-07-23 15:58:08 -040095import com.android.systemui.SwipeHelper;
John Spurlockde84f0e2013-06-12 12:41:00 -040096import com.android.systemui.SystemUI;
Jorim Jaggib835dd72015-06-08 12:28:42 -070097import com.android.systemui.assist.AssistManager;
Jorim Jaggid61f2272014-12-19 20:35:35 +010098import com.android.systemui.recents.Recents;
Christoph Studer37fe6932014-05-26 13:10:30 +020099import com.android.systemui.statusbar.NotificationData.Entry;
Selim Cinek92d892c2014-09-11 15:11:00 +0200100import com.android.systemui.statusbar.phone.NavigationBarView;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100101import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200102import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700103import com.android.systemui.statusbar.policy.HeadsUpManager;
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200104import com.android.systemui.statusbar.policy.PreviewInflater;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100105import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
John Spurlockde84f0e2013-06-12 12:41:00 -0400106
Michael Jurkaa600fd92012-06-25 15:57:05 -0700107import java.util.ArrayList;
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200108import java.util.List;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700109import java.util.Locale;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400110
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100111import static com.android.keyguard.KeyguardHostView.OnDismissAction;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200112
Michael Jurka7f2668c2012-03-27 07:49:52 -0700113public abstract class BaseStatusBar extends SystemUI implements
Winson Chung9214eff2014-06-12 13:59:25 -0700114 CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
Christoph Studerc8db24b2014-07-25 17:50:30 +0200115 RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger,
116 NotificationData.Environment {
Daniel Sandler198a0302012-08-17 16:04:31 -0400117 public static final String TAG = "StatusBar";
John Spurlock7e6809a2014-08-06 16:03:14 -0400118 public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400119 public static final boolean MULTIUSER_DEBUG = false;
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400120
Chris Wren79ac09e2014-10-29 14:20:19 -0400121 // STOPSHIP disable once we resolve b/18102199
Chris Wren755f4022014-10-29 16:43:26 -0400122 private static final boolean NOTIFICATION_CLICK_DEBUG = true;
Chris Wren79ac09e2014-10-29 14:20:19 -0400123
Selim Cinekb5605e52015-02-20 18:21:41 +0100124 public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
125 && SystemProperties.getBoolean("debug.child_notifs", false);
Adrian Roos497ab022015-02-10 20:49:33 +0100126
Winson Chung1e8d71b2014-05-16 17:05:22 -0700127 protected static final int MSG_SHOW_RECENT_APPS = 1019;
128 protected static final int MSG_HIDE_RECENT_APPS = 1020;
129 protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700130 protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
131 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
Winson Chungb1f74992014-08-08 12:53:09 -0700132 protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
133 protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
Chris Wren0c8275b2012-05-08 13:36:48 -0400134
Chris Wren157026f2013-06-28 16:54:01 -0400135 protected static final boolean ENABLE_HEADS_UP = true;
136 // scores above this threshold should be displayed in heads up mode.
Chris Wren5d9b1532014-03-21 14:31:05 -0400137 protected static final int INTERRUPTION_THRESHOLD = 10;
Chris Wren22ae46e2014-02-26 18:08:09 -0500138 protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
Chris Wren0c8275b2012-05-08 13:36:48 -0400139
Michael Jurka56a57832012-05-14 13:24:43 -0700140 // Should match the value in PhoneWindowManager
141 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
142
Chris Wrencd8f4f72014-08-27 18:48:13 -0400143 private static final String BANNER_ACTION_CANCEL =
144 "com.android.systemui.statusbar.banner_action_cancel";
145 private static final String BANNER_ACTION_SETUP =
146 "com.android.systemui.statusbar.banner_action_setup";
147
Joe Onorato808182d2010-07-09 18:52:06 -0400148 protected CommandQueue mCommandQueue;
149 protected IStatusBarService mBarService;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700150 protected H mHandler = createHandler();
151
Chris Wren0c8275b2012-05-08 13:36:48 -0400152 // all notifications
Christoph Studerc8db24b2014-07-25 17:50:30 +0200153 protected NotificationData mNotificationData;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100154 protected NotificationStackScrollLayout mStackScroller;
Chris Wren0c8275b2012-05-08 13:36:48 -0400155
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100156 protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
157
Chris Wrena4ef6202014-06-09 18:07:30 -0400158 // for heads up notifications
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700159 protected HeadsUpManager mHeadsUpManager;
Chris Wren0c8275b2012-05-08 13:36:48 -0400160
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400161 protected int mCurrentUserId = 0;
Kenny Guy2a764942014-04-02 13:29:20 +0100162 final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400163
Daniel Sandler777dcde2013-09-30 10:21:45 -0400164 protected int mLayoutDirection = -1; // invalid
Selim Cineka8fefa52014-09-08 16:10:50 +0200165 protected AccessibilityManager mAccessibilityManager;
Selim Cinek92d892c2014-09-11 15:11:00 +0200166
167 // on-screen navigation buttons
168 protected NavigationBarView mNavigationBarView = null;
Christoph Studere8e28652014-10-29 17:27:53 +0100169
170 protected Boolean mScreenOn;
171
172 // The second field is a bit different from the first one because it only listens to screen on/
173 // screen of events from Keyguard. We need this so we don't have a race condition with the
174 // broadcast. In the future, we should remove the first field altogether and rename the second
175 // field.
176 protected boolean mScreenOnFromKeyguard;
177
178 protected boolean mVisible;
179
180 // mScreenOnFromKeyguard && mVisible.
181 private boolean mVisibleToUser;
182
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700183 private Locale mLocale;
Dan Sandler539aad42014-08-04 00:43:39 -0400184 private float mFontScale;
185
Chris Wrenf6e83f42013-09-11 14:02:59 -0400186 protected boolean mUseHeadsUp = false;
Chris Wren22ae46e2014-02-26 18:08:09 -0500187 protected boolean mHeadsUpTicker = false;
Jason Monkf7019542014-07-31 12:42:25 -0400188 protected boolean mDisableNotificationAlerts = false;
Chris Wren157026f2013-06-28 16:54:01 -0400189
Adrian Roosbd3409c2014-08-12 18:21:09 +0200190 protected DevicePolicyManager mDevicePolicyManager;
Chris Wren157026f2013-06-28 16:54:01 -0400191 protected IDreamManager mDreamManager;
Chris Wren157026f2013-06-28 16:54:01 -0400192 PowerManager mPowerManager;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200193 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Selim Cinek1685e632014-04-08 02:27:49 +0200194 protected int mRowMinHeight;
195 protected int mRowMaxHeight;
Dan Sandlerfd16d562014-02-13 18:43:31 -0800196
197 // public mode, private notifications, etc
198 private boolean mLockscreenPublicMode = false;
199 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
Dan Sandler05c362d2014-09-03 00:16:27 +0200200 private NotificationColorUtil mNotificationColorUtil;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700201
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000202 private UserManager mUserManager;
203
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500204 // UI-specific methods
Daniel Sandler6a858c32012-03-12 14:38:58 -0400205
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500206 /**
207 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
208 * and add them to the window manager.
209 */
210 protected abstract void createAndAddWindows();
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400211
Jeff Brown98365d72012-08-19 20:30:52 -0700212 protected WindowManager mWindowManager;
213 protected IWindowManager mWindowManagerService;
Christoph Studer60748e72014-05-22 16:51:41 +0200214
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700215 protected abstract void refreshLayout(int layoutDirection);
216
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500217 protected Display mDisplay;
Jeff Brown98365d72012-08-19 20:30:52 -0700218
Daniel Sandler26cda272012-05-22 15:44:08 -0400219 private boolean mDeviceProvisioned = false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400220
John Spurlockd08de372013-06-24 13:06:08 -0400221 private RecentsComponent mRecents;
222
John Spurlocke677d712014-02-13 12:52:19 -0500223 protected int mZenMode;
224
Dan Sandler4247a5c2014-07-23 15:58:08 -0400225 // which notification is currently being longpress-examined by the user
Selim Cinek024ca592014-09-01 15:11:28 +0200226 private NotificationGuts mNotificationGutsExposed;
Dan Sandler4247a5c2014-07-23 15:58:08 -0400227
228 private TimeInterpolator mLinearOutSlowIn, mFastOutLinearIn;
229
Jorim Jaggiecbab362014-04-23 16:13:15 +0200230 /**
231 * The {@link StatusBarState} of the status bar.
232 */
233 protected int mState;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200234 protected boolean mBouncerShowing;
John Spurlock4b3bda22014-05-22 14:32:20 -0400235 protected boolean mShowLockscreenNotifications;
Jorim Jaggiecbab362014-04-23 16:13:15 +0200236
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200237 protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
Dan Sandlereceda3d2014-07-21 15:35:01 -0400238 protected DismissView mDismissView;
Jorim Jaggia2052ea2014-08-05 16:22:30 +0200239 protected EmptyShadeView mEmptyShadeView;
Jorim Jaggi649b7082014-04-03 13:15:18 +0200240
Chris Wren42d5dd42015-05-01 10:39:26 -0400241 private NotificationClicker mNotificationClicker = new NotificationClicker();
242
Jorim Jaggib835dd72015-06-08 12:28:42 -0700243 protected AssistManager mAssistManager;
244
Christoph Studerc8db24b2014-07-25 17:50:30 +0200245 @Override // NotificationData.Environment
Daniel Sandler3ffdcc72012-09-23 14:31:48 -0400246 public boolean isDeviceProvisioned() {
Daniel Sandler26cda272012-05-22 15:44:08 -0400247 return mDeviceProvisioned;
248 }
249
John Spurlocke677d712014-02-13 12:52:19 -0500250 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
Daniel Sandler26cda272012-05-22 15:44:08 -0400251 @Override
252 public void onChange(boolean selfChange) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700253 final boolean provisioned = 0 != Settings.Global.getInt(
254 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
Daniel Sandler26cda272012-05-22 15:44:08 -0400255 if (provisioned != mDeviceProvisioned) {
256 mDeviceProvisioned = provisioned;
Christoph Studer37fe6932014-05-26 13:10:30 +0200257 updateNotifications();
Daniel Sandler26cda272012-05-22 15:44:08 -0400258 }
John Spurlocke677d712014-02-13 12:52:19 -0500259 final int mode = Settings.Global.getInt(mContext.getContentResolver(),
260 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
261 setZenMode(mode);
Dan Sandler52e5701e2014-07-22 23:14:54 -0400262
263 updateLockscreenNotificationSetting();
Daniel Sandler26cda272012-05-22 15:44:08 -0400264 }
265 };
266
Dan Sandlerfd16d562014-02-13 18:43:31 -0800267 private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
268 @Override
269 public void onChange(boolean selfChange) {
270 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
271 // so we just dump our cache ...
272 mUsersAllowingPrivateNotifications.clear();
273 // ... and refresh all the notifications
Christoph Studer37fe6932014-05-26 13:10:30 +0200274 updateNotifications();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800275 }
276 };
277
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700278 private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
279 @Override
Adrian Roos7d7090d2014-05-21 13:10:23 +0200280 public boolean onClickHandler(
281 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
Daniel Sandler198a0302012-08-17 16:04:31 -0400282 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400283 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
Daniel Sandler198a0302012-08-17 16:04:31 -0400284 }
Christoph Studer4da84cd2014-10-21 17:24:20 +0200285 logActionClick(view);
Jorim Jaggi89f7f282014-10-17 19:54:15 +0200286 // The intent we are sending is for the application, which
287 // won't have permission to immediately start an activity after
288 // the user switches to home. We know it is safe to do at this
289 // point, so make sure new activity switches are now allowed.
290 try {
291 ActivityManagerNative.getDefault().resumeAppSwitches();
292 } catch (RemoteException e) {
293 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700294 final boolean isActivity = pendingIntent.isActivity();
295 if (isActivity) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200296 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200297 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
298 mContext, pendingIntent.getIntent(), mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +0200299 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200300 @Override
301 public boolean onDismiss() {
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200302 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200303 try {
304 ActivityManagerNative.getDefault()
305 .keyguardWaitingForActivityDrawn();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200306 } catch (RemoteException e) {
307 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200308 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700309
Adrian Roos7d7090d2014-05-21 13:10:23 +0200310 boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200311 overrideActivityPendingAppTransition(keyguardShowing && !afterKeyguardGone);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700312
Adrian Roos7d7090d2014-05-21 13:10:23 +0200313 // close the shade if it was open
314 if (handled) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100315 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
316 true /* force */);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200317 visibilityChanged(false);
318 }
Adrian Roos4314f6d2014-05-28 14:10:27 +0200319 // Wait for activity start.
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200320 return handled;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200321 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200322 }, afterKeyguardGone);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200323 return true;
324 } else {
325 return super.onClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700326 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200327 }
328
Christoph Studer4da84cd2014-10-21 17:24:20 +0200329 private void logActionClick(View view) {
330 ViewParent parent = view.getParent();
331 String key = getNotificationKeyForParent(parent);
332 if (key == null) {
333 Log.w(TAG, "Couldn't determine notification for click.");
334 return;
335 }
336 int index = -1;
337 // If this is a default template, determine the index of the button.
338 if (view.getId() == com.android.internal.R.id.action0 &&
339 parent != null && parent instanceof ViewGroup) {
340 ViewGroup actionGroup = (ViewGroup) parent;
341 index = actionGroup.indexOfChild(view);
342 }
Chris Wren79ac09e2014-10-29 14:20:19 -0400343 if (NOTIFICATION_CLICK_DEBUG) {
344 Log.d(TAG, "Clicked on button " + index + " for " + key);
345 }
Christoph Studer4da84cd2014-10-21 17:24:20 +0200346 try {
347 mBarService.onNotificationActionClick(key, index);
348 } catch (RemoteException e) {
349 // Ignore
350 }
351 }
352
353 private String getNotificationKeyForParent(ViewParent parent) {
354 while (parent != null) {
355 if (parent instanceof ExpandableNotificationRow) {
356 return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
357 }
358 parent = parent.getParent();
359 }
360 return null;
361 }
362
Adrian Roos7d7090d2014-05-21 13:10:23 +0200363 private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
364 Intent fillInIntent) {
365 return super.onClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700366 }
367 };
368
John Spurlock5c454122013-06-17 07:35:46 -0400369 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
370 @Override
371 public void onReceive(Context context, Intent intent) {
372 String action = intent.getAction();
373 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
374 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Kenny Guy2a764942014-04-02 13:29:20 +0100375 updateCurrentProfilesCache();
John Spurlock5c454122013-06-17 07:35:46 -0400376 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
Dan Sandler52e5701e2014-07-22 23:14:54 -0400377
378 updateLockscreenNotificationSetting();
379
John Spurlock5c454122013-06-17 07:35:46 -0400380 userSwitched(mCurrentUserId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000381 } else if (Intent.ACTION_USER_ADDED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +0100382 updateCurrentProfilesCache();
Kenny Guydae30d52015-04-01 19:11:35 +0100383 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
384 List<ActivityManager.RecentTaskInfo> recentTask = null;
385 try {
386 recentTask = ActivityManagerNative.getDefault().getRecentTasks(1,
387 ActivityManager.RECENT_WITH_EXCLUDED
388 | ActivityManager.RECENT_INCLUDE_PROFILES,
389 mCurrentUserId);
390 } catch (RemoteException e) {
391 // Abandon hope activity manager not running.
392 }
393 if (recentTask != null && recentTask.size() > 0) {
394 UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
395 if (user != null && user.isManagedProfile()) {
Kenny Guy63bf8ac2015-06-18 15:09:09 +0100396 Toast toast = Toast.makeText(mContext,
397 R.string.managed_profile_foreground_toast,
398 Toast.LENGTH_SHORT);
399 TextView text = (TextView) toast.getView().findViewById(
400 android.R.id.message);
401 text.setCompoundDrawablesRelativeWithIntrinsicBounds(
402 R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
403 int paddingPx = mContext.getResources().getDimensionPixelSize(
404 R.dimen.managed_profile_toast_padding);
405 text.setCompoundDrawablePadding(paddingPx);
Kenny Guy540f7d22015-06-08 20:24:23 +0100406 toast.show();
Kenny Guydae30d52015-04-01 19:11:35 +0100407 }
408 }
Chris Wrencd8f4f72014-08-27 18:48:13 -0400409 } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
410 NotificationManager noMan = (NotificationManager)
411 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500412 noMan.cancel(R.id.notification_hidden);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400413
414 Settings.Secure.putInt(mContext.getContentResolver(),
415 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
416 if (BANNER_ACTION_SETUP.equals(action)) {
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100417 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
418 true /* force */);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400419 mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
420 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
421
422 );
423 }
John Spurlock5c454122013-06-17 07:35:46 -0400424 }
425 }
426 };
427
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000428 private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
429 @Override
430 public void onReceive(Context context, Intent intent) {
431 String action = intent.getAction();
432 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
433 isCurrentProfile(getSendingUserId())) {
434 mUsersAllowingPrivateNotifications.clear();
435 updateLockscreenNotificationSetting();
436 updateNotifications();
437 }
438 }
439 };
440
Christoph Studer60748e72014-05-22 16:51:41 +0200441 private final NotificationListenerService mNotificationListener =
442 new NotificationListenerService() {
443 @Override
444 public void onListenerConnected() {
445 if (DEBUG) Log.d(TAG, "onListenerConnected");
446 final StatusBarNotification[] notifications = getActiveNotifications();
Christoph Studerd0694b62014-06-04 16:36:01 +0200447 final RankingMap currentRanking = getCurrentRanking();
Christoph Studer60748e72014-05-22 16:51:41 +0200448 mHandler.post(new Runnable() {
449 @Override
450 public void run() {
451 for (StatusBarNotification sbn : notifications) {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100452 addNotification(sbn, currentRanking, null /* oldEntry */);
Christoph Studer60748e72014-05-22 16:51:41 +0200453 }
454 }
455 });
456 }
457
458 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200459 public void onNotificationPosted(final StatusBarNotification sbn,
460 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200461 if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500462 if (sbn != null) {
463 mHandler.post(new Runnable() {
464 @Override
465 public void run() {
Adrian Rooseb91ca52015-06-10 15:49:11 -0700466
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700467 String key = sbn.getKey();
468 boolean isUpdate = mNotificationData.get(key) != null;
Christoph Studerd722f272014-09-02 11:49:19 +0200469
Selim Cinekb5605e52015-02-20 18:21:41 +0100470 // In case we don't allow child notifications, we ignore children of
471 // notifications that have a summary, since we're not going to show them
472 // anyway. This is true also when the summary is canceled,
Chris Wren56919552015-02-24 15:56:34 -0500473 // because children are automatically canceled by NoMan in that case.
Selim Cinekb5605e52015-02-20 18:21:41 +0100474 if (!ENABLE_CHILD_NOTIFICATIONS
475 && mGroupManager.isChildInGroupWithSummary(sbn)) {
Chris Wren56919552015-02-24 15:56:34 -0500476 if (DEBUG) {
477 Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
478 }
479
480 // Remove existing notification to avoid stale data.
481 if (isUpdate) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700482 removeNotification(key, rankingMap);
Chris Wren56919552015-02-24 15:56:34 -0500483 } else {
484 mNotificationData.updateRanking(rankingMap);
485 }
486 return;
Christoph Studerd722f272014-09-02 11:49:19 +0200487 }
Christoph Studerd722f272014-09-02 11:49:19 +0200488 if (isUpdate) {
Chris Wren56919552015-02-24 15:56:34 -0500489 updateNotification(sbn, rankingMap);
Christoph Studerd722f272014-09-02 11:49:19 +0200490 } else {
Selim Cinek379ff8f2015-02-20 17:03:16 +0100491 addNotification(sbn, rankingMap, null /* oldEntry */);
Christoph Studerd722f272014-09-02 11:49:19 +0200492 }
Christoph Studerd722f272014-09-02 11:49:19 +0200493 }
Chris Wren56919552015-02-24 15:56:34 -0500494 });
495 }
Christoph Studer60748e72014-05-22 16:51:41 +0200496 }
497
498 @Override
Chris Wren56919552015-02-24 15:56:34 -0500499 public void onNotificationRemoved(StatusBarNotification sbn,
Christoph Studerd0694b62014-06-04 16:36:01 +0200500 final RankingMap rankingMap) {
Christoph Studer60748e72014-05-22 16:51:41 +0200501 if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
Chris Wren56919552015-02-24 15:56:34 -0500502 if (sbn != null) {
503 final String key = sbn.getKey();
504 mHandler.post(new Runnable() {
505 @Override
506 public void run() {
507 removeNotification(key, rankingMap);
508 }
509 });
510 }
Christoph Studer37fe6932014-05-26 13:10:30 +0200511 }
512
513 @Override
Christoph Studerd0694b62014-06-04 16:36:01 +0200514 public void onNotificationRankingUpdate(final RankingMap rankingMap) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200515 if (DEBUG) Log.d(TAG, "onRankingUpdate");
Chris Wren56919552015-02-24 15:56:34 -0500516 if (rankingMap != null) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200517 mHandler.post(new Runnable() {
518 @Override
519 public void run() {
Christoph Studere71fefc2014-06-24 16:16:49 +0200520 updateNotificationRanking(rankingMap);
Christoph Studer60748e72014-05-22 16:51:41 +0200521 }
522 });
Chris Wren56919552015-02-24 15:56:34 -0500523 } }
Christoph Studer5b638262014-07-07 11:21:49 +0200524
Christoph Studer60748e72014-05-22 16:51:41 +0200525 };
526
Kenny Guy2a764942014-04-02 13:29:20 +0100527 private void updateCurrentProfilesCache() {
528 synchronized (mCurrentProfiles) {
529 mCurrentProfiles.clear();
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000530 if (mUserManager != null) {
Kenny Guy2a764942014-04-02 13:29:20 +0100531 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
532 mCurrentProfiles.put(user.id, user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000533 }
534 }
535 }
536 }
537
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400538 public void start() {
Jeff Brown98365d72012-08-19 20:30:52 -0700539 mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
540 mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
541 mDisplay = mWindowManager.getDefaultDisplay();
Adrian Roosbd3409c2014-08-12 18:21:09 +0200542 mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
543 Context.DEVICE_POLICY_SERVICE);
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500544
Dan Sandler05c362d2014-09-03 00:16:27 +0200545 mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);
546
Christoph Studerc8db24b2014-07-25 17:50:30 +0200547 mNotificationData = new NotificationData(this);
548
Selim Cineka8fefa52014-09-08 16:10:50 +0200549 mAccessibilityManager = (AccessibilityManager)
550 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
551
Chris Wren157026f2013-06-28 16:54:01 -0400552 mDreamManager = IDreamManager.Stub.asInterface(
553 ServiceManager.checkService(DreamService.DREAM_SERVICE));
Chris Wren157026f2013-06-28 16:54:01 -0400554 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
555
Daniel Sandler26cda272012-05-22 15:44:08 -0400556 mContext.getContentResolver().registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700557 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
John Spurlocke677d712014-02-13 12:52:19 -0500558 mSettingsObserver);
559 mContext.getContentResolver().registerContentObserver(
560 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
561 mSettingsObserver);
John Spurlock4b3bda22014-05-22 14:32:20 -0400562 mContext.getContentResolver().registerContentObserver(
Dan Sandler52e5701e2014-07-22 23:14:54 -0400563 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
564 mSettingsObserver,
565 UserHandle.USER_ALL);
Daniel Sandler26cda272012-05-22 15:44:08 -0400566
Dan Sandlerfd16d562014-02-13 18:43:31 -0800567 mContext.getContentResolver().registerContentObserver(
568 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
569 true,
570 mLockscreenSettingsObserver,
571 UserHandle.USER_ALL);
572
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500573 mBarService = IStatusBarService.Stub.asInterface(
574 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400575
Jorim Jaggid61f2272014-12-19 20:35:35 +0100576 mRecents = getComponent(Recents.class);
Winson Chung9214eff2014-06-12 13:59:25 -0700577 mRecents.setCallback(this);
John Spurlockd08de372013-06-24 13:06:08 -0400578
Dan Sandler539aad42014-08-04 00:43:39 -0400579 final Configuration currentConfig = mContext.getResources().getConfiguration();
580 mLocale = currentConfig.locale;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700581 mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
Dan Sandler539aad42014-08-04 00:43:39 -0400582 mFontScale = currentConfig.fontScale;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700583
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000584 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
585
Dan Sandler4247a5c2014-07-23 15:58:08 -0400586 mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
587 android.R.interpolator.linear_out_slow_in);
588 mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext,
589 android.R.interpolator.fast_out_linear_in);
590
Joe Onorato2314aab2010-04-08 16:41:23 -0500591 // Connect in to the status bar manager service
Joe Onorato0cbda992010-05-02 16:28:15 -0700592 StatusBarIconList iconList = new StatusBarIconList();
Joe Onorato66d7d012010-05-14 10:05:10 -0700593 mCommandQueue = new CommandQueue(this, iconList);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400594
Jason Monkb605fec2014-05-02 17:04:10 -0400595 int[] switches = new int[8];
satokcd7cd292010-11-20 15:46:23 +0900596 ArrayList<IBinder> binders = new ArrayList<IBinder>();
Joe Onorato2314aab2010-04-08 16:41:23 -0500597 try {
Christoph Studere71fefc2014-06-24 16:16:49 +0200598 mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders);
Joe Onorato2314aab2010-04-08 16:41:23 -0500599 } catch (RemoteException ex) {
600 // If the system process isn't there we're doomed anyway.
601 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400602
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500603 createAndAddWindows();
Joe Onorato0cbda992010-05-02 16:28:15 -0700604
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100605 mSettingsObserver.onChange(false); // set up
Benjamin Franzcde0a2a2015-04-23 17:19:48 +0100606 disable(switches[0], switches[6], false /* animate */);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700607 setSystemUiVisibility(switches[1], 0xffffffff);
Dianne Hackborn7d049322011-06-14 15:00:32 -0700608 topAppWindowChanged(switches[2] != 0);
satokcd7cd292010-11-20 15:46:23 +0900609 // StatusBarManagerService has a back up of IME token and it's restored here.
Michael Wright665366a2014-08-07 15:44:40 -0700610 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
Joe Onorato93056472010-09-10 10:30:46 -0400611
Joe Onorato0cbda992010-05-02 16:28:15 -0700612 // Set up the initial icon state
Joe Onorato75199e32010-05-29 17:22:51 -0400613 int N = iconList.size();
Joe Onorato0cbda992010-05-02 16:28:15 -0700614 int viewIndex = 0;
615 for (int i=0; i<N; i++) {
616 StatusBarIcon icon = iconList.getIcon(i);
617 if (icon != null) {
618 addIcon(iconList.getSlot(i), i, viewIndex, icon);
619 viewIndex++;
620 }
621 }
622
Christoph Studer71f18fd2014-05-20 17:02:04 +0200623 // Set up the initial notification state.
Christoph Studere71fefc2014-06-24 16:16:49 +0200624 try {
Christoph Studer4600f9b2014-07-22 22:44:43 +0200625 mNotificationListener.registerAsSystemService(mContext,
Christoph Studere71fefc2014-06-24 16:16:49 +0200626 new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
627 UserHandle.USER_ALL);
628 } catch (RemoteException e) {
629 Log.e(TAG, "Unable to register notification listener", e);
Joe Onorato75199e32010-05-29 17:22:51 -0400630 }
631
Christoph Studer60748e72014-05-22 16:51:41 +0200632
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500633 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400634 Log.d(TAG, String.format(
Daniel Sandler6a858c32012-03-12 14:38:58 -0400635 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500636 iconList.size(),
637 switches[0],
638 switches[1],
639 switches[2],
640 switches[3]
641 ));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400642 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400643
Christopher Tate5e08af02012-09-21 17:17:22 -0700644 mCurrentUserId = ActivityManager.getCurrentUser();
Chris Wrena6d4fb62014-11-20 14:46:23 -0500645 setHeadsUpUser(mCurrentUserId);
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400646
647 IntentFilter filter = new IntentFilter();
648 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000649 filter.addAction(Intent.ACTION_USER_ADDED);
Kenny Guydae30d52015-04-01 19:11:35 +0100650 filter.addAction(Intent.ACTION_USER_PRESENT);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400651 filter.addAction(BANNER_ACTION_CANCEL);
652 filter.addAction(BANNER_ACTION_SETUP);
John Spurlock5c454122013-06-17 07:35:46 -0400653 mContext.registerReceiver(mBroadcastReceiver, filter);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000654
Kenny Guy0b7dd1e2015-03-12 17:14:38 +0000655 IntentFilter allUsersFilter = new IntentFilter();
656 allUsersFilter.addAction(
657 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
658 mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
659 null, null);
Kenny Guy2a764942014-04-02 13:29:20 +0100660 updateCurrentProfilesCache();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400661 }
662
Chris Wrencd8f4f72014-08-27 18:48:13 -0400663 protected void notifyUserAboutHiddenNotifications() {
664 if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
665 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
666 Log.d(TAG, "user hasn't seen notification about hidden notifications");
667 final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
Adrian Roosd6aa6cb2015-04-16 19:31:29 -0700668 if (!lockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
Chris Wrencd8f4f72014-08-27 18:48:13 -0400669 Log.d(TAG, "insecure lockscreen, skipping notification");
670 Settings.Secure.putInt(mContext.getContentResolver(),
671 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
672 return;
673 }
674 Log.d(TAG, "disabling lockecreen notifications and alerting the user");
675 // disable lockscreen notifications until user acts on the banner.
676 Settings.Secure.putInt(mContext.getContentResolver(),
677 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
Adrian Roosaee70462014-09-03 16:27:39 +0200678 Settings.Secure.putInt(mContext.getContentResolver(),
679 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
Chris Wrencd8f4f72014-08-27 18:48:13 -0400680
681 final String packageName = mContext.getPackageName();
682 PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
683 new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
684 PendingIntent.FLAG_CANCEL_CURRENT);
685 PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
686 new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
687 PendingIntent.FLAG_CANCEL_CURRENT);
688
689 final Resources res = mContext.getResources();
690 final int colorRes = com.android.internal.R.color.system_notification_accent_color;
691 Notification.Builder note = new Notification.Builder(mContext)
692 .setSmallIcon(R.drawable.ic_android)
693 .setContentTitle(mContext.getString(R.string.hidden_notifications_title))
694 .setContentText(mContext.getString(R.string.hidden_notifications_text))
695 .setPriority(Notification.PRIORITY_HIGH)
696 .setOngoing(true)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700697 .setColor(mContext.getColor(colorRes))
Chris Wrencd8f4f72014-08-27 18:48:13 -0400698 .setContentIntent(setupIntent)
699 .addAction(R.drawable.ic_close,
700 mContext.getString(R.string.hidden_notifications_cancel),
701 cancelIntent)
702 .addAction(R.drawable.ic_settings,
703 mContext.getString(R.string.hidden_notifications_setup),
704 setupIntent);
705
706 NotificationManager noMan =
707 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wrend8775102015-01-16 16:16:43 -0500708 noMan.notify(R.id.notification_hidden, note.build());
Chris Wrencd8f4f72014-08-27 18:48:13 -0400709 }
710 }
711
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400712 public void userSwitched(int newUserId) {
Chris Wrena6d4fb62014-11-20 14:46:23 -0500713 setHeadsUpUser(newUserId);
714 }
715
Selim Cinek29fa89b2015-04-17 10:39:11 -0700716 protected abstract void setHeadsUpUser(int newUserId);
Chris Wrend04f6ce2014-06-11 17:37:28 -0400717
Christoph Studerc8db24b2014-07-25 17:50:30 +0200718 @Override // NotificationData.Environment
719 public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400720 final int thisUserId = mCurrentUserId;
721 final int notificationUserId = n.getUserId();
722 if (DEBUG && MULTIUSER_DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400723 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400724 n, thisUserId, notificationUserId));
725 }
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500726 return isCurrentProfile(notificationUserId);
Joe Onorato2314aab2010-04-08 16:41:23 -0500727 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400728
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700729 protected void setNotificationShown(StatusBarNotification n) {
730 mNotificationListener.setNotificationsShown(new String[] { n.getKey() });
731 }
732
733 protected void setNotificationsShown(String[] keys) {
734 mNotificationListener.setNotificationsShown(keys);
735 }
736
Kenny Guy44fc65f2014-11-28 22:18:14 +0000737 protected boolean isCurrentProfile(int userId) {
738 synchronized (mCurrentProfiles) {
Dan Sandlere63ba4b2014-12-05 00:26:24 -0500739 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
Kenny Guy44fc65f2014-11-28 22:18:14 +0000740 }
741 }
742
Christoph Studer2e731b52014-08-22 16:01:51 +0200743 @Override
744 public String getCurrentMediaNotificationKey() {
745 return null;
746 }
747
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100748 @Override
749 public NotificationGroupManager getGroupManager() {
750 return mGroupManager;
751 }
752
Adrian Roos7d7090d2014-05-21 13:10:23 +0200753 /**
754 * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
755 * @param action A dismiss action that is called if it's safe to start the activity.
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200756 * @param afterKeyguardGone Whether the action should be executed after the Keyguard is gone.
Adrian Roos7d7090d2014-05-21 13:10:23 +0200757 */
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200758 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200759 action.onDismiss();
760 }
761
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700762 @Override
763 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400764 final Locale locale = mContext.getResources().getConfiguration().locale;
765 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
Dan Sandler539aad42014-08-04 00:43:39 -0400766 final float fontScale = newConfig.fontScale;
767
768 if (! locale.equals(mLocale) || ld != mLayoutDirection || fontScale != mFontScale) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400769 if (DEBUG) {
770 Log.v(TAG, String.format(
771 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
772 locale, ld));
773 }
774 mLocale = locale;
775 mLayoutDirection = ld;
776 refreshLayout(ld);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700777 }
778 }
779
Winson Chungc57ccf02011-10-13 15:04:59 -0700780 protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
781 View vetoButton = row.findViewById(R.id.veto);
Selim Cinek8d490d42015-04-10 00:05:50 -0700782 if (n.isClearable()) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400783 final String _pkg = n.getPackageName();
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400784 final String _tag = n.getTag();
785 final int _id = n.getId();
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000786 final int _userId = n.getUserId();
Winson Chungc57ccf02011-10-13 15:04:59 -0700787 vetoButton.setOnClickListener(new View.OnClickListener() {
788 public void onClick(View v) {
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700789 // Accessibility feedback
790 v.announceForAccessibility(
791 mContext.getString(R.string.accessibility_notification_dismissed));
Winson Chungc57ccf02011-10-13 15:04:59 -0700792 try {
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000793 mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700794
Winson Chungc57ccf02011-10-13 15:04:59 -0700795 } catch (RemoteException ex) {
796 // system process is dead if we're here.
797 }
798 }
799 });
800 vetoButton.setVisibility(View.VISIBLE);
801 } else {
802 vetoButton.setVisibility(View.GONE);
803 }
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700804 vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
Winson Chungc57ccf02011-10-13 15:04:59 -0700805 return vetoButton;
806 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400807
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400808
Christoph Studer13b895122014-08-26 15:42:12 +0200809 protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
Jorim Jaggi46739852014-04-15 09:58:24 +0200810 NotificationData.Entry entry) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400811
Selim Cinek684a4422015-04-15 16:18:39 -0700812 if (entry.getContentView().getId()
813 != com.android.internal.R.id.status_bar_latest_event_content) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400814 // Using custom RemoteViews
Jorim Jaggia1eeade2014-09-08 22:34:39 +0200815 if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700816 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
Selim Cinek697178b2014-07-02 19:40:30 +0200817 entry.row.setShowingLegacyBackground(true);
Jorim Jaggi36b15232014-06-10 17:24:20 +0200818 entry.legacy = true;
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400819 }
Dan Sandler842dd772014-05-15 09:36:47 -0400820 } else {
821 // Using platform templates
822 final int color = sbn.getNotification().color;
823 if (isMediaNotification(entry)) {
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +0200824 entry.row.setTintColor(color == Notification.COLOR_DEFAULT
Alan Viverette4a357cd2015-03-18 18:37:18 -0700825 ? mContext.getColor(
Jorim Jaggi17ee3ec2014-08-29 03:47:31 +0200826 R.color.notification_material_background_media_default_color)
827 : color);
Dan Sandler842dd772014-05-15 09:36:47 -0400828 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400829 }
Christoph Studer13b895122014-08-26 15:42:12 +0200830
831 if (entry.icon != null) {
Jorim Jaggidd0107a2015-01-21 22:23:48 +0100832 entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
Christoph Studer13b895122014-08-26 15:42:12 +0200833 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400834 }
835
Dan Sandler16128f42014-05-21 12:48:22 -0400836 public boolean isMediaNotification(NotificationData.Entry entry) {
Dan Sandler842dd772014-05-15 09:36:47 -0400837 // TODO: confirm that there's a valid media key
Selim Cinek684a4422015-04-15 16:18:39 -0700838 return entry.getExpandedContentView() != null &&
839 entry.getExpandedContentView()
840 .findViewById(com.android.internal.R.id.media_actions) != null;
Dan Sandler842dd772014-05-15 09:36:47 -0400841 }
842
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200843 // The gear button in the guts that links to the app's own notification settings
844 private void startAppOwnNotificationSettingsActivity(Intent intent,
845 final int notificationId, final String notificationTag, final int appUid) {
846 intent.putExtra("notification_id", notificationId);
847 intent.putExtra("notification_tag", notificationTag);
848 startNotificationGutsIntent(intent, appUid);
849 }
850
851 // The (i) button in the guts that links to the system notification settings for that app
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200852 private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
853 final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
Dan Sandlere9a4e902014-07-31 01:06:43 -0400854 intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
855 intent.putExtra(Settings.EXTRA_APP_UID, appUid);
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200856 startNotificationGutsIntent(intent, appUid);
857 }
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200858
Dan Sandlerf4db75c2014-09-03 18:02:31 +0200859 private void startNotificationGutsIntent(final Intent intent, final int appUid) {
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200860 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
861 dismissKeyguardThenExecute(new OnDismissAction() {
862 @Override
863 public boolean onDismiss() {
864 AsyncTask.execute(new Runnable() {
865 public void run() {
866 try {
867 if (keyguardShowing) {
868 ActivityManagerNative.getDefault()
869 .keyguardWaitingForActivityDrawn();
870 }
871 TaskStackBuilder.create(mContext)
872 .addNextIntentWithParentStack(intent)
873 .startActivities(null,
874 new UserHandle(UserHandle.getUserId(appUid)));
875 overrideActivityPendingAppTransition(keyguardShowing);
876 } catch (RemoteException e) {
877 }
878 }
879 });
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100880 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
Jorim Jaggifb28c0e2014-08-22 16:28:42 +0200881 return true;
882 }
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200883 }, false /* afterKeyguardGone */);
Dan Sandler4247a5c2014-07-23 15:58:08 -0400884 }
885
Selim Cinekab29aeb2015-02-20 18:18:32 +0100886 private void bindGuts(ExpandableNotificationRow row) {
887 row.inflateGuts();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200888 final StatusBarNotification sbn = row.getStatusBarNotification();
889 PackageManager pmUser = getPackageManagerForUser(
890 sbn.getUser().getIdentifier());
891 row.setTag(sbn.getPackageName());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100892 final View guts = row.getGuts();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200893 final String pkg = sbn.getPackageName();
894 String appname = pkg;
895 Drawable pkgicon = null;
896 int appUid = -1;
897 try {
898 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
899 PackageManager.GET_UNINSTALLED_PACKAGES
900 | PackageManager.GET_DISABLED_COMPONENTS);
901 if (info != null) {
902 appname = String.valueOf(pmUser.getApplicationLabel(info));
903 pkgicon = pmUser.getApplicationIcon(info);
904 appUid = info.uid;
905 }
906 } catch (NameNotFoundException e) {
907 // app is gone, just show package name and generic icon
908 pkgicon = pmUser.getDefaultActivityIcon();
909 }
910 ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
911 ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(sbn.getPostTime());
912 ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
913 final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
914 final View appSettingsButton
915 = guts.findViewById(R.id.notification_inspect_app_provided_settings);
916 if (appUid >= 0) {
917 final int appUidF = appUid;
918 settingsButton.setOnClickListener(new View.OnClickListener() {
919 public void onClick(View v) {
Chris Wrenbd6b5fb2015-06-09 14:58:34 -0400920 MetricsLogger.action(mContext, MetricsLogger.ACTION_NOTE_INFO);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200921 startAppNotificationSettingsActivity(pkg, appUidF);
922 }
923 });
924
925 final Intent appSettingsQueryIntent
926 = new Intent(Intent.ACTION_MAIN)
927 .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
928 .setPackage(pkg);
929 List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
930 if (infos.size() > 0) {
931 appSettingsButton.setVisibility(View.VISIBLE);
932 appSettingsButton.setContentDescription(
933 mContext.getResources().getString(
934 R.string.status_bar_notification_app_settings_title,
935 appname
936 ));
937 final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
938 .setClassName(pkg, infos.get(0).activityInfo.name);
939 appSettingsButton.setOnClickListener(new View.OnClickListener() {
940 public void onClick(View v) {
Chris Wrenbd6b5fb2015-06-09 14:58:34 -0400941 MetricsLogger.action(mContext, MetricsLogger.ACTION_APP_NOTE_SETTINGS);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200942 startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
943 sbn.getId(),
944 sbn.getTag(),
945 appUidF);
946 }
947 });
948 } else {
949 appSettingsButton.setVisibility(View.GONE);
950 }
951 } else {
952 settingsButton.setVisibility(View.GONE);
953 appSettingsButton.setVisibility(View.GONE);
954 }
955
956 }
957
Dan Sandler4247a5c2014-07-23 15:58:08 -0400958 protected SwipeHelper.LongPressListener getNotificationLongClicker() {
959 return new SwipeHelper.LongPressListener() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400960 @Override
Dan Sandler4247a5c2014-07-23 15:58:08 -0400961 public boolean onLongPress(View v, int x, int y) {
962 dismissPopups();
963
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200964 if (!(v instanceof ExpandableNotificationRow)) {
965 return false;
966 }
Selim Cinekabdc5a02014-09-02 13:46:00 +0200967 if (v.getWindowToken() == null) {
968 Log.e(TAG, "Trying to show notification guts, but not attached to window");
969 return false;
970 }
Dan Sandler4247a5c2014-07-23 15:58:08 -0400971
Selim Cinekab29aeb2015-02-20 18:18:32 +0100972 ExpandableNotificationRow row = (ExpandableNotificationRow) v;
973 bindGuts(row);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200974
Dan Sandler4247a5c2014-07-23 15:58:08 -0400975 // Assume we are a status_bar_notification_row
Selim Cinekab29aeb2015-02-20 18:18:32 +0100976 final NotificationGuts guts = row.getGuts();
Selim Cinekbdefcdf2014-09-11 12:41:47 +0200977 if (guts == null) {
978 // This view has no guts. Examples are the more card or the dismiss all view
979 return false;
980 }
Dan Sandler4247a5c2014-07-23 15:58:08 -0400981
982 // Already showing?
Selim Cinekabdc5a02014-09-02 13:46:00 +0200983 if (guts.getVisibility() == View.VISIBLE) {
984 Log.e(TAG, "Trying to show notification guts, but already visible");
985 return false;
986 }
Dan Sandler4247a5c2014-07-23 15:58:08 -0400987
Chris Wrenbd6b5fb2015-06-09 14:58:34 -0400988 MetricsLogger.action(mContext, MetricsLogger.ACTION_NOTE_CONTROLS);
Dan Sandler4247a5c2014-07-23 15:58:08 -0400989 guts.setVisibility(View.VISIBLE);
Selim Cinek024ca592014-09-01 15:11:28 +0200990 final double horz = Math.max(guts.getWidth() - x, x);
991 final double vert = Math.max(guts.getActualHeight() - y, y);
Dan Sandler4247a5c2014-07-23 15:58:08 -0400992 final float r = (float) Math.hypot(horz, vert);
993 final Animator a
994 = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
995 a.setDuration(400);
996 a.setInterpolator(mLinearOutSlowIn);
997 a.start();
998
999 mNotificationGutsExposed = guts;
Daniel Sandlerf7a19562012-04-04 14:04:21 -04001000
1001 return true;
1002 }
1003 };
1004 }
1005
Daniel Sandler469e96e2012-05-04 15:56:19 -04001006 public void dismissPopups() {
Dan Sandler4247a5c2014-07-23 15:58:08 -04001007 if (mNotificationGutsExposed != null) {
Selim Cinek024ca592014-09-01 15:11:28 +02001008 final NotificationGuts v = mNotificationGutsExposed;
Dan Sandler4247a5c2014-07-23 15:58:08 -04001009 mNotificationGutsExposed = null;
1010
Selim Cinekedb893b2014-09-02 12:51:31 +02001011 if (v.getWindowToken() == null) return;
1012
Dan Sandler4247a5c2014-07-23 15:58:08 -04001013 final int x = (v.getLeft() + v.getRight()) / 2;
Selim Cinek024ca592014-09-01 15:11:28 +02001014 final int y = (v.getTop() + v.getActualHeight() / 2);
Dan Sandler4247a5c2014-07-23 15:58:08 -04001015 final Animator a = ViewAnimationUtils.createCircularReveal(v,
1016 x, y, x, 0);
1017 a.setDuration(200);
1018 a.setInterpolator(mFastOutLinearIn);
1019 a.addListener(new AnimatorListenerAdapter() {
1020 @Override
1021 public void onAnimationEnd(Animator animation) {
1022 super.onAnimationEnd(animation);
1023 v.setVisibility(View.GONE);
1024 }
1025 });
1026 a.start();
Daniel Sandler469e96e2012-05-04 15:56:19 -04001027 }
1028 }
1029
Michael Jurka7f2668c2012-03-27 07:49:52 -07001030 @Override
Winson Chung1e8d71b2014-05-16 17:05:22 -07001031 public void showRecentApps(boolean triggeredFromAltTab) {
1032 int msg = MSG_SHOW_RECENT_APPS;
1033 mHandler.removeMessages(msg);
1034 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, 0).sendToTarget();
1035 }
1036
1037 @Override
Winson Chungcdcd4872014-08-05 18:00:13 -07001038 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001039 int msg = MSG_HIDE_RECENT_APPS;
1040 mHandler.removeMessages(msg);
Winson Chungcdcd4872014-08-05 18:00:13 -07001041 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0,
1042 triggeredFromHomeKey ? 1 : 0).sendToTarget();
Winson Chung1e8d71b2014-05-16 17:05:22 -07001043 }
1044
1045 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -07001046 public void toggleRecentApps() {
Jorim Jaggi900fb482015-06-02 15:07:33 -07001047 toggleRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001048 }
1049
1050 @Override
1051 public void preloadRecentApps() {
1052 int msg = MSG_PRELOAD_RECENT_APPS;
1053 mHandler.removeMessages(msg);
1054 mHandler.sendEmptyMessage(msg);
1055 }
1056
1057 @Override
1058 public void cancelPreloadRecentApps() {
1059 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
1060 mHandler.removeMessages(msg);
1061 mHandler.sendEmptyMessage(msg);
1062 }
1063
Winson Chungb1f74992014-08-08 12:53:09 -07001064 /** Jumps to the next affiliated task in the group. */
1065 public void showNextAffiliatedTask() {
1066 int msg = MSG_SHOW_NEXT_AFFILIATED_TASK;
1067 mHandler.removeMessages(msg);
1068 mHandler.sendEmptyMessage(msg);
1069 }
1070
1071 /** Jumps to the previous affiliated task in the group. */
1072 public void showPreviousAffiliatedTask() {
1073 int msg = MSG_SHOW_PREV_AFFILIATED_TASK;
1074 mHandler.removeMessages(msg);
1075 mHandler.sendEmptyMessage(msg);
1076 }
1077
Michael Jurkaecc395a2012-03-30 05:31:46 -07001078 protected H createHandler() {
Michael Jurka7f2668c2012-03-27 07:49:52 -07001079 return new H();
1080 }
1081
Michael Jurka56a57832012-05-14 13:24:43 -07001082 static void sendCloseSystemWindows(Context context, String reason) {
1083 if (ActivityManagerNative.isSystemReady()) {
1084 try {
1085 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
1086 } catch (RemoteException e) {
1087 }
1088 }
1089 }
1090
Michael Jurkacb2522c2012-04-13 09:32:47 -07001091 protected abstract View getStatusBarView();
1092
Michael Jurka80343f62012-10-18 13:13:46 +02001093 protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
1094 // additional optimization when we have software system buttons - start loading the recent
1095 // tasks on touch down
1096 @Override
1097 public boolean onTouch(View v, MotionEvent event) {
1098 int action = event.getAction() & MotionEvent.ACTION_MASK;
1099 if (action == MotionEvent.ACTION_DOWN) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001100 preloadRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001101 } else if (action == MotionEvent.ACTION_CANCEL) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001102 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001103 } else if (action == MotionEvent.ACTION_UP) {
1104 if (!v.isPressed()) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001105 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +02001106 }
1107
1108 }
1109 return false;
1110 }
1111 };
1112
Winson Chung1e8d71b2014-05-16 17:05:22 -07001113 /** Proxy for RecentsComponent */
1114
1115 protected void showRecents(boolean triggeredFromAltTab) {
1116 if (mRecents != null) {
1117 sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
1118 mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
1119 }
1120 }
1121
Winson Chungcdcd4872014-08-05 18:00:13 -07001122 protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001123 if (mRecents != null) {
Winson Chungcdcd4872014-08-05 18:00:13 -07001124 mRecents.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001125 }
1126 }
1127
1128 protected void toggleRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001129 if (mRecents != null) {
Winson Chung4c71aef2014-03-21 15:15:11 -07001130 sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
John Spurlockd08de372013-06-24 13:06:08 -04001131 mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
1132 }
1133 }
Michael Jurka80343f62012-10-18 13:13:46 +02001134
Winson Chung1e8d71b2014-05-16 17:05:22 -07001135 protected void preloadRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001136 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001137 mRecents.preloadRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001138 }
Michael Jurka80343f62012-10-18 13:13:46 +02001139 }
1140
Winson Chung1e8d71b2014-05-16 17:05:22 -07001141 protected void cancelPreloadingRecents() {
John Spurlockd08de372013-06-24 13:06:08 -04001142 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001143 mRecents.cancelPreloadingRecents();
John Spurlockd08de372013-06-24 13:06:08 -04001144 }
Michael Jurka80343f62012-10-18 13:13:46 +02001145 }
1146
Winson Chungb1f74992014-08-08 12:53:09 -07001147 protected void showRecentsNextAffiliatedTask() {
1148 if (mRecents != null) {
1149 mRecents.showNextAffiliatedTask();
1150 }
1151 }
1152
1153 protected void showRecentsPreviousAffiliatedTask() {
1154 if (mRecents != null) {
1155 mRecents.showPrevAffiliatedTask();
1156 }
1157 }
1158
Winson Chung9214eff2014-06-12 13:59:25 -07001159 @Override
1160 public void onVisibilityChanged(boolean visible) {
1161 // Do nothing
1162 }
1163
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001164 /**
Selim Cinek684a4422015-04-15 16:18:39 -07001165 * If there is an active heads-up notification and it has a fullscreen intent, fire it now.
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001166 */
Selim Cinek684a4422015-04-15 16:18:39 -07001167 public abstract void maybeEscalateHeadsUp();
Chris Wrena4ef6202014-06-09 18:07:30 -04001168
Dan Sandlerfd16d562014-02-13 18:43:31 -08001169 /**
1170 * Save the current "public" (locked and secure) state of the lockscreen.
1171 */
1172 public void setLockscreenPublicMode(boolean publicMode) {
1173 mLockscreenPublicMode = publicMode;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001174 }
1175
Dan Sandlerfd16d562014-02-13 18:43:31 -08001176 public boolean isLockscreenPublicMode() {
1177 return mLockscreenPublicMode;
1178 }
1179
1180 /**
1181 * Has the given user chosen to allow their private (full) notifications to be shown even
1182 * when the lockscreen is in "public" (secure & locked) mode?
1183 */
1184 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
1185 if (userHandle == UserHandle.USER_ALL) {
1186 return true;
1187 }
1188
1189 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001190 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
Dan Sandlerfd16d562014-02-13 18:43:31 -08001191 mContext.getContentResolver(),
1192 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
Adrian Roosbd3409c2014-08-12 18:21:09 +02001193 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
1194 userHandle);
1195 final boolean allowedByDpm = (dpmFlags
1196 & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
Kenny Guyb0d3ab22015-02-10 16:13:11 +00001197 final boolean allowed = allowedByUser && allowedByDpm;
1198 mUsersAllowingPrivateNotifications.append(userHandle, allowed);
Dan Sandlerfd16d562014-02-13 18:43:31 -08001199 return allowed;
1200 }
1201
1202 return mUsersAllowingPrivateNotifications.get(userHandle);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001203 }
1204
Christoph Studerc8db24b2014-07-25 17:50:30 +02001205 /**
1206 * Returns true if we're on a secure lockscreen and the user wants to hide "sensitive"
1207 * notification data. If so, private notifications should show their (possibly
1208 * auto-generated) publicVersion, and secret notifications should be totally invisible.
1209 */
1210 @Override // NotificationData.Environment
1211 public boolean shouldHideSensitiveContents(int userid) {
1212 return isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(userid);
1213 }
1214
Chris Wrena4ef6202014-06-09 18:07:30 -04001215 public void onNotificationClear(StatusBarNotification notification) {
1216 try {
1217 mBarService.onNotificationClear(
1218 notification.getPackageName(),
1219 notification.getTag(),
1220 notification.getId(),
1221 notification.getUserId());
1222 } catch (android.os.RemoteException ex) {
1223 // oh well
1224 }
1225 }
1226
Michael Jurka7f2668c2012-03-27 07:49:52 -07001227 protected class H extends Handler {
1228 public void handleMessage(Message m) {
1229 switch (m.what) {
Winson Chung1e8d71b2014-05-16 17:05:22 -07001230 case MSG_SHOW_RECENT_APPS:
1231 showRecents(m.arg1 > 0);
Michael Jurkacb2522c2012-04-13 09:32:47 -07001232 break;
Winson Chung1e8d71b2014-05-16 17:05:22 -07001233 case MSG_HIDE_RECENT_APPS:
Winson Chungcdcd4872014-08-05 18:00:13 -07001234 hideRecents(m.arg1 > 0, m.arg2 > 0);
Winson Chung1e8d71b2014-05-16 17:05:22 -07001235 break;
1236 case MSG_TOGGLE_RECENTS_APPS:
1237 toggleRecents();
Michael Jurkacb2522c2012-04-13 09:32:47 -07001238 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001239 case MSG_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001240 preloadRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001241 break;
1242 case MSG_CANCEL_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -07001243 cancelPreloadingRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -07001244 break;
Winson Chungb1f74992014-08-08 12:53:09 -07001245 case MSG_SHOW_NEXT_AFFILIATED_TASK:
1246 showRecentsNextAffiliatedTask();
1247 break;
1248 case MSG_SHOW_PREV_AFFILIATED_TASK:
1249 showRecentsPreviousAffiliatedTask();
1250 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -07001251 }
1252 }
1253 }
1254
Daniel Sandler6a858c32012-03-12 14:38:58 -04001255 protected void workAroundBadLayerDrawableOpacity(View v) {
1256 }
1257
Selim Cinek8d490d42015-04-10 00:05:50 -07001258 protected boolean inflateViews(Entry entry, ViewGroup parent) {
Dan Sandlere9a4e902014-07-31 01:06:43 -04001259 PackageManager pmUser = getPackageManagerForUser(
1260 entry.notification.getUser().getIdentifier());
1261
Chris Wrend04f6ce2014-06-11 17:37:28 -04001262 int maxHeight = mRowMaxHeight;
Dan Sandlerf4db75c2014-09-03 18:02:31 +02001263 final StatusBarNotification sbn = entry.notification;
Chris Wren574a55e2013-07-15 18:48:37 -04001264 RemoteViews contentView = sbn.getNotification().contentView;
1265 RemoteViews bigContentView = sbn.getNotification().bigContentView;
Selim Cinek8d490d42015-04-10 00:05:50 -07001266 RemoteViews headsUpContentView = sbn.getNotification().headsUpContentView;
Chris Wren8fd39ec2014-02-27 17:43:26 -05001267
Chris Wren574a55e2013-07-15 18:48:37 -04001268 if (contentView == null) {
Daniel Sandler6a858c32012-03-12 14:38:58 -04001269 return false;
1270 }
1271
Dan Sandlerf68448e2014-04-24 15:54:16 -04001272 if (DEBUG) {
1273 Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion);
1274 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001275
1276 Notification publicNotification = sbn.getNotification().publicVersion;
1277
Christoph Studera7fe6312014-06-27 19:32:44 +02001278 ExpandableNotificationRow row;
1279
1280 // Stash away previous user expansion state so we can restore it at
1281 // the end.
1282 boolean hasUserChangedExpansion = false;
1283 boolean userExpanded = false;
1284 boolean userLocked = false;
1285
1286 if (entry.row != null) {
1287 row = entry.row;
1288 hasUserChangedExpansion = row.hasUserChangedExpansion();
1289 userExpanded = row.isUserExpanded();
1290 userLocked = row.isUserLocked();
Christoph Studer22f2ee52014-07-29 22:57:21 +02001291 entry.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +02001292 if (hasUserChangedExpansion) {
1293 row.setUserExpanded(userExpanded);
1294 }
1295 } else {
1296 // create the row view
1297 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
1298 Context.LAYOUT_INFLATER_SERVICE);
1299 row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
1300 parent, false);
Chris Wren78403d72014-07-28 10:23:24 +01001301 row.setExpansionLogger(this, entry.notification.getKey());
Selim Cinekb5605e52015-02-20 18:21:41 +01001302 row.setGroupManager(mGroupManager);
Christoph Studera7fe6312014-06-27 19:32:44 +02001303 }
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001304
Daniel Sandler6a858c32012-03-12 14:38:58 -04001305 workAroundBadLayerDrawableOpacity(row);
1306 View vetoButton = updateNotificationVetoButton(row, sbn);
1307 vetoButton.setContentDescription(mContext.getString(
1308 R.string.accessibility_remove_notification));
1309
1310 // NB: the large icon is now handled entirely by the template
1311
1312 // bind the click event to the content area
Selim Cinek8d490d42015-04-10 00:05:50 -07001313 NotificationContentView contentContainer = row.getPrivateLayout();
1314 NotificationContentView contentContainerPublic = row.getPublicLayout();
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001315
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001316 row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
Daniel Sandlerbc5559f2012-04-19 01:08:15 -04001317
Chris Wren42d5dd42015-05-01 10:39:26 -04001318 mNotificationClicker.register(row, sbn);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001319
Dan Sandlera5e0f412014-01-23 15:11:54 -05001320 // set up the adaptive layout
Chris Wren574a55e2013-07-15 18:48:37 -04001321 View contentViewLocal = null;
1322 View bigContentViewLocal = null;
Selim Cinek8d490d42015-04-10 00:05:50 -07001323 View headsUpContentViewLocal = null;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001324 try {
Selim Cinek8d490d42015-04-10 00:05:50 -07001325 contentViewLocal = contentView.apply(mContext, contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001326 mOnClickHandler);
Chris Wren574a55e2013-07-15 18:48:37 -04001327 if (bigContentView != null) {
Selim Cinek8d490d42015-04-10 00:05:50 -07001328 bigContentViewLocal = bigContentView.apply(mContext, contentContainer,
1329 mOnClickHandler);
1330 }
1331 if (headsUpContentView != null) {
1332 headsUpContentViewLocal = headsUpContentView.apply(mContext, contentContainer,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001333 mOnClickHandler);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001334 }
1335 }
1336 catch (RuntimeException e) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001337 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
John Spurlockcd686b52013-06-05 10:13:46 -04001338 Log.e(TAG, "couldn't inflate view for notification " + ident, e);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001339 return false;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001340 }
1341
Chris Wren574a55e2013-07-15 18:48:37 -04001342 if (contentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001343 contentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001344 contentContainer.setContractedChild(contentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001345 }
Chris Wren574a55e2013-07-15 18:48:37 -04001346 if (bigContentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001347 bigContentViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001348 contentContainer.setExpandedChild(bigContentViewLocal);
1349 }
1350 if (headsUpContentViewLocal != null) {
1351 headsUpContentViewLocal.setIsRootNamespace(true);
1352 contentContainer.setHeadsUpChild(headsUpContentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -04001353 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001354
Dan Sandlera5e0f412014-01-23 15:11:54 -05001355 // now the public version
1356 View publicViewLocal = null;
1357 if (publicNotification != null) {
1358 try {
Selim Cinek684a4422015-04-15 16:18:39 -07001359 publicViewLocal = publicNotification.contentView.apply(mContext,
1360 contentContainerPublic, mOnClickHandler);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001361
1362 if (publicViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -04001363 publicViewLocal.setIsRootNamespace(true);
Selim Cinek8d490d42015-04-10 00:05:50 -07001364 contentContainerPublic.setContractedChild(publicViewLocal);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001365 }
1366 }
1367 catch (RuntimeException e) {
1368 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
1369 Log.e(TAG, "couldn't inflate public view for notification " + ident, e);
1370 publicViewLocal = null;
1371 }
1372 }
1373
Jorim Jaggia1eeade2014-09-08 22:34:39 +02001374 // Extract target SDK version.
1375 try {
1376 ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
1377 entry.targetSdk = info.targetSdkVersion;
1378 } catch (NameNotFoundException ex) {
1379 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
1380 }
1381
Dan Sandlera5e0f412014-01-23 15:11:54 -05001382 if (publicViewLocal == null) {
1383 // Add a basic notification template
1384 publicViewLocal = LayoutInflater.from(mContext).inflate(
Jorim Jaggied713ee2014-09-09 23:56:09 +02001385 R.layout.notification_public_default,
Selim Cinek8d490d42015-04-10 00:05:50 -07001386 contentContainerPublic, false);
Selim Cinekcab4a602014-09-03 14:47:57 +02001387 publicViewLocal.setIsRootNamespace(true);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001388
Jorim Jaggied713ee2014-09-09 23:56:09 +02001389 final TextView title = (TextView) publicViewLocal.findViewById(R.id.title);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001390 try {
Dan Sandlere9a4e902014-07-31 01:06:43 -04001391 title.setText(pmUser.getApplicationLabel(
1392 pmUser.getApplicationInfo(entry.notification.getPackageName(), 0)));
Dan Sandlera5e0f412014-01-23 15:11:54 -05001393 } catch (NameNotFoundException e) {
1394 title.setText(entry.notification.getPackageName());
1395 }
1396
Jorim Jaggied713ee2014-09-09 23:56:09 +02001397 final ImageView icon = (ImageView) publicViewLocal.findViewById(R.id.icon);
Kenny Guy98193ea2014-07-24 19:54:37 +01001398 final ImageView profileBadge = (ImageView) publicViewLocal.findViewById(
Jorim Jaggied713ee2014-09-09 23:56:09 +02001399 R.id.profile_badge_line3);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001400
Dan Sandlerd63f9322015-05-06 15:18:49 -04001401 final StatusBarIcon ic = new StatusBarIcon(
Dan Sandlera5e0f412014-01-23 15:11:54 -05001402 entry.notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04001403 entry.notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04001404 entry.notification.getNotification().getSmallIcon(),
Dan Sandlera5e0f412014-01-23 15:11:54 -05001405 entry.notification.getNotification().iconLevel,
1406 entry.notification.getNotification().number,
1407 entry.notification.getNotification().tickerText);
1408
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01001409 Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
1410 icon.setImageDrawable(iconDrawable);
Dianne Hackborn955d8d62014-10-07 20:17:19 -07001411 if (entry.targetSdk >= Build.VERSION_CODES.LOLLIPOP
Jorim Jaggia1eeade2014-09-08 22:34:39 +02001412 || mNotificationColorUtil.isGrayscaleIcon(iconDrawable)) {
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01001413 icon.setBackgroundResource(
Jorim Jaggi445d3c02014-08-19 22:33:42 +02001414 com.android.internal.R.drawable.notification_icon_legacy_bg);
1415 int padding = mContext.getResources().getDimensionPixelSize(
1416 com.android.internal.R.dimen.notification_large_icon_circle_padding);
1417 icon.setPadding(padding, padding, padding, padding);
Jorim Jaggia1eeade2014-09-08 22:34:39 +02001418 if (sbn.getNotification().color != Notification.COLOR_DEFAULT) {
1419 icon.getBackground().setColorFilter(
1420 sbn.getNotification().color, PorterDuff.Mode.SRC_ATOP);
1421 }
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01001422 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001423
Kenny Guy98193ea2014-07-24 19:54:37 +01001424 if (profileBadge != null) {
Svetoslavc7d62f02014-09-04 15:39:54 -07001425 Drawable profileDrawable = mContext.getPackageManager().getUserBadgeForDensity(
1426 entry.notification.getUser(), 0);
Kenny Guy8a0101b2014-05-08 23:34:12 +01001427 if (profileDrawable != null) {
Kenny Guy98193ea2014-07-24 19:54:37 +01001428 profileBadge.setImageDrawable(profileDrawable);
1429 profileBadge.setVisibility(View.VISIBLE);
Kenny Guy8a0101b2014-05-08 23:34:12 +01001430 } else {
Kenny Guy98193ea2014-07-24 19:54:37 +01001431 profileBadge.setVisibility(View.GONE);
Kenny Guy8a0101b2014-05-08 23:34:12 +01001432 }
1433 }
1434
Dan Sandler18bb4f92014-07-14 16:48:27 -04001435 final View privateTime = contentViewLocal.findViewById(com.android.internal.R.id.time);
Jorim Jaggied713ee2014-09-09 23:56:09 +02001436 final DateTimeView time = (DateTimeView) publicViewLocal.findViewById(R.id.time);
Dan Sandler18bb4f92014-07-14 16:48:27 -04001437 if (privateTime != null && privateTime.getVisibility() == View.VISIBLE) {
Jorim Jaggied713ee2014-09-09 23:56:09 +02001438 time.setVisibility(View.VISIBLE);
1439 time.setTime(entry.notification.getNotification().when);
Dan Sandler18bb4f92014-07-14 16:48:27 -04001440 }
1441
Jorim Jaggied713ee2014-09-09 23:56:09 +02001442 final TextView text = (TextView) publicViewLocal.findViewById(R.id.text);
Dan Sandler18bb4f92014-07-14 16:48:27 -04001443 if (text != null) {
1444 text.setText(R.string.notification_hidden_text);
1445 text.setTextAppearance(mContext,
Alan Viverette41ad3942014-08-27 15:06:51 -07001446 R.style.TextAppearance_Material_Notification_Parenthetical);
Dan Sandler18bb4f92014-07-14 16:48:27 -04001447 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001448
Jorim Jaggi445d3c02014-08-19 22:33:42 +02001449 int topPadding = Notification.Builder.calculateTopPadding(mContext,
1450 false /* hasThreeLines */,
1451 mContext.getResources().getConfiguration().fontScale);
1452 title.setPadding(0, topPadding, 0, 0);
1453
Jorim Jaggi021eee52015-06-11 17:07:18 -07001454 contentContainerPublic.setContractedChild(publicViewLocal);
Jorim Jaggi36b15232014-06-10 17:24:20 +02001455 entry.autoRedacted = true;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001456 }
1457
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001458 if (MULTIUSER_DEBUG) {
1459 TextView debug = (TextView) row.findViewById(R.id.debug_info);
1460 if (debug != null) {
1461 debug.setVisibility(View.VISIBLE);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001462 debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId());
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001463 }
1464 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001465 entry.row = row;
Chris Wrend04f6ce2014-06-11 17:37:28 -04001466 entry.row.setHeightRange(mRowMinHeight, maxHeight);
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001467 entry.row.setOnActivatedListener(this);
Selim Cinek684a4422015-04-15 16:18:39 -07001468 entry.row.setExpandable(bigContentViewLocal != null);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001469
Christoph Studer13b895122014-08-26 15:42:12 +02001470 applyColorsAndBackgrounds(sbn, entry);
Jorim Jaggi46739852014-04-15 09:58:24 +02001471
Christoph Studera7fe6312014-06-27 19:32:44 +02001472 // Restore previous flags.
1473 if (hasUserChangedExpansion) {
1474 // Note: setUserExpanded() conveniently ignores calls with
1475 // userExpanded=true if !isExpandable().
1476 row.setUserExpanded(userExpanded);
1477 }
1478 row.setUserLocked(userLocked);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001479 row.setStatusBarNotification(entry.notification);
Adrian Rooseb91ca52015-06-10 15:49:11 -07001480
Daniel Sandler6a858c32012-03-12 14:38:58 -04001481 return true;
1482 }
1483
Chris Wren42d5dd42015-05-01 10:39:26 -04001484 private final class NotificationClicker implements View.OnClickListener {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001485 public void onClick(final View v) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001486 if (!(v instanceof ExpandableNotificationRow)) {
1487 Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
1488 return;
1489 }
1490
1491 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
1492 final StatusBarNotification sbn = row.getStatusBarNotification();
1493 if (sbn == null) {
1494 Log.e(TAG, "NotificationClicker called on an unclickable notification,");
1495 return;
1496 }
1497
1498 final PendingIntent intent = sbn.getNotification().contentIntent;
1499 final String notificationKey = sbn.getKey();
1500
Chris Wren79ac09e2014-10-29 14:20:19 -04001501 if (NOTIFICATION_CLICK_DEBUG) {
Chris Wren42d5dd42015-05-01 10:39:26 -04001502 Log.d(TAG, "Clicked on content of " + notificationKey);
Chris Wren79ac09e2014-10-29 14:20:19 -04001503 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001504 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
Chris Wren42d5dd42015-05-01 10:39:26 -04001505 final boolean afterKeyguardGone = intent.isActivity()
1506 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001507 mCurrentUserId);
Adrian Roos4314f6d2014-05-28 14:10:27 +02001508 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001509 public boolean onDismiss() {
Chris Wren42d5dd42015-05-01 10:39:26 -04001510 if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
Christoph Studerc6a656c2015-01-22 15:02:49 +01001511 // Release the HUN notification to the shade.
1512 //
1513 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
1514 // become canceled shortly by NoMan, but we can't assume that.
Chris Wren42d5dd42015-05-01 10:39:26 -04001515 mHeadsUpManager.releaseImmediately(notificationKey);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001516 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001517 new Thread() {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001518 @Override
1519 public void run() {
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001520 try {
1521 if (keyguardShowing && !afterKeyguardGone) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001522 ActivityManagerNative.getDefault()
1523 .keyguardWaitingForActivityDrawn();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001524 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001525
1526 // The intent we are sending is for the application, which
1527 // won't have permission to immediately start an activity after
1528 // the user switches to home. We know it is safe to do at this
1529 // point, so make sure new activity switches are now allowed.
1530 ActivityManagerNative.getDefault().resumeAppSwitches();
1531 } catch (RemoteException e) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001532 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001533
Chris Wren42d5dd42015-05-01 10:39:26 -04001534 if (intent != null) {
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001535 try {
Chris Wren42d5dd42015-05-01 10:39:26 -04001536 intent.send();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001537 } catch (PendingIntent.CanceledException e) {
1538 // the stack trace isn't very helpful here.
1539 // Just log the exception message.
1540 Log.w(TAG, "Sending contentIntent failed: " + e);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001541
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001542 // TODO: Dismiss Keyguard.
1543 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001544 if (intent.isActivity()) {
Jorim Jaggib835dd72015-06-08 12:28:42 -07001545 mAssistManager.hideAssist();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001546 overrideActivityPendingAppTransition(keyguardShowing
1547 && !afterKeyguardGone);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001548 }
1549 }
1550
1551 try {
Chris Wren42d5dd42015-05-01 10:39:26 -04001552 mBarService.onNotificationClick(notificationKey);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001553 } catch (RemoteException ex) {
1554 // system process is dead if we're here.
1555 }
Adrian Roos7d7090d2014-05-21 13:10:23 +02001556 }
Jorim Jaggi89f7f282014-10-17 19:54:15 +02001557 }.start();
Adrian Roos7d7090d2014-05-21 13:10:23 +02001558
1559 // close the shade if it was open
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +01001560 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001561 true /* force */, true /* delayed */);
Adrian Roos7d7090d2014-05-21 13:10:23 +02001562 visibilityChanged(false);
1563
Jorim Jaggi8972c2a2015-06-05 16:05:54 -07001564 return true;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001565 }
Jorim Jaggi85dc23c2014-09-08 14:42:29 +02001566 }, afterKeyguardGone);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001567 }
Chris Wren42d5dd42015-05-01 10:39:26 -04001568
1569 public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
1570 final PendingIntent contentIntent = sbn.getNotification().contentIntent;
1571 if (contentIntent != null) {
1572 row.setOnClickListener(this);
1573 } else {
1574 row.setOnClickListener(null);
1575 }
1576 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001577 }
Chris Wrenf29c3b42013-11-27 16:30:30 -05001578
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001579 public void animateCollapsePanels(int flags, boolean force) {
1580 }
1581
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001582 public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
1583 }
1584
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001585 public void overrideActivityPendingAppTransition(boolean keyguardShowing) {
1586 if (keyguardShowing) {
1587 try {
1588 mWindowManagerService.overridePendingAppTransition(null, 0, 0, null);
1589 } catch (RemoteException e) {
1590 Log.w(TAG, "Error overriding app transition: " + e);
1591 }
1592 }
1593 }
1594
Christoph Studere8e28652014-10-29 17:27:53 +01001595 protected void visibilityChanged(boolean visible) {
1596 if (mVisible != visible) {
1597 mVisible = visible;
1598 if (!visible) {
1599 dismissPopups();
1600 }
1601 }
1602 updateVisibleToUser();
1603 }
1604
1605 protected void updateVisibleToUser() {
1606 boolean oldVisibleToUser = mVisibleToUser;
1607 mVisibleToUser = mVisible && mScreenOnFromKeyguard;
1608
1609 if (oldVisibleToUser != mVisibleToUser) {
1610 handleVisibleToUserChanged(mVisibleToUser);
1611 }
1612 }
1613
Daniel Sandler6a858c32012-03-12 14:38:58 -04001614 /**
Christoph Studere8e28652014-10-29 17:27:53 +01001615 * The LEDs are turned off when the notification panel is shown, even just a little bit.
Daniel Sandler6a858c32012-03-12 14:38:58 -04001616 * This was added last-minute and is inconsistent with the way the rest of the notifications
1617 * are handled, because the notification isn't really cancelled. The lights are just
1618 * turned off. If any other notifications happen, the lights will turn back on. Steve says
1619 * this is what he wants. (see bug 1131461)
1620 */
Christoph Studere8e28652014-10-29 17:27:53 +01001621 protected void handleVisibleToUserChanged(boolean visibleToUser) {
1622 try {
1623 if (visibleToUser) {
Christoph Studer1f32c652014-11-26 15:32:20 +01001624 // Only stop blinking, vibrating, ringing when the user went into the shade
1625 // manually (SHADE or SHADE_LOCKED).
1626 boolean clearNotificationEffects =
1627 (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
1628 mBarService.onPanelRevealed(clearNotificationEffects);
Christoph Studere8e28652014-10-29 17:27:53 +01001629 } else {
1630 mBarService.onPanelHidden();
Dan Sandler4247a5c2014-07-23 15:58:08 -04001631 }
Christoph Studere8e28652014-10-29 17:27:53 +01001632 } catch (RemoteException ex) {
1633 // Won't fail unless the world has ended.
Daniel Sandler6a858c32012-03-12 14:38:58 -04001634 }
1635 }
1636
Chris Wren0c8275b2012-05-08 13:36:48 -04001637 /**
1638 * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
1639 * about the failure.
1640 *
1641 * WARNING: this will call back into us. Don't hold any locks.
1642 */
Christoph Studer71f18fd2014-05-20 17:02:04 +02001643 void handleNotificationError(StatusBarNotification n, String message) {
Christoph Studere71fefc2014-06-24 16:16:49 +02001644 removeNotification(n.getKey(), null);
Chris Wren0c8275b2012-05-08 13:36:48 -04001645 try {
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001646 mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
1647 n.getInitialPid(), message, n.getUserId());
Chris Wren0c8275b2012-05-08 13:36:48 -04001648 } catch (RemoteException ex) {
1649 // The end is nigh.
1650 }
1651 }
1652
Christoph Studerd0694b62014-06-04 16:36:01 +02001653 protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
Christoph Studer37fe6932014-05-26 13:10:30 +02001654 NotificationData.Entry entry = mNotificationData.remove(key, ranking);
Chris Wren0c8275b2012-05-08 13:36:48 -04001655 if (entry == null) {
John Spurlockcd686b52013-06-05 10:13:46 -04001656 Log.w(TAG, "removeNotification for unknown key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -04001657 return null;
1658 }
Christoph Studer37fe6932014-05-26 13:10:30 +02001659 updateNotifications();
Chris Wren0c8275b2012-05-08 13:36:48 -04001660 return entry.notification;
1661 }
1662
Selim Cinek8d490d42015-04-10 00:05:50 -07001663 protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04001664 if (DEBUG) {
Christoph Studera0506e72014-07-31 20:27:39 +02001665 Log.d(TAG, "createNotificationViews(notification=" + sbn);
Chris Wren0c8275b2012-05-08 13:36:48 -04001666 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01001667 final StatusBarIconView iconView = createIcon(sbn);
1668 if (iconView == null) {
1669 return null;
1670 }
1671
1672 // Construct the expanded view.
1673 NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
Selim Cinek8d490d42015-04-10 00:05:50 -07001674 if (!inflateViews(entry, mStackScroller)) {
Selim Cinek379ff8f2015-02-20 17:03:16 +01001675 handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
1676 return null;
1677 }
1678 return entry;
1679 }
1680
1681 protected StatusBarIconView createIcon(StatusBarNotification sbn) {
Chris Wren0c8275b2012-05-08 13:36:48 -04001682 // Construct the icon.
Christoph Studera0506e72014-07-31 20:27:39 +02001683 Notification n = sbn.getNotification();
Chris Wren0c8275b2012-05-08 13:36:48 -04001684 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Christoph Studera0506e72014-07-31 20:27:39 +02001685 sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
Chris Wren0c8275b2012-05-08 13:36:48 -04001686 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
1687
Dan Sandlerd63f9322015-05-06 15:18:49 -04001688 final StatusBarIcon ic = new StatusBarIcon(
Christoph Studera0506e72014-07-31 20:27:39 +02001689 sbn.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04001690 sbn.getPackageName(),
1691 n.getSmallIcon(),
1692 n.iconLevel,
1693 n.number,
1694 n.tickerText);
Chris Wren0c8275b2012-05-08 13:36:48 -04001695 if (!iconView.set(ic)) {
Christoph Studera0506e72014-07-31 20:27:39 +02001696 handleNotificationError(sbn, "Couldn't create icon: " + ic);
Chris Wren0c8275b2012-05-08 13:36:48 -04001697 return null;
1698 }
Selim Cinek379ff8f2015-02-20 17:03:16 +01001699 return iconView;
Chris Wrenf0048ce2013-08-07 16:43:43 -04001700 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001701
Christoph Studerd0694b62014-06-04 16:36:01 +02001702 protected void addNotificationViews(Entry entry, RankingMap ranking) {
Raju Yadav5f330262014-03-24 10:44:00 +01001703 if (entry == null) {
1704 return;
1705 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001706 // Add the expanded view and icon.
Christoph Studer37fe6932014-05-26 13:10:30 +02001707 mNotificationData.add(entry, ranking);
1708 updateNotifications();
Selim Cinek8efa6dd2014-05-19 16:27:37 +02001709 }
1710
Jorim Jaggi251957d2014-04-09 04:24:09 +02001711 /**
Jorim Jaggid4a57442014-04-10 02:45:55 +02001712 * @return The number of notifications we show on Keyguard.
1713 */
1714 protected abstract int getMaxKeyguardNotifications();
1715
1716 /**
Jorim Jaggi251957d2014-04-09 04:24:09 +02001717 * Updates expanded, dimmed and locked states of notification rows.
1718 */
1719 protected void updateRowStates() {
Jorim Jaggif6411742014-08-05 17:10:43 +00001720 int maxKeyguardNotifications = getMaxKeyguardNotifications();
1721 mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
1722
Christoph Studerc8db24b2014-07-25 17:50:30 +02001723 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1724 final int N = activeNotifications.size();
1725
Jorim Jaggif6411742014-08-05 17:10:43 +00001726 int visibleNotifications = 0;
Jorim Jaggiecbab362014-04-23 16:13:15 +02001727 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
Christoph Studer37fe6932014-05-26 13:10:30 +02001728 for (int i = 0; i < N; i++) {
Christoph Studerc8db24b2014-07-25 17:50:30 +02001729 NotificationData.Entry entry = activeNotifications.get(i);
Jorim Jaggiecbab362014-04-23 16:13:15 +02001730 if (onKeyguard) {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001731 entry.row.setExpansionDisabled(true);
Chris Wren3ddab0d2012-08-02 16:52:21 -04001732 } else {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001733 entry.row.setExpansionDisabled(false);
Jorim Jaggi649b7082014-04-03 13:15:18 +02001734 if (!entry.row.isUserLocked()) {
Christoph Studer37fe6932014-05-26 13:10:30 +02001735 boolean top = (i == 0);
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001736 entry.row.setSystemExpanded(top);
Jorim Jaggi649b7082014-04-03 13:15:18 +02001737 }
Chris Wren8fd12652012-05-09 21:25:57 -04001738 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001739 boolean isInvisibleChild = !mGroupManager.isVisible(entry.notification);
Jorim Jaggif6411742014-08-05 17:10:43 +00001740 boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
Jorim Jaggi9261b3b2014-09-08 14:02:07 +02001741 if ((isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
Jorim Jaggida30a032014-09-05 15:11:46 +02001742 (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
Selim Cinekb5605e52015-02-20 18:21:41 +01001743 || !showOnKeyguard || isInvisibleChild))) {
Jorim Jaggif6411742014-08-05 17:10:43 +00001744 entry.row.setVisibility(View.GONE);
Selim Cinekb5605e52015-02-20 18:21:41 +01001745 if (onKeyguard && showOnKeyguard && !isInvisibleChild) {
Jorim Jaggif6411742014-08-05 17:10:43 +00001746 mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
1747 }
1748 } else {
1749 boolean wasGone = entry.row.getVisibility() == View.GONE;
1750 entry.row.setVisibility(View.VISIBLE);
Selim Cinekb5605e52015-02-20 18:21:41 +01001751 if (!isInvisibleChild) {
1752 if (wasGone) {
1753 // notify the scroller of a child addition
1754 mStackScroller.generateAddAnimation(entry.row, true /* fromMoreCard */);
1755 }
1756 visibleNotifications++;
Jorim Jaggif6411742014-08-05 17:10:43 +00001757 }
Jorim Jaggif6411742014-08-05 17:10:43 +00001758 }
Chris Wren8fd12652012-05-09 21:25:57 -04001759 }
Jorim Jaggif6411742014-08-05 17:10:43 +00001760
Selim Cinek2cd45df2015-06-09 18:00:07 -07001761 mStackScroller.updateOverflowContainerVisibility(onKeyguard
1762 && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0);
Jorim Jaggif6411742014-08-05 17:10:43 +00001763
Selim Cinek0cce5312015-05-20 22:13:55 -07001764 mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
1765 mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
Jorim Jaggif6411742014-08-05 17:10:43 +00001766 mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
1767 mStackScroller.getChildCount() - 3);
Jorim Jaggif6411742014-08-05 17:10:43 +00001768 }
1769
1770 private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
1771 return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
Chris Wren8fd12652012-05-09 21:25:57 -04001772 }
1773
John Spurlocke677d712014-02-13 12:52:19 -05001774 protected void setZenMode(int mode) {
John Spurlock110e5b12014-02-27 13:09:35 -05001775 if (!isDeviceProvisioned()) return;
John Spurlocke677d712014-02-13 12:52:19 -05001776 mZenMode = mode;
Christoph Studer37fe6932014-05-26 13:10:30 +02001777 updateNotifications();
John Spurlocke677d712014-02-13 12:52:19 -05001778 }
1779
Dan Sandler52e5701e2014-07-22 23:14:54 -04001780 // extended in PhoneStatusBar
1781 protected void setShowLockscreenNotifications(boolean show) {
1782 mShowLockscreenNotifications = show;
1783 }
1784
1785 private void updateLockscreenNotificationSetting() {
1786 final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
1787 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
1788 1,
1789 mCurrentUserId) != 0;
Adrian Roosbd3409c2014-08-12 18:21:09 +02001790 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
1791 null /* admin */, mCurrentUserId);
1792 final boolean allowedByDpm = (dpmFlags
1793 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
1794 setShowLockscreenNotifications(show && allowedByDpm);
Dan Sandler52e5701e2014-07-22 23:14:54 -04001795 }
1796
Chris Wren0c8275b2012-05-08 13:36:48 -04001797 protected abstract void setAreThereNotifications();
Christoph Studer37fe6932014-05-26 13:10:30 +02001798 protected abstract void updateNotifications();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -07001799 public abstract boolean shouldDisableNavbarGestures();
Chris Wren0c8275b2012-05-08 13:36:48 -04001800
Christoph Studere71fefc2014-06-24 16:16:49 +02001801 public abstract void addNotification(StatusBarNotification notification,
Selim Cinek379ff8f2015-02-20 17:03:16 +01001802 RankingMap ranking, Entry oldEntry);
Christoph Studere71fefc2014-06-24 16:16:49 +02001803 protected abstract void updateNotificationRanking(RankingMap ranking);
1804 public abstract void removeNotification(String key, RankingMap ranking);
Christoph Studera7fe6312014-06-27 19:32:44 +02001805
Christoph Studere71fefc2014-06-24 16:16:49 +02001806 public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02001807 if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
Chris Wren0c8275b2012-05-08 13:36:48 -04001808
Chris Wrend04f6ce2014-06-11 17:37:28 -04001809 final String key = notification.getKey();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001810 Entry entry = mNotificationData.get(key);
1811 if (entry == null) {
Chris Wren0c8275b2012-05-08 13:36:48 -04001812 return;
1813 }
1814
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001815 Notification n = notification.getNotification();
1816 if (DEBUG) {
1817 logUpdate(entry, n);
1818 }
1819 boolean applyInPlace = shouldApplyInPlace(entry, n);
Selim Cinekb18a20f2015-06-04 17:08:35 +02001820 boolean shouldInterrupt = shouldInterrupt(entry);
Selim Cinek684a4422015-04-15 16:18:39 -07001821 boolean alertAgain = alertAgain(entry, n);
Chris Wren0c8275b2012-05-08 13:36:48 -04001822
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001823 entry.notification = notification;
1824 mGroupManager.onEntryUpdated(entry, entry.notification);
1825
1826 boolean updateSuccessful = false;
1827 if (applyInPlace) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001828 if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
1829 try {
1830 if (entry.icon != null) {
1831 // Update the icon
Dan Sandlerd63f9322015-05-06 15:18:49 -04001832 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001833 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04001834 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04001835 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001836 n.iconLevel,
1837 n.number,
1838 n.tickerText);
1839 entry.icon.setNotification(n);
1840 if (!entry.icon.set(ic)) {
1841 handleNotificationError(notification, "Couldn't update icon: " + ic);
1842 return;
1843 }
1844 }
Selim Cinek8d490d42015-04-10 00:05:50 -07001845 updateNotificationViews(entry, notification);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001846 updateSuccessful = true;
1847 }
1848 catch (RuntimeException e) {
Selim Cinek684a4422015-04-15 16:18:39 -07001849 // It failed to apply cleanly.
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001850 Log.w(TAG, "Couldn't reapply views for package " + n.contentView.getPackage(), e);
1851 }
1852 }
1853 if (!updateSuccessful) {
1854 if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
Dan Sandlerd63f9322015-05-06 15:18:49 -04001855 final StatusBarIcon ic = new StatusBarIcon(
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001856 notification.getUser(),
Dan Sandler4e787062015-06-17 15:09:48 -04001857 notification.getPackageName(),
Dan Sandlerd63f9322015-05-06 15:18:49 -04001858 n.getSmallIcon(),
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001859 n.iconLevel,
1860 n.number,
1861 n.tickerText);
1862 entry.icon.setNotification(n);
1863 entry.icon.set(ic);
Selim Cinek8d490d42015-04-10 00:05:50 -07001864 inflateViews(entry, mStackScroller);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001865 }
Selim Cinekfbe9a442015-04-13 16:09:49 -07001866 updateHeadsUp(key, entry, shouldInterrupt, alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001867 mNotificationData.updateRanking(ranking);
1868 updateNotifications();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001869
1870 // Update the veto button accordingly (and as a result, whether this row is
1871 // swipe-dismissable)
1872 updateNotificationVetoButton(entry.row, notification);
1873
Selim Cinek684a4422015-04-15 16:18:39 -07001874 if (DEBUG) {
1875 // Is this for you?
1876 boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
1877 Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
1878 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001879
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001880 setAreThereNotifications();
1881 }
1882
Selim Cinek29fa89b2015-04-17 10:39:11 -07001883 protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt,
1884 boolean alertAgain);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001885
1886 private void logUpdate(Entry oldEntry, Notification n) {
1887 StatusBarNotification oldNotification = oldEntry.notification;
1888 Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
1889 + " ongoing=" + oldNotification.isOngoing()
Selim Cinek684a4422015-04-15 16:18:39 -07001890 + " expanded=" + oldEntry.getContentView()
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001891 + " contentView=" + oldNotification.getNotification().contentView
1892 + " bigContentView=" + oldNotification.getNotification().bigContentView
1893 + " publicView=" + oldNotification.getNotification().publicVersion
1894 + " rowParent=" + oldEntry.row.getParent());
1895 Log.d(TAG, "new notification: when=" + n.when
1896 + " ongoing=" + oldNotification.isOngoing()
1897 + " contentView=" + n.contentView
1898 + " bigContentView=" + n.bigContentView
1899 + " publicView=" + n.publicVersion);
1900 }
1901
1902 /**
Selim Cinek684a4422015-04-15 16:18:39 -07001903 * @return whether we can just reapply the RemoteViews from a notification in-place when it is
1904 * updated
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001905 */
1906 private boolean shouldApplyInPlace(Entry entry, Notification n) {
1907 StatusBarNotification oldNotification = entry.notification;
Chris Wren0c8275b2012-05-08 13:36:48 -04001908 // XXX: modify when we do something more intelligent with the two content views
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001909 final RemoteViews oldContentView = oldNotification.getNotification().contentView;
Christoph Studera0506e72014-07-31 20:27:39 +02001910 final RemoteViews contentView = n.contentView;
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001911 final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView;
Christoph Studera0506e72014-07-31 20:27:39 +02001912 final RemoteViews bigContentView = n.bigContentView;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001913 final RemoteViews oldHeadsUpContentView
1914 = oldNotification.getNotification().headsUpContentView;
Christoph Studera0506e72014-07-31 20:27:39 +02001915 final RemoteViews headsUpContentView = n.headsUpContentView;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001916 final Notification oldPublicNotification = oldNotification.getNotification().publicVersion;
1917 final RemoteViews oldPublicContentView = oldPublicNotification != null
1918 ? oldPublicNotification.contentView : null;
Christoph Studera0506e72014-07-31 20:27:39 +02001919 final Notification publicNotification = n.publicVersion;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001920 final RemoteViews publicContentView = publicNotification != null
1921 ? publicNotification.contentView : null;
Selim Cinek684a4422015-04-15 16:18:39 -07001922 boolean contentsUnchanged = entry.getContentView() != null
Chris Wren0c8275b2012-05-08 13:36:48 -04001923 && contentView.getPackage() != null
1924 && oldContentView.getPackage() != null
1925 && oldContentView.getPackage().equals(contentView.getPackage())
1926 && oldContentView.getLayoutId() == contentView.getLayoutId();
Chris Wrene9e37722012-05-11 17:40:14 -04001927 // large view may be null
1928 boolean bigContentsUnchanged =
Selim Cinek684a4422015-04-15 16:18:39 -07001929 (entry.getExpandedContentView() == null && bigContentView == null)
1930 || ((entry.getExpandedContentView() != null && bigContentView != null)
Chris Wrene9e37722012-05-11 17:40:14 -04001931 && bigContentView.getPackage() != null
1932 && oldBigContentView.getPackage() != null
1933 && oldBigContentView.getPackage().equals(bigContentView.getPackage())
1934 && oldBigContentView.getLayoutId() == bigContentView.getLayoutId());
Chris Wren8fd39ec2014-02-27 17:43:26 -05001935 boolean headsUpContentsUnchanged =
1936 (oldHeadsUpContentView == null && headsUpContentView == null)
1937 || ((oldHeadsUpContentView != null && headsUpContentView != null)
1938 && headsUpContentView.getPackage() != null
1939 && oldHeadsUpContentView.getPackage() != null
1940 && oldHeadsUpContentView.getPackage().equals(headsUpContentView.getPackage())
1941 && oldHeadsUpContentView.getLayoutId() == headsUpContentView.getLayoutId());
Dan Sandlera5e0f412014-01-23 15:11:54 -05001942 boolean publicUnchanged =
1943 (oldPublicContentView == null && publicContentView == null)
1944 || ((oldPublicContentView != null && publicContentView != null)
1945 && publicContentView.getPackage() != null
1946 && oldPublicContentView.getPackage() != null
1947 && oldPublicContentView.getPackage().equals(publicContentView.getPackage())
1948 && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001949 return contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
1950 && publicUnchanged;
Chris Wrenf29c3b42013-11-27 16:30:30 -05001951 }
1952
Selim Cinek8d490d42015-04-10 00:05:50 -07001953 private void updateNotificationViews(Entry entry, StatusBarNotification notification) {
Chris Wrene03f4e12013-08-08 16:48:48 -04001954 final RemoteViews contentView = notification.getNotification().contentView;
Selim Cinek8d490d42015-04-10 00:05:50 -07001955 final RemoteViews bigContentView = notification.getNotification().bigContentView;
1956 final RemoteViews headsUpContentView = notification.getNotification().headsUpContentView;
John Spurlock70cf4c12014-02-13 09:39:14 -05001957 final Notification publicVersion = notification.getNotification().publicVersion;
1958 final RemoteViews publicContentView = publicVersion != null ? publicVersion.contentView
1959 : null;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001960
Chris Wrene03f4e12013-08-08 16:48:48 -04001961 // Reapply the RemoteViews
Selim Cinek684a4422015-04-15 16:18:39 -07001962 contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
1963 if (bigContentView != null && entry.getExpandedContentView() != null) {
1964 bigContentView.reapply(mContext, entry.getExpandedContentView(),
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001965 mOnClickHandler);
Chris Wrene03f4e12013-08-08 16:48:48 -04001966 }
Selim Cinek684a4422015-04-15 16:18:39 -07001967 View headsUpChild = entry.getHeadsUpContentView();
Selim Cinek8d490d42015-04-10 00:05:50 -07001968 if (headsUpContentView != null && headsUpChild != null) {
1969 headsUpContentView.reapply(mContext, headsUpChild, mOnClickHandler);
1970 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001971 if (publicContentView != null && entry.getPublicContentView() != null) {
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01001972 publicContentView.reapply(mContext, entry.getPublicContentView(), mOnClickHandler);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001973 }
Chris Wrene03f4e12013-08-08 16:48:48 -04001974 // update the contentIntent
Chris Wren42d5dd42015-05-01 10:39:26 -04001975 mNotificationClicker.register(entry.row, notification);
1976
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001977 entry.row.setStatusBarNotification(notification);
Jorim Jaggibe565df2014-04-28 17:51:23 +02001978 entry.row.notifyContentUpdated();
Selim Cinek51ae05d2014-09-09 15:51:38 +02001979 entry.row.resetHeight();
Chris Wren0c8275b2012-05-08 13:36:48 -04001980 }
John Spurlock36231282012-06-23 17:11:27 -04001981
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001982 protected void notifyHeadsUpScreenOff() {
Selim Cinek684a4422015-04-15 16:18:39 -07001983 maybeEscalateHeadsUp();
Chris Wrene97f90b2013-08-07 17:39:35 -04001984 }
1985
Chris Wrend93d5ad2014-09-08 16:34:03 -04001986 private boolean alertAgain(Entry oldEntry, Notification newNotification) {
1987 return oldEntry == null || !oldEntry.hasInterrupted()
1988 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
Chris Wrend04f6ce2014-06-11 17:37:28 -04001989 }
1990
Selim Cinekb18a20f2015-06-04 17:08:35 +02001991 protected boolean shouldInterrupt(Entry entry) {
1992 StatusBarNotification sbn = entry.notification;
Christoph Studer2f9dbba2014-09-03 17:35:54 +02001993 if (mNotificationData.shouldFilterOut(sbn)) {
1994 if (DEBUG) {
1995 Log.d(TAG, "Skipping HUN check for " + sbn.getKey() + " since it's filtered out.");
1996 }
1997 return false;
1998 }
1999
Selim Cinek29fa89b2015-04-17 10:39:11 -07002000 if (isSnoozedPackage(sbn)) {
Chris Wrena6d4fb62014-11-20 14:46:23 -05002001 return false;
2002 }
2003
Chris Wren51c75102013-07-16 20:49:17 -04002004 Notification notification = sbn.getNotification();
2005 // some predicates to make the boolean logic legible
2006 boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0
2007 || (notification.defaults & Notification.DEFAULT_VIBRATE) != 0
2008 || notification.sound != null
2009 || notification.vibrate != null;
2010 boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD;
2011 boolean isFullscreen = notification.fullScreenIntent != null;
Chris Wren22ae46e2014-02-26 18:08:09 -05002012 boolean hasTicker = mHeadsUpTicker && !TextUtils.isEmpty(notification.tickerText);
Chris Wren51c75102013-07-16 20:49:17 -04002013 boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP,
2014 Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER;
Selim Cineka8fefa52014-09-08 16:10:50 +02002015 boolean accessibilityForcesLaunch = isFullscreen
2016 && mAccessibilityManager.isTouchExplorationEnabled();
Selim Cinekb18a20f2015-06-04 17:08:35 +02002017 boolean justLaunchedFullScreenIntent = entry.hasJustLaunchedFullScreenIntent();
Chris Wren51c75102013-07-16 20:49:17 -04002018
Chris Wren22ae46e2014-02-26 18:08:09 -05002019 boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker)))
Chris Wren51c75102013-07-16 20:49:17 -04002020 && isAllowed
Selim Cineka8fefa52014-09-08 16:10:50 +02002021 && !accessibilityForcesLaunch
Selim Cinekb18a20f2015-06-04 17:08:35 +02002022 && !justLaunchedFullScreenIntent
Chris Wren51c75102013-07-16 20:49:17 -04002023 && mPowerManager.isScreenOn()
Jim Millerab954542014-10-10 18:21:49 -07002024 && (!mStatusBarKeyguardViewManager.isShowing()
2025 || mStatusBarKeyguardViewManager.isOccluded())
2026 && !mStatusBarKeyguardViewManager.isInputRestricted();
Chris Wren157026f2013-06-28 16:54:01 -04002027 try {
2028 interrupt = interrupt && !mDreamManager.isDreaming();
2029 } catch (RemoteException e) {
2030 Log.d(TAG, "failed to query dream manager", e);
2031 }
Chris Wren51c75102013-07-16 20:49:17 -04002032 if (DEBUG) Log.d(TAG, "interrupt: " + interrupt);
Chris Wren157026f2013-06-28 16:54:01 -04002033 return interrupt;
2034 }
2035
Selim Cinek29fa89b2015-04-17 10:39:11 -07002036 protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
2037
John Spurlockcfc359a2013-09-05 10:42:03 -04002038 public void setInteracting(int barWindow, boolean interacting) {
John Spurlockad3e6cb2013-04-30 08:47:43 -04002039 // hook for subclasses
2040 }
John Spurlock5c454122013-06-17 07:35:46 -04002041
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002042 public void setBouncerShowing(boolean bouncerShowing) {
2043 mBouncerShowing = bouncerShowing;
2044 }
2045
2046 /**
2047 * @return Whether the security bouncer from Keyguard is showing.
2048 */
2049 public boolean isBouncerShowing() {
2050 return mBouncerShowing;
2051 }
2052
John Spurlock5c454122013-06-17 07:35:46 -04002053 public void destroy() {
John Spurlock5c454122013-06-17 07:35:46 -04002054 mContext.unregisterReceiver(mBroadcastReceiver);
Christoph Studere71fefc2014-06-24 16:16:49 +02002055 try {
2056 mNotificationListener.unregisterAsSystemService();
2057 } catch (RemoteException e) {
2058 // Ignore.
Christoph Studer37fe6932014-05-26 13:10:30 +02002059 }
John Spurlock5c454122013-06-17 07:35:46 -04002060 }
Kenny Guy4dcb0dc2014-07-15 12:41:24 +01002061
2062 /**
2063 * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
2064 * return PackageManager for mContext
2065 */
2066 protected PackageManager getPackageManagerForUser(int userId) {
2067 Context contextForUser = mContext;
2068 // UserHandle defines special userId as negative values, e.g. USER_ALL
2069 if (userId >= 0) {
2070 try {
2071 // Create a context for the correct user so if a package isn't installed
2072 // for user 0 we can still load information about the package.
2073 contextForUser =
2074 mContext.createPackageContextAsUser(mContext.getPackageName(),
2075 Context.CONTEXT_RESTRICTED,
2076 new UserHandle(userId));
2077 } catch (NameNotFoundException e) {
2078 // Shouldn't fail to find the package name for system ui.
2079 }
2080 }
2081 return contextForUser.getPackageManager();
2082 }
Chris Wren78403d72014-07-28 10:23:24 +01002083
2084 @Override
2085 public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
2086 try {
2087 mBarService.onNotificationExpansionChanged(key, userAction, expanded);
2088 } catch (RemoteException e) {
2089 // Ignore.
2090 }
2091 }
Jim Millerab954542014-10-10 18:21:49 -07002092
2093 public boolean isKeyguardSecure() {
Dan Sandlere163a642015-03-01 22:58:32 -05002094 if (mStatusBarKeyguardViewManager == null) {
2095 // startKeyguard() hasn't been called yet, so we don't know.
2096 // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
2097 // value onVisibilityChanged().
2098 Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
2099 new Throwable());
2100 return false;
2101 }
Jim Millerab954542014-10-10 18:21:49 -07002102 return mStatusBarKeyguardViewManager.isSecure();
2103 }
Adrian Roos4f43dc02015-06-17 16:43:38 -07002104
2105 @Override
2106 public void showAssistDisclosure() {
2107 if (mAssistManager != null) {
2108 mAssistManager.showDisclosure();
2109 }
2110 }
Joe Onorato2314aab2010-04-08 16:41:23 -05002111}