blob: 233d601b6fda0a000731fe5d4d52e19a26b813b9 [file] [log] [blame]
Joe Onorato808182d2010-07-09 18:52:06 -04001/*
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
17package com.android.systemui.statusbar.tablet;
18
Joe Onoratof3c3c4f2010-10-21 11:09:02 -040019import java.io.FileDescriptor;
20import java.io.PrintWriter;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -040021import java.util.ArrayList;
Joe Onoratof3c3c4f2010-10-21 11:09:02 -040022
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -040023import android.animation.LayoutTransition;
24import android.animation.ObjectAnimator;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040025import android.app.ActivityManagerNative;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040026import android.app.PendingIntent;
Joe Onoratoef1e7762010-09-17 18:38:38 -040027import android.app.Notification;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040028import android.app.StatusBarManager;
Joe Onorato808182d2010-07-09 18:52:06 -040029import android.content.Context;
30import android.content.Intent;
Daniel Sandlerce6ff642011-02-18 12:51:08 -050031import android.content.SharedPreferences;
Daniel Sandler0ad460b2010-12-14 12:14:53 -050032import android.content.res.Configuration;
Joe Onorato808182d2010-07-09 18:52:06 -040033import android.content.res.Resources;
Joe Onorato857fd9b2011-01-27 15:08:35 -080034import android.inputmethodservice.InputMethodService;
Daniel Sandler9120d552010-07-23 09:11:14 -040035import android.graphics.PixelFormat;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040036import android.graphics.Rect;
Joe Onorato4daaeaf2010-11-17 20:43:12 -080037import android.graphics.drawable.LayerDrawable;
Daniel Sandler9120d552010-07-23 09:11:14 -040038import android.os.Handler;
Joe Onorato808182d2010-07-09 18:52:06 -040039import android.os.IBinder;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040040import android.os.Message;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040041import android.os.RemoteException;
Daniel Sandler10163c62010-12-08 11:51:05 -050042import android.os.ServiceManager;
Joe Onoratoef1e7762010-09-17 18:38:38 -040043import android.text.TextUtils;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040044import android.util.Slog;
Joe Onorato808182d2010-07-09 18:52:06 -040045import android.view.Gravity;
Daniel Sandler10163c62010-12-08 11:51:05 -050046import android.view.IWindowManager;
47import android.view.KeyEvent;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040048import android.view.LayoutInflater;
Joe Onoratob62ac122010-09-20 16:16:32 -040049import android.view.MotionEvent;
Daniel Sandler8304da42010-10-25 15:53:25 -040050import android.view.VelocityTracker;
Joe Onorato808182d2010-07-09 18:52:06 -040051import android.view.View;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -040052import android.view.ViewConfiguration;
Daniel Sandler9120d552010-07-23 09:11:14 -040053import android.view.ViewGroup;
54import android.view.WindowManager;
55import android.view.WindowManagerImpl;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040056import android.widget.ImageView;
Joe Onorato808182d2010-07-09 18:52:06 -040057import android.widget.LinearLayout;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040058import android.widget.RemoteViews;
59import android.widget.ScrollView;
Daniel Sandler9120d552010-07-23 09:11:14 -040060import android.widget.TextView;
Joe Onorato808182d2010-07-09 18:52:06 -040061
62import com.android.internal.statusbar.StatusBarIcon;
Joe Onorato808182d2010-07-09 18:52:06 -040063import com.android.internal.statusbar.StatusBarNotification;
64
Joe Onorato808182d2010-07-09 18:52:06 -040065import com.android.systemui.R;
Joe Onoratofd52b182010-11-10 18:00:52 -080066import com.android.systemui.statusbar.*;
67import com.android.systemui.statusbar.policy.BatteryController;
Joe Onoratofce2bf32011-02-01 17:00:29 -080068import com.android.systemui.statusbar.policy.BluetoothController;
Daniel Sandlere40451a2011-02-03 14:51:35 -050069import com.android.systemui.statusbar.policy.LocationController;
Joe Onoratofd52b182010-11-10 18:00:52 -080070import com.android.systemui.statusbar.policy.NetworkController;
Daniel Sandlerce6ff642011-02-18 12:51:08 -050071import com.android.systemui.statusbar.policy.Prefs;
Joe Onoratofd52b182010-11-10 18:00:52 -080072import com.android.systemui.recent.RecentApplicationsActivity;
Joe Onorato808182d2010-07-09 18:52:06 -040073
Joe Onoratodc100302011-01-11 17:07:41 -080074public class TabletStatusBar extends StatusBar implements
Jeff Brown2992ea72011-01-28 22:04:14 -080075 HeightReceiver.OnBarHeightChangedListener,
76 InputMethodsPanel.OnHardKeyboardEnabledChangeListener {
Daniel Sandlerfb970e92010-08-20 10:57:17 -040077 public static final boolean DEBUG = false;
Joe Onoratofd52b182010-11-10 18:00:52 -080078 public static final String TAG = "TabletStatusBar";
Joe Onorato808182d2010-07-09 18:52:06 -040079
Daniel Sandler0ad460b2010-12-14 12:14:53 -050080 public static final int MAX_NOTIFICATION_ICONS = 5;
satok82beadf2010-12-27 19:03:06 +090081 // IME switcher icon is big and occupy width of two icons
satok51133822011-01-25 15:01:48 +090082 public static final int MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE = MAX_NOTIFICATION_ICONS - 1;
Daniel Sandler0ad460b2010-12-14 12:14:53 -050083
Joe Onoratob62ac122010-09-20 16:16:32 -040084 public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
85 public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -040086 public static final int MSG_OPEN_NOTIFICATION_PEEK = 1002;
87 public static final int MSG_CLOSE_NOTIFICATION_PEEK = 1003;
Jim Miller44c66fe2010-10-20 18:32:52 -070088 public static final int MSG_OPEN_RECENTS_PANEL = 1020;
89 public static final int MSG_CLOSE_RECENTS_PANEL = 1021;
Daniel Sandler0ad460b2010-12-14 12:14:53 -050090 public static final int MSG_SHOW_CHROME = 1030;
91 public static final int MSG_HIDE_CHROME = 1031;
satok82beadf2010-12-27 19:03:06 +090092 public static final int MSG_OPEN_INPUT_METHODS_PANEL = 1040;
93 public static final int MSG_CLOSE_INPUT_METHODS_PANEL = 1041;
Daniel Sandler2ed08d22011-01-30 16:07:28 -050094 public static final int MSG_STOP_TICKER = 2000;
Jim Miller44c66fe2010-10-20 18:32:52 -070095
Daniel Sandler3a2fded2011-02-23 11:19:59 -050096 // Fitts' Law assistance for LatinIME; see policy.EventHole
Daniel Sandler10163c62010-12-08 11:51:05 -050097 private static final boolean FAKE_SPACE_BAR = true;
98
Joe Onoratodc100302011-01-11 17:07:41 -080099 // The height of the bar, as definied by the build. It may be taller if we're plugged
100 // into hdmi.
101 int mNaturalBarHeight = -1;
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500102 int mIconSize = -1;
103 int mIconHPadding = -1;
Daniel Sandler9120d552010-07-23 09:11:14 -0400104
105 H mHandler = new H();
106
Daniel Sandler10163c62010-12-08 11:51:05 -0500107 IWindowManager mWindowManager;
108
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400109 // tracking all current notifications
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500110 private NotificationData mNotificationData = new NotificationData();
Jim Miller44c66fe2010-10-20 18:32:52 -0700111
Joe Onoratob62ac122010-09-20 16:16:32 -0400112 TabletStatusBarView mStatusBarView;
Joe Onoratofd52b182010-11-10 18:00:52 -0800113 View mNotificationArea;
114 View mNotificationTrigger;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400115 NotificationIconArea mNotificationIconArea;
Joe Onorato091e1b82010-09-26 18:04:44 -0700116 View mNavigationArea;
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500117
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500118 boolean mNotificationDNDMode;
119 NotificationData.Entry mNotificationDNDDummyEntry;
120
Joe Onorato536c58f2010-11-28 17:52:28 -0800121 ImageView mBackButton;
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500122 View mHomeButton;
Daniel Sandlere02d8082010-10-08 15:13:22 -0400123 View mMenuButton;
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400124 View mRecentButton;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400125
Joe Onoratoec51a822011-01-04 16:33:01 -0800126 ViewGroup mNotificationAndImeArea;
satokcd7cd292010-11-20 15:46:23 +0900127 InputMethodButton mInputMethodSwitchButton;
satok06487a52010-10-29 11:37:18 +0900128
Joe Onoratoddf680b2010-09-26 13:59:40 -0700129 NotificationPanel mNotificationPanel;
Joe Onorato8a576712010-11-15 16:50:34 -0800130 NotificationPeekPanel mNotificationPeekWindow;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400131 ViewGroup mNotificationPeekRow;
132 int mNotificationPeekIndex;
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500133 IBinder mNotificationPeekKey;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400134 LayoutTransition mNotificationPeekScrubLeft, mNotificationPeekScrubRight;
135
136 int mNotificationPeekTapDuration;
137 int mNotificationFlingVelocity;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400138
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400139 ViewGroup mPile;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400140
Joe Onoratodc100302011-01-11 17:07:41 -0800141 HeightReceiver mHeightReceiver;
Joe Onoratofd52b182010-11-10 18:00:52 -0800142 BatteryController mBatteryController;
Joe Onoratofce2bf32011-02-01 17:00:29 -0800143 BluetoothController mBluetoothController;
Daniel Sandlere40451a2011-02-03 14:51:35 -0500144 LocationController mLocationController;
Joe Onoratofd52b182010-11-10 18:00:52 -0800145 NetworkController mNetworkController;
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400146
Daniel Sandlerce70d912010-09-02 11:59:41 -0400147 View mBarContents;
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500148
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500149 // hide system chrome ("lights out") support
150 View mShadow;
Daniel Sandlerce70d912010-09-02 11:59:41 -0400151
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400152 NotificationIconArea.IconLayout mIconLayout;
153
Joe Onoratoef1e7762010-09-17 18:38:38 -0400154 TabletTicker mTicker;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400155
Daniel Sandler10163c62010-12-08 11:51:05 -0500156 View mFakeSpaceBar;
157 KeyEvent mSpaceBarKeyEvent = null;
158
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400159 // for disabling the status bar
160 int mDisabled = 0;
161
Jim Miller44c66fe2010-10-20 18:32:52 -0700162 private RecentAppsPanel mRecentsPanel;
satok82beadf2010-12-27 19:03:06 +0900163 private InputMethodsPanel mInputMethodsPanel;
Joe Onorato55d2d762010-09-26 13:02:01 -0700164
Daniel Sandlerc51451a2010-12-16 19:06:46 -0500165 public Context getContext() { return mContext; }
166
Daniel Sandler9120d552010-07-23 09:11:14 -0400167 protected void addPanelWindows() {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400168 final Context context = mContext;
169
Jim Miller44c66fe2010-10-20 18:32:52 -0700170 // Notification Panel
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400171 mNotificationPanel = (NotificationPanel)View.inflate(context,
Joe Onorato755cc742010-11-27 15:45:35 -0800172 R.layout.status_bar_notification_panel, null);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800173 mNotificationPanel.show(false, false);
Joe Onoratob62ac122010-09-20 16:16:32 -0400174 mNotificationPanel.setOnTouchListener(
Joe Onoratoddf680b2010-09-26 13:59:40 -0700175 new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PANEL, mNotificationPanel));
Joe Onoratob62ac122010-09-20 16:16:32 -0400176
Joe Onoratofd52b182010-11-10 18:00:52 -0800177 // the battery and network icons
178 mBatteryController.addIconView((ImageView)mNotificationPanel.findViewById(R.id.battery));
179 mBatteryController.addLabelView(
180 (TextView)mNotificationPanel.findViewById(R.id.battery_text));
Joe Onoratofce2bf32011-02-01 17:00:29 -0800181 mBluetoothController.addIconView(
182 (ImageView)mNotificationPanel.findViewById(R.id.bluetooth));
Joe Onoratoddbba422010-11-23 15:42:28 -0800183 mNetworkController.addCombinedSignalIconView(
Joe Onorato42f8e132010-11-29 15:52:43 -0800184 (ImageView)mNotificationPanel.findViewById(R.id.network_signal));
185 mNetworkController.addDataTypeIconView(
186 (ImageView)mNotificationPanel.findViewById(R.id.network_type));
Joe Onoratofce2bf32011-02-01 17:00:29 -0800187 mNetworkController.addDataDirectionOverlayIconView(
188 (ImageView)mNotificationPanel.findViewById(R.id.network_direction));
Joe Onoratofd52b182010-11-10 18:00:52 -0800189 mNetworkController.addLabelView(
190 (TextView)mNotificationPanel.findViewById(R.id.network_text));
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500191 mNetworkController.addLabelView(
192 (TextView)mBarContents.findViewById(R.id.network_text));
Joe Onoratofd52b182010-11-10 18:00:52 -0800193
Joe Onorato55d2d762010-09-26 13:02:01 -0700194 mStatusBarView.setIgnoreChildren(0, mNotificationTrigger, mNotificationPanel);
Daniel Sandlerd39e3882010-08-31 14:16:13 -0400195
Daniel Sandler9120d552010-07-23 09:11:14 -0400196 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
Daniel Sandleradd26202011-01-20 02:53:43 -0500197 512, // ViewGroup.LayoutParams.MATCH_PARENT,
Joe Onoratocf2b1992010-11-16 21:36:42 -0800198 ViewGroup.LayoutParams.MATCH_PARENT,
Daniel Sandler9120d552010-07-23 09:11:14 -0400199 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
200 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
Jeff Brown46e75292010-11-10 16:53:45 -0800201 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
Joe Onorato7c270fa2010-12-08 17:31:42 -0800202 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
203 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
Daniel Sandler9120d552010-07-23 09:11:14 -0400204 PixelFormat.TRANSLUCENT);
Joe Onoratoea70e632010-09-27 17:59:37 -0700205 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
Daniel Sandler9120d552010-07-23 09:11:14 -0400206 lp.setTitle("NotificationPanel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800207 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
208 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
209 lp.windowAnimations = com.android.internal.R.style.Animation; // == no animation
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500210// lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade
Daniel Sandler9120d552010-07-23 09:11:14 -0400211
212 WindowManagerImpl.getDefault().addView(mNotificationPanel, lp);
213
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400214 // Notification preview window
Joe Onorato8a576712010-11-15 16:50:34 -0800215 mNotificationPeekWindow = (NotificationPeekPanel) View.inflate(context,
Joe Onorato755cc742010-11-27 15:45:35 -0800216 R.layout.status_bar_notification_peek, null);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400217 mNotificationPeekRow = (ViewGroup) mNotificationPeekWindow.findViewById(R.id.content);
218 mNotificationPeekWindow.setVisibility(View.GONE);
219 mNotificationPeekWindow.setOnTouchListener(
Joe Onorato5e759462010-11-28 17:43:50 -0800220 new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PEEK, mNotificationPeekWindow));
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400221 mNotificationPeekScrubRight = new LayoutTransition();
Jim Miller85babff2011-01-11 14:26:03 -0800222 mNotificationPeekScrubRight.setAnimator(LayoutTransition.APPEARING,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400223 ObjectAnimator.ofInt(null, "left", -512, 0));
Jim Miller85babff2011-01-11 14:26:03 -0800224 mNotificationPeekScrubRight.setAnimator(LayoutTransition.DISAPPEARING,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400225 ObjectAnimator.ofInt(null, "left", -512, 0));
226 mNotificationPeekScrubRight.setDuration(500);
227
228 mNotificationPeekScrubLeft = new LayoutTransition();
Jim Miller85babff2011-01-11 14:26:03 -0800229 mNotificationPeekScrubLeft.setAnimator(LayoutTransition.APPEARING,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400230 ObjectAnimator.ofInt(null, "left", 512, 0));
Jim Miller85babff2011-01-11 14:26:03 -0800231 mNotificationPeekScrubLeft.setAnimator(LayoutTransition.DISAPPEARING,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400232 ObjectAnimator.ofInt(null, "left", 512, 0));
233 mNotificationPeekScrubLeft.setDuration(500);
234
235 // XXX: setIgnoreChildren?
236 lp = new WindowManager.LayoutParams(
237 512, // ViewGroup.LayoutParams.WRAP_CONTENT,
238 ViewGroup.LayoutParams.WRAP_CONTENT,
239 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
240 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
Jeff Brown46e75292010-11-10 16:53:45 -0800241 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
242 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400243 PixelFormat.TRANSLUCENT);
244 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
245 lp.setTitle("NotificationPeekWindow");
246 lp.windowAnimations = com.android.internal.R.style.Animation_Toast;
247
248 WindowManagerImpl.getDefault().addView(mNotificationPeekWindow, lp);
249
Jim Miller44c66fe2010-10-20 18:32:52 -0700250 // Recents Panel
Jim Miller85babff2011-01-11 14:26:03 -0800251 mRecentsPanel = (RecentAppsPanel) View.inflate(context,
252 R.layout.status_bar_recent_panel, null);
253 mRecentsPanel.setVisibility(View.GONE);
254 mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
255 mRecentsPanel));
256 mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
Jim Miller44c66fe2010-10-20 18:32:52 -0700257
Jim Miller85babff2011-01-11 14:26:03 -0800258 lp = new WindowManager.LayoutParams(
259 ViewGroup.LayoutParams.WRAP_CONTENT,
260 ViewGroup.LayoutParams.WRAP_CONTENT,
261 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
262 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
263 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
264 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
265 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
266 PixelFormat.TRANSLUCENT);
267 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
268 lp.setTitle("RecentsPanel");
269 lp.windowAnimations = R.style.Animation_RecentPanel;
Jim Miller44c66fe2010-10-20 18:32:52 -0700270
Jim Miller85babff2011-01-11 14:26:03 -0800271 WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
272 mRecentsPanel.setBar(this);
satok82beadf2010-12-27 19:03:06 +0900273
274 // Input methods Panel
275 mInputMethodsPanel = (InputMethodsPanel) View.inflate(context,
276 R.layout.status_bar_input_methods_panel, null);
Jeff Brown2992ea72011-01-28 22:04:14 -0800277 mInputMethodsPanel.setHardKeyboardEnabledChangeListener(this);
satok82beadf2010-12-27 19:03:06 +0900278 mInputMethodsPanel.setOnTouchListener(new TouchOutsideListener(
279 MSG_CLOSE_INPUT_METHODS_PANEL, mInputMethodsPanel));
satok913f42d2011-01-17 16:58:10 +0900280 mInputMethodsPanel.setImeSwitchButton(mInputMethodSwitchButton);
satok82beadf2010-12-27 19:03:06 +0900281 mStatusBarView.setIgnoreChildren(3, mInputMethodSwitchButton, mInputMethodsPanel);
282 lp = new WindowManager.LayoutParams(
283 ViewGroup.LayoutParams.WRAP_CONTENT,
284 ViewGroup.LayoutParams.WRAP_CONTENT,
285 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
286 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
287 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
288 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
289 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
290 PixelFormat.TRANSLUCENT);
291 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
292 lp.setTitle("InputMethodsPanel");
293 lp.windowAnimations = R.style.Animation_RecentPanel;
294
295 WindowManagerImpl.getDefault().addView(mInputMethodsPanel, lp);
Daniel Sandler9120d552010-07-23 09:11:14 -0400296 }
Joe Onorato808182d2010-07-09 18:52:06 -0400297
298 @Override
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400299 public void start() {
300 super.start(); // will add the main bar view
Joe Onorato808182d2010-07-09 18:52:06 -0400301 }
302
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500303 @Override
Joe Onoratodc100302011-01-11 17:07:41 -0800304 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500305 loadDimens();
306 }
307
308 protected void loadDimens() {
309 final Resources res = mContext.getResources();
310
Joe Onoratodc100302011-01-11 17:07:41 -0800311 mNaturalBarHeight = res.getDimensionPixelSize(
312 com.android.internal.R.dimen.status_bar_height);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500313
314 int newIconSize = res.getDimensionPixelSize(
315 com.android.internal.R.dimen.status_bar_icon_size);
316 int newIconHPadding = res.getDimensionPixelSize(
317 R.dimen.status_bar_icon_padding);
318
319 if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
320// Slog.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
321 mIconHPadding = newIconHPadding;
322 mIconSize = newIconSize;
323 reloadAllNotificationIcons(); // reload the tray
324 }
325 }
326
Joe Onorato808182d2010-07-09 18:52:06 -0400327 protected View makeStatusBarView() {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400328 final Context context = mContext;
Jim Miller85babff2011-01-11 14:26:03 -0800329
Daniel Sandler10163c62010-12-08 11:51:05 -0500330 mWindowManager = IWindowManager.Stub.asInterface(
331 ServiceManager.getService(Context.WINDOW_SERVICE));
Joe Onorato808182d2010-07-09 18:52:06 -0400332
Joe Onoratodc100302011-01-11 17:07:41 -0800333 // This guy will listen for HDMI plugged broadcasts so we can resize the
334 // status bar as appropriate.
335 mHeightReceiver = new HeightReceiver(mContext);
336 mHeightReceiver.registerReceiver();
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500337 loadDimens();
Joe Onorato808182d2010-07-09 18:52:06 -0400338
Joe Onoratob62ac122010-09-20 16:16:32 -0400339 final TabletStatusBarView sb = (TabletStatusBarView)View.inflate(
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400340 context, R.layout.status_bar, null);
Joe Onorato808182d2010-07-09 18:52:06 -0400341 mStatusBarView = sb;
342
Joe Onoratob62ac122010-09-20 16:16:32 -0400343 sb.setHandler(mHandler);
344
Daniel Sandlerce70d912010-09-02 11:59:41 -0400345 mBarContents = sb.findViewById(R.id.bar_contents);
Joe Onoratof63b0f42010-09-12 17:03:19 -0400346
Joe Onoratofd52b182010-11-10 18:00:52 -0800347 // the whole right-hand side of the bar
348 mNotificationArea = sb.findViewById(R.id.notificationArea);
349
Joe Onorato55d2d762010-09-26 13:02:01 -0700350 // the button to open the notification area
Joe Onoratofd52b182010-11-10 18:00:52 -0800351 mNotificationTrigger = sb.findViewById(R.id.notificationTrigger);
Daniel Sandler56a6d882011-02-23 16:40:33 -0500352 mNotificationTrigger.setOnTouchListener(new NotificationTriggerTouchListener());
Joe Onorato55d2d762010-09-26 13:02:01 -0700353
Joe Onorato808182d2010-07-09 18:52:06 -0400354 // the more notifications icon
355 mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons);
356
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400357 // where the icons go
358 mIconLayout = (NotificationIconArea.IconLayout) sb.findViewById(R.id.icons);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400359 mIconLayout.setOnTouchListener(new NotificationIconTouchListener());
360
361 ViewConfiguration vc = ViewConfiguration.get(context);
362 mNotificationPeekTapDuration = vc.getTapTimeout();
363 mNotificationFlingVelocity = 300; // px/s
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400364
Daniel Sandlerc51451a2010-12-16 19:06:46 -0500365 mTicker = new TabletTicker(this);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400366
Joe Onoratofd52b182010-11-10 18:00:52 -0800367 // The icons
Daniel Sandlere40451a2011-02-03 14:51:35 -0500368 mLocationController = new LocationController(mContext); // will post a notification
369
Joe Onoratofd52b182010-11-10 18:00:52 -0800370 mBatteryController = new BatteryController(mContext);
371 mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));
Joe Onoratofce2bf32011-02-01 17:00:29 -0800372 mBluetoothController = new BluetoothController(mContext);
373 mBluetoothController.addIconView((ImageView)sb.findViewById(R.id.bluetooth));
Joe Onoratofd52b182010-11-10 18:00:52 -0800374 mNetworkController = new NetworkController(mContext);
Joe Onorato42f8e132010-11-29 15:52:43 -0800375 mNetworkController.addCombinedSignalIconView(
376 (ImageView)sb.findViewById(R.id.network_signal));
377 mNetworkController.addDataTypeIconView(
378 (ImageView)sb.findViewById(R.id.network_type));
Joe Onoratofce2bf32011-02-01 17:00:29 -0800379 mNetworkController.addDataDirectionOverlayIconView(
380 (ImageView)sb.findViewById(R.id.network_direction));
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400381
Joe Onorato091e1b82010-09-26 18:04:44 -0700382 // The navigation buttons
Joe Onorato6478adc2011-01-27 21:15:01 -0800383 mBackButton = (ImageView)sb.findViewById(R.id.back);
Joe Onorato091e1b82010-09-26 18:04:44 -0700384 mNavigationArea = sb.findViewById(R.id.navigationArea);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500385 mHomeButton = mNavigationArea.findViewById(R.id.home);
Daniel Sandlere02d8082010-10-08 15:13:22 -0400386 mMenuButton = mNavigationArea.findViewById(R.id.menu);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500387 mRecentButton = mNavigationArea.findViewById(R.id.recent_apps);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500388 mRecentButton.setOnClickListener(mOnClickListener);
Joe Onorato091e1b82010-09-26 18:04:44 -0700389
satok06487a52010-10-29 11:37:18 +0900390 // The bar contents buttons
Joe Onoratoec51a822011-01-04 16:33:01 -0800391 mNotificationAndImeArea = (ViewGroup)sb.findViewById(R.id.notificationAndImeArea);
satokcd7cd292010-11-20 15:46:23 +0900392 mInputMethodSwitchButton = (InputMethodButton) sb.findViewById(R.id.imeSwitchButton);
satok82beadf2010-12-27 19:03:06 +0900393 // Overwrite the lister
394 mInputMethodSwitchButton.setOnClickListener(mOnClickListener);
satok06487a52010-10-29 11:37:18 +0900395
Daniel Sandler10163c62010-12-08 11:51:05 -0500396 // for redirecting errant bar taps to the IME
397 mFakeSpaceBar = sb.findViewById(R.id.fake_space_bar);
398
Daniel Sandlerb9606992010-11-19 14:47:59 -0500399 // "shadows" of the status bar features, for lights-out mode
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500400 mShadow = sb.findViewById(R.id.bar_shadow);
401 mShadow.setOnTouchListener(
402 new View.OnTouchListener() {
403 public boolean onTouch(View v, MotionEvent ev) {
404 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
Daniel Sandlerd7201552011-01-28 09:58:02 -0500405 // even though setting the systemUI visibility below will turn these views
406 // on, we need them to come up faster so that they can catch this motion
407 // event
408 mShadow.setVisibility(View.GONE);
409 mBarContents.setVisibility(View.VISIBLE);
410
Joe Onorato55bf3802011-01-25 13:42:10 -0800411 try {
412 mBarService.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
413 } catch (RemoteException ex) {
414 // system process dead
415 }
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500416 }
417 return false;
418 }
419 });
Daniel Sandlerb9606992010-11-19 14:47:59 -0500420
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500421 // tuning parameters
422 final int LIGHTS_GOING_OUT_SYSBAR_DURATION = 600;
423 final int LIGHTS_GOING_OUT_SHADOW_DURATION = 1000;
424 final int LIGHTS_GOING_OUT_SHADOW_DELAY = 500;
425
426 final int LIGHTS_COMING_UP_SYSBAR_DURATION = 200;
427// final int LIGHTS_COMING_UP_SYSBAR_DELAY = 50;
428 final int LIGHTS_COMING_UP_SHADOW_DURATION = 0;
429
430 LayoutTransition xition = new LayoutTransition();
431 xition.setAnimator(LayoutTransition.APPEARING,
432 ObjectAnimator.ofFloat(null, "alpha", 0.5f, 1f));
433 xition.setDuration(LayoutTransition.APPEARING, LIGHTS_COMING_UP_SYSBAR_DURATION);
434 xition.setStartDelay(LayoutTransition.APPEARING, 0);
435 xition.setAnimator(LayoutTransition.DISAPPEARING,
436 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
437 xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_GOING_OUT_SYSBAR_DURATION);
438 xition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
439 ((ViewGroup)sb.findViewById(R.id.bar_contents_holder)).setLayoutTransition(xition);
440
441 xition = new LayoutTransition();
442 xition.setAnimator(LayoutTransition.APPEARING,
443 ObjectAnimator.ofFloat(null, "alpha", 0f, 1f));
444 xition.setDuration(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DURATION);
445 xition.setStartDelay(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DELAY);
446 xition.setAnimator(LayoutTransition.DISAPPEARING,
447 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
448 xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_COMING_UP_SHADOW_DURATION);
449 xition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
450 ((ViewGroup)sb.findViewById(R.id.bar_shadow_holder)).setLayoutTransition(xition);
Daniel Sandlerb9606992010-11-19 14:47:59 -0500451
Joe Onorato5dd11692010-09-27 15:34:04 -0700452 // set the initial view visibility
453 setAreThereNotifications();
454
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400455 // Add the windows
456 addPanelWindows();
457
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400458 mPile = (ViewGroup)mNotificationPanel.findViewById(R.id.content);
459 mPile.removeAllViews();
Jim Miller44c66fe2010-10-20 18:32:52 -0700460
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400461 ScrollView scroller = (ScrollView)mPile.getParent();
462 scroller.setFillViewport(true);
463
Joe Onoratodc100302011-01-11 17:07:41 -0800464 mHeightReceiver.addOnBarHeightChangedListener(this);
465
Joe Onorato808182d2010-07-09 18:52:06 -0400466 return sb;
467 }
468
Joe Onoratodc100302011-01-11 17:07:41 -0800469 public int getStatusBarHeight() {
470 return mHeightReceiver.getHeight();
471 }
472
Joe Onorato808182d2010-07-09 18:52:06 -0400473 protected int getStatusBarGravity() {
474 return Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
475 }
476
Joe Onoratodc100302011-01-11 17:07:41 -0800477 public void onBarHeightChanged(int height) {
478 final WindowManager.LayoutParams lp
479 = (WindowManager.LayoutParams)mStatusBarView.getLayoutParams();
480 if (lp == null) {
481 // haven't been added yet
482 return;
483 }
484 if (lp.height != height) {
485 lp.height = height;
486 final WindowManager wm = WindowManagerImpl.getDefault();
487 wm.updateViewLayout(mStatusBarView, lp);
488 }
489 }
490
Daniel Sandler9120d552010-07-23 09:11:14 -0400491 private class H extends Handler {
Daniel Sandler9120d552010-07-23 09:11:14 -0400492 public void handleMessage(Message m) {
493 switch (m.what) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400494 case MSG_OPEN_NOTIFICATION_PEEK:
495 if (DEBUG) Slog.d(TAG, "opening notification peek window; arg=" + m.arg1);
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500496
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400497 if (m.arg1 >= 0) {
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500498 final int N = mNotificationData.size();
499
500 if (!mNotificationDNDMode) {
501 if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
502 NotificationData.Entry entry = mNotificationData.get(N-1-mNotificationPeekIndex);
503 entry.icon.setBackgroundColor(0);
504 mNotificationPeekIndex = -1;
505 mNotificationPeekKey = null;
506 }
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400507 }
508
509 final int peekIndex = m.arg1;
510 if (peekIndex < N) {
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500511 //Slog.d(TAG, "loading peek: " + peekIndex);
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500512 NotificationData.Entry entry =
513 mNotificationDNDMode
514 ? mNotificationDNDDummyEntry
515 : mNotificationData.get(N-1-peekIndex);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400516 NotificationData.Entry copy = new NotificationData.Entry(
Jim Miller85babff2011-01-11 14:26:03 -0800517 entry.key,
518 entry.notification,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400519 entry.icon);
520 inflateViews(copy, mNotificationPeekRow);
521
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500522 if (mNotificationDNDMode) {
523 copy.content.setOnClickListener(new View.OnClickListener() {
524 public void onClick(View v) {
525 SharedPreferences.Editor editor = Prefs.edit(mContext);
526 editor.putBoolean(Prefs.DO_NOT_DISTURB_PREF, false);
527 editor.apply();
528 animateCollapse();
529 }
530 });
531 }
532
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400533 entry.icon.setBackgroundColor(0x20FFFFFF);
534
535// mNotificationPeekRow.setLayoutTransition(
Jim Miller85babff2011-01-11 14:26:03 -0800536// peekIndex < mNotificationPeekIndex
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400537// ? mNotificationPeekScrubLeft
538// : mNotificationPeekScrubRight);
539
540 mNotificationPeekRow.removeAllViews();
541 mNotificationPeekRow.addView(copy.row);
542
543 mNotificationPeekWindow.setVisibility(View.VISIBLE);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800544 mNotificationPanel.show(false, true);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400545
546 mNotificationPeekIndex = peekIndex;
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500547 mNotificationPeekKey = entry.key;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400548 }
549 }
550 break;
551 case MSG_CLOSE_NOTIFICATION_PEEK:
552 if (DEBUG) Slog.d(TAG, "closing notification peek window");
553 mNotificationPeekWindow.setVisibility(View.GONE);
554 mNotificationPeekRow.removeAllViews();
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500555
556 final int N = mNotificationData.size();
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500557 if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500558 NotificationData.Entry entry =
559 mNotificationDNDMode
560 ? mNotificationDNDDummyEntry
561 : mNotificationData.get(N-1-mNotificationPeekIndex);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400562 entry.icon.setBackgroundColor(0);
563 }
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500564
565 mNotificationPeekIndex = -1;
566 mNotificationPeekKey = null;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400567 break;
Daniel Sandler9120d552010-07-23 09:11:14 -0400568 case MSG_OPEN_NOTIFICATION_PANEL:
569 if (DEBUG) Slog.d(TAG, "opening notifications panel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800570 if (!mNotificationPanel.isShowing()) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400571 mNotificationPeekWindow.setVisibility(View.GONE);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800572 mNotificationPanel.show(true, true);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500573 mNotificationArea.setVisibility(View.GONE);
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800574 mTicker.halt();
Joe Onorato091e1b82010-09-26 18:04:44 -0700575 }
Daniel Sandler9120d552010-07-23 09:11:14 -0400576 break;
577 case MSG_CLOSE_NOTIFICATION_PANEL:
578 if (DEBUG) Slog.d(TAG, "closing notifications panel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800579 if (mNotificationPanel.isShowing()) {
580 mNotificationPanel.show(false, true);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500581 mNotificationArea.setVisibility(View.VISIBLE);
Joe Onorato091e1b82010-09-26 18:04:44 -0700582 }
Daniel Sandler9120d552010-07-23 09:11:14 -0400583 break;
Jim Miller44c66fe2010-10-20 18:32:52 -0700584 case MSG_OPEN_RECENTS_PANEL:
585 if (DEBUG) Slog.d(TAG, "opening recents panel");
Jim Miller85babff2011-01-11 14:26:03 -0800586 if (mRecentsPanel != null) {
587 mRecentsPanel.setVisibility(View.VISIBLE);
588 mRecentsPanel.show(true, true);
589 }
Jim Miller44c66fe2010-10-20 18:32:52 -0700590 break;
591 case MSG_CLOSE_RECENTS_PANEL:
592 if (DEBUG) Slog.d(TAG, "closing recents panel");
Jim Miller85babff2011-01-11 14:26:03 -0800593 if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
594 mRecentsPanel.show(false, true);
595 }
Daniel Sandler9120d552010-07-23 09:11:14 -0400596 break;
satok82beadf2010-12-27 19:03:06 +0900597 case MSG_OPEN_INPUT_METHODS_PANEL:
598 if (DEBUG) Slog.d(TAG, "opening input methods panel");
Tadashi G. Takaokae385f0c2011-02-01 02:57:44 +0900599 if (mInputMethodsPanel != null) mInputMethodsPanel.openPanel();
satok82beadf2010-12-27 19:03:06 +0900600 break;
601 case MSG_CLOSE_INPUT_METHODS_PANEL:
602 if (DEBUG) Slog.d(TAG, "closing input methods panel");
Tadashi G. Takaokae385f0c2011-02-01 02:57:44 +0900603 if (mInputMethodsPanel != null) mInputMethodsPanel.closePanel(false);
satok82beadf2010-12-27 19:03:06 +0900604 break;
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500605 case MSG_SHOW_CHROME:
Daniel Sandlere03d1bc2010-11-17 21:36:40 -0500606 if (DEBUG) Slog.d(TAG, "hiding shadows (lights on)");
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500607 mBarContents.setVisibility(View.VISIBLE);
608 mShadow.setVisibility(View.GONE);
Joe Onorato664644d2011-01-23 17:53:23 -0800609 notifyLightsChanged(true);
Daniel Sandler06e66302010-11-05 15:00:06 -0400610 break;
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500611 case MSG_HIDE_CHROME:
Daniel Sandlere03d1bc2010-11-17 21:36:40 -0500612 if (DEBUG) Slog.d(TAG, "showing shadows (lights out)");
Daniel Sandler06e66302010-11-05 15:00:06 -0400613 animateCollapse();
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500614 mBarContents.setVisibility(View.GONE);
615 mShadow.setVisibility(View.VISIBLE);
Joe Onorato664644d2011-01-23 17:53:23 -0800616 notifyLightsChanged(false);
Daniel Sandlere03d1bc2010-11-17 21:36:40 -0500617 break;
Daniel Sandler2ed08d22011-01-30 16:07:28 -0500618 case MSG_STOP_TICKER:
619 mTicker.halt();
620 break;
Daniel Sandler9120d552010-07-23 09:11:14 -0400621 }
622 }
623 }
Daniel Sandler271ea122010-10-22 14:06:10 -0400624
Joe Onorato664644d2011-01-23 17:53:23 -0800625 private void notifyLightsChanged(boolean shown) {
626 try {
627 Slog.d(TAG, "lights " + (shown?"on":"out"));
628 mWindowManager.statusBarVisibilityChanged(
629 shown ? View.STATUS_BAR_VISIBLE : View.STATUS_BAR_HIDDEN);
630 } catch (RemoteException ex) {
631 }
632 }
633
Joe Onorato808182d2010-07-09 18:52:06 -0400634 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400635 if (DEBUG) Slog.d(TAG, "addIcon(" + slot + ") -> " + icon);
Joe Onorato808182d2010-07-09 18:52:06 -0400636 }
637
638 public void updateIcon(String slot, int index, int viewIndex,
639 StatusBarIcon old, StatusBarIcon icon) {
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400640 if (DEBUG) Slog.d(TAG, "updateIcon(" + slot + ") -> " + icon);
Joe Onorato808182d2010-07-09 18:52:06 -0400641 }
642
643 public void removeIcon(String slot, int index, int viewIndex) {
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400644 if (DEBUG) Slog.d(TAG, "removeIcon(" + slot + ")");
Joe Onorato808182d2010-07-09 18:52:06 -0400645 }
646
647 public void addNotification(IBinder key, StatusBarNotification notification) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400648 if (DEBUG) Slog.d(TAG, "addNotification(" + key + " -> " + notification + ")");
649 addNotificationViews(key, notification);
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400650
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800651 final boolean immersive = isImmersive();
Joe Onoratocf2b1992010-11-16 21:36:42 -0800652 if (false && immersive) {
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400653 // TODO: immersive mode popups for tablet
654 } else if (notification.notification.fullScreenIntent != null) {
655 // not immersive & a full-screen alert should be shown
Joe Onoratof68b5002011-01-16 17:00:34 -0800656 Slog.w(TAG, "Notification has fullScreenIntent and activity is not immersive;"
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400657 + " sending fullScreenIntent");
658 try {
659 notification.notification.fullScreenIntent.send();
660 } catch (PendingIntent.CanceledException e) {
661 }
662 } else {
Joe Onoratoeeed9942011-01-04 17:13:53 -0800663 tick(key, notification, true);
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400664 }
Joe Onorato5dd11692010-09-27 15:34:04 -0700665
666 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400667 }
668
669 public void updateNotification(IBinder key, StatusBarNotification notification) {
Daniel Sandler282ff9a2011-02-23 10:36:49 -0500670 if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
Jim Miller44c66fe2010-10-20 18:32:52 -0700671
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500672 final NotificationData.Entry oldEntry = mNotificationData.findByKey(key);
Daniel Sandler379020a2010-07-29 16:20:06 -0400673 if (oldEntry == null) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400674 Slog.w(TAG, "updateNotification for unknown key: " + key);
675 return;
676 }
677
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400678 final StatusBarNotification oldNotification = oldEntry.notification;
679 final RemoteViews oldContentView = oldNotification.notification.contentView;
680
681 final RemoteViews contentView = notification.notification.contentView;
682
Daniel Sandler373a9982010-11-30 12:03:59 -0500683 if (DEBUG) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400684 Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
685 + " ongoing=" + oldNotification.isOngoing()
686 + " expanded=" + oldEntry.expanded
Daniel Sandler282ff9a2011-02-23 10:36:49 -0500687 + " contentView=" + oldContentView
688 + " rowParent=" + oldEntry.row.getParent());
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400689 Slog.d(TAG, "new notification: when=" + notification.notification.when
690 + " ongoing=" + oldNotification.isOngoing()
691 + " contentView=" + contentView);
692 }
693
694 // Can we just reapply the RemoteViews in place? If when didn't change, the order
695 // didn't change.
Joe Onorato80a44402011-01-15 16:22:24 -0800696 boolean contentsUnchanged = oldEntry.expanded != null
697 && contentView != null && oldContentView != null
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400698 && contentView.getPackage() != null
699 && oldContentView.getPackage() != null
700 && oldContentView.getPackage().equals(contentView.getPackage())
Joe Onoratoc9596d62011-01-12 17:03:11 -0800701 && oldContentView.getLayoutId() == contentView.getLayoutId();
Daniel Sandler373a9982010-11-30 12:03:59 -0500702 ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
Joe Onorato80a44402011-01-15 16:22:24 -0800703 boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
Daniel Sandlera31e4192011-02-02 22:00:28 -0500704 && notification.priority == oldNotification.priority;
705 // priority now encompasses isOngoing()
Joe Onoratoc9596d62011-01-12 17:03:11 -0800706 boolean isLastAnyway = rowParent.indexOfChild(oldEntry.row) == rowParent.getChildCount()-1;
707 if (contentsUnchanged && (orderUnchanged || isLastAnyway)) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400708 if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
709 oldEntry.notification = notification;
710 try {
711 // Reapply the RemoteViews
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400712 contentView.reapply(mContext, oldEntry.content);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400713 // update the contentIntent
714 final PendingIntent contentIntent = notification.notification.contentIntent;
715 if (contentIntent != null) {
716 oldEntry.content.setOnClickListener(new NotificationClicker(contentIntent,
717 notification.pkg, notification.tag, notification.id));
Joe Onorato184498c2010-10-08 17:57:18 -0400718 } else {
719 oldEntry.content.setOnClickListener(null);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400720 }
721 // Update the icon.
722 final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
723 notification.notification.icon, notification.notification.iconLevel,
724 notification.notification.number);
725 if (!oldEntry.icon.set(ic)) {
726 handleNotificationError(key, notification, "Couldn't update icon: " + ic);
727 return;
728 }
Joe Onorato80a44402011-01-15 16:22:24 -0800729 // Update the large icon
730 if (notification.notification.largeIcon != null) {
731 oldEntry.largeIcon.setImageBitmap(notification.notification.largeIcon);
732 } else {
733 oldEntry.largeIcon.getLayoutParams().width = 0;
734 oldEntry.largeIcon.setVisibility(View.INVISIBLE);
735 }
Jim Miller85babff2011-01-11 14:26:03 -0800736
Daniel Sandler7ef29b52010-12-16 17:29:50 -0500737 if (key == mNotificationPeekKey) {
738 // must update the peek window
739 Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK);
740 peekMsg.arg1 = mNotificationPeekIndex;
741 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
742 mHandler.sendMessage(peekMsg);
743 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400744 }
745 catch (RuntimeException e) {
746 // It failed to add cleanly. Log, and remove the view from the panel.
747 Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
748 removeNotificationViews(key);
749 addNotificationViews(key, notification);
750 }
751 } else {
752 if (DEBUG) Slog.d(TAG, "not reusing notification for key: " + key);
753 removeNotificationViews(key);
754 addNotificationViews(key, notification);
755 }
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800756 // fullScreenIntent doesn't happen on updates. You need to clear & repost a new
757 // notification.
758 final boolean immersive = isImmersive();
759 if (false && immersive) {
760 // TODO: immersive mode
761 } else {
Joe Onoratoeeed9942011-01-04 17:13:53 -0800762 tick(key, notification, false);
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800763 }
Joe Onorato5dd11692010-09-27 15:34:04 -0700764
765 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400766 }
767
768 public void removeNotification(IBinder key) {
Daniel Sandler3a2fded2011-02-23 11:19:59 -0500769 if (DEBUG) Slog.d(TAG, "removeNotification(" + key + ")");
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400770 removeNotificationViews(key);
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800771 mTicker.remove(key);
Joe Onorato5dd11692010-09-27 15:34:04 -0700772 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400773 }
774
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500775 public void showClock(boolean show) {
776 View clock = mBarContents.findViewById(R.id.clock);
777 View network_text = mBarContents.findViewById(R.id.network_text);
778 if (clock != null) {
779 clock.setVisibility(show ? View.VISIBLE : View.GONE);
780 }
781 if (network_text != null) {
782 network_text.setVisibility((!show) ? View.VISIBLE : View.GONE);
783 }
784 }
785
Joe Onorato808182d2010-07-09 18:52:06 -0400786 public void disable(int state) {
Joe Onorato091e1b82010-09-26 18:04:44 -0700787 int old = mDisabled;
788 int diff = state ^ old;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400789 mDisabled = state;
790
Joe Onorato091e1b82010-09-26 18:04:44 -0700791 // act accordingly
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500792 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
793 boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
Joe Onoratof68b5002011-01-16 17:00:34 -0800794 Slog.i(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes"));
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500795 showClock(show);
796 }
Daniel Sandler6f6cf3c2010-12-16 12:54:03 -0500797 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
798 boolean show = (state & StatusBarManager.DISABLE_SYSTEM_INFO) == 0;
Joe Onoratof68b5002011-01-16 17:00:34 -0800799 Slog.i(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes"));
Daniel Sandler6f6cf3c2010-12-16 12:54:03 -0500800 mNotificationTrigger.setVisibility(show ? View.VISIBLE : View.GONE);
801 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400802 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
803 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
Joe Onoratof68b5002011-01-16 17:00:34 -0800804 Slog.i(TAG, "DISABLE_EXPAND: yes");
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400805 animateCollapse();
806 }
807 }
808 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500809 mNotificationDNDMode = Prefs.read(mContext)
810 .getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT);
Daniel Sandler282ff9a2011-02-23 10:36:49 -0500811
812 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
813 Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes" + (mNotificationDNDMode?" (DND)":""));
814 mTicker.halt();
815 } else {
816 Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no" + (mNotificationDNDMode?" (DND)":""));
817 }
818
819 // refresh icons to show either notifications or the DND message
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500820 reloadAllNotificationIcons();
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400821 } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
Joe Onorato091e1b82010-09-26 18:04:44 -0700822 if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
Joe Onoratoef1e7762010-09-17 18:38:38 -0400823 mTicker.halt();
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400824 }
825 }
Joe Onorato091e1b82010-09-26 18:04:44 -0700826 if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
827 if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
Joe Onoratof68b5002011-01-16 17:00:34 -0800828 Slog.i(TAG, "DISABLE_NAVIGATION: yes");
Joe Onoratofd52b182010-11-10 18:00:52 -0800829 mNavigationArea.setVisibility(View.GONE);
satokb70c82d2010-12-20 17:59:19 +0900830 mInputMethodSwitchButton.setScreenLocked(true);
Joe Onorato091e1b82010-09-26 18:04:44 -0700831 } else {
Joe Onoratof68b5002011-01-16 17:00:34 -0800832 Slog.i(TAG, "DISABLE_NAVIGATION: no");
Joe Onoratofd52b182010-11-10 18:00:52 -0800833 mNavigationArea.setVisibility(View.VISIBLE);
satokb70c82d2010-12-20 17:59:19 +0900834 mInputMethodSwitchButton.setScreenLocked(false);
Joe Onorato091e1b82010-09-26 18:04:44 -0700835 }
836 }
Joe Onorato6478adc2011-01-27 21:15:01 -0800837 if ((diff & StatusBarManager.DISABLE_BACK) != 0) {
838 if ((state & StatusBarManager.DISABLE_BACK) != 0) {
839 Slog.i(TAG, "DISABLE_BACK: yes");
840 mBackButton.setVisibility(View.INVISIBLE);
841 mInputMethodSwitchButton.setScreenLocked(true);
842 } else {
843 Slog.i(TAG, "DISABLE_BACK: no");
844 mBackButton.setVisibility(View.VISIBLE);
845 mInputMethodSwitchButton.setScreenLocked(false);
846 }
847 }
848
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400849 }
850
Joe Onoratoef1e7762010-09-17 18:38:38 -0400851 private boolean hasTicker(Notification n) {
Joe Onorato46439ce2010-11-19 13:56:21 -0800852 return n.tickerView != null || !TextUtils.isEmpty(n.tickerText);
Joe Onoratoef1e7762010-09-17 18:38:38 -0400853 }
854
Joe Onoratoeeed9942011-01-04 17:13:53 -0800855 private void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
Joe Onorato55d2d762010-09-26 13:02:01 -0700856 // Don't show the ticker when the windowshade is open.
Joe Onorato7c270fa2010-12-08 17:31:42 -0800857 if (mNotificationPanel.isShowing()) {
Joe Onorato55d2d762010-09-26 13:02:01 -0700858 return;
859 }
Joe Onoratoeeed9942011-01-04 17:13:53 -0800860 // If they asked for FLAG_ONLY_ALERT_ONCE, then only show this notification
861 // if it's a new notification.
862 if (!firstTime && (n.notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
863 return;
864 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400865 // Show the ticker if one is requested. Also don't do this
866 // until status bar window is attached to the window manager,
867 // because... well, what's the point otherwise? And trying to
868 // run a ticker without being attached will crash!
Joe Onoratoef1e7762010-09-17 18:38:38 -0400869 if (hasTicker(n.notification) && mStatusBarView.getWindowToken() != null) {
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400870 if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
871 | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800872 mTicker.add(key, n);
Joe Onoratoec51a822011-01-04 16:33:01 -0800873 mNotificationAndImeArea.setVisibility(View.GONE);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400874 }
875 }
876 }
877
Daniel Sandlerb8027d82010-12-16 19:35:54 -0500878 // called by TabletTicker when it's done with all queued ticks
879 public void doneTicking() {
Joe Onoratoec51a822011-01-04 16:33:01 -0800880 mNotificationAndImeArea.setVisibility(View.VISIBLE);
Daniel Sandlerb8027d82010-12-16 19:35:54 -0500881 }
882
Joe Onorato808182d2010-07-09 18:52:06 -0400883 public void animateExpand() {
Daniel Sandler56a6d882011-02-23 16:40:33 -0500884 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
885 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
886 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
Joe Onoratob62ac122010-09-20 16:16:32 -0400887 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL);
888 mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL);
Joe Onorato808182d2010-07-09 18:52:06 -0400889 }
890
891 public void animateCollapse() {
Joe Onoratob62ac122010-09-20 16:16:32 -0400892 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL);
893 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
Jim Miller44c66fe2010-10-20 18:32:52 -0700894 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
895 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
satok82beadf2010-12-27 19:03:06 +0900896 mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL);
897 mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL);
Daniel Sandler56a6d882011-02-23 16:40:33 -0500898 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
899 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
Daniel Sandler9120d552010-07-23 09:11:14 -0400900 }
901
Joe Onoratofd52b182010-11-10 18:00:52 -0800902 // called by StatusBar
Daniel Sandler06e66302010-11-05 15:00:06 -0400903 @Override
Joe Onorato93056472010-09-10 10:30:46 -0400904 public void setLightsOn(boolean on) {
Daniel Sandler59485d742010-12-02 00:11:33 -0500905 // Policy note: if the frontmost activity needs the menu key, we assume it is a legacy app
906 // that can't handle lights-out mode.
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500907 if (mMenuButton.getVisibility() == View.VISIBLE) {
Daniel Sandler59485d742010-12-02 00:11:33 -0500908 on = true;
909 }
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500910 mHandler.removeMessages(MSG_HIDE_CHROME);
911 mHandler.removeMessages(MSG_SHOW_CHROME);
912 mHandler.sendEmptyMessage(on ? MSG_SHOW_CHROME : MSG_HIDE_CHROME);
Joe Onorato93056472010-09-10 10:30:46 -0400913 }
914
Daniel Sandlere02d8082010-10-08 15:13:22 -0400915 public void setMenuKeyVisible(boolean visible) {
916 if (DEBUG) {
917 Slog.d(TAG, (visible?"showing":"hiding") + " the MENU button");
918 }
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500919 mMenuButton.setVisibility(visible ? View.VISIBLE : View.GONE);
Daniel Sandler59485d742010-12-02 00:11:33 -0500920
921 // See above re: lights-out policy for legacy apps.
922 if (visible) setLightsOn(true);
Daniel Sandlere02d8082010-10-08 15:13:22 -0400923 }
924
Joe Onorato857fd9b2011-01-27 15:08:35 -0800925 public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
926 mInputMethodSwitchButton.setImeWindowStatus(token,
927 (vis & InputMethodService.IME_ACTIVE) != 0);
satok51133822011-01-25 15:01:48 +0900928 updateNotificationIcons();
satok913f42d2011-01-17 16:58:10 +0900929 mInputMethodsPanel.setImeToken(token);
Joe Onorato857fd9b2011-01-27 15:08:35 -0800930 int res;
931 switch (backDisposition) {
932 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
933 res = R.drawable.ic_sysbar_back;
934 break;
935 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
936 res = R.drawable.ic_sysbar_back_ime;
937 break;
938 case InputMethodService.BACK_DISPOSITION_DEFAULT:
939 default:
940 if ((vis & InputMethodService.IME_VISIBLE) != 0) {
941 res = R.drawable.ic_sysbar_back_ime;
942 } else {
943 res = R.drawable.ic_sysbar_back;
944 }
945 break;
946 }
947 mBackButton.setImageResource(res);
Daniel Sandler10163c62010-12-08 11:51:05 -0500948 if (FAKE_SPACE_BAR) {
Joe Onorato857fd9b2011-01-27 15:08:35 -0800949 mFakeSpaceBar.setVisibility(((vis & InputMethodService.IME_VISIBLE) != 0)
950 ? View.VISIBLE : View.GONE);
Daniel Sandler10163c62010-12-08 11:51:05 -0500951 }
satok06487a52010-10-29 11:37:18 +0900952 }
953
Jeff Brown2992ea72011-01-28 22:04:14 -0800954 @Override
955 public void setHardKeyboardStatus(boolean available, boolean enabled) {
956 if (DEBUG) {
957 Slog.d(TAG, "Set hard keyboard status: available=" + available
958 + ", enabled=" + enabled);
959 }
960 mInputMethodSwitchButton.setHardKeyboardStatus(available);
961 updateNotificationIcons();
962 mInputMethodsPanel.setHardKeyboardStatus(available, enabled);
963 }
964
965 @Override
966 public void onHardKeyboardEnabledChange(boolean enabled) {
967 try {
968 mBarService.setHardKeyboardEnabled(enabled);
969 } catch (RemoteException ex) {
970 }
971 }
972
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800973 private boolean isImmersive() {
974 try {
975 return ActivityManagerNative.getDefault().isTopActivityImmersive();
976 //Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
977 } catch (RemoteException ex) {
978 // the end is nigh
979 return false;
980 }
981 }
Jim Miller85babff2011-01-11 14:26:03 -0800982
Joe Onorato5dd11692010-09-27 15:34:04 -0700983 private void setAreThereNotifications() {
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500984 final boolean hasClearable = mNotificationData.hasClearableItems();
Joe Onorato5dd11692010-09-27 15:34:04 -0700985 }
986
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400987 /**
988 * Cancel this notification and tell the status bar service about the failure. Hold no locks.
989 */
990 void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
991 removeNotification(key);
992 try {
993 mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
994 } catch (RemoteException ex) {
995 // The end is nigh.
996 }
997 }
998
Daniel Sandler10163c62010-12-08 11:51:05 -0500999 private void sendKey(KeyEvent key) {
1000 try {
1001 if (DEBUG) Slog.d(TAG, "injecting key event: " + key);
1002 mWindowManager.injectInputEventNoWait(key);
1003 } catch (RemoteException ex) {
1004 }
1005 }
1006
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001007 private View.OnClickListener mOnClickListener = new View.OnClickListener() {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001008 public void onClick(View v) {
Joe Onoratofd52b182010-11-10 18:00:52 -08001009 if (v == mNotificationTrigger) {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001010 onClickNotificationTrigger();
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001011 } else if (v == mRecentButton) {
1012 onClickRecentButton();
satok82beadf2010-12-27 19:03:06 +09001013 } else if (v == mInputMethodSwitchButton) {
1014 onClickInputMethodSwitchButton();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001015 }
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001016 }
1017 };
1018
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001019 public void onClickNotificationTrigger() {
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001020 if (DEBUG) Slog.d(TAG, "clicked notification icons; disabled=" + mDisabled);
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001021 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
Daniel Sandler3a2fded2011-02-23 11:19:59 -05001022 int msg = !mNotificationPanel.isShowing()
1023 ? MSG_OPEN_NOTIFICATION_PANEL
1024 : MSG_CLOSE_NOTIFICATION_PANEL;
1025 mHandler.removeMessages(msg);
1026 mHandler.sendEmptyMessage(msg);
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001027 }
1028 }
1029
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001030 public void onClickRecentButton() {
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001031 if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled);
Jim Miller44c66fe2010-10-20 18:32:52 -07001032 if (mRecentsPanel == null) {
1033 Intent intent = new Intent();
1034 intent.setClass(mContext, RecentApplicationsActivity.class);
1035 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1036 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
1037 mContext.startActivity(intent);
1038 } else {
1039 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
1040 int msg = (mRecentsPanel.getVisibility() == View.GONE)
1041 ? MSG_OPEN_RECENTS_PANEL
1042 : MSG_CLOSE_RECENTS_PANEL;
1043 mHandler.removeMessages(msg);
1044 mHandler.sendEmptyMessage(msg);
1045 }
1046 }
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001047 }
Joe Onorato55d2d762010-09-26 13:02:01 -07001048
satok82beadf2010-12-27 19:03:06 +09001049 public void onClickInputMethodSwitchButton() {
1050 if (DEBUG) Slog.d(TAG, "clicked input methods panel; disabled=" + mDisabled);
1051 int msg = (mInputMethodsPanel.getVisibility() == View.GONE) ?
1052 MSG_OPEN_INPUT_METHODS_PANEL : MSG_CLOSE_INPUT_METHODS_PANEL;
1053 mHandler.removeMessages(msg);
1054 mHandler.sendEmptyMessage(msg);
1055 }
1056
Daniel Sandlerc51451a2010-12-16 19:06:46 -05001057 public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) {
1058 return new NotificationClicker(intent, pkg, tag, id);
1059 }
1060
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001061 private class NotificationClicker implements View.OnClickListener {
1062 private PendingIntent mIntent;
1063 private String mPkg;
1064 private String mTag;
1065 private int mId;
1066
1067 NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
1068 mIntent = intent;
1069 mPkg = pkg;
1070 mTag = tag;
1071 mId = id;
1072 }
1073
1074 public void onClick(View v) {
1075 try {
1076 // The intent we are sending is for the application, which
1077 // won't have permission to immediately start an activity after
1078 // the user switches to home. We know it is safe to do at this
1079 // point, so make sure new activity switches are now allowed.
1080 ActivityManagerNative.getDefault().resumeAppSwitches();
1081 } catch (RemoteException e) {
1082 }
1083
1084 if (mIntent != null) {
1085 int[] pos = new int[2];
1086 v.getLocationOnScreen(pos);
1087 Intent overlay = new Intent();
1088 overlay.setSourceBounds(
1089 new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
1090 try {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001091 mIntent.send(mContext, 0, overlay);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001092 } catch (PendingIntent.CanceledException e) {
1093 // the stack trace isn't very helpful here. Just log the exception message.
1094 Slog.w(TAG, "Sending contentIntent failed: " + e);
1095 }
1096 }
1097
1098 try {
1099 mBarService.onNotificationClick(mPkg, mTag, mId);
1100 } catch (RemoteException ex) {
1101 // system process is dead if we're here.
1102 }
1103
1104 // close the shade if it was open
1105 animateCollapse();
1106
1107 // If this click was on the intruder alert, hide that instead
1108// mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
1109 }
1110 }
1111
1112 StatusBarNotification removeNotificationViews(IBinder key) {
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001113 NotificationData.Entry entry = mNotificationData.remove(key);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001114 if (entry == null) {
1115 Slog.w(TAG, "removeNotification for unknown key: " + key);
1116 return null;
1117 }
1118 // Remove the expanded view.
1119 ViewGroup rowParent = (ViewGroup)entry.row.getParent();
1120 if (rowParent != null) rowParent.removeView(entry.row);
Daniel Sandlera8e5b062010-12-01 13:53:08 -05001121
1122 if (key == mNotificationPeekKey) {
1123 // must close the peek as well, since it's gone
1124 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
1125 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001126 // Remove the icon.
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001127// ViewGroup iconParent = (ViewGroup)entry.icon.getParent();
1128// if (iconParent != null) iconParent.removeView(entry.icon);
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001129 updateNotificationIcons();
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001130
1131 return entry.notification;
1132 }
1133
Daniel Sandler56a6d882011-02-23 16:40:33 -05001134 private class NotificationTriggerTouchListener implements View.OnTouchListener {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001135 VelocityTracker mVT;
Daniel Sandler56a6d882011-02-23 16:40:33 -05001136 float mInitialTouchX, mInitialTouchY;
1137 int mTouchSlop;
1138
1139 public NotificationTriggerTouchListener() {
1140 mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
1141 }
1142
1143 public boolean onTouch(View v, MotionEvent event) {
1144// Slog.d(TAG, String.format("touch: (%.1f, %.1f) initial: (%.1f, %.1f)",
1145// event.getX(),
1146// event.getY(),
1147// mInitialTouchX,
1148// mInitialTouchY));
1149 final int action = event.getAction();
1150 switch (action) {
1151 case MotionEvent.ACTION_DOWN:
1152 mVT = VelocityTracker.obtain();
1153 mInitialTouchX = event.getX();
1154 mInitialTouchY = event.getY();
1155 // fall through
1156 case MotionEvent.ACTION_OUTSIDE:
1157 case MotionEvent.ACTION_MOVE:
1158 // check for fling
1159 if (mVT != null) {
1160 mVT.addMovement(event);
1161 mVT.computeCurrentVelocity(1000); // pixels per second
1162 // require a little more oomph once we're already in peekaboo mode
1163 if (mVT.getYVelocity() < -mNotificationFlingVelocity) {
1164 animateExpand();
1165 mVT.recycle();
1166 mVT = null;
1167 }
1168 }
1169 return true;
1170 case MotionEvent.ACTION_UP:
1171 case MotionEvent.ACTION_CANCEL:
1172 if (mVT != null) {
1173 if (action == MotionEvent.ACTION_UP
1174 // was this a sloppy tap?
1175 && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
1176 && Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3)
1177 // dragging off the bottom doesn't count
1178 && (int)event.getY() < v.getBottom()) {
1179 animateExpand();
1180 }
1181
1182 mVT.recycle();
1183 mVT = null;
1184 return true;
1185 }
1186 }
1187 return false;
1188 }
1189 }
1190
1191 private class NotificationIconTouchListener implements View.OnTouchListener {
1192 final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms
1193 final static int NOTIFICATION_PEEK_FADE_DELAY = 5000; // ms
1194
1195 VelocityTracker mVT;
1196 int mPeekIndex;
1197 float mInitialTouchX, mInitialTouchY;
1198 int mTouchSlop;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001199
1200 public NotificationIconTouchListener() {
Daniel Sandler56a6d882011-02-23 16:40:33 -05001201 mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001202 }
1203
1204 public boolean onTouch(View v, MotionEvent event) {
1205 boolean peeking = mNotificationPeekWindow.getVisibility() != View.GONE;
Joe Onorato7c270fa2010-12-08 17:31:42 -08001206 boolean panelShowing = mNotificationPanel.isShowing();
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001207 if (panelShowing) return false;
1208
Daniel Sandler56a6d882011-02-23 16:40:33 -05001209 int numIcons = mIconLayout.getChildCount();
1210 int newPeekIndex = (int)(event.getX() * numIcons / mIconLayout.getWidth());
1211 if (newPeekIndex > numIcons - 1) newPeekIndex = numIcons - 1;
1212 else if (newPeekIndex < 0) newPeekIndex = 0;
1213
1214 final int action = event.getAction();
1215 switch (action) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001216 case MotionEvent.ACTION_DOWN:
1217 mVT = VelocityTracker.obtain();
Daniel Sandler56a6d882011-02-23 16:40:33 -05001218 mInitialTouchX = event.getX();
1219 mInitialTouchY = event.getY();
1220 mPeekIndex = -1;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001221
1222 // fall through
1223 case MotionEvent.ACTION_OUTSIDE:
1224 case MotionEvent.ACTION_MOVE:
1225 // peek and switch icons if necessary
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001226
Daniel Sandler56a6d882011-02-23 16:40:33 -05001227 if (newPeekIndex != mPeekIndex) {
1228 mPeekIndex = newPeekIndex;
1229
1230 if (DEBUG) Slog.d(TAG, "will peek at notification #" + mPeekIndex);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001231 Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK);
Daniel Sandler56a6d882011-02-23 16:40:33 -05001232 peekMsg.arg1 = mPeekIndex;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001233
1234 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
1235
Daniel Sandler56a6d882011-02-23 16:40:33 -05001236 if (peeking) {
1237 // no delay if we're scrubbing left-right
1238 mHandler.sendMessage(peekMsg);
1239 } else {
1240 // wait for fling
1241 mHandler.sendMessageDelayed(peekMsg, NOTIFICATION_PEEK_HOLD_THRESH);
1242 }
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001243 }
1244
1245 // check for fling
1246 if (mVT != null) {
1247 mVT.addMovement(event);
Daniel Sandler56a6d882011-02-23 16:40:33 -05001248 mVT.computeCurrentVelocity(1000); // pixels per second
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001249 // require a little more oomph once we're already in peekaboo mode
1250 if (!panelShowing && (
1251 (peeking && mVT.getYVelocity() < -mNotificationFlingVelocity*3)
1252 || (mVT.getYVelocity() < -mNotificationFlingVelocity))) {
1253 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
1254 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL);
1255 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
1256 mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL);
1257 }
1258 }
1259 return true;
1260 case MotionEvent.ACTION_UP:
1261 case MotionEvent.ACTION_CANCEL:
1262 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
Daniel Sandler56a6d882011-02-23 16:40:33 -05001263 if (action == MotionEvent.ACTION_UP
1264 // was this a sloppy tap?
1265 && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
1266 && Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3)
1267 // dragging off the bottom doesn't count
1268 && (int)event.getY() < v.getBottom()) {
1269 Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK);
1270 peekMsg.arg1 = mPeekIndex;
1271 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
1272 mHandler.sendMessage(peekMsg);
1273 peeking = true; // not technically true yet, but the next line will run
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001274 }
Daniel Sandler56a6d882011-02-23 16:40:33 -05001275
1276 if (peeking) {
1277 mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK,
1278 NOTIFICATION_PEEK_FADE_DELAY);
1279 }
1280
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001281 mVT.recycle();
1282 mVT = null;
1283 return true;
1284 }
1285 return false;
1286 }
1287 }
1288
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001289 StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001290 if (DEBUG) {
1291 Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);
1292 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001293 // Construct the icon.
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001294 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001295 notification.pkg + "/0x" + Integer.toHexString(notification.id));
1296 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
1297
1298 final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
1299 notification.notification.icon,
1300 notification.notification.iconLevel,
1301 notification.notification.number);
1302 if (!iconView.set(ic)) {
1303 handleNotificationError(key, notification, "Couldn't attach StatusBarIcon: " + ic);
1304 return null;
1305 }
1306 // Construct the expanded view.
1307 NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001308 if (!inflateViews(entry, mPile)) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001309 handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
1310 + notification);
1311 return null;
1312 }
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001313
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001314 // Add the icon.
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001315 int pos = mNotificationData.add(entry);
Daniel Sandlera31e4192011-02-02 22:00:28 -05001316 if (DEBUG) {
1317 Slog.d(TAG, "addNotificationViews: added at " + pos);
1318 }
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001319 updateNotificationIcons();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001320
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001321 return iconView;
1322 }
1323
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001324 private void reloadAllNotificationIcons() {
1325 if (mIconLayout == null) return;
1326 mIconLayout.removeAllViews();
1327 updateNotificationIcons();
1328 }
1329
1330 private void updateNotificationIcons() {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001331 // XXX: need to implement a new limited linear layout class
1332 // to avoid removing & readding everything
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001333
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001334 if (mIconLayout == null) return;
1335
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001336 // first, populate the main notification panel
1337 loadNotificationPanel();
1338
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001339 final LinearLayout.LayoutParams params
Joe Onoratodc100302011-01-11 17:07:41 -08001340 = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001341
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001342 // alternate behavior in DND mode
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001343 if (mNotificationDNDMode) {
1344 if (mIconLayout.getChildCount() == 0) {
1345 final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd");
1346 iconView.setImageResource(R.drawable.ic_notification_dnd);
1347 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
1348 iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0);
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001349
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001350 final Notification dndNotification = new Notification.Builder(mContext)
1351 .setContentTitle(mContext.getText(R.string.notifications_off_title))
1352 .setContentText(mContext.getText(R.string.notifications_off_text))
1353 .setSmallIcon(R.drawable.ic_notification_dnd)
1354 .setOngoing(true)
1355 .getNotification();
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001356
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001357 mNotificationDNDDummyEntry = new NotificationData.Entry(
1358 null,
1359 new StatusBarNotification("", 0, "", 0, 0, dndNotification),
1360 iconView);
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001361
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001362 mIconLayout.addView(iconView, params);
1363 }
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001364
1365 return;
1366 }
1367
1368 int N = mNotificationData.size();
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001369
1370 if (DEBUG) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001371 Slog.d(TAG, "refreshing icons: " + N + " notifications, mIconLayout=" + mIconLayout);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001372 }
1373
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001374 ArrayList<View> toShow = new ArrayList<View>();
1375
satok82beadf2010-12-27 19:03:06 +09001376 // When IME button is visible, the number of notification icons should be decremented
1377 // to fit the upper limit.
1378 final int maxNotificationIconsCount =
1379 (mInputMethodSwitchButton.getVisibility() != View.GONE) ?
1380 MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE : MAX_NOTIFICATION_ICONS;
1381 for (int i=0; i< maxNotificationIconsCount; i++) {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001382 if (i>=N) break;
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001383 toShow.add(mNotificationData.get(N-i-1).icon);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001384 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001385
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001386 ArrayList<View> toRemove = new ArrayList<View>();
1387 for (int i=0; i<mIconLayout.getChildCount(); i++) {
1388 View child = mIconLayout.getChildAt(i);
1389 if (!toShow.contains(child)) {
1390 toRemove.add(child);
1391 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001392 }
Daniel Sandler271ea122010-10-22 14:06:10 -04001393
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001394 for (View remove : toRemove) {
1395 mIconLayout.removeView(remove);
1396 }
1397
1398 for (int i=0; i<toShow.size(); i++) {
1399 View v = toShow.get(i);
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001400 v.setPadding(mIconHPadding, 0, mIconHPadding, 0);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001401 if (v.getParent() == null) {
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001402 mIconLayout.addView(v, i, params);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001403 }
1404 }
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001405 }
1406
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001407 private void loadNotificationPanel() {
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001408 int N = mNotificationData.size();
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001409
1410 ArrayList<View> toShow = new ArrayList<View>();
1411
1412 for (int i=0; i<N; i++) {
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001413 View row = mNotificationData.get(N-i-1).row;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001414 toShow.add(row);
1415 }
1416
1417 ArrayList<View> toRemove = new ArrayList<View>();
1418 for (int i=0; i<mPile.getChildCount(); i++) {
1419 View child = mPile.getChildAt(i);
1420 if (!toShow.contains(child)) {
1421 toRemove.add(child);
1422 }
1423 }
1424
1425 for (View remove : toRemove) {
1426 mPile.removeView(remove);
1427 }
1428
1429 for (int i=0; i<toShow.size(); i++) {
1430 View v = toShow.get(i);
1431 if (v.getParent() == null) {
Daniel Sandlera31e4192011-02-02 22:00:28 -05001432 mPile.addView(v, N-1-i); // the notification panel has newest at the bottom
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001433 }
1434 }
Daniel Sandler40c15452011-01-22 01:26:22 -05001435
1436 mNotificationPanel.setNotificationCount(N);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001437 }
1438
Joe Onorato4daaeaf2010-11-17 20:43:12 -08001439 void workAroundBadLayerDrawableOpacity(View v) {
1440 LayerDrawable d = (LayerDrawable)v.getBackground();
Daniel Sandlerf844dc42011-01-24 23:44:47 -05001441 if (d == null) return;
Joe Onorato4daaeaf2010-11-17 20:43:12 -08001442 v.setBackgroundDrawable(null);
1443 d.setOpacity(PixelFormat.TRANSLUCENT);
1444 v.setBackgroundDrawable(d);
1445 }
1446
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001447 private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
1448 StatusBarNotification sbn = entry.notification;
1449 RemoteViews remoteViews = sbn.notification.contentView;
1450 if (remoteViews == null) {
1451 return false;
1452 }
1453
1454 // create the row view
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001455 LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
1456 Context.LAYOUT_INFLATER_SERVICE);
Joe Onorato755cc742010-11-27 15:45:35 -08001457 View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
Joe Onorato4daaeaf2010-11-17 20:43:12 -08001458 workAroundBadLayerDrawableOpacity(row);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001459 View vetoButton = row.findViewById(R.id.veto);
Joe Onoratoa4a65032010-09-27 15:53:44 -07001460 if (entry.notification.isClearable()) {
1461 final String _pkg = sbn.pkg;
1462 final String _tag = sbn.tag;
1463 final int _id = sbn.id;
Jim Miller44c66fe2010-10-20 18:32:52 -07001464 vetoButton.setOnClickListener(new View.OnClickListener() {
Joe Onoratoa4a65032010-09-27 15:53:44 -07001465 public void onClick(View v) {
1466 try {
1467 mBarService.onNotificationClear(_pkg, _tag, _id);
1468 } catch (RemoteException ex) {
1469 // system process is dead if we're here.
1470 }
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001471 }
Joe Onoratoa4a65032010-09-27 15:53:44 -07001472 });
1473 } else {
Joe Onorato100748e2011-01-07 11:03:54 -08001474 if ((sbn.notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) {
1475 vetoButton.setVisibility(View.INVISIBLE);
1476 } else {
1477 vetoButton.setVisibility(View.GONE);
1478 }
Joe Onoratoa4a65032010-09-27 15:53:44 -07001479 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001480
Joe Onorato561d3852010-11-20 18:09:34 -08001481 // the large icon
1482 ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);
1483 if (sbn.notification.largeIcon != null) {
1484 largeIcon.setImageBitmap(sbn.notification.largeIcon);
1485 } else {
1486 largeIcon.getLayoutParams().width = 0;
1487 largeIcon.setVisibility(View.INVISIBLE);
1488 }
1489
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001490 // bind the click event to the content area
1491 ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
1492 // XXX: update to allow controls within notification views
1493 content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
1494// content.setOnFocusChangeListener(mFocusChangeListener);
1495 PendingIntent contentIntent = sbn.notification.contentIntent;
1496 if (contentIntent != null) {
1497 content.setOnClickListener(new NotificationClicker(contentIntent,
1498 sbn.pkg, sbn.tag, sbn.id));
Joe Onorato184498c2010-10-08 17:57:18 -04001499 } else {
1500 content.setOnClickListener(null);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001501 }
1502
1503 View expanded = null;
1504 Exception exception = null;
1505 try {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001506 expanded = remoteViews.apply(mContext, content);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001507 }
1508 catch (RuntimeException e) {
1509 exception = e;
1510 }
1511 if (expanded == null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08001512 final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001513 Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
1514 return false;
1515 } else {
1516 content.addView(expanded);
1517 row.setDrawingCacheEnabled(true);
1518 }
1519
1520 entry.row = row;
1521 entry.content = content;
1522 entry.expanded = expanded;
Joe Onorato80a44402011-01-15 16:22:24 -08001523 entry.largeIcon = largeIcon;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001524
1525 return true;
1526 }
Daniel Sandlerce70d912010-09-02 11:59:41 -04001527
Joe Onoratob62ac122010-09-20 16:16:32 -04001528 public class TouchOutsideListener implements View.OnTouchListener {
1529 private int mMsg;
Joe Onoratoddf680b2010-09-26 13:59:40 -07001530 private StatusBarPanel mPanel;
Joe Onoratob62ac122010-09-20 16:16:32 -04001531
Joe Onoratoddf680b2010-09-26 13:59:40 -07001532 public TouchOutsideListener(int msg, StatusBarPanel panel) {
Joe Onoratob62ac122010-09-20 16:16:32 -04001533 mMsg = msg;
Joe Onoratoddf680b2010-09-26 13:59:40 -07001534 mPanel = panel;
Joe Onoratob62ac122010-09-20 16:16:32 -04001535 }
1536
1537 public boolean onTouch(View v, MotionEvent ev) {
Joe Onoratoddf680b2010-09-26 13:59:40 -07001538 final int action = ev.getAction();
1539 if (action == MotionEvent.ACTION_OUTSIDE
1540 || (action == MotionEvent.ACTION_DOWN
1541 && !mPanel.isInContentArea((int)ev.getX(), (int)ev.getY()))) {
Joe Onoratob62ac122010-09-20 16:16:32 -04001542 mHandler.removeMessages(mMsg);
1543 mHandler.sendEmptyMessage(mMsg);
1544 return true;
1545 }
1546 return false;
1547 }
1548 }
Joe Onorato091e1b82010-09-26 18:04:44 -07001549
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001550 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1551 pw.print("mDisabled=0x");
1552 pw.println(Integer.toHexString(mDisabled));
Joe Onorato933464d2011-01-05 15:53:36 -08001553 pw.println("mNetworkController:");
1554 mNetworkController.dump(fd, pw, args);
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001555 }
Joe Onorato808182d2010-07-09 18:52:06 -04001556}
Daniel Sandlerd39e3882010-08-31 14:16:13 -04001557
1558