blob: 06cc476d029518093b5b8265e0d118f1abaa1ba5 [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
Christopher Tate5e08af02012-09-21 17:17:22 -070019import android.app.ActivityManager;
Daniel Sandler6a858c32012-03-12 14:38:58 -040020import android.app.ActivityManagerNative;
Chris Wren51c75102013-07-16 20:49:17 -040021import android.app.Notification;
Daniel Sandler6a858c32012-03-12 14:38:58 -040022import android.app.PendingIntent;
Adam Powell0fc5b2b2012-07-18 18:20:29 -070023import android.app.TaskStackBuilder;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040024import android.content.BroadcastReceiver;
Christoph Studer60748e72014-05-22 16:51:41 +020025import android.content.ComponentName;
Joe Onorato808182d2010-07-09 18:52:06 -040026import android.content.Context;
Daniel Sandler6a858c32012-03-12 14:38:58 -040027import android.content.Intent;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040028import android.content.IntentFilter;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040029import android.content.pm.ApplicationInfo;
Dan Sandlera5e0f412014-01-23 15:11:54 -050030import android.content.pm.PackageManager;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040031import android.content.pm.PackageManager.NameNotFoundException;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000032import android.content.pm.UserInfo;
John Spurlockde84f0e2013-06-12 12:41:00 -040033import android.content.res.Configuration;
Daniel Sandler26cda272012-05-22 15:44:08 -040034import android.database.ContentObserver;
Daniel Sandler6a858c32012-03-12 14:38:58 -040035import android.graphics.Rect;
Jorim Jaggi39fa59f2014-02-25 15:38:45 +010036import android.graphics.drawable.Drawable;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040037import android.net.Uri;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040038import android.os.Build;
Michael Jurka7f2668c2012-03-27 07:49:52 -070039import android.os.Handler;
Joe Onorato808182d2010-07-09 18:52:06 -040040import android.os.IBinder;
Michael Jurka7f2668c2012-03-27 07:49:52 -070041import android.os.Message;
Chris Wren157026f2013-06-28 16:54:01 -040042import android.os.PowerManager;
Joe Onorato808182d2010-07-09 18:52:06 -040043import android.os.RemoteException;
44import android.os.ServiceManager;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070045import android.os.UserHandle;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000046import android.os.UserManager;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040047import android.provider.Settings;
Chris Wren157026f2013-06-28 16:54:01 -040048import android.service.dreams.DreamService;
49import android.service.dreams.IDreamManager;
Christoph Studer60748e72014-05-22 16:51:41 +020050import android.service.notification.NotificationListenerService;
Christoph Studer37fe6932014-05-26 13:10:30 +020051import android.service.notification.NotificationListenerService.Ranking;
John Spurlockde84f0e2013-06-12 12:41:00 -040052import android.service.notification.StatusBarNotification;
Chris Wren0c8275b2012-05-08 13:36:48 -040053import android.text.TextUtils;
Joe Onorato808182d2010-07-09 18:52:06 -040054import android.util.Log;
Kenny Guy3a7c4a52014-03-03 18:24:03 +000055import android.util.SparseArray;
Dan Sandlerfd16d562014-02-13 18:43:31 -080056import android.util.SparseBooleanArray;
Daniel Sandlerc638c1e2011-08-24 16:19:23 -070057import android.view.Display;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050058import android.view.IWindowManager;
Michael Jurka7f2668c2012-03-27 07:49:52 -070059import android.view.LayoutInflater;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040060import android.view.MenuItem;
Michael Jurka7f2668c2012-03-27 07:49:52 -070061import android.view.MotionEvent;
Joe Onorato808182d2010-07-09 18:52:06 -040062import android.view.View;
Daniel Sandler6a858c32012-03-12 14:38:58 -040063import android.view.ViewGroup;
Michael Jurka7f2668c2012-03-27 07:49:52 -070064import android.view.ViewGroup.LayoutParams;
Joe Onorato808182d2010-07-09 18:52:06 -040065import android.view.WindowManager;
Michael Jurka80343f62012-10-18 13:13:46 +020066import android.view.WindowManagerGlobal;
Chris Wren0c8275b2012-05-08 13:36:48 -040067import android.widget.ImageView;
Michael Jurka7f2668c2012-03-27 07:49:52 -070068import android.widget.LinearLayout;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040069import android.widget.PopupMenu;
Michael Jurkaa600fd92012-06-25 15:57:05 -070070import android.widget.RemoteViews;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040071import android.widget.TextView;
Joe Onorato808182d2010-07-09 18:52:06 -040072
John Spurlockde84f0e2013-06-12 12:41:00 -040073import com.android.internal.statusbar.IStatusBarService;
74import com.android.internal.statusbar.StatusBarIcon;
75import com.android.internal.statusbar.StatusBarIconList;
Dan Sandler26e81cf2014-05-06 10:01:27 -040076import com.android.internal.util.NotificationColorUtil;
John Spurlockde84f0e2013-06-12 12:41:00 -040077import com.android.systemui.R;
John Spurlockd08de372013-06-24 13:06:08 -040078import com.android.systemui.RecentsComponent;
John Spurlockde84f0e2013-06-12 12:41:00 -040079import com.android.systemui.SearchPanelView;
80import com.android.systemui.SystemUI;
Christoph Studer37fe6932014-05-26 13:10:30 +020081import com.android.systemui.statusbar.NotificationData.Entry;
Jim Millera999d462013-10-30 13:58:11 -070082import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
Selim Cinekb6d85eb2014-03-28 20:21:01 +010083import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
John Spurlockde84f0e2013-06-12 12:41:00 -040084
Michael Jurkaa600fd92012-06-25 15:57:05 -070085import java.util.ArrayList;
Adrian Roos4314f6d2014-05-28 14:10:27 +020086import java.util.Arrays;
Christoph Studer37fe6932014-05-26 13:10:30 +020087import java.util.Collections;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -070088import java.util.Locale;
Joe Onorato1c95ecb2010-06-28 17:19:12 -040089
Adrian Roos7d7090d2014-05-21 13:10:23 +020090import static com.android.keyguard.KeyguardHostView.OnDismissAction;
91
Michael Jurka7f2668c2012-03-27 07:49:52 -070092public abstract class BaseStatusBar extends SystemUI implements
Jorim Jaggife40f7d2014-04-28 15:20:04 +020093 CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener {
Daniel Sandler198a0302012-08-17 16:04:31 -040094 public static final String TAG = "StatusBar";
95 public static final boolean DEBUG = false;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040096 public static final boolean MULTIUSER_DEBUG = false;
Christoph Studerc2885142014-05-28 14:48:15 +020097 private static final boolean USE_NOTIFICATION_LISTENER = true;
Joe Onorato1c95ecb2010-06-28 17:19:12 -040098
Winson Chung1e8d71b2014-05-16 17:05:22 -070099 protected static final int MSG_SHOW_RECENT_APPS = 1019;
100 protected static final int MSG_HIDE_RECENT_APPS = 1020;
101 protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700102 protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
103 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
Jim Millere898ac52012-04-06 17:10:57 -0700104 protected static final int MSG_OPEN_SEARCH_PANEL = 1024;
105 protected static final int MSG_CLOSE_SEARCH_PANEL = 1025;
Chris Wren157026f2013-06-28 16:54:01 -0400106 protected static final int MSG_SHOW_HEADS_UP = 1026;
107 protected static final int MSG_HIDE_HEADS_UP = 1027;
Chris Wrene97f90b2013-08-07 17:39:35 -0400108 protected static final int MSG_ESCALATE_HEADS_UP = 1028;
Chris Wren0c8275b2012-05-08 13:36:48 -0400109
Chris Wren157026f2013-06-28 16:54:01 -0400110 protected static final boolean ENABLE_HEADS_UP = true;
111 // scores above this threshold should be displayed in heads up mode.
Chris Wren5d9b1532014-03-21 14:31:05 -0400112 protected static final int INTERRUPTION_THRESHOLD = 10;
Chris Wren22ae46e2014-02-26 18:08:09 -0500113 protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
Chris Wren0c8275b2012-05-08 13:36:48 -0400114
Michael Jurka56a57832012-05-14 13:24:43 -0700115 // Should match the value in PhoneWindowManager
116 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
117
Chris Wren0c8275b2012-05-08 13:36:48 -0400118 public static final int EXPANDED_LEAVE_ALONE = -10000;
119 public static final int EXPANDED_FULL_OPEN = -10001;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700120
Adrian Roos4314f6d2014-05-28 14:10:27 +0200121 /** If true, delays dismissing the Keyguard until the ActivityManager calls back. */
122 protected static final boolean DELAY_DISMISS_TO_ACTIVITY_LAUNCH = false;
123
Joe Onorato808182d2010-07-09 18:52:06 -0400124 protected CommandQueue mCommandQueue;
125 protected IStatusBarService mBarService;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700126 protected H mHandler = createHandler();
127
Chris Wren0c8275b2012-05-08 13:36:48 -0400128 // all notifications
129 protected NotificationData mNotificationData = new NotificationData();
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100130 protected NotificationStackScrollLayout mStackScroller;
Chris Wren0c8275b2012-05-08 13:36:48 -0400131
Chris Wren51c75102013-07-16 20:49:17 -0400132 protected NotificationData.Entry mInterruptingNotificationEntry;
133 protected long mInterruptingNotificationTime;
Chris Wren0c8275b2012-05-08 13:36:48 -0400134
Daniel Sandler6a858c32012-03-12 14:38:58 -0400135 // used to notify status bar for suppressing notification LED
136 protected boolean mPanelSlightlyVisible;
137
Jim Millere898ac52012-04-06 17:10:57 -0700138 // Search panel
139 protected SearchPanelView mSearchPanelView;
140
Daniel Sandler469e96e2012-05-04 15:56:19 -0400141 protected PopupMenu mNotificationBlamePopup;
142
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400143 protected int mCurrentUserId = 0;
Kenny Guy2a764942014-04-02 13:29:20 +0100144 final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400145
Daniel Sandler777dcde2013-09-30 10:21:45 -0400146 protected int mLayoutDirection = -1; // invalid
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700147 private Locale mLocale;
Chris Wrenf6e83f42013-09-11 14:02:59 -0400148 protected boolean mUseHeadsUp = false;
Chris Wren22ae46e2014-02-26 18:08:09 -0500149 protected boolean mHeadsUpTicker = false;
Chris Wren157026f2013-06-28 16:54:01 -0400150
151 protected IDreamManager mDreamManager;
Chris Wren157026f2013-06-28 16:54:01 -0400152 PowerManager mPowerManager;
Selim Cinek1685e632014-04-08 02:27:49 +0200153 protected int mRowMinHeight;
154 protected int mRowMaxHeight;
Dan Sandlerfd16d562014-02-13 18:43:31 -0800155
156 // public mode, private notifications, etc
157 private boolean mLockscreenPublicMode = false;
158 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
Dan Sandler26e81cf2014-05-06 10:01:27 -0400159 private NotificationColorUtil mNotificationColorUtil = NotificationColorUtil.getInstance();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700160
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000161 private UserManager mUserManager;
162
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500163 // UI-specific methods
Daniel Sandler6a858c32012-03-12 14:38:58 -0400164
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500165 /**
166 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
167 * and add them to the window manager.
168 */
169 protected abstract void createAndAddWindows();
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400170
Jeff Brown98365d72012-08-19 20:30:52 -0700171 protected WindowManager mWindowManager;
172 protected IWindowManager mWindowManagerService;
Christoph Studer60748e72014-05-22 16:51:41 +0200173
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700174 protected abstract void refreshLayout(int layoutDirection);
175
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500176 protected Display mDisplay;
Jeff Brown98365d72012-08-19 20:30:52 -0700177
Daniel Sandler26cda272012-05-22 15:44:08 -0400178 private boolean mDeviceProvisioned = false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400179
John Spurlockd08de372013-06-24 13:06:08 -0400180 private RecentsComponent mRecents;
181
John Spurlocke677d712014-02-13 12:52:19 -0500182 protected int mZenMode;
183
Jorim Jaggiecbab362014-04-23 16:13:15 +0200184 /**
185 * The {@link StatusBarState} of the status bar.
186 */
187 protected int mState;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200188 protected boolean mBouncerShowing;
John Spurlock4b3bda22014-05-22 14:32:20 -0400189 protected boolean mShowLockscreenNotifications;
Jorim Jaggiecbab362014-04-23 16:13:15 +0200190
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200191 protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
Jorim Jaggi649b7082014-04-03 13:15:18 +0200192
Daniel Sandler3ffdcc72012-09-23 14:31:48 -0400193 public boolean isDeviceProvisioned() {
Daniel Sandler26cda272012-05-22 15:44:08 -0400194 return mDeviceProvisioned;
195 }
196
John Spurlocke677d712014-02-13 12:52:19 -0500197 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
Daniel Sandler26cda272012-05-22 15:44:08 -0400198 @Override
199 public void onChange(boolean selfChange) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700200 final boolean provisioned = 0 != Settings.Global.getInt(
201 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
Daniel Sandler26cda272012-05-22 15:44:08 -0400202 if (provisioned != mDeviceProvisioned) {
203 mDeviceProvisioned = provisioned;
Christoph Studer37fe6932014-05-26 13:10:30 +0200204 updateNotifications();
Daniel Sandler26cda272012-05-22 15:44:08 -0400205 }
John Spurlocke677d712014-02-13 12:52:19 -0500206 final int mode = Settings.Global.getInt(mContext.getContentResolver(),
207 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
208 setZenMode(mode);
John Spurlock4b3bda22014-05-22 14:32:20 -0400209 final boolean show = Settings.Global.getInt(mContext.getContentResolver(),
210 Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1) != 0;
211 setShowLockscreenNotifications(show);
Daniel Sandler26cda272012-05-22 15:44:08 -0400212 }
213 };
214
Dan Sandlerfd16d562014-02-13 18:43:31 -0800215 private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
216 @Override
217 public void onChange(boolean selfChange) {
218 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
219 // so we just dump our cache ...
220 mUsersAllowingPrivateNotifications.clear();
221 // ... and refresh all the notifications
Christoph Studer37fe6932014-05-26 13:10:30 +0200222 updateNotifications();
Dan Sandlerfd16d562014-02-13 18:43:31 -0800223 }
224 };
225
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700226 private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
227 @Override
Adrian Roos7d7090d2014-05-21 13:10:23 +0200228 public boolean onClickHandler(
229 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
Daniel Sandler198a0302012-08-17 16:04:31 -0400230 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400231 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
Daniel Sandler198a0302012-08-17 16:04:31 -0400232 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700233 final boolean isActivity = pendingIntent.isActivity();
234 if (isActivity) {
Adrian Roos4314f6d2014-05-28 14:10:27 +0200235 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200236 @Override
237 public boolean onDismiss() {
238 try {
239 // The intent we are sending is for the application, which
240 // won't have permission to immediately start an activity after
241 // the user switches to home. We know it is safe to do at this
242 // point, so make sure new activity switches are now allowed.
243 ActivityManagerNative.getDefault().resumeAppSwitches();
244 // Also, notifications can be launched from the lock screen,
245 // so dismiss the lock screen when the activity starts.
246 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
247 } catch (RemoteException e) {
248 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700249
Adrian Roos7d7090d2014-05-21 13:10:23 +0200250 boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700251
Adrian Roos7d7090d2014-05-21 13:10:23 +0200252 // close the shade if it was open
253 if (handled) {
254 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
255 visibilityChanged(false);
256 }
Adrian Roos4314f6d2014-05-28 14:10:27 +0200257 // Wait for activity start.
258 return handled && DELAY_DISMISS_TO_ACTIVITY_LAUNCH;
Adrian Roos7d7090d2014-05-21 13:10:23 +0200259 }
260 });
261 return true;
262 } else {
263 return super.onClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700264 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200265 }
266
267 private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
268 Intent fillInIntent) {
269 return super.onClickHandler(view, pendingIntent, fillInIntent);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700270 }
271 };
272
John Spurlock5c454122013-06-17 07:35:46 -0400273 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
274 @Override
275 public void onReceive(Context context, Intent intent) {
276 String action = intent.getAction();
277 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
278 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Kenny Guy2a764942014-04-02 13:29:20 +0100279 updateCurrentProfilesCache();
John Spurlock5c454122013-06-17 07:35:46 -0400280 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
281 userSwitched(mCurrentUserId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000282 } else if (Intent.ACTION_USER_ADDED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +0100283 updateCurrentProfilesCache();
John Spurlock5c454122013-06-17 07:35:46 -0400284 }
285 }
286 };
287
Christoph Studer60748e72014-05-22 16:51:41 +0200288 private final NotificationListenerService mNotificationListener =
289 new NotificationListenerService() {
290 @Override
291 public void onListenerConnected() {
292 if (DEBUG) Log.d(TAG, "onListenerConnected");
293 final StatusBarNotification[] notifications = getActiveNotifications();
Christoph Studer37fe6932014-05-26 13:10:30 +0200294 final Ranking currentRanking = getCurrentRanking();
Christoph Studer60748e72014-05-22 16:51:41 +0200295 mHandler.post(new Runnable() {
296 @Override
297 public void run() {
298 for (StatusBarNotification sbn : notifications) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200299 addNotificationInternal(sbn, currentRanking);
Christoph Studer60748e72014-05-22 16:51:41 +0200300 }
301 }
302 });
303 }
304
305 @Override
306 public void onNotificationPosted(final StatusBarNotification sbn) {
307 if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
Christoph Studer37fe6932014-05-26 13:10:30 +0200308 final Ranking currentRanking = getCurrentRanking();
Christoph Studer60748e72014-05-22 16:51:41 +0200309 mHandler.post(new Runnable() {
310 @Override
311 public void run() {
312 if (mNotificationData.findByKey(sbn.getKey()) != null) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200313 updateNotificationInternal(sbn, currentRanking);
Christoph Studer60748e72014-05-22 16:51:41 +0200314 } else {
Christoph Studer37fe6932014-05-26 13:10:30 +0200315 addNotificationInternal(sbn, currentRanking);
Christoph Studer60748e72014-05-22 16:51:41 +0200316 }
317 }
318 });
319 }
320
321 @Override
322 public void onNotificationRemoved(final StatusBarNotification sbn) {
323 if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
Christoph Studer37fe6932014-05-26 13:10:30 +0200324 final Ranking currentRanking = getCurrentRanking();
Christoph Studer60748e72014-05-22 16:51:41 +0200325 mHandler.post(new Runnable() {
326 @Override
327 public void run() {
Christoph Studer37fe6932014-05-26 13:10:30 +0200328 removeNotificationInternal(sbn.getKey(), currentRanking);
329 }
330 });
331 }
332
333 @Override
334 public void onNotificationRankingUpdate() {
335 if (DEBUG) Log.d(TAG, "onRankingUpdate");
336 final Ranking currentRanking = getCurrentRanking();
337 mHandler.post(new Runnable() {
338 @Override
339 public void run() {
Chris Wren333a61c2014-05-28 16:40:57 -0400340 updateRankingInternal(currentRanking);
Christoph Studer60748e72014-05-22 16:51:41 +0200341 }
342 });
343 }
344 };
345
Kenny Guy2a764942014-04-02 13:29:20 +0100346 private void updateCurrentProfilesCache() {
347 synchronized (mCurrentProfiles) {
348 mCurrentProfiles.clear();
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000349 if (mUserManager != null) {
Kenny Guy2a764942014-04-02 13:29:20 +0100350 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
351 mCurrentProfiles.put(user.id, user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000352 }
353 }
354 }
355 }
356
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400357 public void start() {
Jeff Brown98365d72012-08-19 20:30:52 -0700358 mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
359 mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
360 mDisplay = mWindowManager.getDefaultDisplay();
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500361
Chris Wren157026f2013-06-28 16:54:01 -0400362 mDreamManager = IDreamManager.Stub.asInterface(
363 ServiceManager.checkService(DreamService.DREAM_SERVICE));
Chris Wren157026f2013-06-28 16:54:01 -0400364 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
365
John Spurlocke677d712014-02-13 12:52:19 -0500366 mSettingsObserver.onChange(false); // set up
Daniel Sandler26cda272012-05-22 15:44:08 -0400367 mContext.getContentResolver().registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700368 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
John Spurlocke677d712014-02-13 12:52:19 -0500369 mSettingsObserver);
370 mContext.getContentResolver().registerContentObserver(
371 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
372 mSettingsObserver);
John Spurlock4b3bda22014-05-22 14:32:20 -0400373 mContext.getContentResolver().registerContentObserver(
374 Settings.Global.getUriFor(Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
375 mSettingsObserver);
Daniel Sandler26cda272012-05-22 15:44:08 -0400376
Dan Sandlerfd16d562014-02-13 18:43:31 -0800377 mContext.getContentResolver().registerContentObserver(
378 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
379 true,
380 mLockscreenSettingsObserver,
381 UserHandle.USER_ALL);
382
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500383 mBarService = IStatusBarService.Stub.asInterface(
384 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400385
John Spurlockd08de372013-06-24 13:06:08 -0400386 mRecents = getComponent(RecentsComponent.class);
387
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700388 mLocale = mContext.getResources().getConfiguration().locale;
389 mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
390
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000391 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
392
Joe Onorato2314aab2010-04-08 16:41:23 -0500393 // Connect in to the status bar manager service
Joe Onorato0cbda992010-05-02 16:28:15 -0700394 StatusBarIconList iconList = new StatusBarIconList();
Joe Onorato75199e32010-05-29 17:22:51 -0400395 ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
Joe Onorato66d7d012010-05-14 10:05:10 -0700396 mCommandQueue = new CommandQueue(this, iconList);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400397
Jason Monkb605fec2014-05-02 17:04:10 -0400398 int[] switches = new int[8];
satokcd7cd292010-11-20 15:46:23 +0900399 ArrayList<IBinder> binders = new ArrayList<IBinder>();
Joe Onorato2314aab2010-04-08 16:41:23 -0500400 try {
Christoph Studer71f18fd2014-05-20 17:02:04 +0200401 mBarService.registerStatusBar(mCommandQueue, iconList, notifications,
satokcd7cd292010-11-20 15:46:23 +0900402 switches, binders);
Joe Onorato2314aab2010-04-08 16:41:23 -0500403 } catch (RemoteException ex) {
404 // If the system process isn't there we're doomed anyway.
405 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400406
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500407 createAndAddWindows();
Joe Onorato0cbda992010-05-02 16:28:15 -0700408
Joe Onoratoe4c7b3f2010-10-30 12:15:03 -0700409 disable(switches[0]);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700410 setSystemUiVisibility(switches[1], 0xffffffff);
Dianne Hackborn7d049322011-06-14 15:00:32 -0700411 topAppWindowChanged(switches[2] != 0);
satokcd7cd292010-11-20 15:46:23 +0900412 // StatusBarManagerService has a back up of IME token and it's restored here.
Jason Monkb605fec2014-05-02 17:04:10 -0400413 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[7] != 0);
Jeff Brown2992ea72011-01-28 22:04:14 -0800414 setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);
Joe Onorato93056472010-09-10 10:30:46 -0400415
Joe Onorato0cbda992010-05-02 16:28:15 -0700416 // Set up the initial icon state
Joe Onorato75199e32010-05-29 17:22:51 -0400417 int N = iconList.size();
Joe Onorato0cbda992010-05-02 16:28:15 -0700418 int viewIndex = 0;
419 for (int i=0; i<N; i++) {
420 StatusBarIcon icon = iconList.getIcon(i);
421 if (icon != null) {
422 addIcon(iconList.getSlot(i), i, viewIndex, icon);
423 viewIndex++;
424 }
425 }
426
Christoph Studer71f18fd2014-05-20 17:02:04 +0200427 // Set up the initial notification state.
Christoph Studer60748e72014-05-22 16:51:41 +0200428 if (USE_NOTIFICATION_LISTENER) {
429 try {
430 mNotificationListener.registerAsSystemService(
431 new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
432 UserHandle.USER_ALL);
433 } catch (RemoteException e) {
434 Log.e(TAG, "Unable to register notification listener", e);
435 }
436 } else {
437 N = notifications.size();
438 for (int i=0; i<N; i++) {
439 addNotification(notifications.get(i));
440 }
Joe Onorato75199e32010-05-29 17:22:51 -0400441 }
442
Christoph Studer60748e72014-05-22 16:51:41 +0200443
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500444 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400445 Log.d(TAG, String.format(
Daniel Sandler6a858c32012-03-12 14:38:58 -0400446 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500447 iconList.size(),
448 switches[0],
449 switches[1],
450 switches[2],
451 switches[3]
452 ));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400453 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400454
Christopher Tate5e08af02012-09-21 17:17:22 -0700455 mCurrentUserId = ActivityManager.getCurrentUser();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400456
457 IntentFilter filter = new IntentFilter();
458 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000459 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock5c454122013-06-17 07:35:46 -0400460 mContext.registerReceiver(mBroadcastReceiver, filter);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000461
Kenny Guy2a764942014-04-02 13:29:20 +0100462 updateCurrentProfilesCache();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400463 }
464
465 public void userSwitched(int newUserId) {
466 // should be overridden
467 }
468
Kenny Guy2a764942014-04-02 13:29:20 +0100469 public boolean notificationIsForCurrentProfiles(StatusBarNotification n) {
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400470 final int thisUserId = mCurrentUserId;
471 final int notificationUserId = n.getUserId();
472 if (DEBUG && MULTIUSER_DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400473 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400474 n, thisUserId, notificationUserId));
475 }
Kenny Guy2a764942014-04-02 13:29:20 +0100476 synchronized (mCurrentProfiles) {
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000477 return notificationUserId == UserHandle.USER_ALL
Kenny Guy2a764942014-04-02 13:29:20 +0100478 || mCurrentProfiles.get(notificationUserId) != null;
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000479 }
Joe Onorato2314aab2010-04-08 16:41:23 -0500480 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400481
Adrian Roos7d7090d2014-05-21 13:10:23 +0200482 /**
483 * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
484 * @param action A dismiss action that is called if it's safe to start the activity.
485 */
Adrian Roos4314f6d2014-05-28 14:10:27 +0200486 protected void dismissKeyguardThenExecute(OnDismissAction action) {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200487 action.onDismiss();
488 }
489
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700490 @Override
491 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400492 final Locale locale = mContext.getResources().getConfiguration().locale;
493 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
494 if (! locale.equals(mLocale) || ld != mLayoutDirection) {
495 if (DEBUG) {
496 Log.v(TAG, String.format(
497 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
498 locale, ld));
499 }
500 mLocale = locale;
501 mLayoutDirection = ld;
502 refreshLayout(ld);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700503 }
504 }
505
Winson Chungc57ccf02011-10-13 15:04:59 -0700506 protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
507 View vetoButton = row.findViewById(R.id.veto);
Chris Wren6d15a362013-08-20 18:46:29 -0400508 if (n.isClearable() || (mInterruptingNotificationEntry != null
509 && mInterruptingNotificationEntry.row == row)) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400510 final String _pkg = n.getPackageName();
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400511 final String _tag = n.getTag();
512 final int _id = n.getId();
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000513 final int _userId = n.getUserId();
Winson Chungc57ccf02011-10-13 15:04:59 -0700514 vetoButton.setOnClickListener(new View.OnClickListener() {
515 public void onClick(View v) {
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700516 // Accessibility feedback
517 v.announceForAccessibility(
518 mContext.getString(R.string.accessibility_notification_dismissed));
Winson Chungc57ccf02011-10-13 15:04:59 -0700519 try {
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000520 mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700521
Winson Chungc57ccf02011-10-13 15:04:59 -0700522 } catch (RemoteException ex) {
523 // system process is dead if we're here.
524 }
525 }
526 });
527 vetoButton.setVisibility(View.VISIBLE);
528 } else {
529 vetoButton.setVisibility(View.GONE);
530 }
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700531 vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
Winson Chungc57ccf02011-10-13 15:04:59 -0700532 return vetoButton;
533 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400534
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400535
Jorim Jaggi46739852014-04-15 09:58:24 +0200536 protected void applyLegacyRowBackground(StatusBarNotification sbn,
537 NotificationData.Entry entry) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400538 int version = 0;
539 try {
540 ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.getPackageName(), 0);
541 version = info.targetSdkVersion;
542 } catch (NameNotFoundException ex) {
543 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
544 }
545
Jorim Jaggi46739852014-04-15 09:58:24 +0200546 if (entry.expanded.getId() != com.android.internal.R.id.status_bar_latest_event_content) {
Dan Sandlerfe266a32014-05-15 22:28:06 -0400547 // Using custom RemoteViews
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400548 if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
Jorim Jaggi46739852014-04-15 09:58:24 +0200549 entry.row.setBackgroundResource(R.drawable.notification_row_legacy_bg);
550 } else if (version < Build.VERSION_CODES.L) {
551 entry.row.setBackgroundResourceIds(
552 com.android.internal.R.drawable.notification_bg,
553 com.android.internal.R.drawable.notification_bg_dim);
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400554 }
Dan Sandler842dd772014-05-15 09:36:47 -0400555 } else {
556 // Using platform templates
557 final int color = sbn.getNotification().color;
558 if (isMediaNotification(entry)) {
559 entry.row.setBackgroundResourceIds(
560 com.android.internal.R.drawable.notification_quantum_bg,
561 color,
562 com.android.internal.R.drawable.notification_quantum_bg_dim,
563 color);
564 }
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400565 }
566 }
567
Dan Sandler842dd772014-05-15 09:36:47 -0400568 private boolean isMediaNotification(NotificationData.Entry entry) {
569 // TODO: confirm that there's a valid media key
570 return entry.expandedBig != null &&
571 entry.expandedBig.findViewById(com.android.internal.R.id.media_action_area) != null;
572 }
573
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400574 private void startApplicationDetailsActivity(String packageName) {
575 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
576 Uri.fromParts("package", packageName, null));
Adam Powell0fc5b2b2012-07-18 18:20:29 -0700577 intent.setComponent(intent.resolveActivity(mContext.getPackageManager()));
Amith Yamasaniea7e9152012-09-24 16:11:18 -0700578 TaskStackBuilder.create(mContext).addNextIntentWithParentStack(intent).startActivities(
579 null, UserHandle.CURRENT);
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400580 }
581
Jim Miller9a720f52012-05-30 03:19:43 -0700582 protected View.OnLongClickListener getNotificationLongClicker() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400583 return new View.OnLongClickListener() {
584 @Override
585 public boolean onLongClick(View v) {
586 final String packageNameF = (String) v.getTag();
587 if (packageNameF == null) return false;
Jeff Sharkeyaf232ed2012-04-30 15:19:39 -0700588 if (v.getWindowToken() == null) return false;
Daniel Sandler469e96e2012-05-04 15:56:19 -0400589 mNotificationBlamePopup = new PopupMenu(mContext, v);
590 mNotificationBlamePopup.getMenuInflater().inflate(
591 R.menu.notification_popup_menu,
592 mNotificationBlamePopup.getMenu());
593 mNotificationBlamePopup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400594 public boolean onMenuItemClick(MenuItem item) {
595 if (item.getItemId() == R.id.notification_inspect_item) {
596 startApplicationDetailsActivity(packageNameF);
Daniel Sandler11cf1782012-09-27 14:03:08 -0400597 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400598 } else {
599 return false;
600 }
601 return true;
602 }
603 });
Daniel Sandler469e96e2012-05-04 15:56:19 -0400604 mNotificationBlamePopup.show();
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400605
606 return true;
607 }
608 };
609 }
610
Daniel Sandler469e96e2012-05-04 15:56:19 -0400611 public void dismissPopups() {
612 if (mNotificationBlamePopup != null) {
613 mNotificationBlamePopup.dismiss();
614 mNotificationBlamePopup = null;
615 }
616 }
617
Chris Wren51c75102013-07-16 20:49:17 -0400618 public void onHeadsUpDismissed() {
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400619 }
Michael Jurka7f2668c2012-03-27 07:49:52 -0700620
621 @Override
Winson Chung1e8d71b2014-05-16 17:05:22 -0700622 public void showRecentApps(boolean triggeredFromAltTab) {
623 int msg = MSG_SHOW_RECENT_APPS;
624 mHandler.removeMessages(msg);
625 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, 0).sendToTarget();
626 }
627
628 @Override
Winson Chung6cb485f2014-05-19 10:30:43 -0700629 public void hideRecentApps(boolean triggeredFromAltTab) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700630 int msg = MSG_HIDE_RECENT_APPS;
631 mHandler.removeMessages(msg);
Winson Chung6cb485f2014-05-19 10:30:43 -0700632 mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, 0).sendToTarget();
Winson Chung1e8d71b2014-05-16 17:05:22 -0700633 }
634
635 @Override
Michael Jurka7f2668c2012-03-27 07:49:52 -0700636 public void toggleRecentApps() {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700637 int msg = MSG_TOGGLE_RECENTS_APPS;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700638 mHandler.removeMessages(msg);
639 mHandler.sendEmptyMessage(msg);
640 }
641
642 @Override
643 public void preloadRecentApps() {
644 int msg = MSG_PRELOAD_RECENT_APPS;
645 mHandler.removeMessages(msg);
646 mHandler.sendEmptyMessage(msg);
647 }
648
649 @Override
650 public void cancelPreloadRecentApps() {
651 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
652 mHandler.removeMessages(msg);
653 mHandler.sendEmptyMessage(msg);
654 }
655
656 @Override
Jim Millere898ac52012-04-06 17:10:57 -0700657 public void showSearchPanel() {
658 int msg = MSG_OPEN_SEARCH_PANEL;
659 mHandler.removeMessages(msg);
660 mHandler.sendEmptyMessage(msg);
661 }
662
663 @Override
664 public void hideSearchPanel() {
665 int msg = MSG_CLOSE_SEARCH_PANEL;
666 mHandler.removeMessages(msg);
667 mHandler.sendEmptyMessage(msg);
668 }
669
Jim Millere898ac52012-04-06 17:10:57 -0700670 protected abstract WindowManager.LayoutParams getSearchLayoutParams(
671 LayoutParams layoutParams);
672
Jim Millere898ac52012-04-06 17:10:57 -0700673 protected void updateSearchPanel() {
674 // Search Panel
675 boolean visible = false;
676 if (mSearchPanelView != null) {
677 visible = mSearchPanelView.isShowing();
Jeff Brown98365d72012-08-19 20:30:52 -0700678 mWindowManager.removeView(mSearchPanelView);
Jim Millere898ac52012-04-06 17:10:57 -0700679 }
680
681 // Provide SearchPanel with a temporary parent to allow layout params to work.
682 LinearLayout tmpRoot = new LinearLayout(mContext);
683 mSearchPanelView = (SearchPanelView) LayoutInflater.from(mContext).inflate(
684 R.layout.status_bar_search_panel, tmpRoot, false);
685 mSearchPanelView.setOnTouchListener(
686 new TouchOutsideListener(MSG_CLOSE_SEARCH_PANEL, mSearchPanelView));
687 mSearchPanelView.setVisibility(View.GONE);
688
689 WindowManager.LayoutParams lp = getSearchLayoutParams(mSearchPanelView.getLayoutParams());
690
Jeff Brown98365d72012-08-19 20:30:52 -0700691 mWindowManager.addView(mSearchPanelView, lp);
Jim Millere898ac52012-04-06 17:10:57 -0700692 mSearchPanelView.setBar(this);
693 if (visible) {
694 mSearchPanelView.show(true, false);
695 }
696 }
697
Michael Jurkaecc395a2012-03-30 05:31:46 -0700698 protected H createHandler() {
Michael Jurka7f2668c2012-03-27 07:49:52 -0700699 return new H();
700 }
701
Michael Jurka56a57832012-05-14 13:24:43 -0700702 static void sendCloseSystemWindows(Context context, String reason) {
703 if (ActivityManagerNative.isSystemReady()) {
704 try {
705 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
706 } catch (RemoteException e) {
707 }
708 }
709 }
710
Michael Jurkacb2522c2012-04-13 09:32:47 -0700711 protected abstract View getStatusBarView();
712
Michael Jurka80343f62012-10-18 13:13:46 +0200713 protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
714 // additional optimization when we have software system buttons - start loading the recent
715 // tasks on touch down
716 @Override
717 public boolean onTouch(View v, MotionEvent event) {
718 int action = event.getAction() & MotionEvent.ACTION_MASK;
719 if (action == MotionEvent.ACTION_DOWN) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700720 preloadRecents();
Michael Jurka80343f62012-10-18 13:13:46 +0200721 } else if (action == MotionEvent.ACTION_CANCEL) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700722 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +0200723 } else if (action == MotionEvent.ACTION_UP) {
724 if (!v.isPressed()) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700725 cancelPreloadingRecents();
Michael Jurka80343f62012-10-18 13:13:46 +0200726 }
727
728 }
729 return false;
730 }
731 };
732
Winson Chung1e8d71b2014-05-16 17:05:22 -0700733 /** Proxy for RecentsComponent */
734
735 protected void showRecents(boolean triggeredFromAltTab) {
736 if (mRecents != null) {
737 sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
738 mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
739 }
740 }
741
Winson Chung6cb485f2014-05-19 10:30:43 -0700742 protected void hideRecents(boolean triggeredFromAltTab) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700743 if (mRecents != null) {
Winson Chung6cb485f2014-05-19 10:30:43 -0700744 mRecents.hideRecents(triggeredFromAltTab);
Winson Chung1e8d71b2014-05-16 17:05:22 -0700745 }
746 }
747
748 protected void toggleRecents() {
John Spurlockd08de372013-06-24 13:06:08 -0400749 if (mRecents != null) {
Winson Chung4c71aef2014-03-21 15:15:11 -0700750 sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
John Spurlockd08de372013-06-24 13:06:08 -0400751 mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
752 }
753 }
Michael Jurka80343f62012-10-18 13:13:46 +0200754
Winson Chung1e8d71b2014-05-16 17:05:22 -0700755 protected void preloadRecents() {
John Spurlockd08de372013-06-24 13:06:08 -0400756 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700757 mRecents.preloadRecents();
John Spurlockd08de372013-06-24 13:06:08 -0400758 }
Michael Jurka80343f62012-10-18 13:13:46 +0200759 }
760
Winson Chung1e8d71b2014-05-16 17:05:22 -0700761 protected void cancelPreloadingRecents() {
John Spurlockd08de372013-06-24 13:06:08 -0400762 if (mRecents != null) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700763 mRecents.cancelPreloadingRecents();
John Spurlockd08de372013-06-24 13:06:08 -0400764 }
Michael Jurka80343f62012-10-18 13:13:46 +0200765 }
766
Chris Wren51c75102013-07-16 20:49:17 -0400767 public abstract void resetHeadsUpDecayTimer();
768
Dan Sandlerfd16d562014-02-13 18:43:31 -0800769 /**
770 * Save the current "public" (locked and secure) state of the lockscreen.
771 */
772 public void setLockscreenPublicMode(boolean publicMode) {
773 mLockscreenPublicMode = publicMode;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500774 }
775
Dan Sandlerfd16d562014-02-13 18:43:31 -0800776 public boolean isLockscreenPublicMode() {
777 return mLockscreenPublicMode;
778 }
779
780 /**
781 * Has the given user chosen to allow their private (full) notifications to be shown even
782 * when the lockscreen is in "public" (secure & locked) mode?
783 */
784 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
785 if (userHandle == UserHandle.USER_ALL) {
786 return true;
787 }
788
789 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
790 final boolean allowed = 0 != Settings.Secure.getIntForUser(
791 mContext.getContentResolver(),
792 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
793 mUsersAllowingPrivateNotifications.append(userHandle, allowed);
794 return allowed;
795 }
796
797 return mUsersAllowingPrivateNotifications.get(userHandle);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500798 }
799
Michael Jurka7f2668c2012-03-27 07:49:52 -0700800 protected class H extends Handler {
801 public void handleMessage(Message m) {
Michael Jurka80343f62012-10-18 13:13:46 +0200802 Intent intent;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700803 switch (m.what) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700804 case MSG_SHOW_RECENT_APPS:
805 showRecents(m.arg1 > 0);
Michael Jurkacb2522c2012-04-13 09:32:47 -0700806 break;
Winson Chung1e8d71b2014-05-16 17:05:22 -0700807 case MSG_HIDE_RECENT_APPS:
Winson Chung6cb485f2014-05-19 10:30:43 -0700808 hideRecents(m.arg1 > 0);
Winson Chung1e8d71b2014-05-16 17:05:22 -0700809 break;
810 case MSG_TOGGLE_RECENTS_APPS:
811 toggleRecents();
Michael Jurkacb2522c2012-04-13 09:32:47 -0700812 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700813 case MSG_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -0700814 preloadRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -0700815 break;
816 case MSG_CANCEL_PRELOAD_RECENT_APPS:
Winson Chung1e8d71b2014-05-16 17:05:22 -0700817 cancelPreloadingRecents();
Michael Jurka7f2668c2012-03-27 07:49:52 -0700818 break;
Jim Millere898ac52012-04-06 17:10:57 -0700819 case MSG_OPEN_SEARCH_PANEL:
John Spurlockcd686b52013-06-05 10:13:46 -0400820 if (DEBUG) Log.d(TAG, "opening search panel");
Jim Miller07994402012-05-02 14:22:27 -0700821 if (mSearchPanelView != null && mSearchPanelView.isAssistantAvailable()) {
Jim Millere898ac52012-04-06 17:10:57 -0700822 mSearchPanelView.show(true, true);
Jim Millerad178a42013-10-08 20:03:38 -0700823 onShowSearchPanel();
Jim Millere898ac52012-04-06 17:10:57 -0700824 }
825 break;
826 case MSG_CLOSE_SEARCH_PANEL:
John Spurlockcd686b52013-06-05 10:13:46 -0400827 if (DEBUG) Log.d(TAG, "closing search panel");
Jim Millere898ac52012-04-06 17:10:57 -0700828 if (mSearchPanelView != null && mSearchPanelView.isShowing()) {
829 mSearchPanelView.show(false, true);
Jim Millerad178a42013-10-08 20:03:38 -0700830 onHideSearchPanel();
Jim Millere898ac52012-04-06 17:10:57 -0700831 }
832 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700833 }
834 }
835 }
836
837 public class TouchOutsideListener implements View.OnTouchListener {
838 private int mMsg;
839 private StatusBarPanel mPanel;
840
841 public TouchOutsideListener(int msg, StatusBarPanel panel) {
842 mMsg = msg;
843 mPanel = panel;
844 }
845
846 public boolean onTouch(View v, MotionEvent ev) {
847 final int action = ev.getAction();
848 if (action == MotionEvent.ACTION_OUTSIDE
849 || (action == MotionEvent.ACTION_DOWN
850 && !mPanel.isInContentArea((int)ev.getX(), (int)ev.getY()))) {
851 mHandler.removeMessages(mMsg);
852 mHandler.sendEmptyMessage(mMsg);
853 return true;
854 }
855 return false;
856 }
857 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400858
859 protected void workAroundBadLayerDrawableOpacity(View v) {
860 }
861
Jim Millerad178a42013-10-08 20:03:38 -0700862 protected void onHideSearchPanel() {
863 }
864
865 protected void onShowSearchPanel() {
866 }
867
Chris Wren51c75102013-07-16 20:49:17 -0400868 public boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
Chris Wrenf29c3b42013-11-27 16:30:30 -0500869 return inflateViews(entry, parent, false);
870 }
871
872 public boolean inflateViewsForHeadsUp(NotificationData.Entry entry, ViewGroup parent) {
873 return inflateViews(entry, parent, true);
874 }
875
876 public boolean inflateViews(NotificationData.Entry entry, ViewGroup parent, boolean isHeadsUp) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400877 int minHeight =
878 mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
879 int maxHeight =
880 mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height);
881 StatusBarNotification sbn = entry.notification;
Chris Wren574a55e2013-07-15 18:48:37 -0400882 RemoteViews contentView = sbn.getNotification().contentView;
883 RemoteViews bigContentView = sbn.getNotification().bigContentView;
Chris Wren8fd39ec2014-02-27 17:43:26 -0500884
885 if (isHeadsUp) {
886 maxHeight =
887 mContext.getResources().getDimensionPixelSize(R.dimen.notification_mid_height);
888 bigContentView = sbn.getNotification().headsUpContentView;
889 }
890
Chris Wren574a55e2013-07-15 18:48:37 -0400891 if (contentView == null) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400892 return false;
893 }
894
Dan Sandlerf68448e2014-04-24 15:54:16 -0400895 if (DEBUG) {
896 Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion);
897 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500898
899 Notification publicNotification = sbn.getNotification().publicVersion;
900
Daniel Sandler6a858c32012-03-12 14:38:58 -0400901 // create the row view
902 LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
903 Context.LAYOUT_INFLATER_SERVICE);
Chris Wren51c75102013-07-16 20:49:17 -0400904 ExpandableNotificationRow row = (ExpandableNotificationRow) inflater.inflate(
905 R.layout.status_bar_notification_row, parent, false);
Daniel Sandlerbc5559f2012-04-19 01:08:15 -0400906
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400907 // for blaming (see SwipeHelper.setLongPressListener)
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400908 row.setTag(sbn.getPackageName());
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400909
Daniel Sandler6a858c32012-03-12 14:38:58 -0400910 workAroundBadLayerDrawableOpacity(row);
911 View vetoButton = updateNotificationVetoButton(row, sbn);
912 vetoButton.setContentDescription(mContext.getString(
913 R.string.accessibility_remove_notification));
914
915 // NB: the large icon is now handled entirely by the template
916
917 // bind the click event to the content area
Jorim Jaggibe565df2014-04-28 17:51:23 +0200918 NotificationContentView expanded =
919 (NotificationContentView) row.findViewById(R.id.expanded);
920 NotificationContentView expandedPublic =
921 (NotificationContentView) row.findViewById(R.id.expandedPublic);
Daniel Sandlerbc5559f2012-04-19 01:08:15 -0400922
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200923 row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
Daniel Sandlerbc5559f2012-04-19 01:08:15 -0400924
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400925 PendingIntent contentIntent = sbn.getNotification().contentIntent;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400926 if (contentIntent != null) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200927 final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey(),
928 isHeadsUp);
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200929 row.setOnClickListener(listener);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400930 } else {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200931 row.setOnClickListener(null);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400932 }
933
Dan Sandlera5e0f412014-01-23 15:11:54 -0500934 // set up the adaptive layout
Chris Wren574a55e2013-07-15 18:48:37 -0400935 View contentViewLocal = null;
936 View bigContentViewLocal = null;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400937 try {
Jorim Jaggi5c2d8462014-03-21 17:37:00 +0100938 contentViewLocal = contentView.apply(mContext, expanded,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +0100939 mOnClickHandler);
Chris Wren574a55e2013-07-15 18:48:37 -0400940 if (bigContentView != null) {
Jorim Jaggi5c2d8462014-03-21 17:37:00 +0100941 bigContentViewLocal = bigContentView.apply(mContext, expanded,
Jorim Jaggi39fa59f2014-02-25 15:38:45 +0100942 mOnClickHandler);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400943 }
944 }
945 catch (RuntimeException e) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400946 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
John Spurlockcd686b52013-06-05 10:13:46 -0400947 Log.e(TAG, "couldn't inflate view for notification " + ident, e);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400948 return false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400949 }
950
Chris Wren574a55e2013-07-15 18:48:37 -0400951 if (contentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -0400952 contentViewLocal.setIsRootNamespace(true);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200953 expanded.setContractedChild(contentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -0400954 }
Chris Wren574a55e2013-07-15 18:48:37 -0400955 if (bigContentViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -0400956 bigContentViewLocal.setIsRootNamespace(true);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200957 expanded.setExpandedChild(bigContentViewLocal);
Daniel Sandler8680bf82012-05-15 16:52:52 -0400958 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500959
960 PackageManager pm = mContext.getPackageManager();
961
962 // now the public version
963 View publicViewLocal = null;
964 if (publicNotification != null) {
965 try {
Jorim Jaggi5c2d8462014-03-21 17:37:00 +0100966 publicViewLocal = publicNotification.contentView.apply(mContext, expandedPublic,
967 mOnClickHandler);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500968
969 if (publicViewLocal != null) {
Dan Sandler6d94aa72014-03-12 00:53:21 -0400970 publicViewLocal.setIsRootNamespace(true);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200971 expandedPublic.setContractedChild(publicViewLocal);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500972 }
973 }
974 catch (RuntimeException e) {
975 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
976 Log.e(TAG, "couldn't inflate public view for notification " + ident, e);
977 publicViewLocal = null;
978 }
979 }
980
981 if (publicViewLocal == null) {
982 // Add a basic notification template
983 publicViewLocal = LayoutInflater.from(mContext).inflate(
Jorim Jaggi5c2d8462014-03-21 17:37:00 +0100984 com.android.internal.R.layout.notification_template_quantum_base,
985 expandedPublic, true);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500986
987 final TextView title = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.title);
988 try {
989 title.setText(pm.getApplicationLabel(
990 pm.getApplicationInfo(entry.notification.getPackageName(), 0)));
991 } catch (NameNotFoundException e) {
992 title.setText(entry.notification.getPackageName());
993 }
994
995 final ImageView icon = (ImageView) publicViewLocal.findViewById(com.android.internal.R.id.icon);
996
997 final StatusBarIcon ic = new StatusBarIcon(entry.notification.getPackageName(),
998 entry.notification.getUser(),
999 entry.notification.getNotification().icon,
1000 entry.notification.getNotification().iconLevel,
1001 entry.notification.getNotification().number,
1002 entry.notification.getNotification().tickerText);
1003
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01001004 Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
1005 icon.setImageDrawable(iconDrawable);
Dan Sandler26e81cf2014-05-06 10:01:27 -04001006 if (mNotificationColorUtil.isGrayscale(iconDrawable)) {
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01001007 icon.setBackgroundResource(
1008 com.android.internal.R.drawable.notification_icon_legacy_bg_inset);
1009 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001010
1011 final TextView text = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.text);
1012 text.setText("Unlock your device to see this notification.");
1013
1014 // TODO: fill out "time" as well
1015 }
1016
Daniel Sandler8680bf82012-05-15 16:52:52 -04001017 row.setDrawingCacheEnabled(true);
1018
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001019 if (MULTIUSER_DEBUG) {
1020 TextView debug = (TextView) row.findViewById(R.id.debug_info);
1021 if (debug != null) {
1022 debug.setVisibility(View.VISIBLE);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001023 debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId());
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001024 }
1025 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001026 entry.row = row;
Selim Cinek1685e632014-04-08 02:27:49 +02001027 entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001028 entry.row.setOnActivatedListener(this);
Selim Cinekc27437b2014-05-14 10:23:33 +02001029 entry.row.setIsBelowSpeedBump(isBelowSpeedBump(entry.notification));
Chris Wren574a55e2013-07-15 18:48:37 -04001030 entry.expanded = contentViewLocal;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001031 entry.expandedPublic = publicViewLocal;
Chris Wren574a55e2013-07-15 18:48:37 -04001032 entry.setBigContentView(bigContentViewLocal);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001033
Jorim Jaggi46739852014-04-15 09:58:24 +02001034 applyLegacyRowBackground(sbn, entry);
1035
Daniel Sandler6a858c32012-03-12 14:38:58 -04001036 return true;
1037 }
1038
Christoph Studer03b87a22014-04-30 17:33:27 +02001039 public NotificationClicker makeClicker(PendingIntent intent, String notificationKey,
1040 boolean forHun) {
1041 return new NotificationClicker(intent, notificationKey, forHun);
Daniel Sandler6a858c32012-03-12 14:38:58 -04001042 }
1043
Chris Wren157026f2013-06-28 16:54:01 -04001044 protected class NotificationClicker implements View.OnClickListener {
Daniel Sandler6a858c32012-03-12 14:38:58 -04001045 private PendingIntent mIntent;
Christoph Studer03b87a22014-04-30 17:33:27 +02001046 private final String mNotificationKey;
Chris Wrenf29c3b42013-11-27 16:30:30 -05001047 private boolean mIsHeadsUp;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001048
Christoph Studer03b87a22014-04-30 17:33:27 +02001049 public NotificationClicker(PendingIntent intent, String notificationKey, boolean forHun) {
Daniel Sandler6a858c32012-03-12 14:38:58 -04001050 mIntent = intent;
Christoph Studer03b87a22014-04-30 17:33:27 +02001051 mNotificationKey = notificationKey;
Chris Wrenf29c3b42013-11-27 16:30:30 -05001052 mIsHeadsUp = forHun;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001053 }
1054
Adrian Roos7d7090d2014-05-21 13:10:23 +02001055 public void onClick(final View v) {
Adrian Roos4314f6d2014-05-28 14:10:27 +02001056 dismissKeyguardThenExecute(new OnDismissAction() {
Adrian Roos7d7090d2014-05-21 13:10:23 +02001057 public boolean onDismiss() {
1058 try {
1059 // The intent we are sending is for the application, which
1060 // won't have permission to immediately start an activity after
1061 // the user switches to home. We know it is safe to do at this
1062 // point, so make sure new activity switches are now allowed.
1063 ActivityManagerNative.getDefault().resumeAppSwitches();
1064 // Also, notifications can be launched from the lock screen,
1065 // so dismiss the lock screen when the activity starts.
1066 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
1067 } catch (RemoteException e) {
1068 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001069
Adrian Roos7d7090d2014-05-21 13:10:23 +02001070 boolean sent = false;
1071 if (mIntent != null) {
1072 int[] pos = new int[2];
1073 v.getLocationOnScreen(pos);
1074 Intent overlay = new Intent();
1075 overlay.setSourceBounds(new Rect(pos[0], pos[1],
Adrian Roos4314f6d2014-05-28 14:10:27 +02001076 pos[0] + v.getWidth(), pos[1] + v.getHeight()));
Adrian Roos7d7090d2014-05-21 13:10:23 +02001077 try {
1078 mIntent.send(mContext, 0, overlay);
1079 sent = true;
1080 } catch (PendingIntent.CanceledException e) {
1081 // the stack trace isn't very helpful here.
1082 // Just log the exception message.
1083 Log.w(TAG, "Sending contentIntent failed: " + e);
1084 }
1085 }
1086
1087 try {
1088 if (mIsHeadsUp) {
1089 mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
1090 }
1091 mBarService.onNotificationClick(mNotificationKey);
1092 } catch (RemoteException ex) {
1093 // system process is dead if we're here.
1094 }
1095
1096 // close the shade if it was open
1097 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1098 visibilityChanged(false);
1099
1100 boolean waitForActivityLaunch = sent && mIntent.isActivity();
Adrian Roos4314f6d2014-05-28 14:10:27 +02001101 return waitForActivityLaunch && DELAY_DISMISS_TO_ACTIVITY_LAUNCH;
Daniel Sandler6a858c32012-03-12 14:38:58 -04001102 }
Adrian Roos7d7090d2014-05-21 13:10:23 +02001103 });
Daniel Sandler6a858c32012-03-12 14:38:58 -04001104 }
1105 }
Chris Wrenf29c3b42013-11-27 16:30:30 -05001106
Daniel Sandler6a858c32012-03-12 14:38:58 -04001107 /**
1108 * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
1109 * This was added last-minute and is inconsistent with the way the rest of the notifications
1110 * are handled, because the notification isn't really cancelled. The lights are just
1111 * turned off. If any other notifications happen, the lights will turn back on. Steve says
1112 * this is what he wants. (see bug 1131461)
1113 */
1114 protected void visibilityChanged(boolean visible) {
1115 if (mPanelSlightlyVisible != visible) {
1116 mPanelSlightlyVisible = visible;
1117 try {
Christoph Studer760ea552014-03-21 13:10:21 +01001118 if (visible) {
1119 mBarService.onPanelRevealed();
1120 } else {
1121 mBarService.onPanelHidden();
1122 }
Daniel Sandler6a858c32012-03-12 14:38:58 -04001123 } catch (RemoteException ex) {
1124 // Won't fail unless the world has ended.
1125 }
1126 }
1127 }
1128
Chris Wren0c8275b2012-05-08 13:36:48 -04001129 /**
1130 * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
1131 * about the failure.
1132 *
1133 * WARNING: this will call back into us. Don't hold any locks.
1134 */
Christoph Studer71f18fd2014-05-20 17:02:04 +02001135 void handleNotificationError(StatusBarNotification n, String message) {
1136 removeNotification(n.getKey());
Chris Wren0c8275b2012-05-08 13:36:48 -04001137 try {
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001138 mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
1139 n.getInitialPid(), message, n.getUserId());
Chris Wren0c8275b2012-05-08 13:36:48 -04001140 } catch (RemoteException ex) {
1141 // The end is nigh.
1142 }
1143 }
1144
Christoph Studer37fe6932014-05-26 13:10:30 +02001145 protected StatusBarNotification removeNotificationViews(String key, Ranking ranking) {
1146 NotificationData.Entry entry = mNotificationData.remove(key, ranking);
Chris Wren0c8275b2012-05-08 13:36:48 -04001147 if (entry == null) {
John Spurlockcd686b52013-06-05 10:13:46 -04001148 Log.w(TAG, "removeNotification for unknown key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -04001149 return null;
1150 }
Christoph Studer37fe6932014-05-26 13:10:30 +02001151 updateNotifications();
Chris Wren0c8275b2012-05-08 13:36:48 -04001152 return entry.notification;
1153 }
1154
Christoph Studer71f18fd2014-05-20 17:02:04 +02001155 protected NotificationData.Entry createNotificationViews(StatusBarNotification notification) {
Chris Wren0c8275b2012-05-08 13:36:48 -04001156 if (DEBUG) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02001157 Log.d(TAG, "createNotificationViews(notification=" + notification);
Chris Wren0c8275b2012-05-08 13:36:48 -04001158 }
1159 // Construct the icon.
1160 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001161 notification.getPackageName() + "/0x" + Integer.toHexString(notification.getId()),
John Spurlocke6f0a712013-09-03 16:23:49 -04001162 notification.getNotification());
Chris Wren0c8275b2012-05-08 13:36:48 -04001163 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
1164
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001165 final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001166 notification.getUser(),
1167 notification.getNotification().icon,
1168 notification.getNotification().iconLevel,
1169 notification.getNotification().number,
1170 notification.getNotification().tickerText);
Chris Wren0c8275b2012-05-08 13:36:48 -04001171 if (!iconView.set(ic)) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02001172 handleNotificationError(notification, "Couldn't create icon: " + ic);
Chris Wren0c8275b2012-05-08 13:36:48 -04001173 return null;
1174 }
1175 // Construct the expanded view.
Christoph Studer71f18fd2014-05-20 17:02:04 +02001176 NotificationData.Entry entry = new NotificationData.Entry(notification, iconView);
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001177 if (!inflateViews(entry, mStackScroller)) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02001178 handleNotificationError(notification, "Couldn't expand RemoteViews for: "
Chris Wren0c8275b2012-05-08 13:36:48 -04001179 + notification);
1180 return null;
1181 }
Chris Wrenf0048ce2013-08-07 16:43:43 -04001182 return entry;
1183 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001184
Christoph Studer37fe6932014-05-26 13:10:30 +02001185 protected void addNotificationViews(Entry entry, Ranking ranking) {
Raju Yadav5f330262014-03-24 10:44:00 +01001186 if (entry == null) {
1187 return;
1188 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001189 // Add the expanded view and icon.
Christoph Studer37fe6932014-05-26 13:10:30 +02001190 mNotificationData.add(entry, ranking);
1191 updateNotifications();
Selim Cinek8efa6dd2014-05-19 16:27:37 +02001192 }
1193
Christoph Studer37fe6932014-05-26 13:10:30 +02001194 private void addNotificationViews(StatusBarNotification notification, Ranking ranking) {
1195 addNotificationViews(createNotificationViews(notification), ranking);
Chris Wren0c8275b2012-05-08 13:36:48 -04001196 }
1197
Jorim Jaggi251957d2014-04-09 04:24:09 +02001198 /**
Jorim Jaggid4a57442014-04-10 02:45:55 +02001199 * @return The number of notifications we show on Keyguard.
1200 */
1201 protected abstract int getMaxKeyguardNotifications();
1202
1203 /**
Jorim Jaggi251957d2014-04-09 04:24:09 +02001204 * Updates expanded, dimmed and locked states of notification rows.
1205 */
1206 protected void updateRowStates() {
Jorim Jaggid4a57442014-04-10 02:45:55 +02001207 int maxKeyguardNotifications = getMaxKeyguardNotifications();
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001208 mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
Christoph Studer37fe6932014-05-26 13:10:30 +02001209 final int N = mNotificationData.size();
Jorim Jaggid4a57442014-04-10 02:45:55 +02001210 int visibleNotifications = 0;
Jorim Jaggiecbab362014-04-23 16:13:15 +02001211 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
Christoph Studer37fe6932014-05-26 13:10:30 +02001212 for (int i = 0; i < N; i++) {
Chris Wren8fd12652012-05-09 21:25:57 -04001213 NotificationData.Entry entry = mNotificationData.get(i);
Jorim Jaggiecbab362014-04-23 16:13:15 +02001214 if (onKeyguard) {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001215 entry.row.setExpansionDisabled(true);
Chris Wren3ddab0d2012-08-02 16:52:21 -04001216 } else {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001217 entry.row.setExpansionDisabled(false);
Jorim Jaggi649b7082014-04-03 13:15:18 +02001218 if (!entry.row.isUserLocked()) {
Christoph Studer37fe6932014-05-26 13:10:30 +02001219 boolean top = (i == 0);
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001220 entry.row.setSystemExpanded(top);
Jorim Jaggi649b7082014-04-03 13:15:18 +02001221 }
Chris Wren8fd12652012-05-09 21:25:57 -04001222 }
Jorim Jaggid4a57442014-04-10 02:45:55 +02001223 boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
Jorim Jaggiecbab362014-04-23 16:13:15 +02001224 if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
Jorim Jaggid4a57442014-04-10 02:45:55 +02001225 || !showOnKeyguard)) {
1226 entry.row.setVisibility(View.GONE);
1227 if (showOnKeyguard) {
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001228 mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
Jorim Jaggid4a57442014-04-10 02:45:55 +02001229 }
1230 } else {
Selim Cinek8efa6dd2014-05-19 16:27:37 +02001231 boolean wasGone = entry.row.getVisibility() == View.GONE;
1232 entry.row.setVisibility(View.VISIBLE);
1233 if (wasGone) {
Selim Cinek572bbd42014-04-25 16:43:27 +02001234 // notify the scroller of a child addition
1235 mStackScroller.generateAddAnimation(entry.row);
1236 }
Jorim Jaggid4a57442014-04-10 02:45:55 +02001237 visibleNotifications++;
1238 }
Chris Wren8fd12652012-05-09 21:25:57 -04001239 }
Jorim Jaggid4a57442014-04-10 02:45:55 +02001240
Jorim Jaggiecbab362014-04-23 16:13:15 +02001241 if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
Jorim Jaggid4a57442014-04-10 02:45:55 +02001242 mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
1243 } else {
1244 mKeyguardIconOverflowContainer.setVisibility(View.GONE);
1245 }
Christoph Studer37fe6932014-05-26 13:10:30 +02001246 // Move overflow container to last position.
1247 mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
1248 mStackScroller.getChildCount() - 1);
Jorim Jaggid4a57442014-04-10 02:45:55 +02001249 }
1250
1251 private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
1252 return sbn.getNotification().priority >= Notification.PRIORITY_LOW;
Chris Wren8fd12652012-05-09 21:25:57 -04001253 }
1254
John Spurlocke677d712014-02-13 12:52:19 -05001255 protected void setZenMode(int mode) {
John Spurlock110e5b12014-02-27 13:09:35 -05001256 if (!isDeviceProvisioned()) return;
John Spurlocke677d712014-02-13 12:52:19 -05001257 mZenMode = mode;
Christoph Studer37fe6932014-05-26 13:10:30 +02001258 updateNotifications();
John Spurlocke677d712014-02-13 12:52:19 -05001259 }
1260
John Spurlock4b3bda22014-05-22 14:32:20 -04001261 protected void setShowLockscreenNotifications(boolean show) {
1262 mShowLockscreenNotifications = show;
1263 }
1264
Chris Wren0c8275b2012-05-08 13:36:48 -04001265 protected abstract void haltTicker();
1266 protected abstract void setAreThereNotifications();
Christoph Studer37fe6932014-05-26 13:10:30 +02001267 protected abstract void updateNotifications();
Christoph Studer71f18fd2014-05-20 17:02:04 +02001268 protected abstract void tick(StatusBarNotification n, boolean firstTime);
Chris Wren0c8275b2012-05-08 13:36:48 -04001269 protected abstract void updateExpandedViewPos(int expandedPosition);
Jim Millerb4238e02012-05-14 15:26:20 -07001270 protected abstract boolean shouldDisableNavbarGestures();
Chris Wren0c8275b2012-05-08 13:36:48 -04001271
Christoph Studer60748e72014-05-22 16:51:41 +02001272 @Override
1273 public void addNotification(StatusBarNotification notification) {
1274 if (!USE_NOTIFICATION_LISTENER) {
Christoph Studer37fe6932014-05-26 13:10:30 +02001275 addNotificationInternal(notification, null);
Christoph Studer60748e72014-05-22 16:51:41 +02001276 }
1277 }
1278
Christoph Studer37fe6932014-05-26 13:10:30 +02001279 public abstract void addNotificationInternal(StatusBarNotification notification,
1280 Ranking ranking);
Christoph Studer60748e72014-05-22 16:51:41 +02001281
Chris Wren333a61c2014-05-28 16:40:57 -04001282 protected abstract void updateRankingInternal(Ranking ranking);
1283
Christoph Studer60748e72014-05-22 16:51:41 +02001284 @Override
1285 public void removeNotification(String key) {
1286 if (!USE_NOTIFICATION_LISTENER) {
Christoph Studer37fe6932014-05-26 13:10:30 +02001287 removeNotificationInternal(key, null);
Christoph Studer60748e72014-05-22 16:51:41 +02001288 }
1289 }
1290
Chris Wren333a61c2014-05-28 16:40:57 -04001291 public abstract void removeNotificationInternal(String key, Ranking ranking);
Christoph Studer60748e72014-05-22 16:51:41 +02001292
Christoph Studer71f18fd2014-05-20 17:02:04 +02001293 public void updateNotification(StatusBarNotification notification) {
Christoph Studer60748e72014-05-22 16:51:41 +02001294 if (!USE_NOTIFICATION_LISTENER) {
Christoph Studer37fe6932014-05-26 13:10:30 +02001295 updateNotificationInternal(notification, null);
Christoph Studer60748e72014-05-22 16:51:41 +02001296 }
1297 }
1298
Christoph Studer37fe6932014-05-26 13:10:30 +02001299 public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02001300 if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
Chris Wren0c8275b2012-05-08 13:36:48 -04001301
Christoph Studer71f18fd2014-05-20 17:02:04 +02001302 final NotificationData.Entry oldEntry = mNotificationData.findByKey(notification.getKey());
Chris Wren0c8275b2012-05-08 13:36:48 -04001303 if (oldEntry == null) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02001304 Log.w(TAG, "updateNotification for unknown key: " + notification.getKey());
Chris Wren0c8275b2012-05-08 13:36:48 -04001305 return;
1306 }
1307
1308 final StatusBarNotification oldNotification = oldEntry.notification;
1309
1310 // XXX: modify when we do something more intelligent with the two content views
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001311 final RemoteViews oldContentView = oldNotification.getNotification().contentView;
1312 final RemoteViews contentView = notification.getNotification().contentView;
1313 final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView;
1314 final RemoteViews bigContentView = notification.getNotification().bigContentView;
Chris Wren8fd39ec2014-02-27 17:43:26 -05001315 final RemoteViews oldHeadsUpContentView = oldNotification.getNotification().headsUpContentView;
1316 final RemoteViews headsUpContentView = notification.getNotification().headsUpContentView;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001317 final Notification oldPublicNotification = oldNotification.getNotification().publicVersion;
1318 final RemoteViews oldPublicContentView = oldPublicNotification != null
1319 ? oldPublicNotification.contentView : null;
1320 final Notification publicNotification = notification.getNotification().publicVersion;
1321 final RemoteViews publicContentView = publicNotification != null
1322 ? publicNotification.contentView : null;
Chris Wren0c8275b2012-05-08 13:36:48 -04001323
1324 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -04001325 Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
Chris Wren0c8275b2012-05-08 13:36:48 -04001326 + " ongoing=" + oldNotification.isOngoing()
1327 + " expanded=" + oldEntry.expanded
1328 + " contentView=" + oldContentView
Chris Wrene9e37722012-05-11 17:40:14 -04001329 + " bigContentView=" + oldBigContentView
Dan Sandlera5e0f412014-01-23 15:11:54 -05001330 + " publicView=" + oldPublicContentView
Chris Wren0c8275b2012-05-08 13:36:48 -04001331 + " rowParent=" + oldEntry.row.getParent());
John Spurlockcd686b52013-06-05 10:13:46 -04001332 Log.d(TAG, "new notification: when=" + notification.getNotification().when
Chris Wren0c8275b2012-05-08 13:36:48 -04001333 + " ongoing=" + oldNotification.isOngoing()
Chris Wrene9e37722012-05-11 17:40:14 -04001334 + " contentView=" + contentView
Dan Sandlera5e0f412014-01-23 15:11:54 -05001335 + " bigContentView=" + bigContentView
1336 + " publicView=" + publicContentView);
Chris Wren0c8275b2012-05-08 13:36:48 -04001337 }
1338
1339 // Can we just reapply the RemoteViews in place? If when didn't change, the order
1340 // didn't change.
Chris Wrene9e37722012-05-11 17:40:14 -04001341
1342 // 1U is never null
Chris Wren0c8275b2012-05-08 13:36:48 -04001343 boolean contentsUnchanged = oldEntry.expanded != null
Chris Wren0c8275b2012-05-08 13:36:48 -04001344 && contentView.getPackage() != null
1345 && oldContentView.getPackage() != null
1346 && oldContentView.getPackage().equals(contentView.getPackage())
1347 && oldContentView.getLayoutId() == contentView.getLayoutId();
Chris Wrene9e37722012-05-11 17:40:14 -04001348 // large view may be null
1349 boolean bigContentsUnchanged =
Chris Wren574a55e2013-07-15 18:48:37 -04001350 (oldEntry.getBigContentView() == null && bigContentView == null)
1351 || ((oldEntry.getBigContentView() != null && bigContentView != null)
Chris Wrene9e37722012-05-11 17:40:14 -04001352 && bigContentView.getPackage() != null
1353 && oldBigContentView.getPackage() != null
1354 && oldBigContentView.getPackage().equals(bigContentView.getPackage())
1355 && oldBigContentView.getLayoutId() == bigContentView.getLayoutId());
Chris Wren8fd39ec2014-02-27 17:43:26 -05001356 boolean headsUpContentsUnchanged =
1357 (oldHeadsUpContentView == null && headsUpContentView == null)
1358 || ((oldHeadsUpContentView != null && headsUpContentView != null)
1359 && headsUpContentView.getPackage() != null
1360 && oldHeadsUpContentView.getPackage() != null
1361 && oldHeadsUpContentView.getPackage().equals(headsUpContentView.getPackage())
1362 && oldHeadsUpContentView.getLayoutId() == headsUpContentView.getLayoutId());
Dan Sandlera5e0f412014-01-23 15:11:54 -05001363 boolean publicUnchanged =
1364 (oldPublicContentView == null && publicContentView == null)
1365 || ((oldPublicContentView != null && publicContentView != null)
1366 && publicContentView.getPackage() != null
1367 && oldPublicContentView.getPackage() != null
1368 && oldPublicContentView.getPackage().equals(publicContentView.getPackage())
1369 && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
1370
Chris Wren0c8275b2012-05-08 13:36:48 -04001371
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001372 boolean updateTicker = notification.getNotification().tickerText != null
1373 && !TextUtils.equals(notification.getNotification().tickerText,
Christoph Studer60748e72014-05-22 16:51:41 +02001374 oldEntry.notification.getNotification().tickerText);
Christoph Studer37fe6932014-05-26 13:10:30 +02001375 if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
1376 && publicUnchanged) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02001377 if (DEBUG) Log.d(TAG, "reusing notification for key: " + notification.getKey());
Chris Wren0c8275b2012-05-08 13:36:48 -04001378 oldEntry.notification = notification;
1379 try {
Chris Wrene03f4e12013-08-08 16:48:48 -04001380 updateNotificationViews(oldEntry, notification);
1381
1382 if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
1383 && oldNotification == mInterruptingNotificationEntry.notification) {
1384 if (!shouldInterrupt(notification)) {
1385 if (DEBUG) Log.d(TAG, "no longer interrupts!");
1386 mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
1387 } else {
1388 if (DEBUG) Log.d(TAG, "updating the current heads up:" + notification);
1389 mInterruptingNotificationEntry.notification = notification;
Chris Wrenf29c3b42013-11-27 16:30:30 -05001390 updateHeadsUpViews(mInterruptingNotificationEntry, notification);
Chris Wrene03f4e12013-08-08 16:48:48 -04001391 }
Chris Wrene9e37722012-05-11 17:40:14 -04001392 }
Chris Wrene03f4e12013-08-08 16:48:48 -04001393
Chris Wren0c8275b2012-05-08 13:36:48 -04001394 // Update the icon.
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001395 final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001396 notification.getUser(),
1397 notification.getNotification().icon, notification.getNotification().iconLevel,
1398 notification.getNotification().number,
1399 notification.getNotification().tickerText);
Chris Wren0c8275b2012-05-08 13:36:48 -04001400 if (!oldEntry.icon.set(ic)) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02001401 handleNotificationError(notification, "Couldn't update icon: " + ic);
Chris Wren0c8275b2012-05-08 13:36:48 -04001402 return;
1403 }
Christoph Studer37fe6932014-05-26 13:10:30 +02001404 mNotificationData.updateRanking(ranking);
1405 updateNotifications();
Chris Wren0c8275b2012-05-08 13:36:48 -04001406 }
1407 catch (RuntimeException e) {
1408 // It failed to add cleanly. Log, and remove the view from the panel.
John Spurlockcd686b52013-06-05 10:13:46 -04001409 Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
Christoph Studer37fe6932014-05-26 13:10:30 +02001410 removeNotificationViews(notification.getKey(), ranking);
1411 addNotificationViews(notification, ranking);
Chris Wren0c8275b2012-05-08 13:36:48 -04001412 }
1413 } else {
Christoph Studer71f18fd2014-05-20 17:02:04 +02001414 if (DEBUG) Log.d(TAG, "not reusing notification for key: " + notification.getKey());
John Spurlockcd686b52013-06-05 10:13:46 -04001415 if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
Christoph Studer37fe6932014-05-26 13:10:30 +02001416 removeNotificationViews(notification.getKey(), ranking);
1417 addNotificationViews(notification, ranking); // will also replace the heads up
Christoph Studer71f18fd2014-05-20 17:02:04 +02001418 final NotificationData.Entry newEntry = mNotificationData.findByKey(
1419 notification.getKey());
Selim Cinek1685e632014-04-08 02:27:49 +02001420 final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
1421 if (userChangedExpansion) {
1422 boolean userExpanded = oldEntry.row.isUserExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001423 newEntry.row.setUserExpanded(userExpanded);
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001424 newEntry.row.notifyHeightChanged();
Chris Wrenc9433ecb2012-06-27 17:37:03 -04001425 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001426 }
1427
1428 // Update the veto button accordingly (and as a result, whether this row is
1429 // swipe-dismissable)
1430 updateNotificationVetoButton(oldEntry.row, notification);
1431
John Spurlock61e36832012-09-10 09:43:27 -04001432 // Is this for you?
Kenny Guy2a764942014-04-02 13:29:20 +01001433 boolean isForCurrentUser = notificationIsForCurrentProfiles(notification);
John Spurlockcd686b52013-06-05 10:13:46 -04001434 if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
John Spurlock61e36832012-09-10 09:43:27 -04001435
Chris Wren0c8275b2012-05-08 13:36:48 -04001436 // Restart the ticker if it's still running
John Spurlock61e36832012-09-10 09:43:27 -04001437 if (updateTicker && isForCurrentUser) {
Chris Wren0c8275b2012-05-08 13:36:48 -04001438 haltTicker();
Christoph Studer71f18fd2014-05-20 17:02:04 +02001439 tick(notification, false);
Chris Wren0c8275b2012-05-08 13:36:48 -04001440 }
1441
1442 // Recalculate the position of the sliding windows and the titles.
1443 setAreThereNotifications();
1444 updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
Chris Wrene03f4e12013-08-08 16:48:48 -04001445 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001446
Chris Wrene03f4e12013-08-08 16:48:48 -04001447 private void updateNotificationViews(NotificationData.Entry entry,
1448 StatusBarNotification notification) {
Chris Wrenf29c3b42013-11-27 16:30:30 -05001449 updateNotificationViews(entry, notification, false);
1450 }
1451
1452 private void updateHeadsUpViews(NotificationData.Entry entry,
1453 StatusBarNotification notification) {
1454 updateNotificationViews(entry, notification, true);
1455 }
1456
1457 private void updateNotificationViews(NotificationData.Entry entry,
1458 StatusBarNotification notification, boolean isHeadsUp) {
Chris Wrene03f4e12013-08-08 16:48:48 -04001459 final RemoteViews contentView = notification.getNotification().contentView;
Chris Wren8fd39ec2014-02-27 17:43:26 -05001460 final RemoteViews bigContentView = isHeadsUp
1461 ? notification.getNotification().headsUpContentView
1462 : notification.getNotification().bigContentView;
John Spurlock70cf4c12014-02-13 09:39:14 -05001463 final Notification publicVersion = notification.getNotification().publicVersion;
1464 final RemoteViews publicContentView = publicVersion != null ? publicVersion.contentView
1465 : null;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001466
Chris Wrene03f4e12013-08-08 16:48:48 -04001467 // Reapply the RemoteViews
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01001468 contentView.reapply(mContext, entry.expanded, mOnClickHandler);
Chris Wrene03f4e12013-08-08 16:48:48 -04001469 if (bigContentView != null && entry.getBigContentView() != null) {
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01001470 bigContentView.reapply(mContext, entry.getBigContentView(),
Jorim Jaggi39fa59f2014-02-25 15:38:45 +01001471 mOnClickHandler);
Chris Wrene03f4e12013-08-08 16:48:48 -04001472 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001473 if (publicContentView != null && entry.getPublicContentView() != null) {
Jorim Jaggi5c2d8462014-03-21 17:37:00 +01001474 publicContentView.reapply(mContext, entry.getPublicContentView(), mOnClickHandler);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001475 }
Chris Wrene03f4e12013-08-08 16:48:48 -04001476 // update the contentIntent
1477 final PendingIntent contentIntent = notification.getNotification().contentIntent;
1478 if (contentIntent != null) {
Christoph Studer03b87a22014-04-30 17:33:27 +02001479 final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey(),
1480 isHeadsUp);
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001481 entry.row.setOnClickListener(listener);
Chris Wrene03f4e12013-08-08 16:48:48 -04001482 } else {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001483 entry.row.setOnClickListener(null);
Chris Wren0c8275b2012-05-08 13:36:48 -04001484 }
Selim Cinekc27437b2014-05-14 10:23:33 +02001485 boolean wasBelow = entry.row.isBelowSpeedBump();
1486 boolean nowBelow = isBelowSpeedBump(notification);
1487 if (wasBelow != nowBelow) {
1488 entry.row.setIsBelowSpeedBump(nowBelow);
1489 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001490 entry.row.notifyContentUpdated();
Chris Wren0c8275b2012-05-08 13:36:48 -04001491 }
John Spurlock36231282012-06-23 17:11:27 -04001492
Selim Cinekc27437b2014-05-14 10:23:33 +02001493 private boolean isBelowSpeedBump(StatusBarNotification notification) {
1494 return notification.getNotification().priority ==
1495 Notification.PRIORITY_MIN;
1496 }
1497
Chris Wrene97f90b2013-08-07 17:39:35 -04001498 protected void notifyHeadsUpScreenOn(boolean screenOn) {
1499 if (!screenOn && mInterruptingNotificationEntry != null) {
1500 mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
1501 }
1502 }
1503
Chris Wren51c75102013-07-16 20:49:17 -04001504 protected boolean shouldInterrupt(StatusBarNotification sbn) {
1505 Notification notification = sbn.getNotification();
1506 // some predicates to make the boolean logic legible
1507 boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0
1508 || (notification.defaults & Notification.DEFAULT_VIBRATE) != 0
1509 || notification.sound != null
1510 || notification.vibrate != null;
1511 boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD;
1512 boolean isFullscreen = notification.fullScreenIntent != null;
Chris Wren22ae46e2014-02-26 18:08:09 -05001513 boolean hasTicker = mHeadsUpTicker && !TextUtils.isEmpty(notification.tickerText);
Chris Wren51c75102013-07-16 20:49:17 -04001514 boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP,
1515 Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER;
1516
Jim Millera999d462013-10-30 13:58:11 -07001517 final KeyguardTouchDelegate keyguard = KeyguardTouchDelegate.getInstance(mContext);
Chris Wren22ae46e2014-02-26 18:08:09 -05001518 boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker)))
Chris Wren51c75102013-07-16 20:49:17 -04001519 && isAllowed
1520 && mPowerManager.isScreenOn()
Jorim Jaggi5cf17872014-03-26 18:31:48 +01001521 && !keyguard.isShowingAndNotOccluded()
Jim Millera999d462013-10-30 13:58:11 -07001522 && !keyguard.isInputRestricted();
Chris Wren157026f2013-06-28 16:54:01 -04001523 try {
1524 interrupt = interrupt && !mDreamManager.isDreaming();
1525 } catch (RemoteException e) {
1526 Log.d(TAG, "failed to query dream manager", e);
1527 }
Chris Wren51c75102013-07-16 20:49:17 -04001528 if (DEBUG) Log.d(TAG, "interrupt: " + interrupt);
Chris Wren157026f2013-06-28 16:54:01 -04001529 return interrupt;
1530 }
1531
John Spurlock36231282012-06-23 17:11:27 -04001532 // Q: What kinds of notifications should show during setup?
1533 // A: Almost none! Only things coming from the system (package is "android") that also
1534 // have special "kind" tags marking them as relevant for setup (see below).
1535 protected boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) {
John Spurlockfd7f1e02014-03-18 16:41:57 -04001536 return "android".equals(sbn.getPackageName())
1537 && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP);
John Spurlock36231282012-06-23 17:11:27 -04001538 }
John Spurlock67ad3682012-06-26 17:42:00 -04001539
1540 public boolean inKeyguardRestrictedInputMode() {
Jim Millera999d462013-10-30 13:58:11 -07001541 return KeyguardTouchDelegate.getInstance(mContext).isInputRestricted();
John Spurlock67ad3682012-06-26 17:42:00 -04001542 }
John Spurlockad3e6cb2013-04-30 08:47:43 -04001543
John Spurlockcfc359a2013-09-05 10:42:03 -04001544 public void setInteracting(int barWindow, boolean interacting) {
John Spurlockad3e6cb2013-04-30 08:47:43 -04001545 // hook for subclasses
1546 }
John Spurlock5c454122013-06-17 07:35:46 -04001547
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001548 public void setBouncerShowing(boolean bouncerShowing) {
1549 mBouncerShowing = bouncerShowing;
1550 }
1551
1552 /**
1553 * @return Whether the security bouncer from Keyguard is showing.
1554 */
1555 public boolean isBouncerShowing() {
1556 return mBouncerShowing;
1557 }
1558
John Spurlock5c454122013-06-17 07:35:46 -04001559 public void destroy() {
1560 if (mSearchPanelView != null) {
1561 mWindowManager.removeViewImmediate(mSearchPanelView);
1562 }
1563 mContext.unregisterReceiver(mBroadcastReceiver);
Christoph Studer37fe6932014-05-26 13:10:30 +02001564 if (USE_NOTIFICATION_LISTENER) {
1565 try {
1566 mNotificationListener.unregisterAsSystemService();
1567 } catch (RemoteException e) {
1568 // Ignore.
1569 }
1570 }
John Spurlock5c454122013-06-17 07:35:46 -04001571 }
Joe Onorato2314aab2010-04-08 16:41:23 -05001572}