blob: 25662492ee4c6745be57cf4446c7c70def167d28 [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;
Daniel Sandlerb9606992010-11-19 14:47:59 -050022import java.util.Map;
23import java.util.IdentityHashMap;
Joe Onoratof3c3c4f2010-10-21 11:09:02 -040024
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -040025import android.animation.LayoutTransition;
26import android.animation.ObjectAnimator;
Daniel Sandlerb9606992010-11-19 14:47:59 -050027import android.animation.AnimatorSet;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040028import android.app.ActivityManagerNative;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040029import android.app.PendingIntent;
Joe Onoratoef1e7762010-09-17 18:38:38 -040030import android.app.Notification;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040031import android.app.StatusBarManager;
Joe Onorato808182d2010-07-09 18:52:06 -040032import android.content.Context;
33import android.content.Intent;
Daniel Sandler0ad460b2010-12-14 12:14:53 -050034import android.content.res.Configuration;
Joe Onorato808182d2010-07-09 18:52:06 -040035import android.content.res.Resources;
Daniel Sandler9120d552010-07-23 09:11:14 -040036import android.graphics.PixelFormat;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040037import android.graphics.Rect;
Joe Onorato4daaeaf2010-11-17 20:43:12 -080038import android.graphics.drawable.Drawable;
39import android.graphics.drawable.LayerDrawable;
Daniel Sandler9120d552010-07-23 09:11:14 -040040import android.os.Handler;
Joe Onorato808182d2010-07-09 18:52:06 -040041import android.os.IBinder;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040042import android.os.Message;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040043import android.os.RemoteException;
Daniel Sandler10163c62010-12-08 11:51:05 -050044import android.os.ServiceManager;
Joe Onoratoef1e7762010-09-17 18:38:38 -040045import android.text.TextUtils;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040046import android.util.Slog;
Joe Onorato55d2d762010-09-26 13:02:01 -070047import android.view.animation.Animation;
Daniel Sandlerce70d912010-09-02 11:59:41 -040048import android.view.animation.AnimationUtils;
Joe Onorato808182d2010-07-09 18:52:06 -040049import android.view.Gravity;
Daniel Sandler10163c62010-12-08 11:51:05 -050050import android.view.IWindowManager;
51import android.view.KeyEvent;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040052import android.view.LayoutInflater;
Joe Onoratob62ac122010-09-20 16:16:32 -040053import android.view.MotionEvent;
Daniel Sandler8304da42010-10-25 15:53:25 -040054import android.view.VelocityTracker;
Joe Onorato808182d2010-07-09 18:52:06 -040055import android.view.View;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -040056import android.view.ViewConfiguration;
Daniel Sandler9120d552010-07-23 09:11:14 -040057import android.view.ViewGroup;
58import android.view.WindowManager;
59import android.view.WindowManagerImpl;
Joe Onoratoef1e7762010-09-17 18:38:38 -040060import android.widget.FrameLayout;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040061import android.widget.ImageView;
Joe Onorato808182d2010-07-09 18:52:06 -040062import android.widget.LinearLayout;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040063import android.widget.RemoteViews;
64import android.widget.ScrollView;
65import android.widget.TextSwitcher;
Daniel Sandler9120d552010-07-23 09:11:14 -040066import android.widget.TextView;
Joe Onorato808182d2010-07-09 18:52:06 -040067
68import com.android.internal.statusbar.StatusBarIcon;
Joe Onorato808182d2010-07-09 18:52:06 -040069import com.android.internal.statusbar.StatusBarNotification;
70
Joe Onorato808182d2010-07-09 18:52:06 -040071import com.android.systemui.R;
Joe Onoratofd52b182010-11-10 18:00:52 -080072import com.android.systemui.statusbar.*;
73import com.android.systemui.statusbar.policy.BatteryController;
74import com.android.systemui.statusbar.policy.NetworkController;
75import com.android.systemui.recent.RecentApplicationsActivity;
Joe Onorato808182d2010-07-09 18:52:06 -040076
Joe Onoratofd52b182010-11-10 18:00:52 -080077public class TabletStatusBar extends StatusBar {
Daniel Sandlerfb970e92010-08-20 10:57:17 -040078 public static final boolean DEBUG = false;
Joe Onoratofd52b182010-11-10 18:00:52 -080079 public static final String TAG = "TabletStatusBar";
Joe Onorato808182d2010-07-09 18:52:06 -040080
Daniel Sandler0ad460b2010-12-14 12:14:53 -050081 public static final int MAX_NOTIFICATION_ICONS = 5;
82
Joe Onoratob62ac122010-09-20 16:16:32 -040083 public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
84 public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -040085 public static final int MSG_OPEN_NOTIFICATION_PEEK = 1002;
86 public static final int MSG_CLOSE_NOTIFICATION_PEEK = 1003;
Jim Miller44c66fe2010-10-20 18:32:52 -070087 public static final int MSG_OPEN_RECENTS_PANEL = 1020;
88 public static final int MSG_CLOSE_RECENTS_PANEL = 1021;
Daniel Sandler0ad460b2010-12-14 12:14:53 -050089 public static final int MSG_SHOW_CHROME = 1030;
90 public static final int MSG_HIDE_CHROME = 1031;
Jim Miller44c66fe2010-10-20 18:32:52 -070091
Daniel Sandler10163c62010-12-08 11:51:05 -050092 // Fitts' Law assistance for LatinIME; TODO: replace with a more general approach
93 private static final boolean FAKE_SPACE_BAR = true;
94
Daniel Sandlerd39e3882010-08-31 14:16:13 -040095 private static final int MAX_IMAGE_LEVEL = 10000;
Jim Miller44c66fe2010-10-20 18:32:52 -070096 private static final boolean USE_2D_RECENTS = true;
Daniel Sandlerd39e3882010-08-31 14:16:13 -040097
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -050098 public static final int LIGHTS_ON_DELAY = 5000;
99
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500100 int mBarHeight = -1;
101 int mIconSize = -1;
102 int mIconHPadding = -1;
Daniel Sandler9120d552010-07-23 09:11:14 -0400103
104 H mHandler = new H();
105
Daniel Sandler10163c62010-12-08 11:51:05 -0500106 IWindowManager mWindowManager;
107
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400108 // tracking all current notifications
109 private NotificationData mNotns = new NotificationData();
Jim Miller44c66fe2010-10-20 18:32:52 -0700110
Joe Onoratob62ac122010-09-20 16:16:32 -0400111 TabletStatusBarView mStatusBarView;
Joe Onoratofd52b182010-11-10 18:00:52 -0800112 View mNotificationArea;
113 View mNotificationTrigger;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400114 NotificationIconArea mNotificationIconArea;
Joe Onorato091e1b82010-09-26 18:04:44 -0700115 View mNavigationArea;
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500116
Joe Onorato536c58f2010-11-28 17:52:28 -0800117 ImageView mBackButton;
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500118 View mHomeButton;
Daniel Sandlere02d8082010-10-08 15:13:22 -0400119 View mMenuButton;
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400120 View mRecentButton;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400121
satokcd7cd292010-11-20 15:46:23 +0900122 InputMethodButton mInputMethodSwitchButton;
satok06487a52010-10-29 11:37:18 +0900123
Joe Onoratoddf680b2010-09-26 13:59:40 -0700124 NotificationPanel mNotificationPanel;
Joe Onorato8a576712010-11-15 16:50:34 -0800125 NotificationPeekPanel mNotificationPeekWindow;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400126 ViewGroup mNotificationPeekRow;
127 int mNotificationPeekIndex;
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500128 IBinder mNotificationPeekKey;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400129 LayoutTransition mNotificationPeekScrubLeft, mNotificationPeekScrubRight;
130
131 int mNotificationPeekTapDuration;
132 int mNotificationFlingVelocity;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400133
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400134 ViewGroup mPile;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400135
Joe Onoratofd52b182010-11-10 18:00:52 -0800136 BatteryController mBatteryController;
137 NetworkController mNetworkController;
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400138
Daniel Sandlerce70d912010-09-02 11:59:41 -0400139 View mBarContents;
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500140
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500141 // hide system chrome ("lights out") support
142 View mShadow;
Daniel Sandlerce70d912010-09-02 11:59:41 -0400143
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400144 NotificationIconArea.IconLayout mIconLayout;
145
Joe Onoratoef1e7762010-09-17 18:38:38 -0400146 TabletTicker mTicker;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400147
Daniel Sandler10163c62010-12-08 11:51:05 -0500148 View mFakeSpaceBar;
149 KeyEvent mSpaceBarKeyEvent = null;
150
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400151 // for disabling the status bar
152 int mDisabled = 0;
153
Joe Onorato55d2d762010-09-26 13:02:01 -0700154 boolean mNotificationsOn = true;
Jim Miller44c66fe2010-10-20 18:32:52 -0700155 private RecentAppsPanel mRecentsPanel;
Joe Onorato55d2d762010-09-26 13:02:01 -0700156
Daniel Sandler9120d552010-07-23 09:11:14 -0400157 protected void addPanelWindows() {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400158 final Context context = mContext;
159
Jim Miller44c66fe2010-10-20 18:32:52 -0700160 // Notification Panel
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400161 mNotificationPanel = (NotificationPanel)View.inflate(context,
Joe Onorato755cc742010-11-27 15:45:35 -0800162 R.layout.status_bar_notification_panel, null);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800163 mNotificationPanel.show(false, false);
Joe Onoratob62ac122010-09-20 16:16:32 -0400164 mNotificationPanel.setOnTouchListener(
Joe Onoratoddf680b2010-09-26 13:59:40 -0700165 new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PANEL, mNotificationPanel));
Joe Onoratob62ac122010-09-20 16:16:32 -0400166
Joe Onoratofd52b182010-11-10 18:00:52 -0800167 // the battery and network icons
168 mBatteryController.addIconView((ImageView)mNotificationPanel.findViewById(R.id.battery));
169 mBatteryController.addLabelView(
170 (TextView)mNotificationPanel.findViewById(R.id.battery_text));
Joe Onoratoddbba422010-11-23 15:42:28 -0800171 mNetworkController.addCombinedSignalIconView(
Joe Onorato42f8e132010-11-29 15:52:43 -0800172 (ImageView)mNotificationPanel.findViewById(R.id.network_signal));
173 mNetworkController.addDataTypeIconView(
174 (ImageView)mNotificationPanel.findViewById(R.id.network_type));
Joe Onoratofd52b182010-11-10 18:00:52 -0800175 mNetworkController.addLabelView(
176 (TextView)mNotificationPanel.findViewById(R.id.network_text));
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500177 mNetworkController.addLabelView(
178 (TextView)mBarContents.findViewById(R.id.network_text));
Joe Onoratofd52b182010-11-10 18:00:52 -0800179
Joe Onorato55d2d762010-09-26 13:02:01 -0700180 mStatusBarView.setIgnoreChildren(0, mNotificationTrigger, mNotificationPanel);
Daniel Sandlerd39e3882010-08-31 14:16:13 -0400181
Daniel Sandler9120d552010-07-23 09:11:14 -0400182 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
Joe Onorato4cddc982010-11-21 11:48:15 -0800183 ViewGroup.LayoutParams.MATCH_PARENT,
Joe Onoratocf2b1992010-11-16 21:36:42 -0800184 ViewGroup.LayoutParams.MATCH_PARENT,
Daniel Sandler9120d552010-07-23 09:11:14 -0400185 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
186 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
Jeff Brown46e75292010-11-10 16:53:45 -0800187 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
Joe Onorato7c270fa2010-12-08 17:31:42 -0800188 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
189 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
Daniel Sandler9120d552010-07-23 09:11:14 -0400190 PixelFormat.TRANSLUCENT);
Joe Onoratoea70e632010-09-27 17:59:37 -0700191 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
Daniel Sandler9120d552010-07-23 09:11:14 -0400192 lp.setTitle("NotificationPanel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800193 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
194 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
195 lp.windowAnimations = com.android.internal.R.style.Animation; // == no animation
Daniel Sandler9120d552010-07-23 09:11:14 -0400196
197 WindowManagerImpl.getDefault().addView(mNotificationPanel, lp);
198
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400199 // Notification preview window
Joe Onorato8a576712010-11-15 16:50:34 -0800200 mNotificationPeekWindow = (NotificationPeekPanel) View.inflate(context,
Joe Onorato755cc742010-11-27 15:45:35 -0800201 R.layout.status_bar_notification_peek, null);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400202 mNotificationPeekRow = (ViewGroup) mNotificationPeekWindow.findViewById(R.id.content);
203 mNotificationPeekWindow.setVisibility(View.GONE);
204 mNotificationPeekWindow.setOnTouchListener(
Joe Onorato5e759462010-11-28 17:43:50 -0800205 new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PEEK, mNotificationPeekWindow));
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400206 mNotificationPeekScrubRight = new LayoutTransition();
207 mNotificationPeekScrubRight.setAnimator(LayoutTransition.APPEARING,
208 ObjectAnimator.ofInt(null, "left", -512, 0));
209 mNotificationPeekScrubRight.setAnimator(LayoutTransition.DISAPPEARING,
210 ObjectAnimator.ofInt(null, "left", -512, 0));
211 mNotificationPeekScrubRight.setDuration(500);
212
213 mNotificationPeekScrubLeft = new LayoutTransition();
214 mNotificationPeekScrubLeft.setAnimator(LayoutTransition.APPEARING,
215 ObjectAnimator.ofInt(null, "left", 512, 0));
216 mNotificationPeekScrubLeft.setAnimator(LayoutTransition.DISAPPEARING,
217 ObjectAnimator.ofInt(null, "left", 512, 0));
218 mNotificationPeekScrubLeft.setDuration(500);
219
220 // XXX: setIgnoreChildren?
221 lp = new WindowManager.LayoutParams(
222 512, // ViewGroup.LayoutParams.WRAP_CONTENT,
223 ViewGroup.LayoutParams.WRAP_CONTENT,
224 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
225 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
Jeff Brown46e75292010-11-10 16:53:45 -0800226 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
227 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400228 PixelFormat.TRANSLUCENT);
229 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
230 lp.setTitle("NotificationPeekWindow");
231 lp.windowAnimations = com.android.internal.R.style.Animation_Toast;
232
233 WindowManagerImpl.getDefault().addView(mNotificationPeekWindow, lp);
234
Jim Miller44c66fe2010-10-20 18:32:52 -0700235 // Recents Panel
236 if (USE_2D_RECENTS) {
Joe Onorato755cc742010-11-27 15:45:35 -0800237 mRecentsPanel = (RecentAppsPanel) View.inflate(context,
238 R.layout.status_bar_recent_panel, null);
Jim Miller44c66fe2010-10-20 18:32:52 -0700239 mRecentsPanel.setVisibility(View.GONE);
240 mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
241 mRecentsPanel));
242 mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
243
244 lp = new WindowManager.LayoutParams(
245 ViewGroup.LayoutParams.WRAP_CONTENT,
246 ViewGroup.LayoutParams.WRAP_CONTENT,
247 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
248 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
Jeff Brown46e75292010-11-10 16:53:45 -0800249 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
Jim Miller169a2112010-12-10 18:30:07 -0800250 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
251 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
Jim Miller44c66fe2010-10-20 18:32:52 -0700252 PixelFormat.TRANSLUCENT);
253 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
254 lp.setTitle("RecentsPanel");
Joe Onoratofd52b182010-11-10 18:00:52 -0800255 lp.windowAnimations = R.style.Animation_RecentPanel;
Jim Miller44c66fe2010-10-20 18:32:52 -0700256
257 WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
258 mRecentsPanel.setBar(this);
259 }
Daniel Sandler9120d552010-07-23 09:11:14 -0400260 }
Joe Onorato808182d2010-07-09 18:52:06 -0400261
262 @Override
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400263 public void start() {
264 super.start(); // will add the main bar view
Joe Onorato808182d2010-07-09 18:52:06 -0400265 }
266
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500267 @Override
268 protected void onConfigurationChanged (Configuration newConfig) {
269 loadDimens();
270 }
271
272 protected void loadDimens() {
273 final Resources res = mContext.getResources();
274
275 mBarHeight = res.getDimensionPixelSize(
276 com.android.internal.R.dimen.status_bar_height);
277
278 int newIconSize = res.getDimensionPixelSize(
279 com.android.internal.R.dimen.status_bar_icon_size);
280 int newIconHPadding = res.getDimensionPixelSize(
281 R.dimen.status_bar_icon_padding);
282
283 if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
284// Slog.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
285 mIconHPadding = newIconHPadding;
286 mIconSize = newIconSize;
287 reloadAllNotificationIcons(); // reload the tray
288 }
289 }
290
Joe Onorato808182d2010-07-09 18:52:06 -0400291 protected View makeStatusBarView() {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400292 final Context context = mContext;
Daniel Sandler10163c62010-12-08 11:51:05 -0500293
294 mWindowManager = IWindowManager.Stub.asInterface(
295 ServiceManager.getService(Context.WINDOW_SERVICE));
Joe Onorato808182d2010-07-09 18:52:06 -0400296
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500297 loadDimens();
Joe Onorato808182d2010-07-09 18:52:06 -0400298
Joe Onoratob62ac122010-09-20 16:16:32 -0400299 final TabletStatusBarView sb = (TabletStatusBarView)View.inflate(
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400300 context, R.layout.status_bar, null);
Joe Onorato808182d2010-07-09 18:52:06 -0400301 mStatusBarView = sb;
302
Joe Onoratob62ac122010-09-20 16:16:32 -0400303 sb.setHandler(mHandler);
304
Daniel Sandlerce70d912010-09-02 11:59:41 -0400305 mBarContents = sb.findViewById(R.id.bar_contents);
Joe Onoratof63b0f42010-09-12 17:03:19 -0400306
Joe Onoratofd52b182010-11-10 18:00:52 -0800307 // the whole right-hand side of the bar
308 mNotificationArea = sb.findViewById(R.id.notificationArea);
309
Joe Onorato55d2d762010-09-26 13:02:01 -0700310 // the button to open the notification area
Joe Onoratofd52b182010-11-10 18:00:52 -0800311 mNotificationTrigger = sb.findViewById(R.id.notificationTrigger);
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400312 mNotificationTrigger.setOnClickListener(mOnClickListener);
Joe Onorato55d2d762010-09-26 13:02:01 -0700313
Joe Onorato808182d2010-07-09 18:52:06 -0400314 // the more notifications icon
315 mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons);
316
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400317 // where the icons go
318 mIconLayout = (NotificationIconArea.IconLayout) sb.findViewById(R.id.icons);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400319 mIconLayout.setOnTouchListener(new NotificationIconTouchListener());
320
321 ViewConfiguration vc = ViewConfiguration.get(context);
322 mNotificationPeekTapDuration = vc.getTapTimeout();
323 mNotificationFlingVelocity = 300; // px/s
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400324
Joe Onorato52f80cd2010-11-21 15:34:48 -0800325 mTicker = new TabletTicker(context);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400326
Joe Onoratofd52b182010-11-10 18:00:52 -0800327 // The icons
328 mBatteryController = new BatteryController(mContext);
329 mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));
330 mNetworkController = new NetworkController(mContext);
Joe Onorato42f8e132010-11-29 15:52:43 -0800331 mNetworkController.addCombinedSignalIconView(
332 (ImageView)sb.findViewById(R.id.network_signal));
333 mNetworkController.addDataTypeIconView(
334 (ImageView)sb.findViewById(R.id.network_type));
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400335
Joe Onorato091e1b82010-09-26 18:04:44 -0700336 // The navigation buttons
337 mNavigationArea = sb.findViewById(R.id.navigationArea);
Joe Onorato536c58f2010-11-28 17:52:28 -0800338 mBackButton = (ImageView)mNavigationArea.findViewById(R.id.back);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500339 mHomeButton = mNavigationArea.findViewById(R.id.home);
Daniel Sandlere02d8082010-10-08 15:13:22 -0400340 mMenuButton = mNavigationArea.findViewById(R.id.menu);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500341 mRecentButton = mNavigationArea.findViewById(R.id.recent_apps);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500342 mRecentButton.setOnClickListener(mOnClickListener);
Joe Onorato091e1b82010-09-26 18:04:44 -0700343
satok06487a52010-10-29 11:37:18 +0900344 // The bar contents buttons
satokcd7cd292010-11-20 15:46:23 +0900345 mInputMethodSwitchButton = (InputMethodButton) sb.findViewById(R.id.imeSwitchButton);
satok06487a52010-10-29 11:37:18 +0900346
Daniel Sandler10163c62010-12-08 11:51:05 -0500347 // for redirecting errant bar taps to the IME
348 mFakeSpaceBar = sb.findViewById(R.id.fake_space_bar);
349
Daniel Sandlerb9606992010-11-19 14:47:59 -0500350 // "shadows" of the status bar features, for lights-out mode
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500351 mShadow = sb.findViewById(R.id.bar_shadow);
352 mShadow.setOnTouchListener(
353 new View.OnTouchListener() {
354 public boolean onTouch(View v, MotionEvent ev) {
355 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
356 mShadow.setVisibility(View.GONE);
357 mBarContents.setVisibility(View.VISIBLE);
358 }
359 return false;
360 }
361 });
Daniel Sandlerb9606992010-11-19 14:47:59 -0500362
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500363 // tuning parameters
364 final int LIGHTS_GOING_OUT_SYSBAR_DURATION = 600;
365 final int LIGHTS_GOING_OUT_SHADOW_DURATION = 1000;
366 final int LIGHTS_GOING_OUT_SHADOW_DELAY = 500;
367
368 final int LIGHTS_COMING_UP_SYSBAR_DURATION = 200;
369// final int LIGHTS_COMING_UP_SYSBAR_DELAY = 50;
370 final int LIGHTS_COMING_UP_SHADOW_DURATION = 0;
371
372 LayoutTransition xition = new LayoutTransition();
373 xition.setAnimator(LayoutTransition.APPEARING,
374 ObjectAnimator.ofFloat(null, "alpha", 0.5f, 1f));
375 xition.setDuration(LayoutTransition.APPEARING, LIGHTS_COMING_UP_SYSBAR_DURATION);
376 xition.setStartDelay(LayoutTransition.APPEARING, 0);
377 xition.setAnimator(LayoutTransition.DISAPPEARING,
378 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
379 xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_GOING_OUT_SYSBAR_DURATION);
380 xition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
381 ((ViewGroup)sb.findViewById(R.id.bar_contents_holder)).setLayoutTransition(xition);
382
383 xition = new LayoutTransition();
384 xition.setAnimator(LayoutTransition.APPEARING,
385 ObjectAnimator.ofFloat(null, "alpha", 0f, 1f));
386 xition.setDuration(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DURATION);
387 xition.setStartDelay(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DELAY);
388 xition.setAnimator(LayoutTransition.DISAPPEARING,
389 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
390 xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_COMING_UP_SHADOW_DURATION);
391 xition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
392 ((ViewGroup)sb.findViewById(R.id.bar_shadow_holder)).setLayoutTransition(xition);
Daniel Sandlerb9606992010-11-19 14:47:59 -0500393
Joe Onorato5dd11692010-09-27 15:34:04 -0700394 // set the initial view visibility
395 setAreThereNotifications();
396
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400397 // Add the windows
398 addPanelWindows();
399
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400400 mPile = (ViewGroup)mNotificationPanel.findViewById(R.id.content);
401 mPile.removeAllViews();
Jim Miller44c66fe2010-10-20 18:32:52 -0700402
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400403 ScrollView scroller = (ScrollView)mPile.getParent();
404 scroller.setFillViewport(true);
405
Joe Onorato808182d2010-07-09 18:52:06 -0400406 return sb;
407 }
408
409 protected int getStatusBarGravity() {
410 return Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
411 }
412
Daniel Sandler9120d552010-07-23 09:11:14 -0400413 private class H extends Handler {
Daniel Sandler9120d552010-07-23 09:11:14 -0400414 public void handleMessage(Message m) {
415 switch (m.what) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400416 case MSG_OPEN_NOTIFICATION_PEEK:
417 if (DEBUG) Slog.d(TAG, "opening notification peek window; arg=" + m.arg1);
418 if (m.arg1 >= 0) {
419 final int N = mNotns.size();
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500420 if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400421 NotificationData.Entry entry = mNotns.get(N-1-mNotificationPeekIndex);
422 entry.icon.setBackgroundColor(0);
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500423 mNotificationPeekIndex = -1;
424 mNotificationPeekKey = null;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400425 }
426
427 final int peekIndex = m.arg1;
428 if (peekIndex < N) {
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500429 //Slog.d(TAG, "loading peek: " + peekIndex);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400430 NotificationData.Entry entry = mNotns.get(N-1-peekIndex);
431 NotificationData.Entry copy = new NotificationData.Entry(
432 entry.key,
433 entry.notification,
434 entry.icon);
435 inflateViews(copy, mNotificationPeekRow);
436
437 entry.icon.setBackgroundColor(0x20FFFFFF);
438
439// mNotificationPeekRow.setLayoutTransition(
440// peekIndex < mNotificationPeekIndex
441// ? mNotificationPeekScrubLeft
442// : mNotificationPeekScrubRight);
443
444 mNotificationPeekRow.removeAllViews();
445 mNotificationPeekRow.addView(copy.row);
446
447 mNotificationPeekWindow.setVisibility(View.VISIBLE);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800448 mNotificationPanel.show(false, true);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400449
450 mNotificationPeekIndex = peekIndex;
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500451 mNotificationPeekKey = entry.key;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400452 }
453 }
454 break;
455 case MSG_CLOSE_NOTIFICATION_PEEK:
456 if (DEBUG) Slog.d(TAG, "closing notification peek window");
457 mNotificationPeekWindow.setVisibility(View.GONE);
458 mNotificationPeekRow.removeAllViews();
459 final int N = mNotns.size();
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500460 if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400461 NotificationData.Entry entry = mNotns.get(N-1-mNotificationPeekIndex);
462 entry.icon.setBackgroundColor(0);
463 }
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500464
465 mNotificationPeekIndex = -1;
466 mNotificationPeekKey = null;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400467 break;
Daniel Sandler9120d552010-07-23 09:11:14 -0400468 case MSG_OPEN_NOTIFICATION_PANEL:
469 if (DEBUG) Slog.d(TAG, "opening notifications panel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800470 if (!mNotificationPanel.isShowing()) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400471 mNotificationPeekWindow.setVisibility(View.GONE);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800472 mNotificationPanel.show(true, true);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500473 mNotificationArea.setVisibility(View.GONE);
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800474 mTicker.halt();
Joe Onorato091e1b82010-09-26 18:04:44 -0700475 }
Daniel Sandler9120d552010-07-23 09:11:14 -0400476 break;
477 case MSG_CLOSE_NOTIFICATION_PANEL:
478 if (DEBUG) Slog.d(TAG, "closing notifications panel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800479 if (mNotificationPanel.isShowing()) {
480 mNotificationPanel.show(false, true);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500481 mNotificationArea.setVisibility(View.VISIBLE);
Joe Onorato091e1b82010-09-26 18:04:44 -0700482 }
Daniel Sandler9120d552010-07-23 09:11:14 -0400483 break;
Jim Miller44c66fe2010-10-20 18:32:52 -0700484 case MSG_OPEN_RECENTS_PANEL:
485 if (DEBUG) Slog.d(TAG, "opening recents panel");
486 if (mRecentsPanel != null) mRecentsPanel.setVisibility(View.VISIBLE);
487 break;
488 case MSG_CLOSE_RECENTS_PANEL:
489 if (DEBUG) Slog.d(TAG, "closing recents panel");
490 if (mRecentsPanel != null) mRecentsPanel.setVisibility(View.GONE);
Daniel Sandler9120d552010-07-23 09:11:14 -0400491 break;
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500492 case MSG_SHOW_CHROME:
Daniel Sandlere03d1bc2010-11-17 21:36:40 -0500493 if (DEBUG) Slog.d(TAG, "hiding shadows (lights on)");
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500494 mBarContents.setVisibility(View.VISIBLE);
495 mShadow.setVisibility(View.GONE);
Daniel Sandler06e66302010-11-05 15:00:06 -0400496 break;
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500497 case MSG_HIDE_CHROME:
Daniel Sandlere03d1bc2010-11-17 21:36:40 -0500498 if (DEBUG) Slog.d(TAG, "showing shadows (lights out)");
Daniel Sandler06e66302010-11-05 15:00:06 -0400499 animateCollapse();
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500500 mBarContents.setVisibility(View.GONE);
501 mShadow.setVisibility(View.VISIBLE);
Daniel Sandlere03d1bc2010-11-17 21:36:40 -0500502 break;
Daniel Sandler9120d552010-07-23 09:11:14 -0400503 }
504 }
505 }
Daniel Sandler271ea122010-10-22 14:06:10 -0400506
Joe Onorato808182d2010-07-09 18:52:06 -0400507 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400508 if (DEBUG) Slog.d(TAG, "addIcon(" + slot + ") -> " + icon);
Joe Onorato808182d2010-07-09 18:52:06 -0400509 }
510
511 public void updateIcon(String slot, int index, int viewIndex,
512 StatusBarIcon old, StatusBarIcon icon) {
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400513 if (DEBUG) Slog.d(TAG, "updateIcon(" + slot + ") -> " + icon);
Joe Onorato808182d2010-07-09 18:52:06 -0400514 }
515
516 public void removeIcon(String slot, int index, int viewIndex) {
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400517 if (DEBUG) Slog.d(TAG, "removeIcon(" + slot + ")");
Joe Onorato808182d2010-07-09 18:52:06 -0400518 }
519
520 public void addNotification(IBinder key, StatusBarNotification notification) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400521 if (DEBUG) Slog.d(TAG, "addNotification(" + key + " -> " + notification + ")");
522 addNotificationViews(key, notification);
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400523
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800524 final boolean immersive = isImmersive();
Joe Onoratocf2b1992010-11-16 21:36:42 -0800525 if (false && immersive) {
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400526 // TODO: immersive mode popups for tablet
527 } else if (notification.notification.fullScreenIntent != null) {
528 // not immersive & a full-screen alert should be shown
529 Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
530 + " sending fullScreenIntent");
531 try {
532 notification.notification.fullScreenIntent.send();
533 } catch (PendingIntent.CanceledException e) {
534 }
535 } else {
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800536 tick(key, notification);
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400537 }
Joe Onorato5dd11692010-09-27 15:34:04 -0700538
539 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400540 }
541
542 public void updateNotification(IBinder key, StatusBarNotification notification) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400543 if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ") // TODO");
Jim Miller44c66fe2010-10-20 18:32:52 -0700544
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400545 final NotificationData.Entry oldEntry = mNotns.findByKey(key);
Daniel Sandler379020a2010-07-29 16:20:06 -0400546 if (oldEntry == null) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400547 Slog.w(TAG, "updateNotification for unknown key: " + key);
548 return;
549 }
550
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400551 final StatusBarNotification oldNotification = oldEntry.notification;
552 final RemoteViews oldContentView = oldNotification.notification.contentView;
553
554 final RemoteViews contentView = notification.notification.contentView;
555
Daniel Sandler373a9982010-11-30 12:03:59 -0500556 if (DEBUG) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400557 Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
558 + " ongoing=" + oldNotification.isOngoing()
559 + " expanded=" + oldEntry.expanded
560 + " contentView=" + oldContentView);
561 Slog.d(TAG, "new notification: when=" + notification.notification.when
562 + " ongoing=" + oldNotification.isOngoing()
563 + " contentView=" + contentView);
564 }
565
566 // Can we just reapply the RemoteViews in place? If when didn't change, the order
567 // didn't change.
Daniel Sandler373a9982010-11-30 12:03:59 -0500568 boolean orderUnchanged = (notification.notification.when == oldNotification.notification.when
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400569 && notification.isOngoing() == oldNotification.isOngoing()
570 && oldEntry.expanded != null
571 && contentView != null
572 && oldContentView != null
573 && contentView.getPackage() != null
574 && oldContentView.getPackage() != null
575 && oldContentView.getPackage().equals(contentView.getPackage())
Daniel Sandler373a9982010-11-30 12:03:59 -0500576 && oldContentView.getLayoutId() == contentView.getLayoutId());
577 ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
578 boolean isLastAnyway = rowParent.indexOfChild(oldEntry.row) == rowParent.getChildCount() - 1;
579 if (orderUnchanged || isLastAnyway) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400580 if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
581 oldEntry.notification = notification;
582 try {
583 // Reapply the RemoteViews
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400584 contentView.reapply(mContext, oldEntry.content);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400585 // update the contentIntent
586 final PendingIntent contentIntent = notification.notification.contentIntent;
587 if (contentIntent != null) {
588 oldEntry.content.setOnClickListener(new NotificationClicker(contentIntent,
589 notification.pkg, notification.tag, notification.id));
Joe Onorato184498c2010-10-08 17:57:18 -0400590 } else {
591 oldEntry.content.setOnClickListener(null);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400592 }
593 // Update the icon.
594 final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
595 notification.notification.icon, notification.notification.iconLevel,
596 notification.notification.number);
597 if (!oldEntry.icon.set(ic)) {
598 handleNotificationError(key, notification, "Couldn't update icon: " + ic);
599 return;
600 }
601 }
602 catch (RuntimeException e) {
603 // It failed to add cleanly. Log, and remove the view from the panel.
604 Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
605 removeNotificationViews(key);
606 addNotificationViews(key, notification);
607 }
608 } else {
609 if (DEBUG) Slog.d(TAG, "not reusing notification for key: " + key);
610 removeNotificationViews(key);
611 addNotificationViews(key, notification);
612 }
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800613 // fullScreenIntent doesn't happen on updates. You need to clear & repost a new
614 // notification.
615 final boolean immersive = isImmersive();
616 if (false && immersive) {
617 // TODO: immersive mode
618 } else {
619 tick(key, notification);
620 }
Joe Onorato5dd11692010-09-27 15:34:04 -0700621
622 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400623 }
624
625 public void removeNotification(IBinder key) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400626 if (DEBUG) Slog.d(TAG, "removeNotification(" + key + ") // TODO");
627 removeNotificationViews(key);
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800628 mTicker.remove(key);
Joe Onorato5dd11692010-09-27 15:34:04 -0700629 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400630 }
631
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500632 public void showClock(boolean show) {
633 View clock = mBarContents.findViewById(R.id.clock);
634 View network_text = mBarContents.findViewById(R.id.network_text);
635 if (clock != null) {
636 clock.setVisibility(show ? View.VISIBLE : View.GONE);
637 }
638 if (network_text != null) {
639 network_text.setVisibility((!show) ? View.VISIBLE : View.GONE);
640 }
641 }
642
Joe Onorato808182d2010-07-09 18:52:06 -0400643 public void disable(int state) {
Joe Onorato091e1b82010-09-26 18:04:44 -0700644 int old = mDisabled;
645 int diff = state ^ old;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400646 mDisabled = state;
647
Joe Onorato091e1b82010-09-26 18:04:44 -0700648 // act accordingly
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500649 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
650 boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
651 Slog.d(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes"));
652 showClock(show);
653 }
Daniel Sandler6f6cf3c2010-12-16 12:54:03 -0500654 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
655 boolean show = (state & StatusBarManager.DISABLE_SYSTEM_INFO) == 0;
656 Slog.d(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes"));
657 mNotificationTrigger.setVisibility(show ? View.VISIBLE : View.GONE);
658 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400659 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
660 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
661 Slog.d(TAG, "DISABLE_EXPAND: yes");
662 animateCollapse();
663 }
664 }
665 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
666 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
667 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
Daniel Sandlerb9606992010-11-19 14:47:59 -0500668 // synchronize with current shadow state
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500669 mNotificationIconArea.setVisibility(View.GONE);
Joe Onorato091e1b82010-09-26 18:04:44 -0700670 mTicker.halt();
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400671 } else {
672 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
Daniel Sandlerb9606992010-11-19 14:47:59 -0500673 // synchronize with current shadow state
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500674 mNotificationIconArea.setVisibility(View.VISIBLE);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400675 }
676 } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
Joe Onorato091e1b82010-09-26 18:04:44 -0700677 if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
Joe Onoratoef1e7762010-09-17 18:38:38 -0400678 mTicker.halt();
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400679 }
680 }
Joe Onorato091e1b82010-09-26 18:04:44 -0700681 if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
682 if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
683 Slog.d(TAG, "DISABLE_NAVIGATION: yes");
Joe Onoratofd52b182010-11-10 18:00:52 -0800684 mNavigationArea.setVisibility(View.GONE);
Joe Onorato091e1b82010-09-26 18:04:44 -0700685 } else {
686 Slog.d(TAG, "DISABLE_NAVIGATION: no");
Joe Onoratofd52b182010-11-10 18:00:52 -0800687 mNavigationArea.setVisibility(View.VISIBLE);
Joe Onorato091e1b82010-09-26 18:04:44 -0700688 }
689 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400690 }
691
Joe Onoratoef1e7762010-09-17 18:38:38 -0400692 private boolean hasTicker(Notification n) {
Joe Onorato46439ce2010-11-19 13:56:21 -0800693 return n.tickerView != null || !TextUtils.isEmpty(n.tickerText);
Joe Onoratoef1e7762010-09-17 18:38:38 -0400694 }
695
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800696 private void tick(IBinder key, StatusBarNotification n) {
Joe Onorato55d2d762010-09-26 13:02:01 -0700697 // Don't show the ticker when the windowshade is open.
Joe Onorato7c270fa2010-12-08 17:31:42 -0800698 if (mNotificationPanel.isShowing()) {
Joe Onorato55d2d762010-09-26 13:02:01 -0700699 return;
700 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400701 // Show the ticker if one is requested. Also don't do this
702 // until status bar window is attached to the window manager,
703 // because... well, what's the point otherwise? And trying to
704 // run a ticker without being attached will crash!
Joe Onoratoef1e7762010-09-17 18:38:38 -0400705 if (hasTicker(n.notification) && mStatusBarView.getWindowToken() != null) {
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400706 if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
707 | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800708 mTicker.add(key, n);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400709 }
710 }
711 }
712
Joe Onorato808182d2010-07-09 18:52:06 -0400713 public void animateExpand() {
Joe Onoratob62ac122010-09-20 16:16:32 -0400714 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL);
715 mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL);
Joe Onorato808182d2010-07-09 18:52:06 -0400716 }
717
718 public void animateCollapse() {
Joe Onoratob62ac122010-09-20 16:16:32 -0400719 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL);
720 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
Jim Miller44c66fe2010-10-20 18:32:52 -0700721 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
722 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
Daniel Sandler9120d552010-07-23 09:11:14 -0400723 }
724
Joe Onoratofd52b182010-11-10 18:00:52 -0800725 // called by StatusBar
Daniel Sandler06e66302010-11-05 15:00:06 -0400726 @Override
Joe Onorato93056472010-09-10 10:30:46 -0400727 public void setLightsOn(boolean on) {
Daniel Sandler59485d742010-12-02 00:11:33 -0500728 // Policy note: if the frontmost activity needs the menu key, we assume it is a legacy app
729 // that can't handle lights-out mode.
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500730 if (mMenuButton.getVisibility() == View.VISIBLE) {
Daniel Sandler59485d742010-12-02 00:11:33 -0500731 on = true;
732 }
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500733 mHandler.removeMessages(MSG_HIDE_CHROME);
734 mHandler.removeMessages(MSG_SHOW_CHROME);
735 mHandler.sendEmptyMessage(on ? MSG_SHOW_CHROME : MSG_HIDE_CHROME);
Joe Onorato93056472010-09-10 10:30:46 -0400736 }
737
Daniel Sandlere02d8082010-10-08 15:13:22 -0400738 public void setMenuKeyVisible(boolean visible) {
739 if (DEBUG) {
740 Slog.d(TAG, (visible?"showing":"hiding") + " the MENU button");
741 }
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500742 mMenuButton.setVisibility(visible ? View.VISIBLE : View.GONE);
Daniel Sandler59485d742010-12-02 00:11:33 -0500743
744 // See above re: lights-out policy for legacy apps.
745 if (visible) setLightsOn(true);
Daniel Sandlere02d8082010-10-08 15:13:22 -0400746 }
747
satokcd7cd292010-11-20 15:46:23 +0900748 public void setIMEButtonVisible(IBinder token, boolean visible) {
satok06487a52010-10-29 11:37:18 +0900749 if (DEBUG) {
750 Slog.d(TAG, (visible?"showing":"hiding") + " the IME button");
751 }
satokcd7cd292010-11-20 15:46:23 +0900752 mInputMethodSwitchButton.setIMEButtonVisible(token, visible);
Joe Onorato536c58f2010-11-28 17:52:28 -0800753 mBackButton.setImageResource(
754 visible ? R.drawable.ic_sysbar_back_ime : R.drawable.ic_sysbar_back);
Daniel Sandler10163c62010-12-08 11:51:05 -0500755 if (FAKE_SPACE_BAR) {
756 mFakeSpaceBar.setVisibility(visible ? View.VISIBLE : View.GONE);
757 }
satok06487a52010-10-29 11:37:18 +0900758 }
759
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800760 private boolean isImmersive() {
761 try {
762 return ActivityManagerNative.getDefault().isTopActivityImmersive();
763 //Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
764 } catch (RemoteException ex) {
765 // the end is nigh
766 return false;
767 }
768 }
769
Joe Onorato5dd11692010-09-27 15:34:04 -0700770 private void setAreThereNotifications() {
771 final boolean hasClearable = mNotns.hasClearableItems();
Joe Onorato5dd11692010-09-27 15:34:04 -0700772 }
773
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400774 /**
775 * Cancel this notification and tell the status bar service about the failure. Hold no locks.
776 */
777 void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
778 removeNotification(key);
779 try {
780 mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
781 } catch (RemoteException ex) {
782 // The end is nigh.
783 }
784 }
785
Daniel Sandler10163c62010-12-08 11:51:05 -0500786 private void sendKey(KeyEvent key) {
787 try {
788 if (DEBUG) Slog.d(TAG, "injecting key event: " + key);
789 mWindowManager.injectInputEventNoWait(key);
790 } catch (RemoteException ex) {
791 }
792 }
793
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400794 private View.OnClickListener mOnClickListener = new View.OnClickListener() {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400795 public void onClick(View v) {
Joe Onoratofd52b182010-11-10 18:00:52 -0800796 if (v == mNotificationTrigger) {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400797 onClickNotificationTrigger();
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400798 } else if (v == mRecentButton) {
799 onClickRecentButton();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400800 }
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400801 }
802 };
803
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400804 public void onClickNotificationTrigger() {
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500805 if (DEBUG) Slog.d(TAG, "clicked notification icons; disabled=" + mDisabled);
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400806 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
Daniel Sandler271ea122010-10-22 14:06:10 -0400807 if (!mNotificationsOn) {
808 mNotificationsOn = true;
Daniel Sandlercf3c7cf2010-10-22 15:30:12 -0400809 mIconLayout.setVisibility(View.VISIBLE); // TODO: animation
Daniel Sandler271ea122010-10-22 14:06:10 -0400810 } else {
Joe Onorato7c270fa2010-12-08 17:31:42 -0800811 int msg = !mNotificationPanel.isShowing()
Daniel Sandler271ea122010-10-22 14:06:10 -0400812 ? MSG_OPEN_NOTIFICATION_PANEL
813 : MSG_CLOSE_NOTIFICATION_PANEL;
814 mHandler.removeMessages(msg);
815 mHandler.sendEmptyMessage(msg);
816 }
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400817 }
818 }
819
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400820 public void onClickRecentButton() {
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500821 if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled);
Jim Miller44c66fe2010-10-20 18:32:52 -0700822 if (mRecentsPanel == null) {
823 Intent intent = new Intent();
824 intent.setClass(mContext, RecentApplicationsActivity.class);
825 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
826 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
827 mContext.startActivity(intent);
828 } else {
829 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
830 int msg = (mRecentsPanel.getVisibility() == View.GONE)
831 ? MSG_OPEN_RECENTS_PANEL
832 : MSG_CLOSE_RECENTS_PANEL;
833 mHandler.removeMessages(msg);
834 mHandler.sendEmptyMessage(msg);
835 }
836 }
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400837 }
Joe Onorato55d2d762010-09-26 13:02:01 -0700838
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400839 private class NotificationClicker implements View.OnClickListener {
840 private PendingIntent mIntent;
841 private String mPkg;
842 private String mTag;
843 private int mId;
844
845 NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
846 mIntent = intent;
847 mPkg = pkg;
848 mTag = tag;
849 mId = id;
850 }
851
852 public void onClick(View v) {
853 try {
854 // The intent we are sending is for the application, which
855 // won't have permission to immediately start an activity after
856 // the user switches to home. We know it is safe to do at this
857 // point, so make sure new activity switches are now allowed.
858 ActivityManagerNative.getDefault().resumeAppSwitches();
859 } catch (RemoteException e) {
860 }
861
862 if (mIntent != null) {
863 int[] pos = new int[2];
864 v.getLocationOnScreen(pos);
865 Intent overlay = new Intent();
866 overlay.setSourceBounds(
867 new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
868 try {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400869 mIntent.send(mContext, 0, overlay);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400870 } catch (PendingIntent.CanceledException e) {
871 // the stack trace isn't very helpful here. Just log the exception message.
872 Slog.w(TAG, "Sending contentIntent failed: " + e);
873 }
874 }
875
876 try {
877 mBarService.onNotificationClick(mPkg, mTag, mId);
878 } catch (RemoteException ex) {
879 // system process is dead if we're here.
880 }
881
882 // close the shade if it was open
883 animateCollapse();
884
885 // If this click was on the intruder alert, hide that instead
886// mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
887 }
888 }
889
890 StatusBarNotification removeNotificationViews(IBinder key) {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400891 NotificationData.Entry entry = mNotns.remove(key);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400892 if (entry == null) {
893 Slog.w(TAG, "removeNotification for unknown key: " + key);
894 return null;
895 }
896 // Remove the expanded view.
897 ViewGroup rowParent = (ViewGroup)entry.row.getParent();
898 if (rowParent != null) rowParent.removeView(entry.row);
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500899
900 if (key == mNotificationPeekKey) {
901 // must close the peek as well, since it's gone
902 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
903 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400904 // Remove the icon.
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400905// ViewGroup iconParent = (ViewGroup)entry.icon.getParent();
906// if (iconParent != null) iconParent.removeView(entry.icon);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500907 updateNotificationIcons();
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400908
909 return entry.notification;
910 }
911
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400912 private class NotificationIconTouchListener implements View.OnTouchListener {
913 VelocityTracker mVT;
914
915 public NotificationIconTouchListener() {
916 }
917
918 public boolean onTouch(View v, MotionEvent event) {
919 boolean peeking = mNotificationPeekWindow.getVisibility() != View.GONE;
Joe Onorato7c270fa2010-12-08 17:31:42 -0800920 boolean panelShowing = mNotificationPanel.isShowing();
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400921 if (panelShowing) return false;
922
923 switch (event.getAction()) {
924 case MotionEvent.ACTION_DOWN:
925 mVT = VelocityTracker.obtain();
926
927 // fall through
928 case MotionEvent.ACTION_OUTSIDE:
929 case MotionEvent.ACTION_MOVE:
930 // peek and switch icons if necessary
931 int numIcons = mIconLayout.getChildCount();
Joe Onorato5e759462010-11-28 17:43:50 -0800932 int peekIndex = (int)((float)event.getX() * numIcons / mIconLayout.getWidth());
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400933 if (peekIndex > numIcons - 1) peekIndex = numIcons - 1;
934 else if (peekIndex < 0) peekIndex = 0;
935
936 if (!peeking || mNotificationPeekIndex != peekIndex) {
937 if (DEBUG) Slog.d(TAG, "will peek at notification #" + peekIndex);
938 Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK);
939 peekMsg.arg1 = peekIndex;
940
941 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
942
943 // no delay if we're scrubbing left-right
Joe Onorato5e759462010-11-28 17:43:50 -0800944 mHandler.sendMessage(peekMsg);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400945 }
946
947 // check for fling
948 if (mVT != null) {
949 mVT.addMovement(event);
950 mVT.computeCurrentVelocity(1000);
951 // require a little more oomph once we're already in peekaboo mode
952 if (!panelShowing && (
953 (peeking && mVT.getYVelocity() < -mNotificationFlingVelocity*3)
954 || (mVT.getYVelocity() < -mNotificationFlingVelocity))) {
955 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
956 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL);
957 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
958 mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL);
959 }
960 }
961 return true;
962 case MotionEvent.ACTION_UP:
963 case MotionEvent.ACTION_CANCEL:
964 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
965 if (peeking) {
Joe Onorato5e759462010-11-28 17:43:50 -0800966 mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK, 5000);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400967 }
968 mVT.recycle();
969 mVT = null;
970 return true;
971 }
972 return false;
973 }
974 }
975
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400976 StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400977 if (DEBUG) {
978 Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);
979 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400980 // Construct the icon.
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400981 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400982 notification.pkg + "/0x" + Integer.toHexString(notification.id));
983 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
984
985 final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
986 notification.notification.icon,
987 notification.notification.iconLevel,
988 notification.notification.number);
989 if (!iconView.set(ic)) {
990 handleNotificationError(key, notification, "Couldn't attach StatusBarIcon: " + ic);
991 return null;
992 }
993 // Construct the expanded view.
994 NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400995 if (!inflateViews(entry, mPile)) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400996 handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
997 + notification);
998 return null;
999 }
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001000
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001001 // Add the icon.
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001002 mNotns.add(entry);
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001003 updateNotificationIcons();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001004
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001005 return iconView;
1006 }
1007
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001008 private void reloadAllNotificationIcons() {
1009 if (mIconLayout == null) return;
1010 mIconLayout.removeAllViews();
1011 updateNotificationIcons();
1012 }
1013
1014 private void updateNotificationIcons() {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001015 // XXX: need to implement a new limited linear layout class
1016 // to avoid removing & readding everything
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001017
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001018 if (mIconLayout == null) return;
1019
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001020 final LinearLayout.LayoutParams params
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001021 = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mBarHeight);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001022
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001023 int N = mNotns.size();
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001024
1025 if (DEBUG) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001026 Slog.d(TAG, "refreshing icons: " + N + " notifications, mIconLayout=" + mIconLayout);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001027 }
1028
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001029 ArrayList<View> toShow = new ArrayList<View>();
1030
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001031 for (int i=0; i<MAX_NOTIFICATION_ICONS; i++) {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001032 if (i>=N) break;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001033 toShow.add(mNotns.get(N-i-1).icon);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001034 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001035
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001036 ArrayList<View> toRemove = new ArrayList<View>();
1037 for (int i=0; i<mIconLayout.getChildCount(); i++) {
1038 View child = mIconLayout.getChildAt(i);
1039 if (!toShow.contains(child)) {
1040 toRemove.add(child);
1041 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001042 }
Daniel Sandler271ea122010-10-22 14:06:10 -04001043
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001044 for (View remove : toRemove) {
1045 mIconLayout.removeView(remove);
1046 }
1047
1048 for (int i=0; i<toShow.size(); i++) {
1049 View v = toShow.get(i);
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001050 v.setPadding(mIconHPadding, 0, mIconHPadding, 0);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001051 if (v.getParent() == null) {
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001052 mIconLayout.addView(v, i, params);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001053 }
1054 }
1055
1056 loadNotificationPanel();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001057 }
1058
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001059 private void loadNotificationPanel() {
1060 int N = mNotns.size();
1061
1062 ArrayList<View> toShow = new ArrayList<View>();
1063
1064 for (int i=0; i<N; i++) {
1065 View row = mNotns.get(N-i-1).row;
1066 toShow.add(row);
1067 }
1068
1069 ArrayList<View> toRemove = new ArrayList<View>();
1070 for (int i=0; i<mPile.getChildCount(); i++) {
1071 View child = mPile.getChildAt(i);
1072 if (!toShow.contains(child)) {
1073 toRemove.add(child);
1074 }
1075 }
1076
1077 for (View remove : toRemove) {
1078 mPile.removeView(remove);
1079 }
1080
1081 for (int i=0; i<toShow.size(); i++) {
1082 View v = toShow.get(i);
1083 if (v.getParent() == null) {
1084 mPile.addView(toShow.get(i));
1085 }
1086 }
1087 }
1088
Joe Onorato4daaeaf2010-11-17 20:43:12 -08001089 void workAroundBadLayerDrawableOpacity(View v) {
1090 LayerDrawable d = (LayerDrawable)v.getBackground();
1091 v.setBackgroundDrawable(null);
1092 d.setOpacity(PixelFormat.TRANSLUCENT);
1093 v.setBackgroundDrawable(d);
1094 }
1095
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001096 private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
1097 StatusBarNotification sbn = entry.notification;
1098 RemoteViews remoteViews = sbn.notification.contentView;
1099 if (remoteViews == null) {
1100 return false;
1101 }
1102
1103 // create the row view
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001104 LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
1105 Context.LAYOUT_INFLATER_SERVICE);
Joe Onorato755cc742010-11-27 15:45:35 -08001106 View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
Joe Onorato4daaeaf2010-11-17 20:43:12 -08001107 workAroundBadLayerDrawableOpacity(row);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001108 View vetoButton = row.findViewById(R.id.veto);
Joe Onoratoa4a65032010-09-27 15:53:44 -07001109 if (entry.notification.isClearable()) {
1110 final String _pkg = sbn.pkg;
1111 final String _tag = sbn.tag;
1112 final int _id = sbn.id;
Jim Miller44c66fe2010-10-20 18:32:52 -07001113 vetoButton.setOnClickListener(new View.OnClickListener() {
Joe Onoratoa4a65032010-09-27 15:53:44 -07001114 public void onClick(View v) {
1115 try {
1116 mBarService.onNotificationClear(_pkg, _tag, _id);
1117 } catch (RemoteException ex) {
1118 // system process is dead if we're here.
1119 }
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001120 }
Joe Onoratoa4a65032010-09-27 15:53:44 -07001121 });
1122 } else {
1123 vetoButton.setVisibility(View.INVISIBLE);
1124 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001125
Joe Onorato561d3852010-11-20 18:09:34 -08001126 // the large icon
1127 ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);
1128 if (sbn.notification.largeIcon != null) {
1129 largeIcon.setImageBitmap(sbn.notification.largeIcon);
1130 } else {
1131 largeIcon.getLayoutParams().width = 0;
1132 largeIcon.setVisibility(View.INVISIBLE);
1133 }
1134
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001135 // bind the click event to the content area
1136 ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
1137 // XXX: update to allow controls within notification views
1138 content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
1139// content.setOnFocusChangeListener(mFocusChangeListener);
1140 PendingIntent contentIntent = sbn.notification.contentIntent;
1141 if (contentIntent != null) {
1142 content.setOnClickListener(new NotificationClicker(contentIntent,
1143 sbn.pkg, sbn.tag, sbn.id));
Joe Onorato184498c2010-10-08 17:57:18 -04001144 } else {
1145 content.setOnClickListener(null);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001146 }
1147
1148 View expanded = null;
1149 Exception exception = null;
1150 try {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001151 expanded = remoteViews.apply(mContext, content);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001152 }
1153 catch (RuntimeException e) {
1154 exception = e;
1155 }
1156 if (expanded == null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08001157 final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001158 Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
1159 return false;
1160 } else {
1161 content.addView(expanded);
1162 row.setDrawingCacheEnabled(true);
1163 }
1164
1165 entry.row = row;
1166 entry.content = content;
1167 entry.expanded = expanded;
1168
1169 return true;
1170 }
Daniel Sandlerce70d912010-09-02 11:59:41 -04001171
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001172/*
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001173 public class ShadowController {
1174 boolean mShowShadows;
Daniel Sandlerb9606992010-11-19 14:47:59 -05001175 Map<View, View> mShadowsForElements = new IdentityHashMap<View, View>(7);
1176 Map<View, View> mElementsForShadows = new IdentityHashMap<View, View>(7);
1177 LayoutTransition mElementTransition, mShadowTransition;
1178
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001179 View mTouchTarget;
Daniel Sandlerce70d912010-09-02 11:59:41 -04001180
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001181 ShadowController(boolean showShadows) {
1182 mShowShadows = showShadows;
1183 mTouchTarget = null;
Daniel Sandlerb9606992010-11-19 14:47:59 -05001184
1185 mElementTransition = new LayoutTransition();
1186// AnimatorSet s = new AnimatorSet();
1187// s.play(ObjectAnimator.ofInt(null, "top", 48, 0))
1188// .with(ObjectAnimator.ofFloat(null, "scaleY", 0.5f, 1f))
1189// .with(ObjectAnimator.ofFloat(null, "alpha", 0.5f, 1f))
1190// ;
1191 mElementTransition.setAnimator(LayoutTransition.APPEARING, //s);
1192 ObjectAnimator.ofInt(null, "top", 48, 0));
1193 mElementTransition.setDuration(LayoutTransition.APPEARING, 100);
1194 mElementTransition.setStartDelay(LayoutTransition.APPEARING, 0);
1195
1196// s = new AnimatorSet();
1197// s.play(ObjectAnimator.ofInt(null, "top", 0, 48))
1198// .with(ObjectAnimator.ofFloat(null, "scaleY", 1f, 0.5f))
1199// .with(ObjectAnimator.ofFloat(null, "alpha", 1f, 0.5f))
1200// ;
1201 mElementTransition.setAnimator(LayoutTransition.DISAPPEARING, //s);
1202 ObjectAnimator.ofInt(null, "top", 0, 48));
1203 mElementTransition.setDuration(LayoutTransition.DISAPPEARING, 400);
1204
1205 mShadowTransition = new LayoutTransition();
1206 mShadowTransition.setAnimator(LayoutTransition.APPEARING,
1207 ObjectAnimator.ofFloat(null, "alpha", 0f, 1f));
1208 mShadowTransition.setDuration(LayoutTransition.APPEARING, 200);
1209 mShadowTransition.setStartDelay(LayoutTransition.APPEARING, 100);
1210 mShadowTransition.setAnimator(LayoutTransition.DISAPPEARING,
1211 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
1212 mShadowTransition.setDuration(LayoutTransition.DISAPPEARING, 100);
1213
1214 ViewGroup bar = (ViewGroup) TabletStatusBar.this.mBarContents;
1215 bar.setLayoutTransition(mElementTransition);
1216 ViewGroup nav = (ViewGroup) TabletStatusBar.this.mNavigationArea;
1217 nav.setLayoutTransition(mElementTransition);
1218 ViewGroup shadowGroup = (ViewGroup) bar.findViewById(R.id.shadows);
1219 shadowGroup.setLayoutTransition(mShadowTransition);
1220 }
1221
1222 public void add(View element, View shadow) {
1223 shadow.setOnTouchListener(makeTouchListener());
1224 mShadowsForElements.put(element, shadow);
1225 mElementsForShadows.put(shadow, element);
Joe Onoratof63b0f42010-09-12 17:03:19 -04001226 }
1227
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001228 public boolean getShadowState() {
1229 return mShowShadows;
Joe Onoratof63b0f42010-09-12 17:03:19 -04001230 }
1231
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001232 public View.OnTouchListener makeTouchListener() {
1233 return new View.OnTouchListener() {
1234 public boolean onTouch(View v, MotionEvent ev) {
1235 final int action = ev.getAction();
1236
1237 if (DEBUG) Slog.d(TAG, "ShadowController: v=" + v + ", ev=" + ev);
1238
1239 // currently redirecting events?
1240 if (mTouchTarget == null) {
Daniel Sandlerb9606992010-11-19 14:47:59 -05001241 mTouchTarget = mElementsForShadows.get(v);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001242 }
1243
1244 if (mTouchTarget != null && mTouchTarget.getVisibility() != View.GONE) {
1245 boolean last = false;
1246 switch (action) {
1247 case MotionEvent.ACTION_CANCEL:
1248 case MotionEvent.ACTION_UP:
Daniel Sandlere03d1bc2010-11-17 21:36:40 -05001249 mHandler.removeMessages(MSG_RESTORE_SHADOWS);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001250 if (mShowShadows) {
Daniel Sandlere03d1bc2010-11-17 21:36:40 -05001251 mHandler.sendEmptyMessageDelayed(MSG_RESTORE_SHADOWS,
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001252 v == mNotificationShadow ? 5000 : 500);
1253 }
1254 last = true;
1255 break;
1256 case MotionEvent.ACTION_DOWN:
Daniel Sandlere03d1bc2010-11-17 21:36:40 -05001257 mHandler.removeMessages(MSG_RESTORE_SHADOWS);
Daniel Sandlerb9606992010-11-19 14:47:59 -05001258 setElementShadow(mTouchTarget, false);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001259 break;
1260 }
1261 mTouchTarget.dispatchTouchEvent(ev);
1262 if (last) mTouchTarget = null;
1263 return true;
1264 }
1265
1266 return false;
1267 }
1268 };
Joe Onoratof63b0f42010-09-12 17:03:19 -04001269 }
1270
Daniel Sandlere03d1bc2010-11-17 21:36:40 -05001271 public void refresh() {
Daniel Sandlerb9606992010-11-19 14:47:59 -05001272 for (View element : mShadowsForElements.keySet()) {
1273 setElementShadow(element, mShowShadows);
1274 }
Daniel Sandlere03d1bc2010-11-17 21:36:40 -05001275 }
1276
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001277 public void showAllShadows() {
1278 mShowShadows = true;
Daniel Sandlere03d1bc2010-11-17 21:36:40 -05001279 refresh();
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001280 }
1281
1282 public void hideAllShadows() {
1283 mShowShadows = false;
Daniel Sandlere03d1bc2010-11-17 21:36:40 -05001284 refresh();
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001285 }
1286
1287 // Use View.INVISIBLE for things hidden due to shadowing, and View.GONE for things that are
1288 // disabled (and should not be shadowed or re-shown)
Daniel Sandlerb9606992010-11-19 14:47:59 -05001289 public void setElementShadow(View button, boolean shade) {
1290 View shadow = mShadowsForElements.get(button);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001291 if (shadow != null) {
1292 if (button.getVisibility() != View.GONE) {
1293 shadow.setVisibility(shade ? View.VISIBLE : View.INVISIBLE);
1294 button.setVisibility(shade ? View.INVISIBLE : View.VISIBLE);
1295 }
1296 }
1297 }
Daniel Sandlerb9606992010-11-19 14:47:59 -05001298
1299 // Hide both element and shadow, using default layout animations.
1300 public void hideElement(View button) {
1301 Slog.d(TAG, "hiding: " + button);
1302 View shadow = mShadowsForElements.get(button);
1303 if (shadow != null) {
1304 shadow.setVisibility(View.GONE);
1305 }
1306 button.setVisibility(View.GONE);
1307 }
1308
1309 // Honoring the current shadow state.
1310 public void showElement(View button) {
1311 Slog.d(TAG, "showing: " + button);
1312 View shadow = mShadowsForElements.get(button);
1313 if (shadow != null) {
1314 shadow.setVisibility(mShowShadows ? View.VISIBLE : View.INVISIBLE);
1315 }
1316 button.setVisibility(mShowShadows ? View.INVISIBLE : View.VISIBLE);
1317 }
Daniel Sandlerce70d912010-09-02 11:59:41 -04001318 }
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001319 */
Joe Onoratob62ac122010-09-20 16:16:32 -04001320
1321 public class TouchOutsideListener implements View.OnTouchListener {
1322 private int mMsg;
Joe Onoratoddf680b2010-09-26 13:59:40 -07001323 private StatusBarPanel mPanel;
Joe Onoratob62ac122010-09-20 16:16:32 -04001324
Joe Onoratoddf680b2010-09-26 13:59:40 -07001325 public TouchOutsideListener(int msg, StatusBarPanel panel) {
Joe Onoratob62ac122010-09-20 16:16:32 -04001326 mMsg = msg;
Joe Onoratoddf680b2010-09-26 13:59:40 -07001327 mPanel = panel;
Joe Onoratob62ac122010-09-20 16:16:32 -04001328 }
1329
1330 public boolean onTouch(View v, MotionEvent ev) {
Joe Onoratoddf680b2010-09-26 13:59:40 -07001331 final int action = ev.getAction();
1332 if (action == MotionEvent.ACTION_OUTSIDE
1333 || (action == MotionEvent.ACTION_DOWN
1334 && !mPanel.isInContentArea((int)ev.getX(), (int)ev.getY()))) {
Joe Onoratob62ac122010-09-20 16:16:32 -04001335 mHandler.removeMessages(mMsg);
1336 mHandler.sendEmptyMessage(mMsg);
1337 return true;
1338 }
1339 return false;
1340 }
1341 }
Joe Onorato091e1b82010-09-26 18:04:44 -07001342
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001343 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1344 pw.print("mDisabled=0x");
1345 pw.println(Integer.toHexString(mDisabled));
1346 }
Joe Onorato808182d2010-07-09 18:52:06 -04001347}
Daniel Sandlerd39e3882010-08-31 14:16:13 -04001348
1349