blob: 172aaa1c33fbbbb7c0508302d50da9dafebe637a [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;
Daniel Sandleraa051d62011-03-01 16:23:57 -050045import android.view.accessibility.AccessibilityEvent;
Joe Onorato07949e92011-05-25 17:35:35 -070046import android.view.Display;
Joe Onorato808182d2010-07-09 18:52:06 -040047import android.view.Gravity;
Daniel Sandler10163c62010-12-08 11:51:05 -050048import android.view.IWindowManager;
49import android.view.KeyEvent;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040050import android.view.LayoutInflater;
Joe Onoratob62ac122010-09-20 16:16:32 -040051import android.view.MotionEvent;
Daniel Sandleraa051d62011-03-01 16:23:57 -050052import android.view.SoundEffectConstants;
Daniel Sandler8304da42010-10-25 15:53:25 -040053import android.view.VelocityTracker;
Joe Onorato808182d2010-07-09 18:52:06 -040054import android.view.View;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -040055import android.view.ViewConfiguration;
Daniel Sandler9120d552010-07-23 09:11:14 -040056import android.view.ViewGroup;
57import android.view.WindowManager;
58import android.view.WindowManagerImpl;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -040059import android.widget.ImageView;
Joe Onorato808182d2010-07-09 18:52:06 -040060import android.widget.LinearLayout;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -040061import android.widget.RemoteViews;
62import android.widget.ScrollView;
Daniel Sandler9120d552010-07-23 09:11:14 -040063import android.widget.TextView;
Joe Onorato808182d2010-07-09 18:52:06 -040064
65import com.android.internal.statusbar.StatusBarIcon;
Joe Onorato808182d2010-07-09 18:52:06 -040066import com.android.internal.statusbar.StatusBarNotification;
67
Joe Onorato808182d2010-07-09 18:52:06 -040068import com.android.systemui.R;
Joe Onoratofd52b182010-11-10 18:00:52 -080069import com.android.systemui.statusbar.*;
70import com.android.systemui.statusbar.policy.BatteryController;
Joe Onoratofce2bf32011-02-01 17:00:29 -080071import com.android.systemui.statusbar.policy.BluetoothController;
Daniel Sandlere40451a2011-02-03 14:51:35 -050072import com.android.systemui.statusbar.policy.LocationController;
Joe Onoratofd52b182010-11-10 18:00:52 -080073import com.android.systemui.statusbar.policy.NetworkController;
Daniel Sandlerce6ff642011-02-18 12:51:08 -050074import com.android.systemui.statusbar.policy.Prefs;
Joe Onoratofd52b182010-11-10 18:00:52 -080075import com.android.systemui.recent.RecentApplicationsActivity;
Joe Onorato808182d2010-07-09 18:52:06 -040076
Joe Onoratodc100302011-01-11 17:07:41 -080077public class TabletStatusBar extends StatusBar implements
Jeff Brown2992ea72011-01-28 22:04:14 -080078 HeightReceiver.OnBarHeightChangedListener,
79 InputMethodsPanel.OnHardKeyboardEnabledChangeListener {
Daniel Sandlerfb970e92010-08-20 10:57:17 -040080 public static final boolean DEBUG = false;
Joe Onoratofd52b182010-11-10 18:00:52 -080081 public static final String TAG = "TabletStatusBar";
Joe Onorato808182d2010-07-09 18:52:06 -040082
Daniel Sandler0ad460b2010-12-14 12:14:53 -050083 public static final int MAX_NOTIFICATION_ICONS = 5;
satok82beadf2010-12-27 19:03:06 +090084 // IME switcher icon is big and occupy width of two icons
satok51133822011-01-25 15:01:48 +090085 public static final int MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE = MAX_NOTIFICATION_ICONS - 1;
Daniel Sandler0ad460b2010-12-14 12:14:53 -050086
Joe Onoratob62ac122010-09-20 16:16:32 -040087 public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
88 public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -040089 public static final int MSG_OPEN_NOTIFICATION_PEEK = 1002;
90 public static final int MSG_CLOSE_NOTIFICATION_PEEK = 1003;
Jim Miller44c66fe2010-10-20 18:32:52 -070091 public static final int MSG_OPEN_RECENTS_PANEL = 1020;
92 public static final int MSG_CLOSE_RECENTS_PANEL = 1021;
Daniel Sandler0ad460b2010-12-14 12:14:53 -050093 public static final int MSG_SHOW_CHROME = 1030;
94 public static final int MSG_HIDE_CHROME = 1031;
satok82beadf2010-12-27 19:03:06 +090095 public static final int MSG_OPEN_INPUT_METHODS_PANEL = 1040;
96 public static final int MSG_CLOSE_INPUT_METHODS_PANEL = 1041;
Daniel Sandler2ed08d22011-01-30 16:07:28 -050097 public static final int MSG_STOP_TICKER = 2000;
Jim Miller44c66fe2010-10-20 18:32:52 -070098
Daniel Sandler3a2fded2011-02-23 11:19:59 -050099 // Fitts' Law assistance for LatinIME; see policy.EventHole
Daniel Sandler10163c62010-12-08 11:51:05 -0500100 private static final boolean FAKE_SPACE_BAR = true;
101
Joe Onoratodc100302011-01-11 17:07:41 -0800102 // The height of the bar, as definied by the build. It may be taller if we're plugged
103 // into hdmi.
104 int mNaturalBarHeight = -1;
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500105 int mIconSize = -1;
106 int mIconHPadding = -1;
Daniel Sandler9120d552010-07-23 09:11:14 -0400107
108 H mHandler = new H();
109
Daniel Sandler10163c62010-12-08 11:51:05 -0500110 IWindowManager mWindowManager;
111
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400112 // tracking all current notifications
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500113 private NotificationData mNotificationData = new NotificationData();
Jim Miller44c66fe2010-10-20 18:32:52 -0700114
Joe Onoratob62ac122010-09-20 16:16:32 -0400115 TabletStatusBarView mStatusBarView;
Joe Onoratofd52b182010-11-10 18:00:52 -0800116 View mNotificationArea;
117 View mNotificationTrigger;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400118 NotificationIconArea mNotificationIconArea;
Daniel Sandler21eb86a2011-03-02 11:52:58 -0500119 ViewGroup mNavigationArea;
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500120
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500121 boolean mNotificationDNDMode;
122 NotificationData.Entry mNotificationDNDDummyEntry;
123
Joe Onorato536c58f2010-11-28 17:52:28 -0800124 ImageView mBackButton;
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500125 View mHomeButton;
Daniel Sandlere02d8082010-10-08 15:13:22 -0400126 View mMenuButton;
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400127 View mRecentButton;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400128
Joe Onoratoec51a822011-01-04 16:33:01 -0800129 ViewGroup mNotificationAndImeArea;
satokcd7cd292010-11-20 15:46:23 +0900130 InputMethodButton mInputMethodSwitchButton;
satok06487a52010-10-29 11:37:18 +0900131
Joe Onoratoddf680b2010-09-26 13:59:40 -0700132 NotificationPanel mNotificationPanel;
Joe Onorato07949e92011-05-25 17:35:35 -0700133 WindowManager.LayoutParams mNotificationPanelParams;
Joe Onorato8a576712010-11-15 16:50:34 -0800134 NotificationPeekPanel mNotificationPeekWindow;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400135 ViewGroup mNotificationPeekRow;
136 int mNotificationPeekIndex;
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500137 IBinder mNotificationPeekKey;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400138 LayoutTransition mNotificationPeekScrubLeft, mNotificationPeekScrubRight;
139
140 int mNotificationPeekTapDuration;
141 int mNotificationFlingVelocity;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400142
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400143 ViewGroup mPile;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400144
Joe Onoratodc100302011-01-11 17:07:41 -0800145 HeightReceiver mHeightReceiver;
Joe Onoratofd52b182010-11-10 18:00:52 -0800146 BatteryController mBatteryController;
Joe Onoratofce2bf32011-02-01 17:00:29 -0800147 BluetoothController mBluetoothController;
Daniel Sandlere40451a2011-02-03 14:51:35 -0500148 LocationController mLocationController;
Joe Onoratofd52b182010-11-10 18:00:52 -0800149 NetworkController mNetworkController;
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400150
Daniel Sandler21eb86a2011-03-02 11:52:58 -0500151 ViewGroup mBarContents;
152 LayoutTransition mBarContentsLayoutTransition;
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500153
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500154 // hide system chrome ("lights out") support
155 View mShadow;
Daniel Sandlerce70d912010-09-02 11:59:41 -0400156
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400157 NotificationIconArea.IconLayout mIconLayout;
158
Joe Onoratoef1e7762010-09-17 18:38:38 -0400159 TabletTicker mTicker;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400160
Daniel Sandler10163c62010-12-08 11:51:05 -0500161 View mFakeSpaceBar;
162 KeyEvent mSpaceBarKeyEvent = null;
163
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400164 // for disabling the status bar
165 int mDisabled = 0;
166
Jim Miller44c66fe2010-10-20 18:32:52 -0700167 private RecentAppsPanel mRecentsPanel;
satok82beadf2010-12-27 19:03:06 +0900168 private InputMethodsPanel mInputMethodsPanel;
Joe Onorato55d2d762010-09-26 13:02:01 -0700169
Daniel Sandlerc51451a2010-12-16 19:06:46 -0500170 public Context getContext() { return mContext; }
171
Daniel Sandler9120d552010-07-23 09:11:14 -0400172 protected void addPanelWindows() {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400173 final Context context = mContext;
Joe Onorato07949e92011-05-25 17:35:35 -0700174 final Resources res = mContext.getResources();
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400175
Jim Miller44c66fe2010-10-20 18:32:52 -0700176 // Notification Panel
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400177 mNotificationPanel = (NotificationPanel)View.inflate(context,
Joe Onorato755cc742010-11-27 15:45:35 -0800178 R.layout.status_bar_notification_panel, null);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800179 mNotificationPanel.show(false, false);
Joe Onoratob62ac122010-09-20 16:16:32 -0400180 mNotificationPanel.setOnTouchListener(
Joe Onoratoddf680b2010-09-26 13:59:40 -0700181 new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PANEL, mNotificationPanel));
Joe Onoratob62ac122010-09-20 16:16:32 -0400182
Joe Onoratofd52b182010-11-10 18:00:52 -0800183 // the battery and network icons
184 mBatteryController.addIconView((ImageView)mNotificationPanel.findViewById(R.id.battery));
185 mBatteryController.addLabelView(
186 (TextView)mNotificationPanel.findViewById(R.id.battery_text));
Joe Onoratofce2bf32011-02-01 17:00:29 -0800187 mBluetoothController.addIconView(
188 (ImageView)mNotificationPanel.findViewById(R.id.bluetooth));
Joe Onoratoddbba422010-11-23 15:42:28 -0800189 mNetworkController.addCombinedSignalIconView(
Joe Onorato42f8e132010-11-29 15:52:43 -0800190 (ImageView)mNotificationPanel.findViewById(R.id.network_signal));
191 mNetworkController.addDataTypeIconView(
192 (ImageView)mNotificationPanel.findViewById(R.id.network_type));
Joe Onoratofce2bf32011-02-01 17:00:29 -0800193 mNetworkController.addDataDirectionOverlayIconView(
194 (ImageView)mNotificationPanel.findViewById(R.id.network_direction));
Joe Onoratofd52b182010-11-10 18:00:52 -0800195 mNetworkController.addLabelView(
196 (TextView)mNotificationPanel.findViewById(R.id.network_text));
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500197 mNetworkController.addLabelView(
198 (TextView)mBarContents.findViewById(R.id.network_text));
Joe Onoratofd52b182010-11-10 18:00:52 -0800199
Joe Onorato55d2d762010-09-26 13:02:01 -0700200 mStatusBarView.setIgnoreChildren(0, mNotificationTrigger, mNotificationPanel);
Daniel Sandlerd39e3882010-08-31 14:16:13 -0400201
Joe Onorato07949e92011-05-25 17:35:35 -0700202 WindowManager.LayoutParams lp = mNotificationPanelParams = new WindowManager.LayoutParams(
203 res.getDimensionPixelSize(R.dimen.notification_panel_width),
204 getNotificationPanelHeight(),
Daniel Sandler9120d552010-07-23 09:11:14 -0400205 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
206 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
Joe Onorato07949e92011-05-25 17:35:35 -0700207 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
Jeff Brown46e75292010-11-10 16:53:45 -0800208 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
Joe Onorato7c270fa2010-12-08 17:31:42 -0800209 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
210 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
Daniel Sandler9120d552010-07-23 09:11:14 -0400211 PixelFormat.TRANSLUCENT);
Joe Onoratoea70e632010-09-27 17:59:37 -0700212 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
Daniel Sandler9120d552010-07-23 09:11:14 -0400213 lp.setTitle("NotificationPanel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800214 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
215 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
216 lp.windowAnimations = com.android.internal.R.style.Animation; // == no animation
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500217// lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade
Daniel Sandler9120d552010-07-23 09:11:14 -0400218
219 WindowManagerImpl.getDefault().addView(mNotificationPanel, lp);
220
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400221 // Notification preview window
Joe Onorato8a576712010-11-15 16:50:34 -0800222 mNotificationPeekWindow = (NotificationPeekPanel) View.inflate(context,
Joe Onorato755cc742010-11-27 15:45:35 -0800223 R.layout.status_bar_notification_peek, null);
Daniel Sandler663f0f22011-03-04 16:45:02 -0500224 mNotificationPeekWindow.setBar(this);
225
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400226 mNotificationPeekRow = (ViewGroup) mNotificationPeekWindow.findViewById(R.id.content);
227 mNotificationPeekWindow.setVisibility(View.GONE);
228 mNotificationPeekWindow.setOnTouchListener(
Joe Onorato5e759462010-11-28 17:43:50 -0800229 new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PEEK, mNotificationPeekWindow));
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400230 mNotificationPeekScrubRight = new LayoutTransition();
Jim Miller85babff2011-01-11 14:26:03 -0800231 mNotificationPeekScrubRight.setAnimator(LayoutTransition.APPEARING,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400232 ObjectAnimator.ofInt(null, "left", -512, 0));
Jim Miller85babff2011-01-11 14:26:03 -0800233 mNotificationPeekScrubRight.setAnimator(LayoutTransition.DISAPPEARING,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400234 ObjectAnimator.ofInt(null, "left", -512, 0));
235 mNotificationPeekScrubRight.setDuration(500);
236
237 mNotificationPeekScrubLeft = new LayoutTransition();
Jim Miller85babff2011-01-11 14:26:03 -0800238 mNotificationPeekScrubLeft.setAnimator(LayoutTransition.APPEARING,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400239 ObjectAnimator.ofInt(null, "left", 512, 0));
Jim Miller85babff2011-01-11 14:26:03 -0800240 mNotificationPeekScrubLeft.setAnimator(LayoutTransition.DISAPPEARING,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400241 ObjectAnimator.ofInt(null, "left", 512, 0));
242 mNotificationPeekScrubLeft.setDuration(500);
243
244 // XXX: setIgnoreChildren?
245 lp = new WindowManager.LayoutParams(
246 512, // ViewGroup.LayoutParams.WRAP_CONTENT,
247 ViewGroup.LayoutParams.WRAP_CONTENT,
248 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
249 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
Jeff Brown46e75292010-11-10 16:53:45 -0800250 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
251 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400252 PixelFormat.TRANSLUCENT);
253 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
254 lp.setTitle("NotificationPeekWindow");
255 lp.windowAnimations = com.android.internal.R.style.Animation_Toast;
256
257 WindowManagerImpl.getDefault().addView(mNotificationPeekWindow, lp);
258
Jim Miller44c66fe2010-10-20 18:32:52 -0700259 // Recents Panel
Jim Miller85babff2011-01-11 14:26:03 -0800260 mRecentsPanel = (RecentAppsPanel) View.inflate(context,
261 R.layout.status_bar_recent_panel, null);
262 mRecentsPanel.setVisibility(View.GONE);
263 mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
264 mRecentsPanel));
265 mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
Jim Miller44c66fe2010-10-20 18:32:52 -0700266
Jim Miller85babff2011-01-11 14:26:03 -0800267 lp = new WindowManager.LayoutParams(
268 ViewGroup.LayoutParams.WRAP_CONTENT,
269 ViewGroup.LayoutParams.WRAP_CONTENT,
270 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
271 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
272 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
273 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
274 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
275 PixelFormat.TRANSLUCENT);
276 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
277 lp.setTitle("RecentsPanel");
278 lp.windowAnimations = R.style.Animation_RecentPanel;
Jim Miller5fda69c2011-02-16 15:17:11 -0800279 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
280 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
Jim Miller44c66fe2010-10-20 18:32:52 -0700281
Jim Miller85babff2011-01-11 14:26:03 -0800282 WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
283 mRecentsPanel.setBar(this);
satok82beadf2010-12-27 19:03:06 +0900284
285 // Input methods Panel
286 mInputMethodsPanel = (InputMethodsPanel) View.inflate(context,
287 R.layout.status_bar_input_methods_panel, null);
Jeff Brown2992ea72011-01-28 22:04:14 -0800288 mInputMethodsPanel.setHardKeyboardEnabledChangeListener(this);
satok82beadf2010-12-27 19:03:06 +0900289 mInputMethodsPanel.setOnTouchListener(new TouchOutsideListener(
290 MSG_CLOSE_INPUT_METHODS_PANEL, mInputMethodsPanel));
satok913f42d2011-01-17 16:58:10 +0900291 mInputMethodsPanel.setImeSwitchButton(mInputMethodSwitchButton);
satok82beadf2010-12-27 19:03:06 +0900292 mStatusBarView.setIgnoreChildren(3, mInputMethodSwitchButton, mInputMethodsPanel);
293 lp = new WindowManager.LayoutParams(
294 ViewGroup.LayoutParams.WRAP_CONTENT,
295 ViewGroup.LayoutParams.WRAP_CONTENT,
296 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
297 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
298 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
299 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
300 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
301 PixelFormat.TRANSLUCENT);
302 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
303 lp.setTitle("InputMethodsPanel");
304 lp.windowAnimations = R.style.Animation_RecentPanel;
305
306 WindowManagerImpl.getDefault().addView(mInputMethodsPanel, lp);
Daniel Sandler9120d552010-07-23 09:11:14 -0400307 }
Joe Onorato808182d2010-07-09 18:52:06 -0400308
Joe Onorato07949e92011-05-25 17:35:35 -0700309 private int getNotificationPanelHeight() {
310 final Resources res = mContext.getResources();
311 final Display d = WindowManagerImpl.getDefault().getDefaultDisplay();
312 return Math.max(res.getDimensionPixelSize(R.dimen.notification_panel_min_height),
313 d.getHeight());
314 }
315
Joe Onorato808182d2010-07-09 18:52:06 -0400316 @Override
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400317 public void start() {
318 super.start(); // will add the main bar view
Joe Onorato808182d2010-07-09 18:52:06 -0400319 }
320
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500321 @Override
Joe Onoratodc100302011-01-11 17:07:41 -0800322 protected void onConfigurationChanged(Configuration newConfig) {
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500323 loadDimens();
Joe Onorato07949e92011-05-25 17:35:35 -0700324 mNotificationPanelParams.height = getNotificationPanelHeight();
325 WindowManagerImpl.getDefault().updateViewLayout(mNotificationPanel,
326 mNotificationPanelParams);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500327 }
328
329 protected void loadDimens() {
330 final Resources res = mContext.getResources();
331
Joe Onoratodc100302011-01-11 17:07:41 -0800332 mNaturalBarHeight = res.getDimensionPixelSize(
Dianne Hackborn81e56d52011-05-26 00:55:58 -0700333 com.android.internal.R.dimen.system_bar_height);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500334
335 int newIconSize = res.getDimensionPixelSize(
Dianne Hackborn81e56d52011-05-26 00:55:58 -0700336 com.android.internal.R.dimen.system_bar_icon_size);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500337 int newIconHPadding = res.getDimensionPixelSize(
338 R.dimen.status_bar_icon_padding);
339
340 if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
341// Slog.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
342 mIconHPadding = newIconHPadding;
343 mIconSize = newIconSize;
344 reloadAllNotificationIcons(); // reload the tray
345 }
346 }
347
Joe Onorato808182d2010-07-09 18:52:06 -0400348 protected View makeStatusBarView() {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400349 final Context context = mContext;
Jim Miller85babff2011-01-11 14:26:03 -0800350
Daniel Sandler10163c62010-12-08 11:51:05 -0500351 mWindowManager = IWindowManager.Stub.asInterface(
352 ServiceManager.getService(Context.WINDOW_SERVICE));
Joe Onorato808182d2010-07-09 18:52:06 -0400353
Joe Onoratodc100302011-01-11 17:07:41 -0800354 // This guy will listen for HDMI plugged broadcasts so we can resize the
355 // status bar as appropriate.
356 mHeightReceiver = new HeightReceiver(mContext);
357 mHeightReceiver.registerReceiver();
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500358 loadDimens();
Joe Onorato808182d2010-07-09 18:52:06 -0400359
Joe Onoratob62ac122010-09-20 16:16:32 -0400360 final TabletStatusBarView sb = (TabletStatusBarView)View.inflate(
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400361 context, R.layout.status_bar, null);
Joe Onorato808182d2010-07-09 18:52:06 -0400362 mStatusBarView = sb;
363
Joe Onoratob62ac122010-09-20 16:16:32 -0400364 sb.setHandler(mHandler);
365
Daniel Sandler21eb86a2011-03-02 11:52:58 -0500366 mBarContents = (ViewGroup) sb.findViewById(R.id.bar_contents);
367 // layout transitions for the status bar's contents
368 mBarContentsLayoutTransition = new LayoutTransition();
369 // add/removal will fade as normal
370 mBarContentsLayoutTransition.setAnimator(LayoutTransition.APPEARING,
371 ObjectAnimator.ofFloat(null, "alpha", 0f, 1f));
372 mBarContentsLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING,
373 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
374 // no animations for siblings on change: just jump into place please
375 mBarContentsLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, null);
376 mBarContentsLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, null);
377 // quick like bunny
378 mBarContentsLayoutTransition.setDuration(250 * (DEBUG?10:1));
379 mBarContents.setLayoutTransition(mBarContentsLayoutTransition);
Joe Onoratof63b0f42010-09-12 17:03:19 -0400380
Joe Onoratofd52b182010-11-10 18:00:52 -0800381 // the whole right-hand side of the bar
382 mNotificationArea = sb.findViewById(R.id.notificationArea);
383
Joe Onorato55d2d762010-09-26 13:02:01 -0700384 // the button to open the notification area
Joe Onoratofd52b182010-11-10 18:00:52 -0800385 mNotificationTrigger = sb.findViewById(R.id.notificationTrigger);
Daniel Sandler56a6d882011-02-23 16:40:33 -0500386 mNotificationTrigger.setOnTouchListener(new NotificationTriggerTouchListener());
Joe Onorato55d2d762010-09-26 13:02:01 -0700387
Joe Onorato808182d2010-07-09 18:52:06 -0400388 // the more notifications icon
389 mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons);
390
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400391 // where the icons go
392 mIconLayout = (NotificationIconArea.IconLayout) sb.findViewById(R.id.icons);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400393 mIconLayout.setOnTouchListener(new NotificationIconTouchListener());
394
395 ViewConfiguration vc = ViewConfiguration.get(context);
396 mNotificationPeekTapDuration = vc.getTapTimeout();
397 mNotificationFlingVelocity = 300; // px/s
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400398
Daniel Sandlerc51451a2010-12-16 19:06:46 -0500399 mTicker = new TabletTicker(this);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400400
Joe Onoratofd52b182010-11-10 18:00:52 -0800401 // The icons
Daniel Sandlere40451a2011-02-03 14:51:35 -0500402 mLocationController = new LocationController(mContext); // will post a notification
403
Joe Onoratofd52b182010-11-10 18:00:52 -0800404 mBatteryController = new BatteryController(mContext);
405 mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));
Joe Onoratofce2bf32011-02-01 17:00:29 -0800406 mBluetoothController = new BluetoothController(mContext);
407 mBluetoothController.addIconView((ImageView)sb.findViewById(R.id.bluetooth));
Joe Onoratofd52b182010-11-10 18:00:52 -0800408 mNetworkController = new NetworkController(mContext);
Joe Onorato42f8e132010-11-29 15:52:43 -0800409 mNetworkController.addCombinedSignalIconView(
410 (ImageView)sb.findViewById(R.id.network_signal));
411 mNetworkController.addDataTypeIconView(
412 (ImageView)sb.findViewById(R.id.network_type));
Joe Onoratofce2bf32011-02-01 17:00:29 -0800413 mNetworkController.addDataDirectionOverlayIconView(
414 (ImageView)sb.findViewById(R.id.network_direction));
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400415
Joe Onorato091e1b82010-09-26 18:04:44 -0700416 // The navigation buttons
Joe Onorato6478adc2011-01-27 21:15:01 -0800417 mBackButton = (ImageView)sb.findViewById(R.id.back);
Daniel Sandler21eb86a2011-03-02 11:52:58 -0500418 mNavigationArea = (ViewGroup) sb.findViewById(R.id.navigationArea);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500419 mHomeButton = mNavigationArea.findViewById(R.id.home);
Daniel Sandlere02d8082010-10-08 15:13:22 -0400420 mMenuButton = mNavigationArea.findViewById(R.id.menu);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500421 mRecentButton = mNavigationArea.findViewById(R.id.recent_apps);
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500422 mRecentButton.setOnClickListener(mOnClickListener);
Daniel Sandler21eb86a2011-03-02 11:52:58 -0500423 mNavigationArea.setLayoutTransition(mBarContentsLayoutTransition);
Joe Onorato091e1b82010-09-26 18:04:44 -0700424
satok06487a52010-10-29 11:37:18 +0900425 // The bar contents buttons
Joe Onoratoec51a822011-01-04 16:33:01 -0800426 mNotificationAndImeArea = (ViewGroup)sb.findViewById(R.id.notificationAndImeArea);
satokcd7cd292010-11-20 15:46:23 +0900427 mInputMethodSwitchButton = (InputMethodButton) sb.findViewById(R.id.imeSwitchButton);
satok82beadf2010-12-27 19:03:06 +0900428 // Overwrite the lister
429 mInputMethodSwitchButton.setOnClickListener(mOnClickListener);
satok06487a52010-10-29 11:37:18 +0900430
Daniel Sandler10163c62010-12-08 11:51:05 -0500431 // for redirecting errant bar taps to the IME
432 mFakeSpaceBar = sb.findViewById(R.id.fake_space_bar);
433
Daniel Sandlerb9606992010-11-19 14:47:59 -0500434 // "shadows" of the status bar features, for lights-out mode
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500435 mShadow = sb.findViewById(R.id.bar_shadow);
436 mShadow.setOnTouchListener(
437 new View.OnTouchListener() {
438 public boolean onTouch(View v, MotionEvent ev) {
439 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
Daniel Sandlerd7201552011-01-28 09:58:02 -0500440 // even though setting the systemUI visibility below will turn these views
441 // on, we need them to come up faster so that they can catch this motion
442 // event
443 mShadow.setVisibility(View.GONE);
444 mBarContents.setVisibility(View.VISIBLE);
445
Joe Onorato55bf3802011-01-25 13:42:10 -0800446 try {
447 mBarService.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
448 } catch (RemoteException ex) {
449 // system process dead
450 }
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500451 }
452 return false;
453 }
454 });
Daniel Sandlerb9606992010-11-19 14:47:59 -0500455
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500456 // tuning parameters
457 final int LIGHTS_GOING_OUT_SYSBAR_DURATION = 600;
458 final int LIGHTS_GOING_OUT_SHADOW_DURATION = 1000;
459 final int LIGHTS_GOING_OUT_SHADOW_DELAY = 500;
460
461 final int LIGHTS_COMING_UP_SYSBAR_DURATION = 200;
462// final int LIGHTS_COMING_UP_SYSBAR_DELAY = 50;
463 final int LIGHTS_COMING_UP_SHADOW_DURATION = 0;
464
465 LayoutTransition xition = new LayoutTransition();
466 xition.setAnimator(LayoutTransition.APPEARING,
467 ObjectAnimator.ofFloat(null, "alpha", 0.5f, 1f));
468 xition.setDuration(LayoutTransition.APPEARING, LIGHTS_COMING_UP_SYSBAR_DURATION);
469 xition.setStartDelay(LayoutTransition.APPEARING, 0);
470 xition.setAnimator(LayoutTransition.DISAPPEARING,
471 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
472 xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_GOING_OUT_SYSBAR_DURATION);
473 xition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
474 ((ViewGroup)sb.findViewById(R.id.bar_contents_holder)).setLayoutTransition(xition);
475
476 xition = new LayoutTransition();
477 xition.setAnimator(LayoutTransition.APPEARING,
478 ObjectAnimator.ofFloat(null, "alpha", 0f, 1f));
479 xition.setDuration(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DURATION);
480 xition.setStartDelay(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DELAY);
481 xition.setAnimator(LayoutTransition.DISAPPEARING,
482 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
483 xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_COMING_UP_SHADOW_DURATION);
484 xition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
485 ((ViewGroup)sb.findViewById(R.id.bar_shadow_holder)).setLayoutTransition(xition);
Daniel Sandlerb9606992010-11-19 14:47:59 -0500486
Joe Onorato5dd11692010-09-27 15:34:04 -0700487 // set the initial view visibility
488 setAreThereNotifications();
489
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400490 // Add the windows
491 addPanelWindows();
492
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400493 mPile = (ViewGroup)mNotificationPanel.findViewById(R.id.content);
494 mPile.removeAllViews();
Jim Miller44c66fe2010-10-20 18:32:52 -0700495
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400496 ScrollView scroller = (ScrollView)mPile.getParent();
497 scroller.setFillViewport(true);
498
Joe Onoratodc100302011-01-11 17:07:41 -0800499 mHeightReceiver.addOnBarHeightChangedListener(this);
500
Joe Onorato808182d2010-07-09 18:52:06 -0400501 return sb;
502 }
503
Joe Onoratodc100302011-01-11 17:07:41 -0800504 public int getStatusBarHeight() {
505 return mHeightReceiver.getHeight();
506 }
507
Joe Onorato808182d2010-07-09 18:52:06 -0400508 protected int getStatusBarGravity() {
509 return Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
510 }
511
Joe Onoratodc100302011-01-11 17:07:41 -0800512 public void onBarHeightChanged(int height) {
513 final WindowManager.LayoutParams lp
514 = (WindowManager.LayoutParams)mStatusBarView.getLayoutParams();
515 if (lp == null) {
516 // haven't been added yet
517 return;
518 }
519 if (lp.height != height) {
520 lp.height = height;
521 final WindowManager wm = WindowManagerImpl.getDefault();
522 wm.updateViewLayout(mStatusBarView, lp);
523 }
524 }
525
Daniel Sandler9120d552010-07-23 09:11:14 -0400526 private class H extends Handler {
Daniel Sandler9120d552010-07-23 09:11:14 -0400527 public void handleMessage(Message m) {
528 switch (m.what) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400529 case MSG_OPEN_NOTIFICATION_PEEK:
530 if (DEBUG) Slog.d(TAG, "opening notification peek window; arg=" + m.arg1);
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500531
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400532 if (m.arg1 >= 0) {
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500533 final int N = mNotificationData.size();
534
535 if (!mNotificationDNDMode) {
536 if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
537 NotificationData.Entry entry = mNotificationData.get(N-1-mNotificationPeekIndex);
538 entry.icon.setBackgroundColor(0);
539 mNotificationPeekIndex = -1;
540 mNotificationPeekKey = null;
541 }
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400542 }
543
544 final int peekIndex = m.arg1;
545 if (peekIndex < N) {
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500546 //Slog.d(TAG, "loading peek: " + peekIndex);
Jim Miller5fda69c2011-02-16 15:17:11 -0800547 NotificationData.Entry entry =
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500548 mNotificationDNDMode
549 ? mNotificationDNDDummyEntry
550 : mNotificationData.get(N-1-peekIndex);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400551 NotificationData.Entry copy = new NotificationData.Entry(
Jim Miller85babff2011-01-11 14:26:03 -0800552 entry.key,
553 entry.notification,
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400554 entry.icon);
555 inflateViews(copy, mNotificationPeekRow);
556
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500557 if (mNotificationDNDMode) {
558 copy.content.setOnClickListener(new View.OnClickListener() {
559 public void onClick(View v) {
560 SharedPreferences.Editor editor = Prefs.edit(mContext);
561 editor.putBoolean(Prefs.DO_NOT_DISTURB_PREF, false);
562 editor.apply();
563 animateCollapse();
564 }
565 });
566 }
567
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400568 entry.icon.setBackgroundColor(0x20FFFFFF);
569
570// mNotificationPeekRow.setLayoutTransition(
Jim Miller85babff2011-01-11 14:26:03 -0800571// peekIndex < mNotificationPeekIndex
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400572// ? mNotificationPeekScrubLeft
573// : mNotificationPeekScrubRight);
574
575 mNotificationPeekRow.removeAllViews();
576 mNotificationPeekRow.addView(copy.row);
577
578 mNotificationPeekWindow.setVisibility(View.VISIBLE);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800579 mNotificationPanel.show(false, true);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400580
581 mNotificationPeekIndex = peekIndex;
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500582 mNotificationPeekKey = entry.key;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400583 }
584 }
585 break;
586 case MSG_CLOSE_NOTIFICATION_PEEK:
587 if (DEBUG) Slog.d(TAG, "closing notification peek window");
588 mNotificationPeekWindow.setVisibility(View.GONE);
589 mNotificationPeekRow.removeAllViews();
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500590
591 final int N = mNotificationData.size();
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500592 if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
Jim Miller5fda69c2011-02-16 15:17:11 -0800593 NotificationData.Entry entry =
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500594 mNotificationDNDMode
595 ? mNotificationDNDDummyEntry
596 : mNotificationData.get(N-1-mNotificationPeekIndex);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400597 entry.icon.setBackgroundColor(0);
598 }
Daniel Sandlera8e5b062010-12-01 13:53:08 -0500599
600 mNotificationPeekIndex = -1;
601 mNotificationPeekKey = null;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400602 break;
Daniel Sandler9120d552010-07-23 09:11:14 -0400603 case MSG_OPEN_NOTIFICATION_PANEL:
604 if (DEBUG) Slog.d(TAG, "opening notifications panel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800605 if (!mNotificationPanel.isShowing()) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -0400606 mNotificationPeekWindow.setVisibility(View.GONE);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800607 mNotificationPanel.show(true, true);
Daniel Sandler21eb86a2011-03-02 11:52:58 -0500608 mNotificationArea.setVisibility(View.INVISIBLE);
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800609 mTicker.halt();
Joe Onorato091e1b82010-09-26 18:04:44 -0700610 }
Daniel Sandler9120d552010-07-23 09:11:14 -0400611 break;
612 case MSG_CLOSE_NOTIFICATION_PANEL:
613 if (DEBUG) Slog.d(TAG, "closing notifications panel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800614 if (mNotificationPanel.isShowing()) {
615 mNotificationPanel.show(false, true);
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500616 mNotificationArea.setVisibility(View.VISIBLE);
Joe Onorato091e1b82010-09-26 18:04:44 -0700617 }
Daniel Sandler9120d552010-07-23 09:11:14 -0400618 break;
Jim Miller44c66fe2010-10-20 18:32:52 -0700619 case MSG_OPEN_RECENTS_PANEL:
620 if (DEBUG) Slog.d(TAG, "opening recents panel");
Jim Miller85babff2011-01-11 14:26:03 -0800621 if (mRecentsPanel != null) {
Jim Millerb5a2b292011-03-01 16:14:59 -0800622 disable(StatusBarManager.DISABLE_BACK);
Jim Miller85babff2011-01-11 14:26:03 -0800623 mRecentsPanel.setVisibility(View.VISIBLE);
624 mRecentsPanel.show(true, true);
625 }
Jim Miller44c66fe2010-10-20 18:32:52 -0700626 break;
627 case MSG_CLOSE_RECENTS_PANEL:
628 if (DEBUG) Slog.d(TAG, "closing recents panel");
Jim Miller85babff2011-01-11 14:26:03 -0800629 if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
Jim Miller5fda69c2011-02-16 15:17:11 -0800630 disable(StatusBarManager.DISABLE_NONE);
Jim Miller85babff2011-01-11 14:26:03 -0800631 mRecentsPanel.show(false, true);
632 }
Daniel Sandler9120d552010-07-23 09:11:14 -0400633 break;
satok82beadf2010-12-27 19:03:06 +0900634 case MSG_OPEN_INPUT_METHODS_PANEL:
635 if (DEBUG) Slog.d(TAG, "opening input methods panel");
Tadashi G. Takaokae385f0c2011-02-01 02:57:44 +0900636 if (mInputMethodsPanel != null) mInputMethodsPanel.openPanel();
satok82beadf2010-12-27 19:03:06 +0900637 break;
638 case MSG_CLOSE_INPUT_METHODS_PANEL:
639 if (DEBUG) Slog.d(TAG, "closing input methods panel");
Tadashi G. Takaokae385f0c2011-02-01 02:57:44 +0900640 if (mInputMethodsPanel != null) mInputMethodsPanel.closePanel(false);
satok82beadf2010-12-27 19:03:06 +0900641 break;
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500642 case MSG_SHOW_CHROME:
Daniel Sandlere03d1bc2010-11-17 21:36:40 -0500643 if (DEBUG) Slog.d(TAG, "hiding shadows (lights on)");
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500644 mBarContents.setVisibility(View.VISIBLE);
645 mShadow.setVisibility(View.GONE);
Joe Onorato664644d2011-01-23 17:53:23 -0800646 notifyLightsChanged(true);
Daniel Sandler06e66302010-11-05 15:00:06 -0400647 break;
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500648 case MSG_HIDE_CHROME:
Daniel Sandlere03d1bc2010-11-17 21:36:40 -0500649 if (DEBUG) Slog.d(TAG, "showing shadows (lights out)");
Daniel Sandler06e66302010-11-05 15:00:06 -0400650 animateCollapse();
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500651 mBarContents.setVisibility(View.GONE);
652 mShadow.setVisibility(View.VISIBLE);
Joe Onorato664644d2011-01-23 17:53:23 -0800653 notifyLightsChanged(false);
Daniel Sandlere03d1bc2010-11-17 21:36:40 -0500654 break;
Daniel Sandler2ed08d22011-01-30 16:07:28 -0500655 case MSG_STOP_TICKER:
656 mTicker.halt();
657 break;
Daniel Sandler9120d552010-07-23 09:11:14 -0400658 }
659 }
660 }
Daniel Sandler271ea122010-10-22 14:06:10 -0400661
Joe Onorato664644d2011-01-23 17:53:23 -0800662 private void notifyLightsChanged(boolean shown) {
663 try {
664 Slog.d(TAG, "lights " + (shown?"on":"out"));
665 mWindowManager.statusBarVisibilityChanged(
666 shown ? View.STATUS_BAR_VISIBLE : View.STATUS_BAR_HIDDEN);
667 } catch (RemoteException ex) {
668 }
669 }
670
Joe Onorato808182d2010-07-09 18:52:06 -0400671 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400672 if (DEBUG) Slog.d(TAG, "addIcon(" + slot + ") -> " + icon);
Joe Onorato808182d2010-07-09 18:52:06 -0400673 }
674
675 public void updateIcon(String slot, int index, int viewIndex,
676 StatusBarIcon old, StatusBarIcon icon) {
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400677 if (DEBUG) Slog.d(TAG, "updateIcon(" + slot + ") -> " + icon);
Joe Onorato808182d2010-07-09 18:52:06 -0400678 }
679
680 public void removeIcon(String slot, int index, int viewIndex) {
Daniel Sandler1e3ed8f2010-08-13 10:12:48 -0400681 if (DEBUG) Slog.d(TAG, "removeIcon(" + slot + ")");
Joe Onorato808182d2010-07-09 18:52:06 -0400682 }
683
684 public void addNotification(IBinder key, StatusBarNotification notification) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400685 if (DEBUG) Slog.d(TAG, "addNotification(" + key + " -> " + notification + ")");
686 addNotificationViews(key, notification);
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400687
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800688 final boolean immersive = isImmersive();
Joe Onoratocf2b1992010-11-16 21:36:42 -0800689 if (false && immersive) {
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400690 // TODO: immersive mode popups for tablet
691 } else if (notification.notification.fullScreenIntent != null) {
692 // not immersive & a full-screen alert should be shown
Joe Onoratof68b5002011-01-16 17:00:34 -0800693 Slog.w(TAG, "Notification has fullScreenIntent and activity is not immersive;"
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400694 + " sending fullScreenIntent");
695 try {
696 notification.notification.fullScreenIntent.send();
697 } catch (PendingIntent.CanceledException e) {
698 }
699 } else {
Joe Onoratoeeed9942011-01-04 17:13:53 -0800700 tick(key, notification, true);
Daniel Sandlerfb970e92010-08-20 10:57:17 -0400701 }
Joe Onorato5dd11692010-09-27 15:34:04 -0700702
703 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400704 }
705
706 public void updateNotification(IBinder key, StatusBarNotification notification) {
Daniel Sandler282ff9a2011-02-23 10:36:49 -0500707 if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
Jim Miller44c66fe2010-10-20 18:32:52 -0700708
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500709 final NotificationData.Entry oldEntry = mNotificationData.findByKey(key);
Daniel Sandler379020a2010-07-29 16:20:06 -0400710 if (oldEntry == null) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400711 Slog.w(TAG, "updateNotification for unknown key: " + key);
712 return;
713 }
714
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400715 final StatusBarNotification oldNotification = oldEntry.notification;
716 final RemoteViews oldContentView = oldNotification.notification.contentView;
717
718 final RemoteViews contentView = notification.notification.contentView;
719
Daniel Sandler373a9982010-11-30 12:03:59 -0500720 if (DEBUG) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400721 Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
722 + " ongoing=" + oldNotification.isOngoing()
723 + " expanded=" + oldEntry.expanded
Daniel Sandler282ff9a2011-02-23 10:36:49 -0500724 + " contentView=" + oldContentView
725 + " rowParent=" + oldEntry.row.getParent());
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400726 Slog.d(TAG, "new notification: when=" + notification.notification.when
727 + " ongoing=" + oldNotification.isOngoing()
728 + " contentView=" + contentView);
729 }
730
731 // Can we just reapply the RemoteViews in place? If when didn't change, the order
732 // didn't change.
Joe Onorato80a44402011-01-15 16:22:24 -0800733 boolean contentsUnchanged = oldEntry.expanded != null
734 && contentView != null && oldContentView != null
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400735 && contentView.getPackage() != null
736 && oldContentView.getPackage() != null
737 && oldContentView.getPackage().equals(contentView.getPackage())
Joe Onoratoc9596d62011-01-12 17:03:11 -0800738 && oldContentView.getLayoutId() == contentView.getLayoutId();
Daniel Sandler373a9982010-11-30 12:03:59 -0500739 ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
Joe Onorato80a44402011-01-15 16:22:24 -0800740 boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
Jim Miller5fda69c2011-02-16 15:17:11 -0800741 && notification.priority == oldNotification.priority;
Daniel Sandlera31e4192011-02-02 22:00:28 -0500742 // priority now encompasses isOngoing()
Joe Onoratoc9596d62011-01-12 17:03:11 -0800743 boolean isLastAnyway = rowParent.indexOfChild(oldEntry.row) == rowParent.getChildCount()-1;
744 if (contentsUnchanged && (orderUnchanged || isLastAnyway)) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400745 if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
746 oldEntry.notification = notification;
747 try {
748 // Reapply the RemoteViews
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400749 contentView.reapply(mContext, oldEntry.content);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400750 // update the contentIntent
751 final PendingIntent contentIntent = notification.notification.contentIntent;
752 if (contentIntent != null) {
753 oldEntry.content.setOnClickListener(new NotificationClicker(contentIntent,
754 notification.pkg, notification.tag, notification.id));
Joe Onorato184498c2010-10-08 17:57:18 -0400755 } else {
756 oldEntry.content.setOnClickListener(null);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400757 }
758 // Update the icon.
759 final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
760 notification.notification.icon, notification.notification.iconLevel,
761 notification.notification.number);
762 if (!oldEntry.icon.set(ic)) {
763 handleNotificationError(key, notification, "Couldn't update icon: " + ic);
764 return;
765 }
Joe Onorato80a44402011-01-15 16:22:24 -0800766 // Update the large icon
767 if (notification.notification.largeIcon != null) {
768 oldEntry.largeIcon.setImageBitmap(notification.notification.largeIcon);
769 } else {
770 oldEntry.largeIcon.getLayoutParams().width = 0;
771 oldEntry.largeIcon.setVisibility(View.INVISIBLE);
772 }
Jim Miller85babff2011-01-11 14:26:03 -0800773
Daniel Sandler7ef29b52010-12-16 17:29:50 -0500774 if (key == mNotificationPeekKey) {
775 // must update the peek window
776 Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK);
777 peekMsg.arg1 = mNotificationPeekIndex;
778 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
779 mHandler.sendMessage(peekMsg);
780 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400781 }
782 catch (RuntimeException e) {
783 // It failed to add cleanly. Log, and remove the view from the panel.
784 Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
785 removeNotificationViews(key);
786 addNotificationViews(key, notification);
787 }
788 } else {
789 if (DEBUG) Slog.d(TAG, "not reusing notification for key: " + key);
790 removeNotificationViews(key);
791 addNotificationViews(key, notification);
792 }
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800793 // fullScreenIntent doesn't happen on updates. You need to clear & repost a new
794 // notification.
795 final boolean immersive = isImmersive();
796 if (false && immersive) {
797 // TODO: immersive mode
798 } else {
Joe Onoratoeeed9942011-01-04 17:13:53 -0800799 tick(key, notification, false);
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800800 }
Joe Onorato5dd11692010-09-27 15:34:04 -0700801
802 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400803 }
804
805 public void removeNotification(IBinder key) {
Daniel Sandler3a2fded2011-02-23 11:19:59 -0500806 if (DEBUG) Slog.d(TAG, "removeNotification(" + key + ")");
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400807 removeNotificationViews(key);
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800808 mTicker.remove(key);
Joe Onorato5dd11692010-09-27 15:34:04 -0700809 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400810 }
811
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500812 public void showClock(boolean show) {
813 View clock = mBarContents.findViewById(R.id.clock);
814 View network_text = mBarContents.findViewById(R.id.network_text);
815 if (clock != null) {
816 clock.setVisibility(show ? View.VISIBLE : View.GONE);
817 }
818 if (network_text != null) {
819 network_text.setVisibility((!show) ? View.VISIBLE : View.GONE);
820 }
821 }
822
Joe Onorato808182d2010-07-09 18:52:06 -0400823 public void disable(int state) {
Joe Onorato091e1b82010-09-26 18:04:44 -0700824 int old = mDisabled;
825 int diff = state ^ old;
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400826 mDisabled = state;
827
Joe Onorato091e1b82010-09-26 18:04:44 -0700828 // act accordingly
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500829 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
830 boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
Joe Onoratof68b5002011-01-16 17:00:34 -0800831 Slog.i(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes"));
Daniel Sandler3e8f5a22010-12-03 14:52:10 -0500832 showClock(show);
833 }
Daniel Sandler6f6cf3c2010-12-16 12:54:03 -0500834 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
835 boolean show = (state & StatusBarManager.DISABLE_SYSTEM_INFO) == 0;
Joe Onoratof68b5002011-01-16 17:00:34 -0800836 Slog.i(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes"));
Daniel Sandler6f6cf3c2010-12-16 12:54:03 -0500837 mNotificationTrigger.setVisibility(show ? View.VISIBLE : View.GONE);
838 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400839 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
840 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
Joe Onoratof68b5002011-01-16 17:00:34 -0800841 Slog.i(TAG, "DISABLE_EXPAND: yes");
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400842 animateCollapse();
843 }
844 }
845 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500846 mNotificationDNDMode = Prefs.read(mContext)
847 .getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT);
Daniel Sandler282ff9a2011-02-23 10:36:49 -0500848
849 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
850 Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes" + (mNotificationDNDMode?" (DND)":""));
851 mTicker.halt();
852 } else {
853 Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no" + (mNotificationDNDMode?" (DND)":""));
854 }
855
856 // refresh icons to show either notifications or the DND message
Daniel Sandlerce6ff642011-02-18 12:51:08 -0500857 reloadAllNotificationIcons();
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400858 } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
Joe Onorato091e1b82010-09-26 18:04:44 -0700859 if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
Joe Onoratoef1e7762010-09-17 18:38:38 -0400860 mTicker.halt();
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400861 }
862 }
Joe Onorato091e1b82010-09-26 18:04:44 -0700863 if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
864 if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
Joe Onoratof68b5002011-01-16 17:00:34 -0800865 Slog.i(TAG, "DISABLE_NAVIGATION: yes");
Daniel Sandler21eb86a2011-03-02 11:52:58 -0500866 mNavigationArea.setVisibility(View.INVISIBLE);
satokb70c82d2010-12-20 17:59:19 +0900867 mInputMethodSwitchButton.setScreenLocked(true);
Joe Onorato091e1b82010-09-26 18:04:44 -0700868 } else {
Joe Onoratof68b5002011-01-16 17:00:34 -0800869 Slog.i(TAG, "DISABLE_NAVIGATION: no");
Joe Onoratofd52b182010-11-10 18:00:52 -0800870 mNavigationArea.setVisibility(View.VISIBLE);
satokb70c82d2010-12-20 17:59:19 +0900871 mInputMethodSwitchButton.setScreenLocked(false);
Joe Onorato091e1b82010-09-26 18:04:44 -0700872 }
873 }
Joe Onorato6478adc2011-01-27 21:15:01 -0800874 if ((diff & StatusBarManager.DISABLE_BACK) != 0) {
875 if ((state & StatusBarManager.DISABLE_BACK) != 0) {
876 Slog.i(TAG, "DISABLE_BACK: yes");
877 mBackButton.setVisibility(View.INVISIBLE);
878 mInputMethodSwitchButton.setScreenLocked(true);
879 } else {
880 Slog.i(TAG, "DISABLE_BACK: no");
881 mBackButton.setVisibility(View.VISIBLE);
882 mInputMethodSwitchButton.setScreenLocked(false);
883 }
884 }
885
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400886 }
887
Joe Onoratoef1e7762010-09-17 18:38:38 -0400888 private boolean hasTicker(Notification n) {
Joe Onorato46439ce2010-11-19 13:56:21 -0800889 return n.tickerView != null || !TextUtils.isEmpty(n.tickerText);
Joe Onoratoef1e7762010-09-17 18:38:38 -0400890 }
891
Joe Onoratoeeed9942011-01-04 17:13:53 -0800892 private void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
Joe Onorato55d2d762010-09-26 13:02:01 -0700893 // Don't show the ticker when the windowshade is open.
Joe Onorato7c270fa2010-12-08 17:31:42 -0800894 if (mNotificationPanel.isShowing()) {
Joe Onorato55d2d762010-09-26 13:02:01 -0700895 return;
896 }
Joe Onoratoeeed9942011-01-04 17:13:53 -0800897 // If they asked for FLAG_ONLY_ALERT_ONCE, then only show this notification
898 // if it's a new notification.
899 if (!firstTime && (n.notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
900 return;
901 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400902 // Show the ticker if one is requested. Also don't do this
903 // until status bar window is attached to the window manager,
904 // because... well, what's the point otherwise? And trying to
905 // run a ticker without being attached will crash!
Joe Onoratoef1e7762010-09-17 18:38:38 -0400906 if (hasTicker(n.notification) && mStatusBarView.getWindowToken() != null) {
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400907 if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
908 | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
Joe Onorato50ec5ec2010-11-28 17:15:26 -0800909 mTicker.add(key, n);
Joe Onoratoec51a822011-01-04 16:33:01 -0800910 mNotificationAndImeArea.setVisibility(View.GONE);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -0400911 }
912 }
913 }
914
Daniel Sandlerb8027d82010-12-16 19:35:54 -0500915 // called by TabletTicker when it's done with all queued ticks
916 public void doneTicking() {
Joe Onoratoec51a822011-01-04 16:33:01 -0800917 mNotificationAndImeArea.setVisibility(View.VISIBLE);
Daniel Sandlerb8027d82010-12-16 19:35:54 -0500918 }
919
Joe Onorato808182d2010-07-09 18:52:06 -0400920 public void animateExpand() {
Daniel Sandler56a6d882011-02-23 16:40:33 -0500921 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
922 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
923 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
Joe Onoratob62ac122010-09-20 16:16:32 -0400924 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL);
925 mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL);
Joe Onorato808182d2010-07-09 18:52:06 -0400926 }
927
928 public void animateCollapse() {
Joe Onoratob62ac122010-09-20 16:16:32 -0400929 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL);
930 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
Jim Miller44c66fe2010-10-20 18:32:52 -0700931 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
932 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
satok82beadf2010-12-27 19:03:06 +0900933 mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL);
934 mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL);
Daniel Sandler56a6d882011-02-23 16:40:33 -0500935 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
936 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
Daniel Sandler9120d552010-07-23 09:11:14 -0400937 }
938
Joe Onoratofd52b182010-11-10 18:00:52 -0800939 // called by StatusBar
Daniel Sandler06e66302010-11-05 15:00:06 -0400940 @Override
Joe Onorato93056472010-09-10 10:30:46 -0400941 public void setLightsOn(boolean on) {
Daniel Sandler59485d742010-12-02 00:11:33 -0500942 // Policy note: if the frontmost activity needs the menu key, we assume it is a legacy app
943 // that can't handle lights-out mode.
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500944 if (mMenuButton.getVisibility() == View.VISIBLE) {
Daniel Sandler59485d742010-12-02 00:11:33 -0500945 on = true;
946 }
Daniel Sandler0ad460b2010-12-14 12:14:53 -0500947 mHandler.removeMessages(MSG_HIDE_CHROME);
948 mHandler.removeMessages(MSG_SHOW_CHROME);
949 mHandler.sendEmptyMessage(on ? MSG_SHOW_CHROME : MSG_HIDE_CHROME);
Joe Onorato93056472010-09-10 10:30:46 -0400950 }
951
Daniel Sandlere02d8082010-10-08 15:13:22 -0400952 public void setMenuKeyVisible(boolean visible) {
953 if (DEBUG) {
954 Slog.d(TAG, (visible?"showing":"hiding") + " the MENU button");
955 }
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -0500956 mMenuButton.setVisibility(visible ? View.VISIBLE : View.GONE);
Daniel Sandler59485d742010-12-02 00:11:33 -0500957
958 // See above re: lights-out policy for legacy apps.
959 if (visible) setLightsOn(true);
Daniel Sandlere02d8082010-10-08 15:13:22 -0400960 }
961
Joe Onorato857fd9b2011-01-27 15:08:35 -0800962 public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
963 mInputMethodSwitchButton.setImeWindowStatus(token,
964 (vis & InputMethodService.IME_ACTIVE) != 0);
satok51133822011-01-25 15:01:48 +0900965 updateNotificationIcons();
satok913f42d2011-01-17 16:58:10 +0900966 mInputMethodsPanel.setImeToken(token);
Joe Onorato857fd9b2011-01-27 15:08:35 -0800967 int res;
968 switch (backDisposition) {
969 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
970 res = R.drawable.ic_sysbar_back;
971 break;
972 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
973 res = R.drawable.ic_sysbar_back_ime;
974 break;
975 case InputMethodService.BACK_DISPOSITION_DEFAULT:
976 default:
977 if ((vis & InputMethodService.IME_VISIBLE) != 0) {
978 res = R.drawable.ic_sysbar_back_ime;
979 } else {
980 res = R.drawable.ic_sysbar_back;
981 }
982 break;
983 }
984 mBackButton.setImageResource(res);
Daniel Sandler10163c62010-12-08 11:51:05 -0500985 if (FAKE_SPACE_BAR) {
Joe Onorato857fd9b2011-01-27 15:08:35 -0800986 mFakeSpaceBar.setVisibility(((vis & InputMethodService.IME_VISIBLE) != 0)
987 ? View.VISIBLE : View.GONE);
Daniel Sandler10163c62010-12-08 11:51:05 -0500988 }
satok06487a52010-10-29 11:37:18 +0900989 }
990
Jeff Brown2992ea72011-01-28 22:04:14 -0800991 @Override
992 public void setHardKeyboardStatus(boolean available, boolean enabled) {
993 if (DEBUG) {
994 Slog.d(TAG, "Set hard keyboard status: available=" + available
995 + ", enabled=" + enabled);
996 }
997 mInputMethodSwitchButton.setHardKeyboardStatus(available);
998 updateNotificationIcons();
999 mInputMethodsPanel.setHardKeyboardStatus(available, enabled);
1000 }
1001
1002 @Override
1003 public void onHardKeyboardEnabledChange(boolean enabled) {
1004 try {
1005 mBarService.setHardKeyboardEnabled(enabled);
1006 } catch (RemoteException ex) {
1007 }
1008 }
1009
Joe Onorato50ec5ec2010-11-28 17:15:26 -08001010 private boolean isImmersive() {
1011 try {
1012 return ActivityManagerNative.getDefault().isTopActivityImmersive();
1013 //Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
1014 } catch (RemoteException ex) {
1015 // the end is nigh
1016 return false;
1017 }
1018 }
Jim Miller85babff2011-01-11 14:26:03 -08001019
Joe Onorato5dd11692010-09-27 15:34:04 -07001020 private void setAreThereNotifications() {
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001021 final boolean hasClearable = mNotificationData.hasClearableItems();
Joe Onorato5dd11692010-09-27 15:34:04 -07001022 }
1023
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001024 /**
1025 * Cancel this notification and tell the status bar service about the failure. Hold no locks.
1026 */
1027 void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
1028 removeNotification(key);
1029 try {
1030 mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
1031 } catch (RemoteException ex) {
1032 // The end is nigh.
1033 }
1034 }
1035
Daniel Sandler10163c62010-12-08 11:51:05 -05001036 private void sendKey(KeyEvent key) {
1037 try {
1038 if (DEBUG) Slog.d(TAG, "injecting key event: " + key);
1039 mWindowManager.injectInputEventNoWait(key);
1040 } catch (RemoteException ex) {
1041 }
1042 }
1043
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001044 private View.OnClickListener mOnClickListener = new View.OnClickListener() {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001045 public void onClick(View v) {
Joe Onoratofd52b182010-11-10 18:00:52 -08001046 if (v == mNotificationTrigger) {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001047 onClickNotificationTrigger();
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001048 } else if (v == mRecentButton) {
1049 onClickRecentButton();
satok82beadf2010-12-27 19:03:06 +09001050 } else if (v == mInputMethodSwitchButton) {
1051 onClickInputMethodSwitchButton();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001052 }
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001053 }
1054 };
1055
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001056 public void onClickNotificationTrigger() {
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001057 if (DEBUG) Slog.d(TAG, "clicked notification icons; disabled=" + mDisabled);
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001058 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
Daniel Sandler3a2fded2011-02-23 11:19:59 -05001059 int msg = !mNotificationPanel.isShowing()
1060 ? MSG_OPEN_NOTIFICATION_PANEL
1061 : MSG_CLOSE_NOTIFICATION_PANEL;
1062 mHandler.removeMessages(msg);
1063 mHandler.sendEmptyMessage(msg);
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001064 }
1065 }
1066
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001067 public void onClickRecentButton() {
Daniel Sandlerb6d3dc62010-11-17 16:51:26 -05001068 if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled);
Jim Miller44c66fe2010-10-20 18:32:52 -07001069 if (mRecentsPanel == null) {
1070 Intent intent = new Intent();
1071 intent.setClass(mContext, RecentApplicationsActivity.class);
1072 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1073 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
1074 mContext.startActivity(intent);
1075 } else {
1076 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
1077 int msg = (mRecentsPanel.getVisibility() == View.GONE)
1078 ? MSG_OPEN_RECENTS_PANEL
1079 : MSG_CLOSE_RECENTS_PANEL;
1080 mHandler.removeMessages(msg);
1081 mHandler.sendEmptyMessage(msg);
1082 }
1083 }
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001084 }
Joe Onorato55d2d762010-09-26 13:02:01 -07001085
satok82beadf2010-12-27 19:03:06 +09001086 public void onClickInputMethodSwitchButton() {
1087 if (DEBUG) Slog.d(TAG, "clicked input methods panel; disabled=" + mDisabled);
1088 int msg = (mInputMethodsPanel.getVisibility() == View.GONE) ?
1089 MSG_OPEN_INPUT_METHODS_PANEL : MSG_CLOSE_INPUT_METHODS_PANEL;
1090 mHandler.removeMessages(msg);
1091 mHandler.sendEmptyMessage(msg);
1092 }
1093
Daniel Sandlerc51451a2010-12-16 19:06:46 -05001094 public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) {
1095 return new NotificationClicker(intent, pkg, tag, id);
1096 }
1097
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001098 private class NotificationClicker implements View.OnClickListener {
1099 private PendingIntent mIntent;
1100 private String mPkg;
1101 private String mTag;
1102 private int mId;
1103
1104 NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
1105 mIntent = intent;
1106 mPkg = pkg;
1107 mTag = tag;
1108 mId = id;
1109 }
1110
1111 public void onClick(View v) {
1112 try {
1113 // The intent we are sending is for the application, which
1114 // won't have permission to immediately start an activity after
1115 // the user switches to home. We know it is safe to do at this
1116 // point, so make sure new activity switches are now allowed.
1117 ActivityManagerNative.getDefault().resumeAppSwitches();
1118 } catch (RemoteException e) {
1119 }
1120
1121 if (mIntent != null) {
1122 int[] pos = new int[2];
1123 v.getLocationOnScreen(pos);
1124 Intent overlay = new Intent();
1125 overlay.setSourceBounds(
1126 new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
1127 try {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001128 mIntent.send(mContext, 0, overlay);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001129 } catch (PendingIntent.CanceledException e) {
1130 // the stack trace isn't very helpful here. Just log the exception message.
1131 Slog.w(TAG, "Sending contentIntent failed: " + e);
1132 }
1133 }
1134
1135 try {
1136 mBarService.onNotificationClick(mPkg, mTag, mId);
1137 } catch (RemoteException ex) {
1138 // system process is dead if we're here.
1139 }
1140
1141 // close the shade if it was open
1142 animateCollapse();
1143
1144 // If this click was on the intruder alert, hide that instead
1145// mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
1146 }
1147 }
1148
1149 StatusBarNotification removeNotificationViews(IBinder key) {
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001150 NotificationData.Entry entry = mNotificationData.remove(key);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001151 if (entry == null) {
1152 Slog.w(TAG, "removeNotification for unknown key: " + key);
1153 return null;
1154 }
1155 // Remove the expanded view.
1156 ViewGroup rowParent = (ViewGroup)entry.row.getParent();
1157 if (rowParent != null) rowParent.removeView(entry.row);
Daniel Sandlera8e5b062010-12-01 13:53:08 -05001158
1159 if (key == mNotificationPeekKey) {
1160 // must close the peek as well, since it's gone
1161 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
1162 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001163 // Remove the icon.
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001164// ViewGroup iconParent = (ViewGroup)entry.icon.getParent();
1165// if (iconParent != null) iconParent.removeView(entry.icon);
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001166 updateNotificationIcons();
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001167
1168 return entry.notification;
1169 }
1170
Daniel Sandler56a6d882011-02-23 16:40:33 -05001171 private class NotificationTriggerTouchListener implements View.OnTouchListener {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001172 VelocityTracker mVT;
Daniel Sandler56a6d882011-02-23 16:40:33 -05001173 float mInitialTouchX, mInitialTouchY;
1174 int mTouchSlop;
1175
1176 public NotificationTriggerTouchListener() {
1177 mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
1178 }
1179
1180 public boolean onTouch(View v, MotionEvent event) {
1181// Slog.d(TAG, String.format("touch: (%.1f, %.1f) initial: (%.1f, %.1f)",
1182// event.getX(),
1183// event.getY(),
1184// mInitialTouchX,
1185// mInitialTouchY));
1186 final int action = event.getAction();
1187 switch (action) {
1188 case MotionEvent.ACTION_DOWN:
1189 mVT = VelocityTracker.obtain();
1190 mInitialTouchX = event.getX();
1191 mInitialTouchY = event.getY();
1192 // fall through
1193 case MotionEvent.ACTION_OUTSIDE:
1194 case MotionEvent.ACTION_MOVE:
1195 // check for fling
1196 if (mVT != null) {
1197 mVT.addMovement(event);
1198 mVT.computeCurrentVelocity(1000); // pixels per second
1199 // require a little more oomph once we're already in peekaboo mode
1200 if (mVT.getYVelocity() < -mNotificationFlingVelocity) {
1201 animateExpand();
1202 mVT.recycle();
1203 mVT = null;
1204 }
1205 }
1206 return true;
1207 case MotionEvent.ACTION_UP:
1208 case MotionEvent.ACTION_CANCEL:
1209 if (mVT != null) {
1210 if (action == MotionEvent.ACTION_UP
1211 // was this a sloppy tap?
1212 && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
1213 && Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3)
1214 // dragging off the bottom doesn't count
1215 && (int)event.getY() < v.getBottom()) {
1216 animateExpand();
Daniel Sandleraa051d62011-03-01 16:23:57 -05001217 v.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
1218 v.playSoundEffect(SoundEffectConstants.CLICK);
Daniel Sandler56a6d882011-02-23 16:40:33 -05001219 }
1220
1221 mVT.recycle();
1222 mVT = null;
1223 return true;
1224 }
1225 }
1226 return false;
1227 }
1228 }
1229
Daniel Sandler663f0f22011-03-04 16:45:02 -05001230 final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms
1231 final static int NOTIFICATION_PEEK_FADE_DELAY = 3000; // ms
Daniel Sandler56a6d882011-02-23 16:40:33 -05001232
Daniel Sandler663f0f22011-03-04 16:45:02 -05001233 public void resetNotificationPeekFadeTimer() {
1234 if (DEBUG) {
1235 Slog.d(TAG, "setting peek fade timer for " + NOTIFICATION_PEEK_FADE_DELAY
1236 + "ms from now");
1237 }
1238 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
1239 mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK,
1240 NOTIFICATION_PEEK_FADE_DELAY);
1241 }
1242
1243 private class NotificationIconTouchListener implements View.OnTouchListener {
Daniel Sandler56a6d882011-02-23 16:40:33 -05001244 VelocityTracker mVT;
1245 int mPeekIndex;
1246 float mInitialTouchX, mInitialTouchY;
1247 int mTouchSlop;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001248
1249 public NotificationIconTouchListener() {
Daniel Sandler56a6d882011-02-23 16:40:33 -05001250 mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001251 }
1252
1253 public boolean onTouch(View v, MotionEvent event) {
1254 boolean peeking = mNotificationPeekWindow.getVisibility() != View.GONE;
Joe Onorato7c270fa2010-12-08 17:31:42 -08001255 boolean panelShowing = mNotificationPanel.isShowing();
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001256 if (panelShowing) return false;
1257
Daniel Sandler56a6d882011-02-23 16:40:33 -05001258 int numIcons = mIconLayout.getChildCount();
1259 int newPeekIndex = (int)(event.getX() * numIcons / mIconLayout.getWidth());
1260 if (newPeekIndex > numIcons - 1) newPeekIndex = numIcons - 1;
1261 else if (newPeekIndex < 0) newPeekIndex = 0;
1262
1263 final int action = event.getAction();
1264 switch (action) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001265 case MotionEvent.ACTION_DOWN:
1266 mVT = VelocityTracker.obtain();
Daniel Sandler56a6d882011-02-23 16:40:33 -05001267 mInitialTouchX = event.getX();
1268 mInitialTouchY = event.getY();
1269 mPeekIndex = -1;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001270
1271 // fall through
1272 case MotionEvent.ACTION_OUTSIDE:
1273 case MotionEvent.ACTION_MOVE:
1274 // peek and switch icons if necessary
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001275
Daniel Sandler56a6d882011-02-23 16:40:33 -05001276 if (newPeekIndex != mPeekIndex) {
1277 mPeekIndex = newPeekIndex;
1278
1279 if (DEBUG) Slog.d(TAG, "will peek at notification #" + mPeekIndex);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001280 Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK);
Daniel Sandler56a6d882011-02-23 16:40:33 -05001281 peekMsg.arg1 = mPeekIndex;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001282
1283 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
1284
Daniel Sandler56a6d882011-02-23 16:40:33 -05001285 if (peeking) {
1286 // no delay if we're scrubbing left-right
1287 mHandler.sendMessage(peekMsg);
1288 } else {
1289 // wait for fling
1290 mHandler.sendMessageDelayed(peekMsg, NOTIFICATION_PEEK_HOLD_THRESH);
1291 }
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001292 }
1293
1294 // check for fling
1295 if (mVT != null) {
1296 mVT.addMovement(event);
Daniel Sandler56a6d882011-02-23 16:40:33 -05001297 mVT.computeCurrentVelocity(1000); // pixels per second
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001298 // require a little more oomph once we're already in peekaboo mode
1299 if (!panelShowing && (
1300 (peeking && mVT.getYVelocity() < -mNotificationFlingVelocity*3)
1301 || (mVT.getYVelocity() < -mNotificationFlingVelocity))) {
1302 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
1303 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL);
1304 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
1305 mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL);
1306 }
1307 }
1308 return true;
1309 case MotionEvent.ACTION_UP:
1310 case MotionEvent.ACTION_CANCEL:
1311 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
Daniel Sandleraa051d62011-03-01 16:23:57 -05001312 if (!peeking) {
1313 if (action == MotionEvent.ACTION_UP
1314 // was this a sloppy tap?
1315 && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
1316 && Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3)
1317 // dragging off the bottom doesn't count
1318 && (int)event.getY() < v.getBottom()) {
1319 Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK);
1320 peekMsg.arg1 = mPeekIndex;
1321 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
1322 mHandler.sendMessage(peekMsg);
1323
1324 v.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
1325 v.playSoundEffect(SoundEffectConstants.CLICK);
1326
1327 peeking = true; // not technically true yet, but the next line will run
1328 }
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001329 }
Daniel Sandler56a6d882011-02-23 16:40:33 -05001330
1331 if (peeking) {
Daniel Sandler663f0f22011-03-04 16:45:02 -05001332 resetNotificationPeekFadeTimer();
Daniel Sandler56a6d882011-02-23 16:40:33 -05001333 }
1334
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001335 mVT.recycle();
1336 mVT = null;
1337 return true;
1338 }
1339 return false;
1340 }
1341 }
1342
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001343 StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001344 if (DEBUG) {
1345 Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);
1346 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001347 // Construct the icon.
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001348 final StatusBarIconView iconView = new StatusBarIconView(mContext,
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001349 notification.pkg + "/0x" + Integer.toHexString(notification.id));
1350 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
1351
1352 final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
1353 notification.notification.icon,
1354 notification.notification.iconLevel,
1355 notification.notification.number);
1356 if (!iconView.set(ic)) {
1357 handleNotificationError(key, notification, "Couldn't attach StatusBarIcon: " + ic);
1358 return null;
1359 }
1360 // Construct the expanded view.
1361 NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001362 if (!inflateViews(entry, mPile)) {
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001363 handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
1364 + notification);
1365 return null;
1366 }
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001367
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001368 // Add the icon.
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001369 int pos = mNotificationData.add(entry);
Daniel Sandlera31e4192011-02-02 22:00:28 -05001370 if (DEBUG) {
1371 Slog.d(TAG, "addNotificationViews: added at " + pos);
1372 }
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001373 updateNotificationIcons();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001374
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001375 return iconView;
1376 }
1377
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001378 private void reloadAllNotificationIcons() {
1379 if (mIconLayout == null) return;
1380 mIconLayout.removeAllViews();
1381 updateNotificationIcons();
1382 }
1383
1384 private void updateNotificationIcons() {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001385 // XXX: need to implement a new limited linear layout class
1386 // to avoid removing & readding everything
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001387
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001388 if (mIconLayout == null) return;
1389
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001390 // first, populate the main notification panel
1391 loadNotificationPanel();
1392
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001393 final LinearLayout.LayoutParams params
Joe Onoratodc100302011-01-11 17:07:41 -08001394 = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001395
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001396 // alternate behavior in DND mode
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001397 if (mNotificationDNDMode) {
1398 if (mIconLayout.getChildCount() == 0) {
1399 final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd");
1400 iconView.setImageResource(R.drawable.ic_notification_dnd);
1401 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
1402 iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0);
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001403
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001404 final Notification dndNotification = new Notification.Builder(mContext)
1405 .setContentTitle(mContext.getText(R.string.notifications_off_title))
1406 .setContentText(mContext.getText(R.string.notifications_off_text))
1407 .setSmallIcon(R.drawable.ic_notification_dnd)
1408 .setOngoing(true)
1409 .getNotification();
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001410
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001411 mNotificationDNDDummyEntry = new NotificationData.Entry(
1412 null,
1413 new StatusBarNotification("", 0, "", 0, 0, dndNotification),
1414 iconView);
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001415
Daniel Sandler282ff9a2011-02-23 10:36:49 -05001416 mIconLayout.addView(iconView, params);
1417 }
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001418
1419 return;
1420 }
1421
1422 int N = mNotificationData.size();
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001423
1424 if (DEBUG) {
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001425 Slog.d(TAG, "refreshing icons: " + N + " notifications, mIconLayout=" + mIconLayout);
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001426 }
1427
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001428 ArrayList<View> toShow = new ArrayList<View>();
1429
satok82beadf2010-12-27 19:03:06 +09001430 // When IME button is visible, the number of notification icons should be decremented
1431 // to fit the upper limit.
1432 final int maxNotificationIconsCount =
1433 (mInputMethodSwitchButton.getVisibility() != View.GONE) ?
1434 MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE : MAX_NOTIFICATION_ICONS;
1435 for (int i=0; i< maxNotificationIconsCount; i++) {
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001436 if (i>=N) break;
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001437 toShow.add(mNotificationData.get(N-i-1).icon);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001438 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001439
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001440 ArrayList<View> toRemove = new ArrayList<View>();
1441 for (int i=0; i<mIconLayout.getChildCount(); i++) {
1442 View child = mIconLayout.getChildAt(i);
1443 if (!toShow.contains(child)) {
1444 toRemove.add(child);
1445 }
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001446 }
Daniel Sandler271ea122010-10-22 14:06:10 -04001447
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001448 for (View remove : toRemove) {
1449 mIconLayout.removeView(remove);
1450 }
1451
1452 for (int i=0; i<toShow.size(); i++) {
1453 View v = toShow.get(i);
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001454 v.setPadding(mIconHPadding, 0, mIconHPadding, 0);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001455 if (v.getParent() == null) {
Daniel Sandler0ad460b2010-12-14 12:14:53 -05001456 mIconLayout.addView(v, i, params);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001457 }
1458 }
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001459 }
1460
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001461 private void loadNotificationPanel() {
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001462 int N = mNotificationData.size();
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001463
1464 ArrayList<View> toShow = new ArrayList<View>();
1465
1466 for (int i=0; i<N; i++) {
Daniel Sandlerce6ff642011-02-18 12:51:08 -05001467 View row = mNotificationData.get(N-i-1).row;
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001468 toShow.add(row);
1469 }
1470
1471 ArrayList<View> toRemove = new ArrayList<View>();
1472 for (int i=0; i<mPile.getChildCount(); i++) {
1473 View child = mPile.getChildAt(i);
1474 if (!toShow.contains(child)) {
1475 toRemove.add(child);
1476 }
1477 }
1478
1479 for (View remove : toRemove) {
1480 mPile.removeView(remove);
1481 }
1482
1483 for (int i=0; i<toShow.size(); i++) {
1484 View v = toShow.get(i);
1485 if (v.getParent() == null) {
Daniel Sandlera31e4192011-02-02 22:00:28 -05001486 mPile.addView(v, N-1-i); // the notification panel has newest at the bottom
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001487 }
1488 }
Daniel Sandler40c15452011-01-22 01:26:22 -05001489
1490 mNotificationPanel.setNotificationCount(N);
Daniel Sandlerb0cc50d2010-10-26 16:55:56 -04001491 }
1492
Joe Onorato4daaeaf2010-11-17 20:43:12 -08001493 void workAroundBadLayerDrawableOpacity(View v) {
1494 LayerDrawable d = (LayerDrawable)v.getBackground();
Daniel Sandlerf844dc42011-01-24 23:44:47 -05001495 if (d == null) return;
Joe Onorato4daaeaf2010-11-17 20:43:12 -08001496 v.setBackgroundDrawable(null);
1497 d.setOpacity(PixelFormat.TRANSLUCENT);
1498 v.setBackgroundDrawable(d);
1499 }
1500
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001501 private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
1502 StatusBarNotification sbn = entry.notification;
1503 RemoteViews remoteViews = sbn.notification.contentView;
1504 if (remoteViews == null) {
1505 return false;
1506 }
1507
1508 // create the row view
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001509 LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
1510 Context.LAYOUT_INFLATER_SERVICE);
Joe Onorato755cc742010-11-27 15:45:35 -08001511 View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
Joe Onorato4daaeaf2010-11-17 20:43:12 -08001512 workAroundBadLayerDrawableOpacity(row);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001513 View vetoButton = row.findViewById(R.id.veto);
Joe Onoratoa4a65032010-09-27 15:53:44 -07001514 if (entry.notification.isClearable()) {
1515 final String _pkg = sbn.pkg;
1516 final String _tag = sbn.tag;
1517 final int _id = sbn.id;
Jim Miller44c66fe2010-10-20 18:32:52 -07001518 vetoButton.setOnClickListener(new View.OnClickListener() {
Joe Onoratoa4a65032010-09-27 15:53:44 -07001519 public void onClick(View v) {
1520 try {
1521 mBarService.onNotificationClear(_pkg, _tag, _id);
1522 } catch (RemoteException ex) {
1523 // system process is dead if we're here.
1524 }
Daniel Sandler0f0b11c2010-08-04 15:54:58 -04001525 }
Joe Onoratoa4a65032010-09-27 15:53:44 -07001526 });
1527 } else {
Joe Onorato100748e2011-01-07 11:03:54 -08001528 if ((sbn.notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) {
1529 vetoButton.setVisibility(View.INVISIBLE);
1530 } else {
1531 vetoButton.setVisibility(View.GONE);
1532 }
Joe Onoratoa4a65032010-09-27 15:53:44 -07001533 }
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001534
Joe Onorato561d3852010-11-20 18:09:34 -08001535 // the large icon
1536 ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);
1537 if (sbn.notification.largeIcon != null) {
1538 largeIcon.setImageBitmap(sbn.notification.largeIcon);
1539 } else {
1540 largeIcon.getLayoutParams().width = 0;
1541 largeIcon.setVisibility(View.INVISIBLE);
1542 }
1543
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001544 // bind the click event to the content area
1545 ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
1546 // XXX: update to allow controls within notification views
1547 content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
1548// content.setOnFocusChangeListener(mFocusChangeListener);
1549 PendingIntent contentIntent = sbn.notification.contentIntent;
1550 if (contentIntent != null) {
1551 content.setOnClickListener(new NotificationClicker(contentIntent,
1552 sbn.pkg, sbn.tag, sbn.id));
Joe Onorato184498c2010-10-08 17:57:18 -04001553 } else {
1554 content.setOnClickListener(null);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001555 }
1556
1557 View expanded = null;
1558 Exception exception = null;
1559 try {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001560 expanded = remoteViews.apply(mContext, content);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001561 }
1562 catch (RuntimeException e) {
1563 exception = e;
1564 }
1565 if (expanded == null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08001566 final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001567 Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
1568 return false;
1569 } else {
1570 content.addView(expanded);
1571 row.setDrawingCacheEnabled(true);
1572 }
1573
1574 entry.row = row;
1575 entry.content = content;
1576 entry.expanded = expanded;
Joe Onorato80a44402011-01-15 16:22:24 -08001577 entry.largeIcon = largeIcon;
Daniel Sandler3eebd1f2010-07-27 08:39:33 -04001578
1579 return true;
1580 }
Daniel Sandlerce70d912010-09-02 11:59:41 -04001581
Joe Onoratob62ac122010-09-20 16:16:32 -04001582 public class TouchOutsideListener implements View.OnTouchListener {
1583 private int mMsg;
Joe Onoratoddf680b2010-09-26 13:59:40 -07001584 private StatusBarPanel mPanel;
Joe Onoratob62ac122010-09-20 16:16:32 -04001585
Joe Onoratoddf680b2010-09-26 13:59:40 -07001586 public TouchOutsideListener(int msg, StatusBarPanel panel) {
Joe Onoratob62ac122010-09-20 16:16:32 -04001587 mMsg = msg;
Joe Onoratoddf680b2010-09-26 13:59:40 -07001588 mPanel = panel;
Joe Onoratob62ac122010-09-20 16:16:32 -04001589 }
1590
1591 public boolean onTouch(View v, MotionEvent ev) {
Joe Onoratoddf680b2010-09-26 13:59:40 -07001592 final int action = ev.getAction();
1593 if (action == MotionEvent.ACTION_OUTSIDE
1594 || (action == MotionEvent.ACTION_DOWN
1595 && !mPanel.isInContentArea((int)ev.getX(), (int)ev.getY()))) {
Joe Onoratob62ac122010-09-20 16:16:32 -04001596 mHandler.removeMessages(mMsg);
1597 mHandler.sendEmptyMessage(mMsg);
1598 return true;
1599 }
1600 return false;
1601 }
1602 }
Joe Onorato091e1b82010-09-26 18:04:44 -07001603
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001604 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1605 pw.print("mDisabled=0x");
1606 pw.println(Integer.toHexString(mDisabled));
Joe Onorato933464d2011-01-05 15:53:36 -08001607 pw.println("mNetworkController:");
1608 mNetworkController.dump(fd, pw, args);
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04001609 }
Joe Onorato808182d2010-07-09 18:52:06 -04001610}
Daniel Sandlerd39e3882010-08-31 14:16:13 -04001611
1612