blob: a7cfaba8b190b936d05db8b1a8749855d966e573 [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;
Joe Onorato808182d2010-07-09 18:52:06 -040025import android.content.Context;
Daniel Sandler6a858c32012-03-12 14:38:58 -040026import android.content.Intent;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040027import android.content.IntentFilter;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040028import android.content.pm.ApplicationInfo;
Dan Sandlera5e0f412014-01-23 15:11:54 -050029import android.content.pm.PackageManager;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040030import android.content.pm.PackageManager.NameNotFoundException;
John Spurlockde84f0e2013-06-12 12:41:00 -040031import android.content.res.Configuration;
Daniel Sandler26cda272012-05-22 15:44:08 -040032import android.database.ContentObserver;
Daniel Sandler6a858c32012-03-12 14:38:58 -040033import android.graphics.Rect;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040034import android.net.Uri;
Daniel Sandler96fd7c12012-03-30 16:37:36 -040035import android.os.Build;
Michael Jurka7f2668c2012-03-27 07:49:52 -070036import android.os.Handler;
Joe Onorato808182d2010-07-09 18:52:06 -040037import android.os.IBinder;
Michael Jurka7f2668c2012-03-27 07:49:52 -070038import android.os.Message;
Chris Wren157026f2013-06-28 16:54:01 -040039import android.os.PowerManager;
Joe Onorato808182d2010-07-09 18:52:06 -040040import android.os.RemoteException;
41import android.os.ServiceManager;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070042import android.os.UserHandle;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040043import android.provider.Settings;
Chris Wren157026f2013-06-28 16:54:01 -040044import android.service.dreams.DreamService;
45import android.service.dreams.IDreamManager;
John Spurlockde84f0e2013-06-12 12:41:00 -040046import android.service.notification.StatusBarNotification;
Chris Wren0c8275b2012-05-08 13:36:48 -040047import android.text.TextUtils;
Joe Onorato808182d2010-07-09 18:52:06 -040048import android.util.Log;
Daniel Sandlerc638c1e2011-08-24 16:19:23 -070049import android.view.Display;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050050import android.view.IWindowManager;
Michael Jurka7f2668c2012-03-27 07:49:52 -070051import android.view.LayoutInflater;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040052import android.view.MenuItem;
Michael Jurka7f2668c2012-03-27 07:49:52 -070053import android.view.MotionEvent;
Joe Onorato808182d2010-07-09 18:52:06 -040054import android.view.View;
Daniel Sandler6a858c32012-03-12 14:38:58 -040055import android.view.ViewGroup;
Michael Jurka7f2668c2012-03-27 07:49:52 -070056import android.view.ViewGroup.LayoutParams;
Joe Onorato808182d2010-07-09 18:52:06 -040057import android.view.WindowManager;
Michael Jurka80343f62012-10-18 13:13:46 +020058import android.view.WindowManagerGlobal;
Chris Wren0c8275b2012-05-08 13:36:48 -040059import android.widget.ImageView;
Michael Jurka7f2668c2012-03-27 07:49:52 -070060import android.widget.LinearLayout;
Daniel Sandlerf7a19562012-04-04 14:04:21 -040061import android.widget.PopupMenu;
Michael Jurkaa600fd92012-06-25 15:57:05 -070062import android.widget.RemoteViews;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040063import android.widget.TextView;
Joe Onorato808182d2010-07-09 18:52:06 -040064
John Spurlockde84f0e2013-06-12 12:41:00 -040065import com.android.internal.statusbar.IStatusBarService;
66import com.android.internal.statusbar.StatusBarIcon;
67import com.android.internal.statusbar.StatusBarIconList;
68import com.android.internal.widget.SizeAdaptiveLayout;
69import com.android.systemui.R;
John Spurlockd08de372013-06-24 13:06:08 -040070import com.android.systemui.RecentsComponent;
John Spurlockde84f0e2013-06-12 12:41:00 -040071import com.android.systemui.SearchPanelView;
72import com.android.systemui.SystemUI;
Jim Millera999d462013-10-30 13:58:11 -070073import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
John Spurlockde84f0e2013-06-12 12:41:00 -040074import com.android.systemui.statusbar.policy.NotificationRowLayout;
John Spurlockde84f0e2013-06-12 12:41:00 -040075
Michael Jurkaa600fd92012-06-25 15:57:05 -070076import java.util.ArrayList;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -070077import java.util.Locale;
Joe Onorato1c95ecb2010-06-28 17:19:12 -040078
Michael Jurka7f2668c2012-03-27 07:49:52 -070079public abstract class BaseStatusBar extends SystemUI implements
Michael Jurkacb2522c2012-04-13 09:32:47 -070080 CommandQueue.Callbacks {
Daniel Sandler198a0302012-08-17 16:04:31 -040081 public static final String TAG = "StatusBar";
82 public static final boolean DEBUG = false;
Daniel Sandlerb9301c32012-08-14 15:08:24 -040083 public static final boolean MULTIUSER_DEBUG = false;
Joe Onorato1c95ecb2010-06-28 17:19:12 -040084
Michael Jurkacb2522c2012-04-13 09:32:47 -070085 protected static final int MSG_TOGGLE_RECENTS_PANEL = 1020;
Michael Jurka7f2668c2012-03-27 07:49:52 -070086 protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
87 protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
88 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
Jim Millere898ac52012-04-06 17:10:57 -070089 protected static final int MSG_OPEN_SEARCH_PANEL = 1024;
90 protected static final int MSG_CLOSE_SEARCH_PANEL = 1025;
Chris Wren157026f2013-06-28 16:54:01 -040091 protected static final int MSG_SHOW_HEADS_UP = 1026;
92 protected static final int MSG_HIDE_HEADS_UP = 1027;
Chris Wrene97f90b2013-08-07 17:39:35 -040093 protected static final int MSG_ESCALATE_HEADS_UP = 1028;
Chris Wren0c8275b2012-05-08 13:36:48 -040094
Chris Wren157026f2013-06-28 16:54:01 -040095 protected static final boolean ENABLE_HEADS_UP = true;
96 // scores above this threshold should be displayed in heads up mode.
Chris Wrenf6e83f42013-09-11 14:02:59 -040097 protected static final int INTERRUPTION_THRESHOLD = 11;
98 protected static final String SETTING_HEADS_UP = "heads_up_enabled";
Chris Wren0c8275b2012-05-08 13:36:48 -040099
Michael Jurka56a57832012-05-14 13:24:43 -0700100 // Should match the value in PhoneWindowManager
101 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
102
Chris Wren0c8275b2012-05-08 13:36:48 -0400103 public static final int EXPANDED_LEAVE_ALONE = -10000;
104 public static final int EXPANDED_FULL_OPEN = -10001;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700105
Joe Onorato808182d2010-07-09 18:52:06 -0400106 protected CommandQueue mCommandQueue;
107 protected IStatusBarService mBarService;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700108 protected H mHandler = createHandler();
109
Chris Wren0c8275b2012-05-08 13:36:48 -0400110 // all notifications
111 protected NotificationData mNotificationData = new NotificationData();
112 protected NotificationRowLayout mPile;
113
Chris Wren51c75102013-07-16 20:49:17 -0400114 protected NotificationData.Entry mInterruptingNotificationEntry;
115 protected long mInterruptingNotificationTime;
Chris Wren0c8275b2012-05-08 13:36:48 -0400116
Daniel Sandler6a858c32012-03-12 14:38:58 -0400117 // used to notify status bar for suppressing notification LED
118 protected boolean mPanelSlightlyVisible;
119
Jim Millere898ac52012-04-06 17:10:57 -0700120 // Search panel
121 protected SearchPanelView mSearchPanelView;
122
Daniel Sandler469e96e2012-05-04 15:56:19 -0400123 protected PopupMenu mNotificationBlamePopup;
124
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400125 protected int mCurrentUserId = 0;
126
Daniel Sandler777dcde2013-09-30 10:21:45 -0400127 protected int mLayoutDirection = -1; // invalid
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700128 private Locale mLocale;
Chris Wrenf6e83f42013-09-11 14:02:59 -0400129 protected boolean mUseHeadsUp = false;
Chris Wren157026f2013-06-28 16:54:01 -0400130
131 protected IDreamManager mDreamManager;
Chris Wren157026f2013-06-28 16:54:01 -0400132 PowerManager mPowerManager;
Chris Wren51c75102013-07-16 20:49:17 -0400133 protected int mRowHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500134 private boolean mPublicMode = false;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700135
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500136 // UI-specific methods
Daniel Sandler6a858c32012-03-12 14:38:58 -0400137
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500138 /**
139 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
140 * and add them to the window manager.
141 */
142 protected abstract void createAndAddWindows();
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400143
Jeff Brown98365d72012-08-19 20:30:52 -0700144 protected WindowManager mWindowManager;
145 protected IWindowManager mWindowManagerService;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700146 protected abstract void refreshLayout(int layoutDirection);
147
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500148 protected Display mDisplay;
Jeff Brown98365d72012-08-19 20:30:52 -0700149
Daniel Sandler26cda272012-05-22 15:44:08 -0400150 private boolean mDeviceProvisioned = false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400151
John Spurlockd08de372013-06-24 13:06:08 -0400152 private RecentsComponent mRecents;
153
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500154 public IStatusBarService getStatusBarService() {
155 return mBarService;
156 }
Joe Onorato2039e482010-11-29 14:54:24 -0800157
Daniel Sandler3ffdcc72012-09-23 14:31:48 -0400158 public boolean isDeviceProvisioned() {
Daniel Sandler26cda272012-05-22 15:44:08 -0400159 return mDeviceProvisioned;
160 }
161
162 private ContentObserver mProvisioningObserver = new ContentObserver(new Handler()) {
163 @Override
164 public void onChange(boolean selfChange) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700165 final boolean provisioned = 0 != Settings.Global.getInt(
166 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
Daniel Sandler26cda272012-05-22 15:44:08 -0400167 if (provisioned != mDeviceProvisioned) {
168 mDeviceProvisioned = provisioned;
169 updateNotificationIcons();
170 }
171 }
172 };
173
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700174 private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
175 @Override
176 public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) {
Daniel Sandler198a0302012-08-17 16:04:31 -0400177 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400178 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
Daniel Sandler198a0302012-08-17 16:04:31 -0400179 }
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700180 final boolean isActivity = pendingIntent.isActivity();
181 if (isActivity) {
182 try {
183 // The intent we are sending is for the application, which
184 // won't have permission to immediately start an activity after
185 // the user switches to home. We know it is safe to do at this
186 // point, so make sure new activity switches are now allowed.
187 ActivityManagerNative.getDefault().resumeAppSwitches();
188 // Also, notifications can be launched from the lock screen,
189 // so dismiss the lock screen when the activity starts.
190 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
191 } catch (RemoteException e) {
192 }
193 }
194
195 boolean handled = super.onClickHandler(view, pendingIntent, fillInIntent);
196
197 if (isActivity && handled) {
198 // close the shade if it was open
Daniel Sandler11cf1782012-09-27 14:03:08 -0400199 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
Dianne Hackborn1927ae82012-06-22 15:21:36 -0700200 visibilityChanged(false);
201 }
202 return handled;
203 }
204 };
205
John Spurlock5c454122013-06-17 07:35:46 -0400206 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
207 @Override
208 public void onReceive(Context context, Intent intent) {
209 String action = intent.getAction();
210 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
211 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
212 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
213 userSwitched(mCurrentUserId);
214 }
215 }
216 };
217
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400218 public void start() {
Jeff Brown98365d72012-08-19 20:30:52 -0700219 mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
220 mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
221 mDisplay = mWindowManager.getDefaultDisplay();
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500222
Chris Wren157026f2013-06-28 16:54:01 -0400223 mDreamManager = IDreamManager.Stub.asInterface(
224 ServiceManager.checkService(DreamService.DREAM_SERVICE));
Chris Wren157026f2013-06-28 16:54:01 -0400225 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
226
Daniel Sandler26cda272012-05-22 15:44:08 -0400227 mProvisioningObserver.onChange(false); // set up
228 mContext.getContentResolver().registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700229 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
Daniel Sandler26cda272012-05-22 15:44:08 -0400230 mProvisioningObserver);
231
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500232 mBarService = IStatusBarService.Stub.asInterface(
233 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400234
John Spurlockd08de372013-06-24 13:06:08 -0400235 mRecents = getComponent(RecentsComponent.class);
236
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700237 mLocale = mContext.getResources().getConfiguration().locale;
238 mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
239
Joe Onorato2314aab2010-04-08 16:41:23 -0500240 // Connect in to the status bar manager service
Joe Onorato0cbda992010-05-02 16:28:15 -0700241 StatusBarIconList iconList = new StatusBarIconList();
Joe Onorato75199e32010-05-29 17:22:51 -0400242 ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();
243 ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
Joe Onorato66d7d012010-05-14 10:05:10 -0700244 mCommandQueue = new CommandQueue(this, iconList);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400245
Jeff Brown2992ea72011-01-28 22:04:14 -0800246 int[] switches = new int[7];
satokcd7cd292010-11-20 15:46:23 +0900247 ArrayList<IBinder> binders = new ArrayList<IBinder>();
Joe Onorato2314aab2010-04-08 16:41:23 -0500248 try {
Joe Onorato93056472010-09-10 10:30:46 -0400249 mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
satokcd7cd292010-11-20 15:46:23 +0900250 switches, binders);
Joe Onorato2314aab2010-04-08 16:41:23 -0500251 } catch (RemoteException ex) {
252 // If the system process isn't there we're doomed anyway.
253 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400254
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500255 createAndAddWindows();
Joe Onorato0cbda992010-05-02 16:28:15 -0700256
Joe Onoratoe4c7b3f2010-10-30 12:15:03 -0700257 disable(switches[0]);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700258 setSystemUiVisibility(switches[1], 0xffffffff);
Dianne Hackborn7d049322011-06-14 15:00:32 -0700259 topAppWindowChanged(switches[2] != 0);
satokcd7cd292010-11-20 15:46:23 +0900260 // StatusBarManagerService has a back up of IME token and it's restored here.
Joe Onorato857fd9b2011-01-27 15:08:35 -0800261 setImeWindowStatus(binders.get(0), switches[3], switches[4]);
Jeff Brown2992ea72011-01-28 22:04:14 -0800262 setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);
Joe Onorato93056472010-09-10 10:30:46 -0400263
Joe Onorato0cbda992010-05-02 16:28:15 -0700264 // Set up the initial icon state
Joe Onorato75199e32010-05-29 17:22:51 -0400265 int N = iconList.size();
Joe Onorato0cbda992010-05-02 16:28:15 -0700266 int viewIndex = 0;
267 for (int i=0; i<N; i++) {
268 StatusBarIcon icon = iconList.getIcon(i);
269 if (icon != null) {
270 addIcon(iconList.getSlot(i), i, viewIndex, icon);
271 viewIndex++;
272 }
273 }
274
Joe Onorato75199e32010-05-29 17:22:51 -0400275 // Set up the initial notification state
276 N = notificationKeys.size();
Joe Onorato75199e32010-05-29 17:22:51 -0400277 if (N == notifications.size()) {
278 for (int i=0; i<N; i++) {
279 addNotification(notificationKeys.get(i), notifications.get(i));
280 }
281 } else {
282 Log.wtf(TAG, "Notification list length mismatch: keys=" + N
283 + " notifications=" + notifications.size());
284 }
285
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500286 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400287 Log.d(TAG, String.format(
Daniel Sandler6a858c32012-03-12 14:38:58 -0400288 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500289 iconList.size(),
290 switches[0],
291 switches[1],
292 switches[2],
293 switches[3]
294 ));
Joe Onorato1c95ecb2010-06-28 17:19:12 -0400295 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400296
Christopher Tate5e08af02012-09-21 17:17:22 -0700297 mCurrentUserId = ActivityManager.getCurrentUser();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400298
299 IntentFilter filter = new IntentFilter();
300 filter.addAction(Intent.ACTION_USER_SWITCHED);
John Spurlock5c454122013-06-17 07:35:46 -0400301 mContext.registerReceiver(mBroadcastReceiver, filter);
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400302 }
303
304 public void userSwitched(int newUserId) {
305 // should be overridden
306 }
307
308 public boolean notificationIsForCurrentUser(StatusBarNotification n) {
309 final int thisUserId = mCurrentUserId;
310 final int notificationUserId = n.getUserId();
311 if (DEBUG && MULTIUSER_DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400312 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400313 n, thisUserId, notificationUserId));
314 }
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700315 return notificationUserId == UserHandle.USER_ALL
316 || thisUserId == notificationUserId;
Joe Onorato2314aab2010-04-08 16:41:23 -0500317 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400318
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700319 @Override
320 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler777dcde2013-09-30 10:21:45 -0400321 final Locale locale = mContext.getResources().getConfiguration().locale;
322 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
323 if (! locale.equals(mLocale) || ld != mLayoutDirection) {
324 if (DEBUG) {
325 Log.v(TAG, String.format(
326 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
327 locale, ld));
328 }
329 mLocale = locale;
330 mLayoutDirection = ld;
331 refreshLayout(ld);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700332 }
333 }
334
Winson Chungc57ccf02011-10-13 15:04:59 -0700335 protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
336 View vetoButton = row.findViewById(R.id.veto);
Chris Wren6d15a362013-08-20 18:46:29 -0400337 if (n.isClearable() || (mInterruptingNotificationEntry != null
338 && mInterruptingNotificationEntry.row == row)) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400339 final String _pkg = n.getPackageName();
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400340 final String _tag = n.getTag();
341 final int _id = n.getId();
Winson Chungc57ccf02011-10-13 15:04:59 -0700342 vetoButton.setOnClickListener(new View.OnClickListener() {
343 public void onClick(View v) {
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700344 // Accessibility feedback
345 v.announceForAccessibility(
346 mContext.getString(R.string.accessibility_notification_dismissed));
Winson Chungc57ccf02011-10-13 15:04:59 -0700347 try {
348 mBarService.onNotificationClear(_pkg, _tag, _id);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700349
Winson Chungc57ccf02011-10-13 15:04:59 -0700350 } catch (RemoteException ex) {
351 // system process is dead if we're here.
352 }
353 }
354 });
355 vetoButton.setVisibility(View.VISIBLE);
356 } else {
357 vetoButton.setVisibility(View.GONE);
358 }
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700359 vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
Winson Chungc57ccf02011-10-13 15:04:59 -0700360 return vetoButton;
361 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400362
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400363
364 protected void applyLegacyRowBackground(StatusBarNotification sbn, View content) {
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400365 if (sbn.getNotification().contentView.getLayoutId() !=
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400366 com.android.internal.R.layout.notification_template_base) {
367 int version = 0;
368 try {
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400369 ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.getPackageName(), 0);
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400370 version = info.targetSdkVersion;
371 } catch (NameNotFoundException ex) {
John Spurlockcd686b52013-06-05 10:13:46 -0400372 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400373 }
374 if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
375 content.setBackgroundResource(R.drawable.notification_row_legacy_bg);
376 } else {
Chris Wrend84e5932012-04-19 17:58:03 -0400377 content.setBackgroundResource(com.android.internal.R.drawable.notification_bg);
Daniel Sandler96fd7c12012-03-30 16:37:36 -0400378 }
379 }
380 }
381
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400382 private void startApplicationDetailsActivity(String packageName) {
383 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
384 Uri.fromParts("package", packageName, null));
Adam Powell0fc5b2b2012-07-18 18:20:29 -0700385 intent.setComponent(intent.resolveActivity(mContext.getPackageManager()));
Amith Yamasaniea7e9152012-09-24 16:11:18 -0700386 TaskStackBuilder.create(mContext).addNextIntentWithParentStack(intent).startActivities(
387 null, UserHandle.CURRENT);
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400388 }
389
Jim Miller9a720f52012-05-30 03:19:43 -0700390 protected View.OnLongClickListener getNotificationLongClicker() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400391 return new View.OnLongClickListener() {
392 @Override
393 public boolean onLongClick(View v) {
394 final String packageNameF = (String) v.getTag();
395 if (packageNameF == null) return false;
Jeff Sharkeyaf232ed2012-04-30 15:19:39 -0700396 if (v.getWindowToken() == null) return false;
Daniel Sandler469e96e2012-05-04 15:56:19 -0400397 mNotificationBlamePopup = new PopupMenu(mContext, v);
398 mNotificationBlamePopup.getMenuInflater().inflate(
399 R.menu.notification_popup_menu,
400 mNotificationBlamePopup.getMenu());
401 mNotificationBlamePopup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400402 public boolean onMenuItemClick(MenuItem item) {
403 if (item.getItemId() == R.id.notification_inspect_item) {
404 startApplicationDetailsActivity(packageNameF);
Daniel Sandler11cf1782012-09-27 14:03:08 -0400405 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400406 } else {
407 return false;
408 }
409 return true;
410 }
411 });
Daniel Sandler469e96e2012-05-04 15:56:19 -0400412 mNotificationBlamePopup.show();
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400413
414 return true;
415 }
416 };
417 }
418
Daniel Sandler469e96e2012-05-04 15:56:19 -0400419 public void dismissPopups() {
420 if (mNotificationBlamePopup != null) {
421 mNotificationBlamePopup.dismiss();
422 mNotificationBlamePopup = null;
423 }
424 }
425
Chris Wren51c75102013-07-16 20:49:17 -0400426 public void onHeadsUpDismissed() {
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400427 }
Michael Jurka7f2668c2012-03-27 07:49:52 -0700428
429 @Override
430 public void toggleRecentApps() {
Michael Jurkacb2522c2012-04-13 09:32:47 -0700431 int msg = MSG_TOGGLE_RECENTS_PANEL;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700432 mHandler.removeMessages(msg);
433 mHandler.sendEmptyMessage(msg);
434 }
435
436 @Override
437 public void preloadRecentApps() {
438 int msg = MSG_PRELOAD_RECENT_APPS;
439 mHandler.removeMessages(msg);
440 mHandler.sendEmptyMessage(msg);
441 }
442
443 @Override
444 public void cancelPreloadRecentApps() {
445 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
446 mHandler.removeMessages(msg);
447 mHandler.sendEmptyMessage(msg);
448 }
449
450 @Override
Jim Millere898ac52012-04-06 17:10:57 -0700451 public void showSearchPanel() {
452 int msg = MSG_OPEN_SEARCH_PANEL;
453 mHandler.removeMessages(msg);
454 mHandler.sendEmptyMessage(msg);
455 }
456
457 @Override
458 public void hideSearchPanel() {
459 int msg = MSG_CLOSE_SEARCH_PANEL;
460 mHandler.removeMessages(msg);
461 mHandler.sendEmptyMessage(msg);
462 }
463
Jim Millere898ac52012-04-06 17:10:57 -0700464 protected abstract WindowManager.LayoutParams getSearchLayoutParams(
465 LayoutParams layoutParams);
466
Jim Millere898ac52012-04-06 17:10:57 -0700467 protected void updateSearchPanel() {
468 // Search Panel
469 boolean visible = false;
470 if (mSearchPanelView != null) {
471 visible = mSearchPanelView.isShowing();
Jeff Brown98365d72012-08-19 20:30:52 -0700472 mWindowManager.removeView(mSearchPanelView);
Jim Millere898ac52012-04-06 17:10:57 -0700473 }
474
475 // Provide SearchPanel with a temporary parent to allow layout params to work.
476 LinearLayout tmpRoot = new LinearLayout(mContext);
477 mSearchPanelView = (SearchPanelView) LayoutInflater.from(mContext).inflate(
478 R.layout.status_bar_search_panel, tmpRoot, false);
479 mSearchPanelView.setOnTouchListener(
480 new TouchOutsideListener(MSG_CLOSE_SEARCH_PANEL, mSearchPanelView));
481 mSearchPanelView.setVisibility(View.GONE);
482
483 WindowManager.LayoutParams lp = getSearchLayoutParams(mSearchPanelView.getLayoutParams());
484
Jeff Brown98365d72012-08-19 20:30:52 -0700485 mWindowManager.addView(mSearchPanelView, lp);
Jim Millere898ac52012-04-06 17:10:57 -0700486 mSearchPanelView.setBar(this);
487 if (visible) {
488 mSearchPanelView.show(true, false);
489 }
490 }
491
Michael Jurkaecc395a2012-03-30 05:31:46 -0700492 protected H createHandler() {
Michael Jurka7f2668c2012-03-27 07:49:52 -0700493 return new H();
494 }
495
Michael Jurka56a57832012-05-14 13:24:43 -0700496 static void sendCloseSystemWindows(Context context, String reason) {
497 if (ActivityManagerNative.isSystemReady()) {
498 try {
499 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
500 } catch (RemoteException e) {
501 }
502 }
503 }
504
Michael Jurkacb2522c2012-04-13 09:32:47 -0700505 protected abstract View getStatusBarView();
506
Michael Jurka80343f62012-10-18 13:13:46 +0200507 protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
508 // additional optimization when we have software system buttons - start loading the recent
509 // tasks on touch down
510 @Override
511 public boolean onTouch(View v, MotionEvent event) {
512 int action = event.getAction() & MotionEvent.ACTION_MASK;
513 if (action == MotionEvent.ACTION_DOWN) {
514 preloadRecentTasksList();
515 } else if (action == MotionEvent.ACTION_CANCEL) {
516 cancelPreloadingRecentTasksList();
517 } else if (action == MotionEvent.ACTION_UP) {
518 if (!v.isPressed()) {
519 cancelPreloadingRecentTasksList();
520 }
521
522 }
523 return false;
524 }
525 };
526
John Spurlockd08de372013-06-24 13:06:08 -0400527 protected void toggleRecentsActivity() {
528 if (mRecents != null) {
529 mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
530 }
531 }
Michael Jurka80343f62012-10-18 13:13:46 +0200532
John Spurlockd08de372013-06-24 13:06:08 -0400533 protected void preloadRecentTasksList() {
534 if (mRecents != null) {
535 mRecents.preloadRecentTasksList();
536 }
Michael Jurka80343f62012-10-18 13:13:46 +0200537 }
538
539 protected void cancelPreloadingRecentTasksList() {
John Spurlockd08de372013-06-24 13:06:08 -0400540 if (mRecents != null) {
541 mRecents.cancelPreloadingRecentTasksList();
542 }
543 }
Michael Jurka80343f62012-10-18 13:13:46 +0200544
John Spurlockd08de372013-06-24 13:06:08 -0400545 protected void closeRecents() {
546 if (mRecents != null) {
547 mRecents.closeRecents();
548 }
Michael Jurka80343f62012-10-18 13:13:46 +0200549 }
550
Chris Wren51c75102013-07-16 20:49:17 -0400551 public abstract void resetHeadsUpDecayTimer();
552
Dan Sandlera5e0f412014-01-23 15:11:54 -0500553 public void setPublicMode(boolean publicMode) {
554 mPublicMode = publicMode;
555 }
556
557 public boolean isPublicMode() {
558 return mPublicMode;
559 }
560
Michael Jurka7f2668c2012-03-27 07:49:52 -0700561 protected class H extends Handler {
562 public void handleMessage(Message m) {
Michael Jurka80343f62012-10-18 13:13:46 +0200563 Intent intent;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700564 switch (m.what) {
Michael Jurkacb2522c2012-04-13 09:32:47 -0700565 case MSG_TOGGLE_RECENTS_PANEL:
Michael Jurkacb2522c2012-04-13 09:32:47 -0700566 toggleRecentsActivity();
567 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700568 case MSG_CLOSE_RECENTS_PANEL:
John Spurlockd08de372013-06-24 13:06:08 -0400569 closeRecents();
Michael Jurkacb2522c2012-04-13 09:32:47 -0700570 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700571 case MSG_PRELOAD_RECENT_APPS:
Michael Jurka80343f62012-10-18 13:13:46 +0200572 preloadRecentTasksList();
Michael Jurka7f2668c2012-03-27 07:49:52 -0700573 break;
574 case MSG_CANCEL_PRELOAD_RECENT_APPS:
Michael Jurka80343f62012-10-18 13:13:46 +0200575 cancelPreloadingRecentTasksList();
Michael Jurka7f2668c2012-03-27 07:49:52 -0700576 break;
Jim Millere898ac52012-04-06 17:10:57 -0700577 case MSG_OPEN_SEARCH_PANEL:
John Spurlockcd686b52013-06-05 10:13:46 -0400578 if (DEBUG) Log.d(TAG, "opening search panel");
Jim Miller07994402012-05-02 14:22:27 -0700579 if (mSearchPanelView != null && mSearchPanelView.isAssistantAvailable()) {
Jim Millere898ac52012-04-06 17:10:57 -0700580 mSearchPanelView.show(true, true);
Jim Millerad178a42013-10-08 20:03:38 -0700581 onShowSearchPanel();
Jim Millere898ac52012-04-06 17:10:57 -0700582 }
583 break;
584 case MSG_CLOSE_SEARCH_PANEL:
John Spurlockcd686b52013-06-05 10:13:46 -0400585 if (DEBUG) Log.d(TAG, "closing search panel");
Jim Millere898ac52012-04-06 17:10:57 -0700586 if (mSearchPanelView != null && mSearchPanelView.isShowing()) {
587 mSearchPanelView.show(false, true);
Jim Millerad178a42013-10-08 20:03:38 -0700588 onHideSearchPanel();
Jim Millere898ac52012-04-06 17:10:57 -0700589 }
590 break;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700591 }
592 }
593 }
594
595 public class TouchOutsideListener implements View.OnTouchListener {
596 private int mMsg;
597 private StatusBarPanel mPanel;
598
599 public TouchOutsideListener(int msg, StatusBarPanel panel) {
600 mMsg = msg;
601 mPanel = panel;
602 }
603
604 public boolean onTouch(View v, MotionEvent ev) {
605 final int action = ev.getAction();
606 if (action == MotionEvent.ACTION_OUTSIDE
607 || (action == MotionEvent.ACTION_DOWN
608 && !mPanel.isInContentArea((int)ev.getX(), (int)ev.getY()))) {
609 mHandler.removeMessages(mMsg);
610 mHandler.sendEmptyMessage(mMsg);
611 return true;
612 }
613 return false;
614 }
615 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400616
617 protected void workAroundBadLayerDrawableOpacity(View v) {
618 }
619
Jim Millerad178a42013-10-08 20:03:38 -0700620 protected void onHideSearchPanel() {
621 }
622
623 protected void onShowSearchPanel() {
624 }
625
Chris Wren51c75102013-07-16 20:49:17 -0400626 public boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400627 int minHeight =
628 mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
629 int maxHeight =
630 mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height);
631 StatusBarNotification sbn = entry.notification;
Chris Wren574a55e2013-07-15 18:48:37 -0400632 RemoteViews contentView = sbn.getNotification().contentView;
633 RemoteViews bigContentView = sbn.getNotification().bigContentView;
634 if (contentView == null) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400635 return false;
636 }
637
Dan Sandlera5e0f412014-01-23 15:11:54 -0500638 Log.v(TAG, "publicNotification: "
639 + sbn.getNotification().publicVersion);
640
641 Notification publicNotification = sbn.getNotification().publicVersion;
642
Daniel Sandler6a858c32012-03-12 14:38:58 -0400643 // create the row view
644 LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
645 Context.LAYOUT_INFLATER_SERVICE);
Chris Wren51c75102013-07-16 20:49:17 -0400646 ExpandableNotificationRow row = (ExpandableNotificationRow) inflater.inflate(
647 R.layout.status_bar_notification_row, parent, false);
Daniel Sandlerbc5559f2012-04-19 01:08:15 -0400648
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400649 // for blaming (see SwipeHelper.setLongPressListener)
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400650 row.setTag(sbn.getPackageName());
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400651
Daniel Sandler6a858c32012-03-12 14:38:58 -0400652 workAroundBadLayerDrawableOpacity(row);
653 View vetoButton = updateNotificationVetoButton(row, sbn);
654 vetoButton.setContentDescription(mContext.getString(
655 R.string.accessibility_remove_notification));
656
657 // NB: the large icon is now handled entirely by the template
658
659 // bind the click event to the content area
Dan Sandlera5e0f412014-01-23 15:11:54 -0500660 ViewGroup content = (ViewGroup)row.findViewById(R.id.container);
661 SizeAdaptiveLayout expanded = (SizeAdaptiveLayout)row.findViewById(R.id.expanded);
662 SizeAdaptiveLayout expandedPublic
663 = (SizeAdaptiveLayout)row.findViewById(R.id.expandedPublic);
Daniel Sandlerbc5559f2012-04-19 01:08:15 -0400664
Daniel Sandler6a858c32012-03-12 14:38:58 -0400665 content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
Daniel Sandlerbc5559f2012-04-19 01:08:15 -0400666
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400667 PendingIntent contentIntent = sbn.getNotification().contentIntent;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400668 if (contentIntent != null) {
669 final View.OnClickListener listener = new NotificationClicker(contentIntent,
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400670 sbn.getPackageName(), sbn.getTag(), sbn.getId());
Daniel Sandler6a858c32012-03-12 14:38:58 -0400671 content.setOnClickListener(listener);
672 } else {
673 content.setOnClickListener(null);
674 }
675
Dan Sandlera5e0f412014-01-23 15:11:54 -0500676 // set up the adaptive layout
Chris Wren574a55e2013-07-15 18:48:37 -0400677 View contentViewLocal = null;
678 View bigContentViewLocal = null;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400679 try {
Dan Sandlera5e0f412014-01-23 15:11:54 -0500680 contentViewLocal = contentView.apply(mContext, expanded, mOnClickHandler);
Chris Wren574a55e2013-07-15 18:48:37 -0400681 if (bigContentView != null) {
Dan Sandlera5e0f412014-01-23 15:11:54 -0500682 bigContentViewLocal = bigContentView.apply(mContext, expanded, mOnClickHandler);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400683 }
684 }
685 catch (RuntimeException e) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400686 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
John Spurlockcd686b52013-06-05 10:13:46 -0400687 Log.e(TAG, "couldn't inflate view for notification " + ident, e);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400688 return false;
Daniel Sandler6a858c32012-03-12 14:38:58 -0400689 }
690
Chris Wren574a55e2013-07-15 18:48:37 -0400691 if (contentViewLocal != null) {
Daniel Sandler8680bf82012-05-15 16:52:52 -0400692 SizeAdaptiveLayout.LayoutParams params =
Chris Wren574a55e2013-07-15 18:48:37 -0400693 new SizeAdaptiveLayout.LayoutParams(contentViewLocal.getLayoutParams());
Chris Wrened5cc0e2012-06-21 11:25:58 -0400694 params.minHeight = minHeight;
695 params.maxHeight = minHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500696 expanded.addView(contentViewLocal, params);
Daniel Sandler8680bf82012-05-15 16:52:52 -0400697 }
Chris Wren574a55e2013-07-15 18:48:37 -0400698 if (bigContentViewLocal != null) {
Daniel Sandler8680bf82012-05-15 16:52:52 -0400699 SizeAdaptiveLayout.LayoutParams params =
Chris Wren574a55e2013-07-15 18:48:37 -0400700 new SizeAdaptiveLayout.LayoutParams(bigContentViewLocal.getLayoutParams());
Chris Wrened5cc0e2012-06-21 11:25:58 -0400701 params.minHeight = minHeight+1;
Daniel Sandler8680bf82012-05-15 16:52:52 -0400702 params.maxHeight = maxHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500703 expanded.addView(bigContentViewLocal, params);
Daniel Sandler8680bf82012-05-15 16:52:52 -0400704 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500705
706 PackageManager pm = mContext.getPackageManager();
707
708 // now the public version
709 View publicViewLocal = null;
710 if (publicNotification != null) {
711 try {
712 publicViewLocal = publicNotification.contentView.apply(mContext,
713 expandedPublic, mOnClickHandler);
714
715 if (publicViewLocal != null) {
716 SizeAdaptiveLayout.LayoutParams params =
717 new SizeAdaptiveLayout.LayoutParams(publicViewLocal.getLayoutParams());
718 params.minHeight = minHeight;
719 params.maxHeight = minHeight;
720 expandedPublic.addView(publicViewLocal, params);
721 }
722 }
723 catch (RuntimeException e) {
724 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
725 Log.e(TAG, "couldn't inflate public view for notification " + ident, e);
726 publicViewLocal = null;
727 }
728 }
729
730 if (publicViewLocal == null) {
731 // Add a basic notification template
732 publicViewLocal = LayoutInflater.from(mContext).inflate(
733 com.android.internal.R.layout.notification_template_base, expandedPublic, true);
734
735 final TextView title = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.title);
736 try {
737 title.setText(pm.getApplicationLabel(
738 pm.getApplicationInfo(entry.notification.getPackageName(), 0)));
739 } catch (NameNotFoundException e) {
740 title.setText(entry.notification.getPackageName());
741 }
742
743 final ImageView icon = (ImageView) publicViewLocal.findViewById(com.android.internal.R.id.icon);
744
745 final StatusBarIcon ic = new StatusBarIcon(entry.notification.getPackageName(),
746 entry.notification.getUser(),
747 entry.notification.getNotification().icon,
748 entry.notification.getNotification().iconLevel,
749 entry.notification.getNotification().number,
750 entry.notification.getNotification().tickerText);
751
752 icon.setImageDrawable(StatusBarIconView.getIcon(mContext, ic));
753
754 final TextView text = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.text);
755 text.setText("Unlock your device to see this notification.");
756
757 // TODO: fill out "time" as well
758 }
759
Daniel Sandler8680bf82012-05-15 16:52:52 -0400760 row.setDrawingCacheEnabled(true);
761
Daniel Sandler6a858c32012-03-12 14:38:58 -0400762 applyLegacyRowBackground(sbn, content);
763
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400764 if (MULTIUSER_DEBUG) {
765 TextView debug = (TextView) row.findViewById(R.id.debug_info);
766 if (debug != null) {
767 debug.setVisibility(View.VISIBLE);
768 debug.setText("U " + entry.notification.getUserId());
769 }
770 }
Daniel Sandler6a858c32012-03-12 14:38:58 -0400771 entry.row = row;
Chris Wren51c75102013-07-16 20:49:17 -0400772 entry.row.setRowHeight(mRowHeight);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400773 entry.content = content;
Chris Wren574a55e2013-07-15 18:48:37 -0400774 entry.expanded = contentViewLocal;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500775 entry.expandedPublic = publicViewLocal;
Chris Wren574a55e2013-07-15 18:48:37 -0400776 entry.setBigContentView(bigContentViewLocal);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400777
778 return true;
779 }
780
781 public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) {
782 return new NotificationClicker(intent, pkg, tag, id);
783 }
784
Chris Wren157026f2013-06-28 16:54:01 -0400785 protected class NotificationClicker implements View.OnClickListener {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400786 private PendingIntent mIntent;
787 private String mPkg;
788 private String mTag;
789 private int mId;
790
Chris Wren157026f2013-06-28 16:54:01 -0400791 public NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400792 mIntent = intent;
793 mPkg = pkg;
794 mTag = tag;
795 mId = id;
796 }
797
798 public void onClick(View v) {
799 try {
800 // The intent we are sending is for the application, which
801 // won't have permission to immediately start an activity after
802 // the user switches to home. We know it is safe to do at this
803 // point, so make sure new activity switches are now allowed.
804 ActivityManagerNative.getDefault().resumeAppSwitches();
805 // Also, notifications can be launched from the lock screen,
806 // so dismiss the lock screen when the activity starts.
807 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
808 } catch (RemoteException e) {
809 }
810
811 if (mIntent != null) {
812 int[] pos = new int[2];
813 v.getLocationOnScreen(pos);
814 Intent overlay = new Intent();
815 overlay.setSourceBounds(
816 new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
817 try {
818 mIntent.send(mContext, 0, overlay);
819 } catch (PendingIntent.CanceledException e) {
820 // the stack trace isn't very helpful here. Just log the exception message.
John Spurlockcd686b52013-06-05 10:13:46 -0400821 Log.w(TAG, "Sending contentIntent failed: " + e);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400822 }
823
Jim Millera999d462013-10-30 13:58:11 -0700824 KeyguardTouchDelegate.getInstance(mContext).dismiss();
Daniel Sandler6a858c32012-03-12 14:38:58 -0400825 }
826
827 try {
828 mBarService.onNotificationClick(mPkg, mTag, mId);
829 } catch (RemoteException ex) {
830 // system process is dead if we're here.
831 }
832
833 // close the shade if it was open
Daniel Sandler11cf1782012-09-27 14:03:08 -0400834 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400835 visibilityChanged(false);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400836 }
837 }
838 /**
839 * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
840 * This was added last-minute and is inconsistent with the way the rest of the notifications
841 * are handled, because the notification isn't really cancelled. The lights are just
842 * turned off. If any other notifications happen, the lights will turn back on. Steve says
843 * this is what he wants. (see bug 1131461)
844 */
845 protected void visibilityChanged(boolean visible) {
846 if (mPanelSlightlyVisible != visible) {
847 mPanelSlightlyVisible = visible;
848 try {
849 mBarService.onPanelRevealed();
850 } catch (RemoteException ex) {
851 // Won't fail unless the world has ended.
852 }
853 }
854 }
855
Chris Wren0c8275b2012-05-08 13:36:48 -0400856 /**
857 * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
858 * about the failure.
859 *
860 * WARNING: this will call back into us. Don't hold any locks.
861 */
862 void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
863 removeNotification(key);
864 try {
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400865 mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(), n.getInitialPid(), message);
Chris Wren0c8275b2012-05-08 13:36:48 -0400866 } catch (RemoteException ex) {
867 // The end is nigh.
868 }
869 }
870
871 protected StatusBarNotification removeNotificationViews(IBinder key) {
872 NotificationData.Entry entry = mNotificationData.remove(key);
873 if (entry == null) {
John Spurlockcd686b52013-06-05 10:13:46 -0400874 Log.w(TAG, "removeNotification for unknown key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -0400875 return null;
876 }
877 // Remove the expanded view.
878 ViewGroup rowParent = (ViewGroup)entry.row.getParent();
879 if (rowParent != null) rowParent.removeView(entry.row);
Chris Wren8fd12652012-05-09 21:25:57 -0400880 updateExpansionStates();
Chris Wren0c8275b2012-05-08 13:36:48 -0400881 updateNotificationIcons();
882
883 return entry.notification;
884 }
885
Chris Wrenf0048ce2013-08-07 16:43:43 -0400886 protected NotificationData.Entry createNotificationViews(IBinder key,
Chris Wren0c8275b2012-05-08 13:36:48 -0400887 StatusBarNotification notification) {
888 if (DEBUG) {
Chris Wrenf0048ce2013-08-07 16:43:43 -0400889 Log.d(TAG, "createNotificationViews(key=" + key + ", notification=" + notification);
Chris Wren0c8275b2012-05-08 13:36:48 -0400890 }
891 // Construct the icon.
892 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400893 notification.getPackageName() + "/0x" + Integer.toHexString(notification.getId()),
John Spurlocke6f0a712013-09-03 16:23:49 -0400894 notification.getNotification());
Chris Wren0c8275b2012-05-08 13:36:48 -0400895 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
896
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400897 final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400898 notification.getUser(),
899 notification.getNotification().icon,
900 notification.getNotification().iconLevel,
901 notification.getNotification().number,
902 notification.getNotification().tickerText);
Chris Wren0c8275b2012-05-08 13:36:48 -0400903 if (!iconView.set(ic)) {
904 handleNotificationError(key, notification, "Couldn't create icon: " + ic);
905 return null;
906 }
907 // Construct the expanded view.
908 NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
909 if (!inflateViews(entry, mPile)) {
910 handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
911 + notification);
912 return null;
913 }
Chris Wrenf0048ce2013-08-07 16:43:43 -0400914 return entry;
915 }
Chris Wren0c8275b2012-05-08 13:36:48 -0400916
Chris Wrenf0048ce2013-08-07 16:43:43 -0400917 protected void addNotificationViews(NotificationData.Entry entry) {
Chris Wren0c8275b2012-05-08 13:36:48 -0400918 // Add the expanded view and icon.
919 int pos = mNotificationData.add(entry);
920 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400921 Log.d(TAG, "addNotificationViews: added at " + pos);
Chris Wren0c8275b2012-05-08 13:36:48 -0400922 }
Chris Wren8fd12652012-05-09 21:25:57 -0400923 updateExpansionStates();
Chris Wren0c8275b2012-05-08 13:36:48 -0400924 updateNotificationIcons();
Chris Wrenf0048ce2013-08-07 16:43:43 -0400925 }
Chris Wren0c8275b2012-05-08 13:36:48 -0400926
Chris Wrenf0048ce2013-08-07 16:43:43 -0400927 private void addNotificationViews(IBinder key, StatusBarNotification notification) {
928 addNotificationViews(createNotificationViews(key, notification));
Chris Wren0c8275b2012-05-08 13:36:48 -0400929 }
930
Chris Wren8fd12652012-05-09 21:25:57 -0400931 protected void updateExpansionStates() {
932 int N = mNotificationData.size();
933 for (int i = 0; i < N; i++) {
934 NotificationData.Entry entry = mNotificationData.get(i);
Chris Wren51c75102013-07-16 20:49:17 -0400935 if (!entry.row.isUserLocked()) {
Chris Wren3ddab0d2012-08-02 16:52:21 -0400936 if (i == (N-1)) {
John Spurlockcd686b52013-06-05 10:13:46 -0400937 if (DEBUG) Log.d(TAG, "expanding top notification at " + i);
Chris Wren51c75102013-07-16 20:49:17 -0400938 entry.row.setExpanded(true);
Chris Wren8fd12652012-05-09 21:25:57 -0400939 } else {
Chris Wren51c75102013-07-16 20:49:17 -0400940 if (!entry.row.isUserExpanded()) {
John Spurlockcd686b52013-06-05 10:13:46 -0400941 if (DEBUG) Log.d(TAG, "collapsing notification at " + i);
Chris Wren51c75102013-07-16 20:49:17 -0400942 entry.row.setExpanded(false);
Chris Wren3ddab0d2012-08-02 16:52:21 -0400943 } else {
John Spurlockcd686b52013-06-05 10:13:46 -0400944 if (DEBUG) Log.d(TAG, "ignoring user-modified notification at " + i);
Chris Wren3ddab0d2012-08-02 16:52:21 -0400945 }
Chris Wren8fd12652012-05-09 21:25:57 -0400946 }
Chris Wren3ddab0d2012-08-02 16:52:21 -0400947 } else {
John Spurlockcd686b52013-06-05 10:13:46 -0400948 if (DEBUG) Log.d(TAG, "ignoring notification being held by user at " + i);
Chris Wren8fd12652012-05-09 21:25:57 -0400949 }
950 }
951 }
952
Chris Wren0c8275b2012-05-08 13:36:48 -0400953 protected abstract void haltTicker();
954 protected abstract void setAreThereNotifications();
955 protected abstract void updateNotificationIcons();
956 protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
957 protected abstract void updateExpandedViewPos(int expandedPosition);
Chris Wren8fd12652012-05-09 21:25:57 -0400958 protected abstract int getExpandedViewMaxHeight();
Jim Millerb4238e02012-05-14 15:26:20 -0700959 protected abstract boolean shouldDisableNavbarGestures();
Chris Wren0c8275b2012-05-08 13:36:48 -0400960
961 protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
Daniel Sandler26cda272012-05-22 15:44:08 -0400962 return parent != null && parent.indexOfChild(entry.row) == 0;
Chris Wren0c8275b2012-05-08 13:36:48 -0400963 }
964
965 public void updateNotification(IBinder key, StatusBarNotification notification) {
John Spurlockcd686b52013-06-05 10:13:46 -0400966 if (DEBUG) Log.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
Chris Wren0c8275b2012-05-08 13:36:48 -0400967
968 final NotificationData.Entry oldEntry = mNotificationData.findByKey(key);
969 if (oldEntry == null) {
John Spurlockcd686b52013-06-05 10:13:46 -0400970 Log.w(TAG, "updateNotification for unknown key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -0400971 return;
972 }
973
974 final StatusBarNotification oldNotification = oldEntry.notification;
975
976 // XXX: modify when we do something more intelligent with the two content views
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400977 final RemoteViews oldContentView = oldNotification.getNotification().contentView;
978 final RemoteViews contentView = notification.getNotification().contentView;
979 final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView;
980 final RemoteViews bigContentView = notification.getNotification().bigContentView;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500981 final Notification oldPublicNotification = oldNotification.getNotification().publicVersion;
982 final RemoteViews oldPublicContentView = oldPublicNotification != null
983 ? oldPublicNotification.contentView : null;
984 final Notification publicNotification = notification.getNotification().publicVersion;
985 final RemoteViews publicContentView = publicNotification != null
986 ? publicNotification.contentView : null;
Chris Wren0c8275b2012-05-08 13:36:48 -0400987
988 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400989 Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
Chris Wren0c8275b2012-05-08 13:36:48 -0400990 + " ongoing=" + oldNotification.isOngoing()
991 + " expanded=" + oldEntry.expanded
992 + " contentView=" + oldContentView
Chris Wrene9e37722012-05-11 17:40:14 -0400993 + " bigContentView=" + oldBigContentView
Dan Sandlera5e0f412014-01-23 15:11:54 -0500994 + " publicView=" + oldPublicContentView
Chris Wren0c8275b2012-05-08 13:36:48 -0400995 + " rowParent=" + oldEntry.row.getParent());
John Spurlockcd686b52013-06-05 10:13:46 -0400996 Log.d(TAG, "new notification: when=" + notification.getNotification().when
Chris Wren0c8275b2012-05-08 13:36:48 -0400997 + " ongoing=" + oldNotification.isOngoing()
Chris Wrene9e37722012-05-11 17:40:14 -0400998 + " contentView=" + contentView
Dan Sandlera5e0f412014-01-23 15:11:54 -0500999 + " bigContentView=" + bigContentView
1000 + " publicView=" + publicContentView);
Chris Wren0c8275b2012-05-08 13:36:48 -04001001 }
1002
1003 // Can we just reapply the RemoteViews in place? If when didn't change, the order
1004 // didn't change.
Chris Wrene9e37722012-05-11 17:40:14 -04001005
1006 // 1U is never null
Chris Wren0c8275b2012-05-08 13:36:48 -04001007 boolean contentsUnchanged = oldEntry.expanded != null
Chris Wren0c8275b2012-05-08 13:36:48 -04001008 && contentView.getPackage() != null
1009 && oldContentView.getPackage() != null
1010 && oldContentView.getPackage().equals(contentView.getPackage())
1011 && oldContentView.getLayoutId() == contentView.getLayoutId();
Chris Wrene9e37722012-05-11 17:40:14 -04001012 // large view may be null
1013 boolean bigContentsUnchanged =
Chris Wren574a55e2013-07-15 18:48:37 -04001014 (oldEntry.getBigContentView() == null && bigContentView == null)
1015 || ((oldEntry.getBigContentView() != null && bigContentView != null)
Chris Wrene9e37722012-05-11 17:40:14 -04001016 && bigContentView.getPackage() != null
1017 && oldBigContentView.getPackage() != null
1018 && oldBigContentView.getPackage().equals(bigContentView.getPackage())
1019 && oldBigContentView.getLayoutId() == bigContentView.getLayoutId());
Dan Sandlera5e0f412014-01-23 15:11:54 -05001020 boolean publicUnchanged =
1021 (oldPublicContentView == null && publicContentView == null)
1022 || ((oldPublicContentView != null && publicContentView != null)
1023 && publicContentView.getPackage() != null
1024 && oldPublicContentView.getPackage() != null
1025 && oldPublicContentView.getPackage().equals(publicContentView.getPackage())
1026 && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
1027
Chris Wren0c8275b2012-05-08 13:36:48 -04001028 ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
Dan Sandlera5e0f412014-01-23 15:11:54 -05001029 boolean orderUnchanged =
1030 notification.getNotification().when == oldNotification.getNotification().when
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001031 && notification.getScore() == oldNotification.getScore();
Chris Wren0c8275b2012-05-08 13:36:48 -04001032 // score now encompasses/supersedes isOngoing()
1033
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001034 boolean updateTicker = notification.getNotification().tickerText != null
1035 && !TextUtils.equals(notification.getNotification().tickerText,
1036 oldEntry.notification.getNotification().tickerText);
Chris Wren0c8275b2012-05-08 13:36:48 -04001037 boolean isTopAnyway = isTopNotification(rowParent, oldEntry);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001038 if (contentsUnchanged && bigContentsUnchanged && publicUnchanged
1039 && (orderUnchanged || isTopAnyway)) {
John Spurlockcd686b52013-06-05 10:13:46 -04001040 if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
Chris Wren0c8275b2012-05-08 13:36:48 -04001041 oldEntry.notification = notification;
1042 try {
Chris Wrene03f4e12013-08-08 16:48:48 -04001043 updateNotificationViews(oldEntry, notification);
1044
1045 if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
1046 && oldNotification == mInterruptingNotificationEntry.notification) {
1047 if (!shouldInterrupt(notification)) {
1048 if (DEBUG) Log.d(TAG, "no longer interrupts!");
1049 mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
1050 } else {
1051 if (DEBUG) Log.d(TAG, "updating the current heads up:" + notification);
1052 mInterruptingNotificationEntry.notification = notification;
1053 updateNotificationViews(mInterruptingNotificationEntry, notification);
1054 }
Chris Wrene9e37722012-05-11 17:40:14 -04001055 }
Chris Wrene03f4e12013-08-08 16:48:48 -04001056
Chris Wren0c8275b2012-05-08 13:36:48 -04001057 // Update the icon.
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001058 final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001059 notification.getUser(),
1060 notification.getNotification().icon, notification.getNotification().iconLevel,
1061 notification.getNotification().number,
1062 notification.getNotification().tickerText);
Chris Wren0c8275b2012-05-08 13:36:48 -04001063 if (!oldEntry.icon.set(ic)) {
1064 handleNotificationError(key, notification, "Couldn't update icon: " + ic);
1065 return;
1066 }
Chris Wren8fd12652012-05-09 21:25:57 -04001067 updateExpansionStates();
Chris Wren0c8275b2012-05-08 13:36:48 -04001068 }
1069 catch (RuntimeException e) {
1070 // It failed to add cleanly. Log, and remove the view from the panel.
John Spurlockcd686b52013-06-05 10:13:46 -04001071 Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
Chris Wren0c8275b2012-05-08 13:36:48 -04001072 removeNotificationViews(key);
1073 addNotificationViews(key, notification);
1074 }
1075 } else {
John Spurlockcd686b52013-06-05 10:13:46 -04001076 if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
1077 if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
1078 if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
1079 if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
Chris Wren51c75102013-07-16 20:49:17 -04001080 final boolean wasExpanded = oldEntry.row.isUserExpanded();
Chris Wren0c8275b2012-05-08 13:36:48 -04001081 removeNotificationViews(key);
Chris Wrene03f4e12013-08-08 16:48:48 -04001082 addNotificationViews(key, notification); // will also replace the heads up
Chris Wrenc9433ecb2012-06-27 17:37:03 -04001083 if (wasExpanded) {
1084 final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
Chris Wren51c75102013-07-16 20:49:17 -04001085 newEntry.row.setExpanded(true);
1086 newEntry.row.setUserExpanded(true);
Chris Wrenc9433ecb2012-06-27 17:37:03 -04001087 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001088 }
1089
1090 // Update the veto button accordingly (and as a result, whether this row is
1091 // swipe-dismissable)
1092 updateNotificationVetoButton(oldEntry.row, notification);
1093
John Spurlock61e36832012-09-10 09:43:27 -04001094 // Is this for you?
1095 boolean isForCurrentUser = notificationIsForCurrentUser(notification);
John Spurlockcd686b52013-06-05 10:13:46 -04001096 if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
John Spurlock61e36832012-09-10 09:43:27 -04001097
Chris Wren0c8275b2012-05-08 13:36:48 -04001098 // Restart the ticker if it's still running
John Spurlock61e36832012-09-10 09:43:27 -04001099 if (updateTicker && isForCurrentUser) {
Chris Wren0c8275b2012-05-08 13:36:48 -04001100 haltTicker();
1101 tick(key, notification, false);
1102 }
1103
1104 // Recalculate the position of the sliding windows and the titles.
1105 setAreThereNotifications();
1106 updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
Chris Wrene03f4e12013-08-08 16:48:48 -04001107 }
Chris Wren0c8275b2012-05-08 13:36:48 -04001108
Chris Wrene03f4e12013-08-08 16:48:48 -04001109 private void updateNotificationViews(NotificationData.Entry entry,
1110 StatusBarNotification notification) {
1111 final RemoteViews contentView = notification.getNotification().contentView;
1112 final RemoteViews bigContentView = notification.getNotification().bigContentView;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001113 final RemoteViews publicContentView
1114 = notification.getNotification().publicVersion.contentView;
1115
Chris Wrene03f4e12013-08-08 16:48:48 -04001116 // Reapply the RemoteViews
1117 contentView.reapply(mContext, entry.expanded, mOnClickHandler);
1118 if (bigContentView != null && entry.getBigContentView() != null) {
1119 bigContentView.reapply(mContext, entry.getBigContentView(), mOnClickHandler);
1120 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001121 if (publicContentView != null && entry.getPublicContentView() != null) {
1122 publicContentView.reapply(mContext, entry.getPublicContentView(), mOnClickHandler);
1123 }
Chris Wrene03f4e12013-08-08 16:48:48 -04001124 // update the contentIntent
1125 final PendingIntent contentIntent = notification.getNotification().contentIntent;
1126 if (contentIntent != null) {
1127 final View.OnClickListener listener = makeClicker(contentIntent,
1128 notification.getPackageName(), notification.getTag(), notification.getId());
1129 entry.content.setOnClickListener(listener);
1130 } else {
1131 entry.content.setOnClickListener(null);
Chris Wren0c8275b2012-05-08 13:36:48 -04001132 }
1133 }
John Spurlock36231282012-06-23 17:11:27 -04001134
Chris Wrene97f90b2013-08-07 17:39:35 -04001135 protected void notifyHeadsUpScreenOn(boolean screenOn) {
1136 if (!screenOn && mInterruptingNotificationEntry != null) {
1137 mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
1138 }
1139 }
1140
Chris Wren51c75102013-07-16 20:49:17 -04001141 protected boolean shouldInterrupt(StatusBarNotification sbn) {
1142 Notification notification = sbn.getNotification();
1143 // some predicates to make the boolean logic legible
1144 boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0
1145 || (notification.defaults & Notification.DEFAULT_VIBRATE) != 0
1146 || notification.sound != null
1147 || notification.vibrate != null;
1148 boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD;
1149 boolean isFullscreen = notification.fullScreenIntent != null;
1150 boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP,
1151 Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER;
1152
Jim Millera999d462013-10-30 13:58:11 -07001153 final KeyguardTouchDelegate keyguard = KeyguardTouchDelegate.getInstance(mContext);
Chris Wren51c75102013-07-16 20:49:17 -04001154 boolean interrupt = (isFullscreen || (isHighPriority && isNoisy))
1155 && isAllowed
1156 && mPowerManager.isScreenOn()
Jim Millera999d462013-10-30 13:58:11 -07001157 && !keyguard.isShowingAndNotHidden()
1158 && !keyguard.isInputRestricted();
Chris Wren157026f2013-06-28 16:54:01 -04001159 try {
1160 interrupt = interrupt && !mDreamManager.isDreaming();
1161 } catch (RemoteException e) {
1162 Log.d(TAG, "failed to query dream manager", e);
1163 }
Chris Wren51c75102013-07-16 20:49:17 -04001164 if (DEBUG) Log.d(TAG, "interrupt: " + interrupt);
Chris Wren157026f2013-06-28 16:54:01 -04001165 return interrupt;
1166 }
1167
John Spurlock36231282012-06-23 17:11:27 -04001168 // Q: What kinds of notifications should show during setup?
1169 // A: Almost none! Only things coming from the system (package is "android") that also
1170 // have special "kind" tags marking them as relevant for setup (see below).
1171 protected boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) {
Daniel Sandler4f91efd2013-04-25 16:38:41 -04001172 if ("android".equals(sbn.getPackageName())) {
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001173 if (sbn.getNotification().kind != null) {
1174 for (String aKind : sbn.getNotification().kind) {
John Spurlock36231282012-06-23 17:11:27 -04001175 // IME switcher, created by InputMethodManagerService
1176 if ("android.system.imeswitcher".equals(aKind)) return true;
1177 // OTA availability & errors, created by SystemUpdateService
1178 if ("android.system.update".equals(aKind)) return true;
1179 }
1180 }
1181 }
1182 return false;
1183 }
John Spurlock67ad3682012-06-26 17:42:00 -04001184
1185 public boolean inKeyguardRestrictedInputMode() {
Jim Millera999d462013-10-30 13:58:11 -07001186 return KeyguardTouchDelegate.getInstance(mContext).isInputRestricted();
John Spurlock67ad3682012-06-26 17:42:00 -04001187 }
John Spurlockad3e6cb2013-04-30 08:47:43 -04001188
John Spurlockcfc359a2013-09-05 10:42:03 -04001189 public void setInteracting(int barWindow, boolean interacting) {
John Spurlockad3e6cb2013-04-30 08:47:43 -04001190 // hook for subclasses
1191 }
John Spurlock5c454122013-06-17 07:35:46 -04001192
1193 public void destroy() {
1194 if (mSearchPanelView != null) {
1195 mWindowManager.removeViewImmediate(mSearchPanelView);
1196 }
1197 mContext.unregisterReceiver(mBroadcastReceiver);
1198 }
Joe Onorato2314aab2010-04-08 16:41:23 -05001199}