blob: 7d23e894a54e78caf18ca982825def923df4bbb3 [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
Joe Onoratofd52b182010-11-10 18:00:52 -080017package com.android.systemui.statusbar.phone;
Joe Onorato808182d2010-07-09 18:52:06 -040018
Daniel Sandlerd7e96862012-04-26 01:10:29 -040019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.AnimatorSet;
Daniel Sandler0761e4c2011-08-11 00:19:49 -040022import android.animation.ObjectAnimator;
Daniel Sandler101784e2012-10-15 13:39:38 -040023import android.animation.TimeInterpolator;
Dianne Hackbornfc8fa632011-08-17 16:20:47 -070024import android.app.ActivityManager;
Joe Onorato808182d2010-07-09 18:52:06 -040025import android.app.ActivityManagerNative;
Joe Onorato808182d2010-07-09 18:52:06 -040026import android.app.Notification;
27import android.app.PendingIntent;
Joe Onorato808182d2010-07-09 18:52:06 -040028import android.app.StatusBarManager;
Daniel Sandler5feceeb2013-03-22 18:29:23 -070029import android.service.notification.StatusBarNotification;
Joe Onorato808182d2010-07-09 18:52:06 -040030import android.content.BroadcastReceiver;
31import android.content.Context;
32import android.content.Intent;
33import android.content.IntentFilter;
Daniel Sandlerb17a7262012-10-05 14:32:50 -040034import android.content.SharedPreferences;
Michael Jurka7f2668c2012-03-27 07:49:52 -070035import android.content.res.Resources;
John Spurlock919adac2012-10-02 16:41:12 -040036import android.database.ContentObserver;
Romain Guy648342f2012-05-25 10:44:45 -070037import android.graphics.Canvas;
38import android.graphics.ColorFilter;
Joe Onorato808182d2010-07-09 18:52:06 -040039import android.graphics.PixelFormat;
Daniel Sandlere680f542012-09-28 12:22:27 -040040import android.graphics.Point;
Romain Guy648342f2012-05-25 10:44:45 -070041import android.graphics.PorterDuff;
Joe Onorato808182d2010-07-09 18:52:06 -040042import android.graphics.Rect;
Romain Guy648342f2012-05-25 10:44:45 -070043import android.graphics.drawable.Drawable;
Michael Jurka7f2668c2012-03-27 07:49:52 -070044import android.inputmethodservice.InputMethodService;
John Spurlock919adac2012-10-02 16:41:12 -040045import android.os.Handler;
Joe Onorato808182d2010-07-09 18:52:06 -040046import android.os.IBinder;
Joe Onorato808182d2010-07-09 18:52:06 -040047import android.os.Message;
Michael Jurka7f2668c2012-03-27 07:49:52 -070048import android.os.RemoteException;
Daniel Sandler1d4d30a2011-04-28 12:35:29 -040049import android.os.ServiceManager;
Joe Onorato808182d2010-07-09 18:52:06 -040050import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070051import android.os.UserHandle;
Daniel Sandlerd3090562011-08-09 00:28:44 -040052import android.provider.Settings;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070053import android.service.dreams.DreamService;
Daniel Sandlera2fbe532012-08-10 01:19:03 -040054import android.service.dreams.IDreamManager;
Daniel Sandler36412a72011-08-04 09:35:13 -040055import android.util.DisplayMetrics;
Chris Wren64161cc2012-12-17 16:49:30 -050056import android.util.EventLog;
Joe Onorato808182d2010-07-09 18:52:06 -040057import android.util.Log;
Michael Jurka7f2668c2012-03-27 07:49:52 -070058import android.util.Slog;
Joe Onorato808182d2010-07-09 18:52:06 -040059import android.view.Display;
60import android.view.Gravity;
Joe Onorato808182d2010-07-09 18:52:06 -040061import android.view.MotionEvent;
62import android.view.VelocityTracker;
63import android.view.View;
64import android.view.ViewGroup;
Jim Millerf2a16b22011-07-06 17:32:48 -070065import android.view.ViewGroup.LayoutParams;
Daniel Sandler101784e2012-10-15 13:39:38 -040066import android.view.ViewPropertyAnimator;
Daniel Sandlerb17a7262012-10-05 14:32:50 -040067import android.view.ViewStub;
Joe Onorato808182d2010-07-09 18:52:06 -040068import android.view.WindowManager;
Daniel Sandlerd7e96862012-04-26 01:10:29 -040069import android.view.animation.AccelerateInterpolator;
Joe Onorato808182d2010-07-09 18:52:06 -040070import android.view.animation.Animation;
71import android.view.animation.AnimationUtils;
Daniel Sandler67e7d902012-06-06 16:32:21 -040072import android.view.animation.DecelerateInterpolator;
Daniel Sandler21b274e2012-05-02 15:07:51 -040073import android.widget.FrameLayout;
Joe Onorato808182d2010-07-09 18:52:06 -040074import android.widget.ImageView;
75import android.widget.LinearLayout;
Joe Onorato808182d2010-07-09 18:52:06 -040076import android.widget.ScrollView;
77import android.widget.TextView;
Michael Jurkaa600fd92012-06-25 15:57:05 -070078
Joe Onorato808182d2010-07-09 18:52:06 -040079import com.android.internal.statusbar.StatusBarIcon;
Chris Wren64161cc2012-12-17 16:49:30 -050080import com.android.systemui.EventLogTags;
Joe Onorato808182d2010-07-09 18:52:06 -040081import com.android.systemui.R;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050082import com.android.systemui.statusbar.BaseStatusBar;
Michael Jurkaa600fd92012-06-25 15:57:05 -070083import com.android.systemui.statusbar.CommandQueue;
Daniel Sandler33805342012-07-23 15:45:12 -040084import com.android.systemui.statusbar.GestureRecorder;
Michael Jurka7f2668c2012-03-27 07:49:52 -070085import com.android.systemui.statusbar.NotificationData;
Daniel Sandler58b173b2012-05-03 11:25:29 -040086import com.android.systemui.statusbar.NotificationData.Entry;
Christian Robertson2e347422011-08-11 14:01:04 -070087import com.android.systemui.statusbar.SignalClusterView;
Michael Jurka7f2668c2012-03-27 07:49:52 -070088import com.android.systemui.statusbar.StatusBarIconView;
Daniel Sandler2b697352011-07-22 16:23:09 -040089import com.android.systemui.statusbar.policy.BatteryController;
Winson Chungd63c59782012-09-05 17:34:41 -070090import com.android.systemui.statusbar.policy.BluetoothController;
Michael Jurka7f2668c2012-03-27 07:49:52 -070091import com.android.systemui.statusbar.policy.DateView;
Daniel Sandler6a858c32012-03-12 14:38:58 -040092import com.android.systemui.statusbar.policy.IntruderAlertView;
Daniel Sandler2b697352011-07-22 16:23:09 -040093import com.android.systemui.statusbar.policy.LocationController;
94import com.android.systemui.statusbar.policy.NetworkController;
Daniel Sandler8ba33c92011-10-04 21:49:30 -040095import com.android.systemui.statusbar.policy.NotificationRowLayout;
Michael Jurkaa600fd92012-06-25 15:57:05 -070096import com.android.systemui.statusbar.policy.OnSizeChangedListener;
Daniel Sandlerb17a7262012-10-05 14:32:50 -040097import com.android.systemui.statusbar.policy.Prefs;
Joe Onorato808182d2010-07-09 18:52:06 -040098
Daniel Sandler6a858c32012-03-12 14:38:58 -040099import java.io.FileDescriptor;
100import java.io.PrintWriter;
101import java.util.ArrayList;
102
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500103public class PhoneStatusBar extends BaseStatusBar {
Joe Onoratofd52b182010-11-10 18:00:52 -0800104 static final String TAG = "PhoneStatusBar";
Daniel Sandler198a0302012-08-17 16:04:31 -0400105 public static final boolean DEBUG = BaseStatusBar.DEBUG;
Daniel Sandlerc1ebee42012-03-26 19:39:46 -0400106 public static final boolean SPEW = DEBUG;
Daniel Sandler7579bca2011-08-18 15:47:26 -0400107 public static final boolean DUMPTRUCK = true; // extra dumpsys info
Daniel Sandlerfa027f52013-04-11 22:01:47 -0400108 public static final boolean DEBUG_GESTURES = false;
Joe Onorato808182d2010-07-09 18:52:06 -0400109
Daniel Sandlerb17a7262012-10-05 14:32:50 -0400110 public static final boolean DEBUG_CLINGS = false;
111
Daniel Sandlerace0bd72012-10-11 09:56:45 -0700112 public static final boolean ENABLE_NOTIFICATION_PANEL_CLING = false;
113
Daniel Sandler040c2e42012-10-17 00:56:33 -0400114 public static final boolean SETTINGS_DRAG_SHORTCUT = true;
115
Daniel Sandler96e61c3c82011-08-04 22:49:06 -0400116 // additional instrumentation for testing purposes; intended to be left on during development
Daniel Sandler7c351742011-10-17 10:48:06 -0400117 public static final boolean CHATTY = DEBUG;
Daniel Sandler96e61c3c82011-08-04 22:49:06 -0400118
Joe Onorato808182d2010-07-09 18:52:06 -0400119 public static final String ACTION_STATUSBAR_START
120 = "com.android.internal.policy.statusbar.START";
121
Daniel Sandler8ba33c92011-10-04 21:49:30 -0400122 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
Daniel Sandler11cf1782012-09-27 14:03:08 -0400123 private static final int MSG_CLOSE_PANELS = 1001;
124 private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
Michael Jurka7f2668c2012-03-27 07:49:52 -0700125 // 1020-1030 reserved for BaseStatusBar
Joe Onorato808182d2010-07-09 18:52:06 -0400126
127 // will likely move to a resource or other tunable param at some point
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400128 private static final int INTRUDER_ALERT_DECAY_MS = 0; // disabled, was 10000;
Joe Onorato808182d2010-07-09 18:52:06 -0400129
Daniel Sandler8cc36e52011-10-17 14:18:46 -0400130 private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
131
Daniel Sandler58b173b2012-05-03 11:25:29 -0400132 private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
133 private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
134
Daniel Sandlerdc940ea2011-08-25 14:35:53 -0700135 // fling gesture tuning parameters, scaled to display density
136 private float mSelfExpandVelocityPx; // classic value: 2000px/s
137 private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
138 private float mFlingExpandMinVelocityPx; // classic value: 200px/s
139 private float mFlingCollapseMinVelocityPx; // classic value: 200px/s
140 private float mCollapseMinDisplayFraction; // classic value: 0.08 (25px/min(320px,480px) on G1)
141 private float mExpandMinDisplayFraction; // classic value: 0.5 (drag open halfway to expand)
142 private float mFlingGestureMaxXVelocityPx; // classic value: 150px/s
143
144 private float mExpandAccelPx; // classic value: 2000px/s/s
145 private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up")
146
Daniel Sandlere5011a32012-06-11 16:07:52 -0400147 private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little
148 // faster than mSelfCollapseVelocityPx)
149
Joe Onoratofd52b182010-11-10 18:00:52 -0800150 PhoneStatusBarPolicy mIconPolicy;
Joe Onorato808182d2010-07-09 18:52:06 -0400151
Daniel Sandler2b697352011-07-22 16:23:09 -0400152 // These are no longer handled by the policy, because we need custom strategies for them
Winson Chungd63c59782012-09-05 17:34:41 -0700153 BluetoothController mBluetoothController;
Daniel Sandler2b697352011-07-22 16:23:09 -0400154 BatteryController mBatteryController;
155 LocationController mLocationController;
156 NetworkController mNetworkController;
Jim Miller5e6af442011-12-02 18:24:26 -0800157
Daniel Sandler7c3e39d2011-07-29 16:30:49 -0400158 int mNaturalBarHeight = -1;
159 int mIconSize = -1;
160 int mIconHPadding = -1;
Joe Onorato808182d2010-07-09 18:52:06 -0400161 Display mDisplay;
Daniel Sandlere680f542012-09-28 12:22:27 -0400162 Point mCurrentDisplaySize = new Point();
Joe Onorato808182d2010-07-09 18:52:06 -0400163
Daniel Sandlera2fbe532012-08-10 01:19:03 -0400164 IDreamManager mDreamManager;
Daniel Sandler1d4d30a2011-04-28 12:35:29 -0400165
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400166 StatusBarWindowView mStatusBarWindow;
Joe Onoratofd52b182010-11-10 18:00:52 -0800167 PhoneStatusBarView mStatusBarView;
Daniel Sandlera310af82012-04-24 01:20:13 -0400168
Joe Onorato808182d2010-07-09 18:52:06 -0400169 int mPixelFormat;
Joe Onorato808182d2010-07-09 18:52:06 -0400170 Object mQueueLock = new Object();
171
Daniel Sandler173bae22012-09-25 14:37:42 -0400172 // viewgroup containing the normal contents of the statusbar
173 LinearLayout mStatusBarContents;
174
175 // right-hand icons
176 LinearLayout mSystemIconArea;
177
178 // left-hand icons
Joe Onorato808182d2010-07-09 18:52:06 -0400179 LinearLayout mStatusIcons;
Daniel Sandler173bae22012-09-25 14:37:42 -0400180 // the icons themselves
181 IconMerger mNotificationIcons;
182 // [+>
183 View mMoreIcon;
Joe Onorato808182d2010-07-09 18:52:06 -0400184
185 // expanded notifications
Daniel Sandler040c2e42012-10-17 00:56:33 -0400186 NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
Joe Onorato808182d2010-07-09 18:52:06 -0400187 ScrollView mScrollView;
Joe Onorato808182d2010-07-09 18:52:06 -0400188 View mExpandedContents;
Daniel Sandler21b274e2012-05-02 15:07:51 -0400189 int mNotificationPanelGravity;
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400190 int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
Daniel Sandlere680f542012-09-28 12:22:27 -0400191 float mNotificationPanelMinHeightFrac;
Daniel Sandler66d92f82012-06-13 13:36:52 -0400192 boolean mNotificationPanelIsFullScreenWidth;
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400193 TextView mNotificationPanelDebugText;
Daniel Sandler21b274e2012-05-02 15:07:51 -0400194
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400195 // settings
Daniel Sandler101784e2012-10-15 13:39:38 -0400196 QuickSettings mQS;
197 boolean mHasSettingsPanel, mHasFlipSettings;
Daniel Sandler3ffdcc72012-09-23 14:31:48 -0400198 SettingsPanelView mSettingsPanel;
Daniel Sandler101784e2012-10-15 13:39:38 -0400199 View mFlipSettingsView;
200 QuickSettingsContainerView mSettingsContainer;
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400201 int mSettingsPanelGravity;
202
Joe Onorato808182d2010-07-09 18:52:06 -0400203 // top bar
Daniel Sandler3679bf52012-10-16 21:30:28 -0400204 View mNotificationPanelHeader;
205 View mDateTimeView;
Daniel Sandler1347c302011-08-01 16:47:53 -0400206 View mClearButton;
Daniel Sandler101784e2012-10-15 13:39:38 -0400207 ImageView mSettingsButton, mNotificationButton;
Daniel Sandlerd3090562011-08-09 00:28:44 -0400208
Daniel Sandler3d32a242012-06-05 13:44:14 -0400209 // carrier/wifi label
210 private TextView mCarrierLabel;
211 private boolean mCarrierLabelVisible = false;
212 private int mCarrierLabelHeight;
Daniel Sandlerdd4ef492012-07-27 11:19:52 -0400213 private TextView mEmergencyCallLabel;
Daniel Sandlerbf526d12012-09-04 22:56:44 -0400214 private int mNotificationHeaderHeight;
215
216 private boolean mShowCarrierInPanel = false;
Daniel Sandler3d32a242012-06-05 13:44:14 -0400217
Joe Onorato808182d2010-07-09 18:52:06 -0400218 // position
219 int[] mPositionTmp = new int[2];
Joe Onorato808182d2010-07-09 18:52:06 -0400220 boolean mExpandedVisible;
221
222 // the date view
223 DateView mDateView;
224
225 // for immersive activities
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400226 private IntruderAlertView mIntruderAlertView;
Joe Onorato808182d2010-07-09 18:52:06 -0400227
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400228 // on-screen navigation buttons
Daniel Sandler0129b312011-05-11 11:54:11 -0400229 private NavigationBarView mNavigationBarView = null;
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400230
Joe Onorato808182d2010-07-09 18:52:06 -0400231 // the tracker view
Joe Onorato808182d2010-07-09 18:52:06 -0400232 int mTrackingPosition; // the position of the top of the tracking view.
Joe Onorato808182d2010-07-09 18:52:06 -0400233
234 // ticker
235 private Ticker mTicker;
236 private View mTickerView;
237 private boolean mTicking;
238
239 // Tracking finger for opening/closing.
240 int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
241 boolean mTracking;
242 VelocityTracker mVelocityTracker;
243
Daniel Sandlerb17a7262012-10-05 14:32:50 -0400244 // help screen
245 private boolean mClingShown;
246 private ViewGroup mCling;
247 private boolean mSuppressStatusBarDrags; // while a cling is up, briefly deaden the bar to give things time to settle
248
Joe Onorato808182d2010-07-09 18:52:06 -0400249 int[] mAbsPos = new int[2];
Chet Haase2f2022a2011-10-11 06:41:59 -0700250 Runnable mPostCollapseCleanup = null;
251
Daniel Sandler173bae22012-09-25 14:37:42 -0400252 private Animator mLightsOutAnimation;
253 private Animator mLightsOnAnimation;
Joe Onorato808182d2010-07-09 18:52:06 -0400254
255 // for disabling the status bar
256 int mDisabled = 0;
257
Daniel Sandler60ee2562011-07-22 12:34:33 -0400258 // tracking calls to View.setSystemUiVisibility()
259 int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
260
Daniel Sandler36412a72011-08-04 09:35:13 -0400261 DisplayMetrics mDisplayMetrics = new DisplayMetrics();
Dianne Hackborn1dacf272011-08-02 15:01:22 -0700262
Daniel Sandler33805342012-07-23 15:45:12 -0400263 // XXX: gesture research
Daniel Sandler151f00d2012-10-02 22:33:08 -0400264 private final GestureRecorder mGestureRec = DEBUG_GESTURES
265 ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
266 : null;
Daniel Sandler33805342012-07-23 15:45:12 -0400267
Daniel Sandler328310c2011-09-23 15:56:52 -0400268 private int mNavigationIconHints = 0;
Romain Guyf7f16f72012-05-24 19:13:56 -0700269 private final Animator.AnimatorListener mMakeIconsInvisible = new AnimatorListenerAdapter() {
270 @Override
271 public void onAnimationEnd(Animator animation) {
Daniel Sandler67e7d902012-06-06 16:32:21 -0400272 // double-check to avoid races
Daniel Sandler173bae22012-09-25 14:37:42 -0400273 if (mStatusBarContents.getAlpha() == 0) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -0800274 if (DEBUG) Slog.d(TAG, "makeIconsInvisible");
Daniel Sandler173bae22012-09-25 14:37:42 -0400275 mStatusBarContents.setVisibility(View.INVISIBLE);
Daniel Sandler67e7d902012-06-06 16:32:21 -0400276 }
Romain Guyf7f16f72012-05-24 19:13:56 -0700277 }
278 };
Daniel Sandler328310c2011-09-23 15:56:52 -0400279
John Spurlock919adac2012-10-02 16:41:12 -0400280 // ensure quick settings is disabled until the current user makes it through the setup wizard
281 private boolean mUserSetup = false;
282 private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
283 @Override
284 public void onChange(boolean selfChange) {
285 final boolean userSetup = 0 != Settings.Secure.getIntForUser(
286 mContext.getContentResolver(),
287 Settings.Secure.USER_SETUP_COMPLETE,
288 0 /*default */,
289 mCurrentUserId);
John Spurlocke4e8c562012-10-04 09:55:01 -0400290 if (MULTIUSER_DEBUG) Slog.d(TAG, String.format("User setup changed: " +
291 "selfChange=%s userSetup=%s mUserSetup=%s",
292 selfChange, userSetup, mUserSetup));
Daniel Sandlera8ef3b02012-11-29 15:52:39 -0500293 if (mSettingsButton != null && mHasFlipSettings) {
Daniel Sandler101784e2012-10-15 13:39:38 -0400294 mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
295 }
296 if (mSettingsPanel != null) {
John Spurlocke4e8c562012-10-04 09:55:01 -0400297 mSettingsPanel.setEnabled(userSetup);
Daniel Sandler101784e2012-10-15 13:39:38 -0400298 }
John Spurlock919adac2012-10-02 16:41:12 -0400299 if (userSetup != mUserSetup) {
300 mUserSetup = userSetup;
John Spurlock919adac2012-10-02 16:41:12 -0400301 if (!mUserSetup && mStatusBarView != null)
302 animateCollapseQuickSettings();
303 }
304 }
305 };
306
Joe Onorato808182d2010-07-09 18:52:06 -0400307 @Override
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400308 public void start() {
309 mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
310 .getDefaultDisplay();
Joe Onorato808182d2010-07-09 18:52:06 -0400311
Daniel Sandlera2fbe532012-08-10 01:19:03 -0400312 mDreamManager = IDreamManager.Stub.asInterface(
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700313 ServiceManager.checkService(DreamService.DREAM_SERVICE));
Daniel Sandlera2fbe532012-08-10 01:19:03 -0400314
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500315 super.start(); // calls createAndAddWindows()
Joe Onorato808182d2010-07-09 18:52:06 -0400316
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400317 addNavigationBar();
318
Daniel Sandlerfc6fda32012-02-24 22:00:46 -0500319 if (ENABLE_INTRUDERS) addIntruderView();
Joe Onorato808182d2010-07-09 18:52:06 -0400320
321 // Lastly, call to the icon policy to install/update all the icons.
Joe Onoratofd52b182010-11-10 18:00:52 -0800322 mIconPolicy = new PhoneStatusBarPolicy(mContext);
Joe Onorato808182d2010-07-09 18:52:06 -0400323 }
324
325 // ================================================================================
326 // Constructing the view
327 // ================================================================================
Jim Millere898ac52012-04-06 17:10:57 -0700328 protected PhoneStatusBarView makeStatusBarView() {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -0400329 final Context context = mContext;
Joe Onorato808182d2010-07-09 18:52:06 -0400330
331 Resources res = context.getResources();
332
Daniel Sandler6e8db882011-10-26 15:40:51 -0400333 updateDisplaySize(); // populates mDisplayMetrics
Daniel Sandler7c3e39d2011-07-29 16:30:49 -0400334 loadDimens();
Joe Onorato808182d2010-07-09 18:52:06 -0400335
Dianne Hackborn1dacf272011-08-02 15:01:22 -0700336 mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
337
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400338 mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
Daniel Sandlera310af82012-04-24 01:20:13 -0400339 R.layout.super_status_bar, null);
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400340 mStatusBarWindow.mService = this;
Daniel Sandler21b274e2012-05-02 15:07:51 -0400341 mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
342 @Override
343 public boolean onTouch(View v, MotionEvent event) {
344 if (event.getAction() == MotionEvent.ACTION_DOWN) {
Daniel Sandler37a38aa2013-02-13 17:15:57 -0500345 if (mExpandedVisible) {
Daniel Sandler11cf1782012-09-27 14:03:08 -0400346 animateCollapsePanels();
Daniel Sandler21b274e2012-05-02 15:07:51 -0400347 }
348 }
Chris Wren5de6e942012-05-16 14:22:21 -0400349 return mStatusBarWindow.onTouchEvent(event);
Daniel Sandler21b274e2012-05-02 15:07:51 -0400350 }});
351
Daniel Sandlera310af82012-04-24 01:20:13 -0400352 mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400353 mStatusBarView.setBar(this);
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700354
Daniel Sandler08d05e32012-08-08 16:39:54 -0400355
356 PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
357 mStatusBarView.setPanelHolder(holder);
358
Daniel Sandler040c2e42012-10-17 00:56:33 -0400359 mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
360 mNotificationPanel.setStatusBar(this);
Daniel Sandler66d92f82012-06-13 13:36:52 -0400361 mNotificationPanelIsFullScreenWidth =
362 (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
Joe Onorato808182d2010-07-09 18:52:06 -0400363
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700364 // make the header non-responsive to clicks
365 mNotificationPanel.findViewById(R.id.header).setOnTouchListener(
366 new View.OnTouchListener() {
367 @Override
368 public boolean onTouch(View v, MotionEvent event) {
369 return true; // e eats everything
370 }
371 });
372
Jeff Brown98365d72012-08-19 20:30:52 -0700373 if (!ActivityManager.isHighEndGfx()) {
Romain Guy328b3582012-05-08 15:30:57 -0700374 mStatusBarWindow.setBackground(null);
Romain Guy648342f2012-05-25 10:44:45 -0700375 mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
376 R.color.notification_panel_solid_background)));
Romain Guy328b3582012-05-08 15:30:57 -0700377 }
Daniel Sandler6b318802012-04-13 14:05:19 -0400378 if (ENABLE_INTRUDERS) {
379 mIntruderAlertView = (IntruderAlertView) View.inflate(context, R.layout.intruder_alert, null);
380 mIntruderAlertView.setVisibility(View.GONE);
381 mIntruderAlertView.setBar(this);
382 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400383 if (MULTIUSER_DEBUG) {
384 mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(R.id.header_debug_info);
385 mNotificationPanelDebugText.setVisibility(View.VISIBLE);
386 }
Joe Onorato808182d2010-07-09 18:52:06 -0400387
John Spurlockd5ef5462012-06-13 11:19:51 -0400388 updateShowSearchHoldoff();
389
Daniel Sandler0129b312011-05-11 11:54:11 -0400390 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700391 boolean showNav = mWindowManagerService.hasNavigationBar();
Daniel Sandler4a066c52012-04-20 14:49:13 -0400392 if (DEBUG) Slog.v(TAG, "hasNavigationBar=" + showNav);
Daniel Sandler0129b312011-05-11 11:54:11 -0400393 if (showNav) {
Jim Miller5e6af442011-12-02 18:24:26 -0800394 mNavigationBarView =
Daniel Sandler0129b312011-05-11 11:54:11 -0400395 (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
Daniel Sandler60ee2562011-07-22 12:34:33 -0400396
Daniel Sandler6da2b762011-09-14 16:04:59 -0400397 mNavigationBarView.setDisabledFlags(mDisabled);
Jim Millere898ac52012-04-06 17:10:57 -0700398 mNavigationBarView.setBar(this);
Daniel Sandler0129b312011-05-11 11:54:11 -0400399 }
Daniel Sandler0c4ccff2011-10-19 16:39:14 -0400400 } catch (RemoteException ex) {
401 // no window manager? good luck with that
Daniel Sandler0129b312011-05-11 11:54:11 -0400402 }
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400403
Joe Onorato808182d2010-07-09 18:52:06 -0400404 // figure out which pixel-format to use for the status bar.
Daniel Sandlerf733c2a2011-09-25 15:03:40 -0400405 mPixelFormat = PixelFormat.OPAQUE;
Daniel Sandler173bae22012-09-25 14:37:42 -0400406
407 mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area);
Daniel Sandlera310af82012-04-24 01:20:13 -0400408 mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
409 mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
Mats H Carlssoncd231432012-10-10 13:37:38 +0200410 mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
Daniel Sandler05e24142011-11-10 11:56:49 -0500411 mNotificationIcons.setOverflowIndicator(mMoreIcon);
Daniel Sandler173bae22012-09-25 14:37:42 -0400412 mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
Daniel Sandlera310af82012-04-24 01:20:13 -0400413 mTickerView = mStatusBarView.findViewById(R.id.ticker);
Joe Onorato808182d2010-07-09 18:52:06 -0400414
Daniel Sandlera310af82012-04-24 01:20:13 -0400415 mPile = (NotificationRowLayout)mStatusBarWindow.findViewById(R.id.latestItems);
Daniel Sandlere5011a32012-06-11 16:07:52 -0400416 mPile.setLayoutTransitionsEnabled(false);
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400417 mPile.setLongPressListener(getNotificationLongClicker());
Daniel Sandler0761e4c2011-08-11 00:19:49 -0400418 mExpandedContents = mPile; // was: expanded.findViewById(R.id.notificationLinearLayout);
Daniel Sandlerd7141482011-08-18 15:14:52 -0400419
Daniel Sandler3679bf52012-10-16 21:30:28 -0400420 mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
421
Daniel Sandlera310af82012-04-24 01:20:13 -0400422 mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
Joe Onorato808182d2010-07-09 18:52:06 -0400423 mClearButton.setOnClickListener(mClearButtonListener);
Daniel Sandler0761e4c2011-08-11 00:19:49 -0400424 mClearButton.setAlpha(0f);
Romain Guy8900e632012-05-25 12:08:39 -0700425 mClearButton.setVisibility(View.INVISIBLE);
Daniel Sandler8ba33c92011-10-04 21:49:30 -0400426 mClearButton.setEnabled(false);
Daniel Sandlera310af82012-04-24 01:20:13 -0400427 mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
Daniel Sandlere111ad32012-10-13 15:17:45 -0400428
429 mHasSettingsPanel = res.getBoolean(R.bool.config_hasSettingsPanel);
Daniel Sandler101784e2012-10-15 13:39:38 -0400430 mHasFlipSettings = res.getBoolean(R.bool.config_hasFlipSettingsPanel);
Daniel Sandlere111ad32012-10-13 15:17:45 -0400431
Daniel Sandler3679bf52012-10-16 21:30:28 -0400432 mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
Daniel Sandler458d5e12013-02-21 15:12:49 -0500433 if (mDateTimeView != null) {
Daniel Sandler3679bf52012-10-16 21:30:28 -0400434 mDateTimeView.setOnClickListener(mClockClickListener);
435 mDateTimeView.setEnabled(true);
436 }
437
Daniel Sandlere111ad32012-10-13 15:17:45 -0400438 mSettingsButton = (ImageView) mStatusBarWindow.findViewById(R.id.settings_button);
Daniel Sandler6e5fe432012-09-16 15:34:36 -0400439 if (mSettingsButton != null) {
Daniel Sandlere111ad32012-10-13 15:17:45 -0400440 mSettingsButton.setOnClickListener(mSettingsButtonListener);
441 if (mHasSettingsPanel) {
442 if (mStatusBarView.hasFullWidthNotifications()) {
443 // the settings panel is hiding behind this button
444 mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
445 mSettingsButton.setVisibility(View.VISIBLE);
446 } else {
447 // there is a settings panel, but it's on the other side of the (large) screen
Daniel Sandler7382a022012-10-22 14:36:50 -0400448 final View buttonHolder = mStatusBarWindow.findViewById(
449 R.id.settings_button_holder);
450 if (buttonHolder != null) {
451 buttonHolder.setVisibility(View.GONE);
452 }
Daniel Sandlere111ad32012-10-13 15:17:45 -0400453 }
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700454 } else {
Daniel Sandlere111ad32012-10-13 15:17:45 -0400455 // no settings panel, go straight to settings
456 mSettingsButton.setVisibility(View.VISIBLE);
457 mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700458 }
Daniel Sandler6e5fe432012-09-16 15:34:36 -0400459 }
Daniel Sandler101784e2012-10-15 13:39:38 -0400460 if (mHasFlipSettings) {
461 mNotificationButton = (ImageView) mStatusBarWindow.findViewById(R.id.notification_button);
462 if (mNotificationButton != null) {
463 mNotificationButton.setOnClickListener(mNotificationButtonListener);
464 }
465 }
466
Daniel Sandlera310af82012-04-24 01:20:13 -0400467 mScrollView = (ScrollView)mStatusBarWindow.findViewById(R.id.scroll);
Daniel Sandler079b33d2012-03-02 16:29:41 -0500468 mScrollView.setVerticalScrollBarEnabled(false); // less drawing during pulldowns
Daniel Sandler3679bf52012-10-16 21:30:28 -0400469 if (!mNotificationPanelIsFullScreenWidth) {
470 mScrollView.setSystemUiVisibility(
471 View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER |
472 View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
473 View.STATUS_BAR_DISABLE_CLOCK);
474 }
Joe Onorato808182d2010-07-09 18:52:06 -0400475
Daniel Sandlera310af82012-04-24 01:20:13 -0400476 mTicker = new MyTicker(context, mStatusBarView);
Joe Onorato808182d2010-07-09 18:52:06 -0400477
Daniel Sandlera310af82012-04-24 01:20:13 -0400478 TickerView tickerView = (TickerView)mStatusBarView.findViewById(R.id.tickerText);
Joe Onorato808182d2010-07-09 18:52:06 -0400479 tickerView.mTicker = mTicker;
480
Joe Onorato808182d2010-07-09 18:52:06 -0400481 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
482
Joe Onorato808182d2010-07-09 18:52:06 -0400483 // set the inital view visibility
484 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400485
Daniel Sandler2b697352011-07-22 16:23:09 -0400486 // Other icons
487 mLocationController = new LocationController(mContext); // will post a notification
488 mBatteryController = new BatteryController(mContext);
Daniel Sandlera310af82012-04-24 01:20:13 -0400489 mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery));
Daniel Sandler2b697352011-07-22 16:23:09 -0400490 mNetworkController = new NetworkController(mContext);
Winson Chungd63c59782012-09-05 17:34:41 -0700491 mBluetoothController = new BluetoothController(mContext);
Jim Miller5e6af442011-12-02 18:24:26 -0800492 final SignalClusterView signalCluster =
Daniel Sandlera310af82012-04-24 01:20:13 -0400493 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
Daniel Sandler3d32a242012-06-05 13:44:14 -0400494
Winson Chungd63c59782012-09-05 17:34:41 -0700495
Christian Robertson2e347422011-08-11 14:01:04 -0700496 mNetworkController.addSignalCluster(signalCluster);
Daniel Sandler28f89d42011-08-15 14:04:15 -0400497 signalCluster.setNetworkController(mNetworkController);
Daniel Sandler18ac7822012-06-11 16:07:18 -0400498
Daniel Sandler8b268d42013-05-28 16:17:13 -0400499 final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
500 if (isAPhone) {
501 mEmergencyCallLabel =
502 (TextView) mStatusBarWindow.findViewById(R.id.emergency_calls_only);
503 if (mEmergencyCallLabel != null) {
504 mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
505 mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
506 public void onClick(View v) { }});
507 mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
508 @Override
509 public void onLayoutChange(View v, int left, int top, int right, int bottom,
510 int oldLeft, int oldTop, int oldRight, int oldBottom) {
511 updateCarrierLabelVisibility(false);
512 }});
513 }
Daniel Sandlerdd4ef492012-07-27 11:19:52 -0400514 }
515
Daniel Sandlerbf526d12012-09-04 22:56:44 -0400516 mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
517 mShowCarrierInPanel = (mCarrierLabel != null);
Dianne Hackborn7ff30112012-11-08 11:12:09 -0800518 if (DEBUG) Slog.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel);
Daniel Sandlerbf526d12012-09-04 22:56:44 -0400519 if (mShowCarrierInPanel) {
Daniel Sandlerdd4ef492012-07-27 11:19:52 -0400520 mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE);
521
Daniel Sandler67234c42012-06-15 13:17:39 -0400522 // for mobile devices, we always show mobile connection info here (SPN/PLMN)
523 // for other devices, we show whatever network is connected
Daniel Sandler18ac7822012-06-11 16:07:18 -0400524 if (mNetworkController.hasMobileDataFeature()) {
525 mNetworkController.addMobileLabelView(mCarrierLabel);
526 } else {
Daniel Sandler67234c42012-06-15 13:17:39 -0400527 mNetworkController.addCombinedLabelView(mCarrierLabel);
Daniel Sandler18ac7822012-06-11 16:07:18 -0400528 }
Daniel Sandlerdd4ef492012-07-27 11:19:52 -0400529
530 // set up the dynamic hide/show of the label
531 mPile.setOnSizeChangedListener(new OnSizeChangedListener() {
532 @Override
533 public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
534 updateCarrierLabelVisibility(false);
535 }
536 });
Daniel Sandler3d32a242012-06-05 13:44:14 -0400537 }
538
Daniel Sandlere111ad32012-10-13 15:17:45 -0400539 // Quick Settings (where available, some restrictions apply)
540 if (mHasSettingsPanel) {
Daniel Sandler101784e2012-10-15 13:39:38 -0400541 // first, figure out where quick settings should be inflated
542 final View settings_stub;
543 if (mHasFlipSettings) {
544 // a version of quick settings that flips around behind the notifications
545 settings_stub = mStatusBarWindow.findViewById(R.id.flip_settings_stub);
546 if (settings_stub != null) {
547 mFlipSettingsView = ((ViewStub)settings_stub).inflate();
548 mFlipSettingsView.setVisibility(View.GONE);
549 mFlipSettingsView.setVerticalScrollBarEnabled(false);
550 }
Daniel Sandlere111ad32012-10-13 15:17:45 -0400551 } else {
Daniel Sandler101784e2012-10-15 13:39:38 -0400552 // full quick settings panel
553 settings_stub = mStatusBarWindow.findViewById(R.id.quick_settings_stub);
554 if (settings_stub != null) {
555 mSettingsPanel = (SettingsPanelView) ((ViewStub)settings_stub).inflate();
556 } else {
557 mSettingsPanel = (SettingsPanelView) mStatusBarWindow.findViewById(R.id.settings_panel);
558 }
559
560 if (mSettingsPanel != null) {
Daniel Sandler101784e2012-10-15 13:39:38 -0400561 if (!ActivityManager.isHighEndGfx()) {
562 mSettingsPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
563 R.color.notification_panel_solid_background)));
564 }
565 }
Daniel Sandlere111ad32012-10-13 15:17:45 -0400566 }
567
Daniel Sandler101784e2012-10-15 13:39:38 -0400568 // wherever you find it, Quick Settings needs a container to survive
569 mSettingsContainer = (QuickSettingsContainerView)
570 mStatusBarWindow.findViewById(R.id.quick_settings_container);
571 if (mSettingsContainer != null) {
572 mQS = new QuickSettings(mContext, mSettingsContainer);
Daniel Sandler3679bf52012-10-16 21:30:28 -0400573 if (!mNotificationPanelIsFullScreenWidth) {
574 mSettingsContainer.setSystemUiVisibility(
575 View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
576 | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
577 }
Daniel Sandler101784e2012-10-15 13:39:38 -0400578 if (mSettingsPanel != null) {
579 mSettingsPanel.setQuickSettings(mQS);
Daniel Sandlere111ad32012-10-13 15:17:45 -0400580 }
Daniel Sandler101784e2012-10-15 13:39:38 -0400581 mQS.setService(this);
Daniel Sandlerfe3376b2012-10-16 19:54:02 -0400582 mQS.setBar(mStatusBarView);
Daniel Sandler101784e2012-10-15 13:39:38 -0400583 mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
584 mLocationController);
585 } else {
586 mQS = null; // fly away, be free
Daniel Sandlere111ad32012-10-13 15:17:45 -0400587 }
Siva Velusamy537421b2012-09-14 14:45:02 -0700588 }
589
Daniel Sandlerb17a7262012-10-05 14:32:50 -0400590 mClingShown = ! (DEBUG_CLINGS
591 || !Prefs.read(mContext).getBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, false));
592
Daniel Sandlerace0bd72012-10-11 09:56:45 -0700593 if (!ENABLE_NOTIFICATION_PANEL_CLING || ActivityManager.isRunningInTestHarness()) {
Daniel Sandlerb17a7262012-10-05 14:32:50 -0400594 mClingShown = true;
595 }
596
Jim Miller5e6af442011-12-02 18:24:26 -0800597// final ImageView wimaxRSSI =
Daniel Sandler633eabe2011-11-09 16:49:44 -0500598// (ImageView)sb.findViewById(R.id.wimax_signal);
599// if (wimaxRSSI != null) {
600// mNetworkController.addWimaxIconView(wimaxRSSI);
601// }
Michael Jurka3b1fc472011-06-13 10:54:40 -0700602
Joe Onorato808182d2010-07-09 18:52:06 -0400603 // receive broadcasts
604 IntentFilter filter = new IntentFilter();
605 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
606 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
607 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandler7f3cf952012-08-31 14:57:09 -0400608 filter.addAction(Intent.ACTION_SCREEN_ON);
Joe Onorato808182d2010-07-09 18:52:06 -0400609 context.registerReceiver(mBroadcastReceiver, filter);
610
John Spurlock919adac2012-10-02 16:41:12 -0400611 // listen for USER_SETUP_COMPLETE setting (per-user)
612 resetUserSetupObserver();
613
Daniel Sandlera310af82012-04-24 01:20:13 -0400614 return mStatusBarView;
Joe Onorato808182d2010-07-09 18:52:06 -0400615 }
616
Michael Jurka7f2668c2012-03-27 07:49:52 -0700617 @Override
Michael Jurkacb2522c2012-04-13 09:32:47 -0700618 protected View getStatusBarView() {
619 return mStatusBarView;
620 }
621
622 @Override
Jim Millerf2a16b22011-07-06 17:32:48 -0700623 protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) {
Michael Jurka3cd0a592011-08-16 12:40:30 -0700624 boolean opaque = false;
Michael Jurka3b1fc472011-06-13 10:54:40 -0700625 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
Jim Millerf2a16b22011-07-06 17:32:48 -0700626 layoutParams.width,
627 layoutParams.height,
Michael Jurka3b1fc472011-06-13 10:54:40 -0700628 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
629 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
630 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700631 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
Michael Jurka3cd0a592011-08-16 12:40:30 -0700632 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
Jeff Brown98365d72012-08-19 20:30:52 -0700633 if (ActivityManager.isHighEndGfx()) {
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700634 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
Michael Jurkaf16fc512012-02-27 15:02:23 -0800635 } else {
636 lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
Michael Jurkaf3abbad2012-06-04 14:00:32 -0700637 lp.dimAmount = 0.75f;
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700638 }
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700639 lp.gravity = Gravity.BOTTOM | Gravity.START;
Michael Jurka3b1fc472011-06-13 10:54:40 -0700640 lp.setTitle("RecentsPanel");
Michael Jurka99a96552012-01-27 17:23:38 -0800641 lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
Michael Jurka3b1fc472011-06-13 10:54:40 -0700642 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
643 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
644 return lp;
645 }
646
Jim Millere898ac52012-04-06 17:10:57 -0700647 @Override
648 protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
649 boolean opaque = false;
650 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
651 LayoutParams.MATCH_PARENT,
652 LayoutParams.MATCH_PARENT,
653 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
654 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
655 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
656 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
657 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
Jeff Brown98365d72012-08-19 20:30:52 -0700658 if (ActivityManager.isHighEndGfx()) {
Jim Millere898ac52012-04-06 17:10:57 -0700659 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
Jim Millere898ac52012-04-06 17:10:57 -0700660 }
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700661 lp.gravity = Gravity.BOTTOM | Gravity.START;
Jim Millere898ac52012-04-06 17:10:57 -0700662 lp.setTitle("SearchPanel");
663 // TODO: Define custom animation for Search panel
664 lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
665 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
666 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
667 return lp;
668 }
669
Jim Millere898ac52012-04-06 17:10:57 -0700670 @Override
671 protected void updateSearchPanel() {
672 super.updateSearchPanel();
Jim Miller354619c2012-04-27 17:33:44 -0700673 mSearchPanelView.setStatusBarView(mNavigationBarView);
Jim Millere898ac52012-04-06 17:10:57 -0700674 mNavigationBarView.setDelegateView(mSearchPanelView);
675 }
676
677 @Override
678 public void showSearchPanel() {
Jim Millerb490c3e2012-05-31 13:34:16 -0700679 super.showSearchPanel();
John Spurlock7a733442012-11-08 09:08:14 -0500680 mHandler.removeCallbacks(mShowSearchPanel);
Daniel Sandlerd5483c32012-10-19 16:44:15 -0400681
682 // we want to freeze the sysui state wherever it is
683 mSearchPanelView.setSystemUiVisibility(mSystemUiVisibility);
684
Jim Millere898ac52012-04-06 17:10:57 -0700685 WindowManager.LayoutParams lp =
686 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
687 lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
Jeff Brown98365d72012-08-19 20:30:52 -0700688 mWindowManager.updateViewLayout(mNavigationBarView, lp);
Jim Millere898ac52012-04-06 17:10:57 -0700689 }
690
691 @Override
692 public void hideSearchPanel() {
693 super.hideSearchPanel();
694 WindowManager.LayoutParams lp =
695 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
696 lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
Jeff Brown98365d72012-08-19 20:30:52 -0700697 mWindowManager.updateViewLayout(mNavigationBarView, lp);
Jim Millere898ac52012-04-06 17:10:57 -0700698 }
699
Joe Onorato808182d2010-07-09 18:52:06 -0400700 protected int getStatusBarGravity() {
701 return Gravity.TOP | Gravity.FILL_HORIZONTAL;
702 }
703
Joe Onoratodc100302011-01-11 17:07:41 -0800704 public int getStatusBarHeight() {
Daniel Sandlera310af82012-04-24 01:20:13 -0400705 if (mNaturalBarHeight < 0) {
706 final Resources res = mContext.getResources();
Jim Millera073e572012-05-23 17:03:27 -0700707 mNaturalBarHeight =
Daniel Sandlera310af82012-04-24 01:20:13 -0400708 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
709 }
710 return mNaturalBarHeight;
Joe Onoratodc100302011-01-11 17:07:41 -0800711 }
712
Daniel Sandler5c8da942011-06-28 00:29:04 -0400713 private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
714 public void onClick(View v) {
John Spurlockc8b46ca2013-04-08 12:59:26 -0400715 awakenDreams();
Daniel Sandler5c8da942011-06-28 00:29:04 -0400716 toggleRecentApps();
717 }
718 };
Chris Wren0c8275b2012-05-08 13:36:48 -0400719
Jim Miller9a720f52012-05-30 03:19:43 -0700720 private int mShowSearchHoldoff = 0;
721 private Runnable mShowSearchPanel = new Runnable() {
722 public void run() {
723 showSearchPanel();
Daniel Sandlera2fbe532012-08-10 01:19:03 -0400724 awakenDreams();
Jim Miller9a720f52012-05-30 03:19:43 -0700725 }
726 };
727
Jim Millere898ac52012-04-06 17:10:57 -0700728 View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
729 public boolean onTouch(View v, MotionEvent event) {
730 switch(event.getAction()) {
Jim Miller9a720f52012-05-30 03:19:43 -0700731 case MotionEvent.ACTION_DOWN:
Daniel Sandlerd5483c32012-10-19 16:44:15 -0400732 if (!shouldDisableNavbarGestures()) {
Jim Miller9a720f52012-05-30 03:19:43 -0700733 mHandler.removeCallbacks(mShowSearchPanel);
734 mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
735 }
736 break;
737
738 case MotionEvent.ACTION_UP:
739 case MotionEvent.ACTION_CANCEL:
740 mHandler.removeCallbacks(mShowSearchPanel);
Daniel Sandlera2fbe532012-08-10 01:19:03 -0400741 awakenDreams();
Jim Miller9a720f52012-05-30 03:19:43 -0700742 break;
743 }
744 return false;
Jim Millere898ac52012-04-06 17:10:57 -0700745 }
746 };
Daniel Sandler5c8da942011-06-28 00:29:04 -0400747
Daniel Sandlera2fbe532012-08-10 01:19:03 -0400748 private void awakenDreams() {
749 if (mDreamManager != null) {
750 try {
751 mDreamManager.awaken();
752 } catch (RemoteException e) {
753 // fine, stay asleep then
754 }
755 }
756 }
757
Michael Jurka412cba82011-10-17 09:05:00 -0700758 private void prepareNavigationBarView() {
759 mNavigationBarView.reorient();
760
761 mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
Michael Jurka80343f62012-10-18 13:13:46 +0200762 mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
Jim Miller998bb762012-05-21 13:37:27 -0700763 mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
Daniel Sandler207d5482012-11-06 16:23:43 -0500764 mNavigationBarView.getSearchLight().setOnTouchListener(mHomeSearchActionListener);
Jim Millere898ac52012-04-06 17:10:57 -0700765 updateSearchPanel();
Michael Jurka412cba82011-10-17 09:05:00 -0700766 }
767
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400768 // For small-screen devices (read: phones) that lack hardware navigation buttons
769 private void addNavigationBar() {
Daniel Sandler4a066c52012-04-20 14:49:13 -0400770 if (DEBUG) Slog.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
Daniel Sandler0129b312011-05-11 11:54:11 -0400771 if (mNavigationBarView == null) return;
Jim Miller17dfec72011-07-08 19:09:55 -0700772
Michael Jurka412cba82011-10-17 09:05:00 -0700773 prepareNavigationBarView();
Daniel Sandler5c8da942011-06-28 00:29:04 -0400774
Jeff Brown98365d72012-08-19 20:30:52 -0700775 mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400776 }
777
778 private void repositionNavigationBar() {
Daniel Sandler0129b312011-05-11 11:54:11 -0400779 if (mNavigationBarView == null) return;
Jim Miller17dfec72011-07-08 19:09:55 -0700780
Michael Jurka412cba82011-10-17 09:05:00 -0700781 prepareNavigationBarView();
Daniel Sandler5c8da942011-06-28 00:29:04 -0400782
Jeff Brown98365d72012-08-19 20:30:52 -0700783 mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams());
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400784 }
785
John Spurlock1bbd49d2012-10-19 11:09:32 -0400786 private void notifyNavigationBarScreenOn(boolean screenOn) {
787 if (mNavigationBarView == null) return;
788 mNavigationBarView.notifyScreenOn(screenOn);
789 }
790
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400791 private WindowManager.LayoutParams getNavigationBarLayoutParams() {
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400792 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
Dianne Hackborn1f903c32011-09-13 19:18:06 -0700793 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400794 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
795 0
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400796 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
797 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
Dianne Hackborndf89e652011-10-06 22:35:11 -0700798 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400799 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
Jim Millerd99e7fd2012-05-08 16:30:42 -0700800 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
Daniel Sandlera3884492011-08-16 15:55:44 -0400801 PixelFormat.OPAQUE);
Daniel Sandlerc638c1e2011-08-24 16:19:23 -0700802 // this will allow the navbar to run in an overlay on devices that support this
Jeff Brown98365d72012-08-19 20:30:52 -0700803 if (ActivityManager.isHighEndGfx()) {
Daniel Sandlerc638c1e2011-08-24 16:19:23 -0700804 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
805 }
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400806
807 lp.setTitle("NavigationBar");
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400808 lp.windowAnimations = 0;
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400809 return lp;
810 }
811
Joe Onoratodc100302011-01-11 17:07:41 -0800812 private void addIntruderView() {
Joe Onorato808182d2010-07-09 18:52:06 -0400813 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
814 ViewGroup.LayoutParams.MATCH_PARENT,
815 ViewGroup.LayoutParams.WRAP_CONTENT,
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400816 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar!
Joe Onorato808182d2010-07-09 18:52:06 -0400817 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
818 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
819 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
820 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
Jeff Brown46e75292010-11-10 16:53:45 -0800821 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
822 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
Joe Onorato808182d2010-07-09 18:52:06 -0400823 PixelFormat.TRANSLUCENT);
824 lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400825 //lp.y += height * 1.5; // FIXME
Joe Onorato808182d2010-07-09 18:52:06 -0400826 lp.setTitle("IntruderAlert");
Dianne Hackborn59aed382011-08-02 17:31:44 -0700827 lp.packageName = mContext.getPackageName();
828 lp.windowAnimations = R.style.Animation_StatusBar_IntruderAlert;
Joe Onorato808182d2010-07-09 18:52:06 -0400829
Jeff Brown98365d72012-08-19 20:30:52 -0700830 mWindowManager.addView(mIntruderAlertView, lp);
Joe Onorato808182d2010-07-09 18:52:06 -0400831 }
832
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800833 public void refreshAllStatusBarIcons() {
Fabrice Di Meglioc0cea0f2013-01-11 16:18:00 -0800834 refreshAllIconsForLayout(mStatusIcons);
835 refreshAllIconsForLayout(mNotificationIcons);
836 }
837
838 private void refreshAllIconsForLayout(LinearLayout ll) {
839 final int count = ll.getChildCount();
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800840 for (int n = 0; n < count; n++) {
Fabrice Di Meglioc0cea0f2013-01-11 16:18:00 -0800841 View child = ll.getChildAt(n);
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800842 if (child instanceof StatusBarIconView) {
843 ((StatusBarIconView) child).updateDrawable();
844 }
845 }
846 }
847
Joe Onorato808182d2010-07-09 18:52:06 -0400848 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
849 if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
850 + " icon=" + icon);
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700851 StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
Joe Onorato808182d2010-07-09 18:52:06 -0400852 view.set(icon);
853 mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
854 }
855
856 public void updateIcon(String slot, int index, int viewIndex,
857 StatusBarIcon old, StatusBarIcon icon) {
858 if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
859 + " old=" + old + " icon=" + icon);
860 StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
861 view.set(icon);
862 }
863
864 public void removeIcon(String slot, int index, int viewIndex) {
865 if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
866 mStatusIcons.removeViewAt(viewIndex);
867 }
868
869 public void addNotification(IBinder key, StatusBarNotification notification) {
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400870 if (DEBUG) Slog.d(TAG, "addNotification score=" + notification.getScore());
Joe Onorato808182d2010-07-09 18:52:06 -0400871 StatusBarIconView iconView = addNotificationViews(key, notification);
872 if (iconView == null) return;
873
874 boolean immersive = false;
875 try {
876 immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
Daniel Sandler8355e932011-08-11 00:27:45 -0400877 if (DEBUG) {
878 Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
879 }
Joe Onorato808182d2010-07-09 18:52:06 -0400880 } catch (RemoteException ex) {
881 }
Daniel Sandler6b318802012-04-13 14:05:19 -0400882
883 /*
884 * DISABLED due to missing API
Daniel Sandlerfc6fda32012-02-24 22:00:46 -0500885 if (ENABLE_INTRUDERS && (
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400886 // TODO(dsandler): Only if the screen is on
887 notification.notification.intruderView != null)) {
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500888 Slog.d(TAG, "Presenting high-priority notification");
889 // special new transient ticker mode
890 // 1. Populate mIntruderAlertView
Jim Millere898ac52012-04-06 17:10:57 -0700891
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400892 if (notification.notification.intruderView == null) {
893 Slog.e(TAG, notification.notification.toString() + " wanted to intrude but intruderView was null");
894 return;
895 }
Joe Onorato808182d2010-07-09 18:52:06 -0400896
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400897 // bind the click event to the content area
898 PendingIntent contentIntent = notification.notification.contentIntent;
899 final View.OnClickListener listener = (contentIntent != null)
900 ? new NotificationClicker(contentIntent,
901 notification.pkg, notification.tag, notification.id)
902 : null;
Joe Onorato808182d2010-07-09 18:52:06 -0400903
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400904 mIntruderAlertView.applyIntruderContent(notification.notification.intruderView, listener);
Joe Onorato808182d2010-07-09 18:52:06 -0400905
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400906 mCurrentlyIntrudingNotification = notification;
Jim Millere898ac52012-04-06 17:10:57 -0700907
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500908 // 2. Animate mIntruderAlertView in
909 mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
Joe Onorato808182d2010-07-09 18:52:06 -0400910
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500911 // 3. Set alarm to age the notification off (TODO)
912 mHandler.removeMessages(MSG_HIDE_INTRUDER);
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400913 if (INTRUDER_ALERT_DECAY_MS > 0) {
914 mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
915 }
Jim Millera073e572012-05-23 17:03:27 -0700916 } else
Daniel Sandler6b318802012-04-13 14:05:19 -0400917 */
Jim Millera073e572012-05-23 17:03:27 -0700918
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400919 if (notification.getNotification().fullScreenIntent != null) {
Daniel Sandlerc9ce0ab2012-09-04 13:27:09 -0400920 // Stop screensaver if the notification has a full-screen intent.
921 // (like an incoming phone call)
922 awakenDreams();
923
Joe Onorato808182d2010-07-09 18:52:06 -0400924 // not immersive & a full-screen alert should be shown
Dianne Hackborn7ff30112012-11-08 11:12:09 -0800925 if (DEBUG) Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
Joe Onorato808182d2010-07-09 18:52:06 -0400926 try {
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400927 notification.getNotification().fullScreenIntent.send();
Joe Onorato808182d2010-07-09 18:52:06 -0400928 } catch (PendingIntent.CanceledException e) {
929 }
930 } else {
931 // usual case: status bar visible & not immersive
932
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400933 // show the ticker if there isn't an intruder too
934 if (mCurrentlyIntrudingNotification == null) {
Chris Wren0c8275b2012-05-08 13:36:48 -0400935 tick(null, notification, true);
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400936 }
Joe Onorato808182d2010-07-09 18:52:06 -0400937 }
938
939 // Recalculate the position of the sliding windows and the titles.
940 setAreThereNotifications();
941 updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
942 }
943
Joe Onorato808182d2010-07-09 18:52:06 -0400944 public void removeNotification(IBinder key) {
Joe Onorato808182d2010-07-09 18:52:06 -0400945 StatusBarNotification old = removeNotificationViews(key);
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400946 if (SPEW) Slog.d(TAG, "removeNotification key=" + key + " old=" + old);
Joe Onorato808182d2010-07-09 18:52:06 -0400947
948 if (old != null) {
949 // Cancel the ticker if it's still running
950 mTicker.removeEntry(old);
951
952 // Recalculate the position of the sliding windows and the titles.
Joe Onorato808182d2010-07-09 18:52:06 -0400953 updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
Jim Millere898ac52012-04-06 17:10:57 -0700954
Daniel Sandler6b318802012-04-13 14:05:19 -0400955 if (ENABLE_INTRUDERS && old == mCurrentlyIntrudingNotification) {
Daniel Sandlerfa7887b2012-03-26 09:43:31 -0400956 mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
957 }
Daniel Sandler8cc36e52011-10-17 14:18:46 -0400958
Daniel Sandler37a38aa2013-02-13 17:15:57 -0500959 if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0) {
Daniel Sandler11cf1782012-09-27 14:03:08 -0400960 animateCollapsePanels();
Daniel Sandler8cc36e52011-10-17 14:18:46 -0400961 }
Joe Onorato808182d2010-07-09 18:52:06 -0400962 }
Daniel Sandler0761e4c2011-08-11 00:19:49 -0400963
964 setAreThereNotifications();
Joe Onorato808182d2010-07-09 18:52:06 -0400965 }
966
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700967 @Override
968 protected void refreshLayout(int layoutDirection) {
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700969 if (mNavigationBarView != null) {
970 mNavigationBarView.setLayoutDirection(layoutDirection);
971 }
972
973 if (mClearButton != null && mClearButton instanceof ImageView) {
974 // Force asset reloading
975 ((ImageView)mClearButton).setImageDrawable(null);
976 ((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear);
977 }
978
979 if (mSettingsButton != null) {
980 // Force asset reloading
981 mSettingsButton.setImageDrawable(null);
982 mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
983 }
984
985 if (mNotificationButton != null) {
986 // Force asset reloading
987 mNotificationButton.setImageDrawable(null);
988 mNotificationButton.setImageResource(R.drawable.ic_notifications);
989 }
Fabrice Di Meglio82fca5d2013-01-09 15:42:31 -0800990
991 refreshAllStatusBarIcons();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700992 }
993
John Spurlockd5ef5462012-06-13 11:19:51 -0400994 private void updateShowSearchHoldoff() {
995 mShowSearchHoldoff = mContext.getResources().getInteger(
996 R.integer.config_show_search_delay);
Michael Jurka3b1fc472011-06-13 10:54:40 -0700997 }
998
Daniel Sandler7c3e39d2011-07-29 16:30:49 -0400999 private void loadNotificationShade() {
Daniel Sandler26cda272012-05-22 15:44:08 -04001000 if (mPile == null) return;
1001
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04001002 int N = mNotificationData.size();
1003
1004 ArrayList<View> toShow = new ArrayList<View>();
1005
Daniel Sandler26cda272012-05-22 15:44:08 -04001006 final boolean provisioned = isDeviceProvisioned();
1007 // If the device hasn't been through Setup, we only show system notifications
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04001008 for (int i=0; i<N; i++) {
Daniel Sandler26cda272012-05-22 15:44:08 -04001009 Entry ent = mNotificationData.get(N-i-1);
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001010 if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
1011 if (!notificationIsForCurrentUser(ent.notification)) continue;
1012 toShow.add(ent.row);
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04001013 }
1014
1015 ArrayList<View> toRemove = new ArrayList<View>();
1016 for (int i=0; i<mPile.getChildCount(); i++) {
1017 View child = mPile.getChildAt(i);
1018 if (!toShow.contains(child)) {
1019 toRemove.add(child);
Joe Onorato808182d2010-07-09 18:52:06 -04001020 }
1021 }
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04001022
1023 for (View remove : toRemove) {
1024 mPile.removeView(remove);
1025 }
1026
1027 for (int i=0; i<toShow.size(); i++) {
1028 View v = toShow.get(i);
1029 if (v.getParent() == null) {
Daniel Sandler2561b0b2012-02-13 21:04:12 -05001030 mPile.addView(v, i);
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04001031 }
1032 }
Daniel Sandler26cda272012-05-22 15:44:08 -04001033
Daniel Sandler6e5fe432012-09-16 15:34:36 -04001034 if (mSettingsButton != null) {
1035 mSettingsButton.setEnabled(isDeviceProvisioned());
1036 }
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04001037 }
1038
Chris Wren0c8275b2012-05-08 13:36:48 -04001039 @Override
1040 protected void updateNotificationIcons() {
Daniel Sandler26cda272012-05-22 15:44:08 -04001041 if (mNotificationIcons == null) return;
1042
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04001043 loadNotificationShade();
1044
1045 final LinearLayout.LayoutParams params
1046 = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
1047
1048 int N = mNotificationData.size();
1049
1050 if (DEBUG) {
1051 Slog.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + mNotificationIcons);
1052 }
1053
1054 ArrayList<View> toShow = new ArrayList<View>();
1055
Daniel Sandler26cda272012-05-22 15:44:08 -04001056 final boolean provisioned = isDeviceProvisioned();
1057 // If the device hasn't been through Setup, we only show system notifications
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04001058 for (int i=0; i<N; i++) {
Daniel Sandler58b173b2012-05-03 11:25:29 -04001059 Entry ent = mNotificationData.get(N-i-1);
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001060 if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE)
Daniel Sandlerb9301c32012-08-14 15:08:24 -04001061 || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
1062 if (!notificationIsForCurrentUser(ent.notification)) continue;
1063 toShow.add(ent.icon);
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04001064 }
1065
1066 ArrayList<View> toRemove = new ArrayList<View>();
1067 for (int i=0; i<mNotificationIcons.getChildCount(); i++) {
1068 View child = mNotificationIcons.getChildAt(i);
1069 if (!toShow.contains(child)) {
1070 toRemove.add(child);
1071 }
1072 }
1073
1074 for (View remove : toRemove) {
1075 mNotificationIcons.removeView(remove);
1076 }
1077
1078 for (int i=0; i<toShow.size(); i++) {
1079 View v = toShow.get(i);
1080 if (v.getParent() == null) {
1081 mNotificationIcons.addView(v, i, params);
1082 }
1083 }
1084 }
1085
Daniel Sandlere5011a32012-06-11 16:07:52 -04001086 protected void updateCarrierLabelVisibility(boolean force) {
Daniel Sandlerbf526d12012-09-04 22:56:44 -04001087 if (!mShowCarrierInPanel) return;
Daniel Sandler3d32a242012-06-05 13:44:14 -04001088 // The idea here is to only show the carrier label when there is enough room to see it,
1089 // i.e. when there aren't enough notifications to fill the panel.
1090 if (DEBUG) {
1091 Slog.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d",
1092 mPile.getHeight(), mScrollView.getHeight(), mCarrierLabelHeight));
1093 }
Daniel Sandlerdd4ef492012-07-27 11:19:52 -04001094
1095 final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null;
1096 final boolean makeVisible =
1097 !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
Daniel Sandler101784e2012-10-15 13:39:38 -04001098 && mPile.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight)
1099 && mScrollView.getVisibility() == View.VISIBLE;
Daniel Sandler3d32a242012-06-05 13:44:14 -04001100
Daniel Sandlere5011a32012-06-11 16:07:52 -04001101 if (force || mCarrierLabelVisible != makeVisible) {
Daniel Sandler3d32a242012-06-05 13:44:14 -04001102 mCarrierLabelVisible = makeVisible;
1103 if (DEBUG) {
1104 Slog.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible"));
1105 }
1106 mCarrierLabel.animate().cancel();
1107 if (makeVisible) {
1108 mCarrierLabel.setVisibility(View.VISIBLE);
1109 }
1110 mCarrierLabel.animate()
1111 .alpha(makeVisible ? 1f : 0f)
1112 //.setStartDelay(makeVisible ? 500 : 0)
1113 //.setDuration(makeVisible ? 750 : 100)
1114 .setDuration(150)
1115 .setListener(makeVisible ? null : new AnimatorListenerAdapter() {
1116 @Override
1117 public void onAnimationEnd(Animator animation) {
1118 if (!mCarrierLabelVisible) { // race
1119 mCarrierLabel.setVisibility(View.INVISIBLE);
1120 mCarrierLabel.setAlpha(0f);
1121 }
1122 }
1123 })
1124 .start();
1125 }
1126 }
1127
Chris Wren0c8275b2012-05-08 13:36:48 -04001128 @Override
1129 protected void setAreThereNotifications() {
Daniel Sandler0761e4c2011-08-11 00:19:49 -04001130 final boolean any = mNotificationData.size() > 0;
Joe Onorato808182d2010-07-09 18:52:06 -04001131
Daniel Sandler0761e4c2011-08-11 00:19:49 -04001132 final boolean clearable = any && mNotificationData.hasClearableItems();
1133
1134 if (DEBUG) {
1135 Slog.d(TAG, "setAreThereNotifications: N=" + mNotificationData.size()
1136 + " any=" + any + " clearable=" + clearable);
1137 }
1138
Daniel Sandler6e2810b2012-10-17 09:40:09 -04001139 if (mHasFlipSettings
1140 && mFlipSettingsView != null
Daniel Sandlerf249efc2012-10-17 16:42:36 -04001141 && mFlipSettingsView.getVisibility() == View.VISIBLE
1142 && mScrollView.getVisibility() != View.VISIBLE) {
1143 // the flip settings panel is unequivocally showing; we should not be shown
Daniel Sandler6e2810b2012-10-17 09:40:09 -04001144 mClearButton.setVisibility(View.INVISIBLE);
1145 } else if (mClearButton.isShown()) {
Daniel Sandler0761e4c2011-08-11 00:19:49 -04001146 if (clearable != (mClearButton.getAlpha() == 1.0f)) {
Romain Guy8900e632012-05-25 12:08:39 -07001147 ObjectAnimator clearAnimation = ObjectAnimator.ofFloat(
1148 mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250);
1149 clearAnimation.addListener(new AnimatorListenerAdapter() {
1150 @Override
1151 public void onAnimationEnd(Animator animation) {
1152 if (mClearButton.getAlpha() <= 0.0f) {
1153 mClearButton.setVisibility(View.INVISIBLE);
1154 }
1155 }
1156
1157 @Override
1158 public void onAnimationStart(Animator animation) {
1159 if (mClearButton.getAlpha() <= 0.0f) {
1160 mClearButton.setVisibility(View.VISIBLE);
1161 }
1162 }
1163 });
1164 clearAnimation.start();
Daniel Sandler0761e4c2011-08-11 00:19:49 -04001165 }
1166 } else {
1167 mClearButton.setAlpha(clearable ? 1.0f : 0.0f);
Romain Guy8900e632012-05-25 12:08:39 -07001168 mClearButton.setVisibility(clearable ? View.VISIBLE : View.INVISIBLE);
Daniel Sandler0761e4c2011-08-11 00:19:49 -04001169 }
Daniel Sandler8ba33c92011-10-04 21:49:30 -04001170 mClearButton.setEnabled(clearable);
Romain Guy8900e632012-05-25 12:08:39 -07001171
Daniel Sandlerd7e96862012-04-26 01:10:29 -04001172 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
1173 final boolean showDot = (any&&!areLightsOn());
1174 if (showDot != (nlo.getAlpha() == 1.0f)) {
1175 if (showDot) {
1176 nlo.setAlpha(0f);
1177 nlo.setVisibility(View.VISIBLE);
1178 }
1179 nlo.animate()
1180 .alpha(showDot?1:0)
1181 .setDuration(showDot?750:250)
1182 .setInterpolator(new AccelerateInterpolator(2.0f))
1183 .setListener(showDot ? null : new AnimatorListenerAdapter() {
1184 @Override
1185 public void onAnimationEnd(Animator _a) {
1186 nlo.setVisibility(View.GONE);
1187 }
1188 })
1189 .start();
1190 }
Daniel Sandler3d32a242012-06-05 13:44:14 -04001191
Daniel Sandlere5011a32012-06-11 16:07:52 -04001192 updateCarrierLabelVisibility(false);
Joe Onorato808182d2010-07-09 18:52:06 -04001193 }
1194
Jeff Sharkeyf52c70b2011-08-30 22:05:47 -07001195 public void showClock(boolean show) {
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -05001196 if (mStatusBarView == null) return;
Jeff Sharkeyf52c70b2011-08-30 22:05:47 -07001197 View clock = mStatusBarView.findViewById(R.id.clock);
1198 if (clock != null) {
1199 clock.setVisibility(show ? View.VISIBLE : View.GONE);
1200 }
1201 }
Joe Onorato808182d2010-07-09 18:52:06 -04001202
1203 /**
1204 * State is one or more of the DISABLE constants from StatusBarManager.
1205 */
1206 public void disable(int state) {
1207 final int old = mDisabled;
1208 final int diff = state ^ old;
1209 mDisabled = state;
1210
Daniel Sandlere21f2882011-08-18 10:14:59 -04001211 if (DEBUG) {
1212 Slog.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)",
1213 old, state, diff));
1214 }
1215
Daniel Sandler6da2b762011-09-14 16:04:59 -04001216 StringBuilder flagdbg = new StringBuilder();
1217 flagdbg.append("disable: < ");
1218 flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
1219 flagdbg.append(((diff & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
1220 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
1221 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
1222 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
1223 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
1224 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) ? "TICKER" : "ticker");
1225 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) ? "* " : " ");
1226 flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
1227 flagdbg.append(((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
Daniel Sandler6da2b762011-09-14 16:04:59 -04001228 flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
1229 flagdbg.append(((diff & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
Daniel Sandlerdba93562011-10-06 16:39:58 -04001230 flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
1231 flagdbg.append(((diff & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
1232 flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
1233 flagdbg.append(((diff & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
Daniel Sandler6da2b762011-09-14 16:04:59 -04001234 flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
1235 flagdbg.append(((diff & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
Daniel Sandlerd5483c32012-10-19 16:44:15 -04001236 flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
1237 flagdbg.append(((diff & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
Daniel Sandler6da2b762011-09-14 16:04:59 -04001238 flagdbg.append(">");
1239 Slog.d(TAG, flagdbg.toString());
Jim Millera073e572012-05-23 17:03:27 -07001240
Daniel Sandler8e18dc72012-05-17 00:44:59 -04001241 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
Daniel Sandler173bae22012-09-25 14:37:42 -04001242 mSystemIconArea.animate().cancel();
Daniel Sandler8e18dc72012-05-17 00:44:59 -04001243 if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
Daniel Sandler173bae22012-09-25 14:37:42 -04001244 mSystemIconArea.animate()
Daniel Sandler67e7d902012-06-06 16:32:21 -04001245 .alpha(0f)
1246 .translationY(mNaturalBarHeight*0.5f)
Daniel Sandler67e7d902012-06-06 16:32:21 -04001247 .setDuration(175)
1248 .setInterpolator(new DecelerateInterpolator(1.5f))
1249 .setListener(mMakeIconsInvisible)
1250 .start();
Daniel Sandler8e18dc72012-05-17 00:44:59 -04001251 } else {
Daniel Sandler173bae22012-09-25 14:37:42 -04001252 mSystemIconArea.setVisibility(View.VISIBLE);
1253 mSystemIconArea.animate()
Daniel Sandler67e7d902012-06-06 16:32:21 -04001254 .alpha(1f)
1255 .translationY(0)
1256 .setStartDelay(0)
1257 .setInterpolator(new DecelerateInterpolator(1.5f))
1258 .setDuration(175)
1259 .start();
Daniel Sandler8e18dc72012-05-17 00:44:59 -04001260 }
1261 }
Daniel Sandler6da2b762011-09-14 16:04:59 -04001262
Jeff Sharkeyf52c70b2011-08-30 22:05:47 -07001263 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
1264 boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
1265 showClock(show);
1266 }
Joe Onorato808182d2010-07-09 18:52:06 -04001267 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
1268 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
Daniel Sandler11cf1782012-09-27 14:03:08 -04001269 animateCollapsePanels();
Joe Onorato808182d2010-07-09 18:52:06 -04001270 }
1271 }
Daniel Sandlere21f2882011-08-18 10:14:59 -04001272
Jim Miller5e6af442011-12-02 18:24:26 -08001273 if ((diff & (StatusBarManager.DISABLE_HOME
1274 | StatusBarManager.DISABLE_RECENT
Daniel Sandlerd5483c32012-10-19 16:44:15 -04001275 | StatusBarManager.DISABLE_BACK
1276 | StatusBarManager.DISABLE_SEARCH)) != 0) {
Daniel Sandlerdba93562011-10-06 16:39:58 -04001277 // the nav bar will take care of these
Daniel Sandlerd9283b902011-09-14 21:42:00 -04001278 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state);
Daniel Sandler6da2b762011-09-14 16:04:59 -04001279
Daniel Sandlerdba93562011-10-06 16:39:58 -04001280 if ((state & StatusBarManager.DISABLE_RECENT) != 0) {
Daniel Sandler6da2b762011-09-14 16:04:59 -04001281 // close recents if it's visible
1282 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
1283 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
1284 }
Daniel Sandlere21f2882011-08-18 10:14:59 -04001285 }
1286
Joe Onorato808182d2010-07-09 18:52:06 -04001287 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
1288 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
Joe Onorato808182d2010-07-09 18:52:06 -04001289 if (mTicking) {
Daniel Sandlerf59a90c2012-09-28 15:33:14 -04001290 haltTicker();
Joe Onorato808182d2010-07-09 18:52:06 -04001291 }
Daniel Sandler173bae22012-09-25 14:37:42 -04001292
1293 mNotificationIcons.animate()
1294 .alpha(0f)
1295 .translationY(mNaturalBarHeight*0.5f)
1296 .setDuration(175)
1297 .setInterpolator(new DecelerateInterpolator(1.5f))
1298 .setListener(mMakeIconsInvisible)
1299 .start();
Joe Onorato808182d2010-07-09 18:52:06 -04001300 } else {
Daniel Sandler173bae22012-09-25 14:37:42 -04001301 mNotificationIcons.setVisibility(View.VISIBLE);
1302 mNotificationIcons.animate()
1303 .alpha(1f)
1304 .translationY(0)
1305 .setStartDelay(0)
1306 .setInterpolator(new DecelerateInterpolator(1.5f))
1307 .setDuration(175)
1308 .start();
Joe Onorato808182d2010-07-09 18:52:06 -04001309 }
1310 } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
1311 if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
Daniel Sandlerf59a90c2012-09-28 15:33:14 -04001312 haltTicker();
Joe Onorato808182d2010-07-09 18:52:06 -04001313 }
1314 }
1315 }
1316
Michael Jurka7f2668c2012-03-27 07:49:52 -07001317 @Override
Michael Jurkaecc395a2012-03-30 05:31:46 -07001318 protected BaseStatusBar.H createHandler() {
Michael Jurka7f2668c2012-03-27 07:49:52 -07001319 return new PhoneStatusBar.H();
1320 }
1321
Joe Onorato808182d2010-07-09 18:52:06 -04001322 /**
1323 * All changes to the status bar and notifications funnel through here and are batched.
1324 */
Michael Jurka7f2668c2012-03-27 07:49:52 -07001325 private class H extends BaseStatusBar.H {
Joe Onorato808182d2010-07-09 18:52:06 -04001326 public void handleMessage(Message m) {
Michael Jurka7f2668c2012-03-27 07:49:52 -07001327 super.handleMessage(m);
Joe Onorato808182d2010-07-09 18:52:06 -04001328 switch (m.what) {
Daniel Sandler8ba33c92011-10-04 21:49:30 -04001329 case MSG_OPEN_NOTIFICATION_PANEL:
Daniel Sandler11cf1782012-09-27 14:03:08 -04001330 animateExpandNotificationsPanel();
Daniel Sandler8ba33c92011-10-04 21:49:30 -04001331 break;
Daniel Sandler11cf1782012-09-27 14:03:08 -04001332 case MSG_OPEN_SETTINGS_PANEL:
1333 animateExpandSettingsPanel();
1334 break;
1335 case MSG_CLOSE_PANELS:
1336 animateCollapsePanels();
Daniel Sandler8ba33c92011-10-04 21:49:30 -04001337 break;
Joe Onorato808182d2010-07-09 18:52:06 -04001338 case MSG_SHOW_INTRUDER:
1339 setIntruderAlertVisibility(true);
1340 break;
1341 case MSG_HIDE_INTRUDER:
1342 setIntruderAlertVisibility(false);
Daniel Sandlerfa7887b2012-03-26 09:43:31 -04001343 mCurrentlyIntrudingNotification = null;
Joe Onorato808182d2010-07-09 18:52:06 -04001344 break;
1345 }
1346 }
1347 }
1348
Daniel Sandler040c2e42012-10-17 00:56:33 -04001349 public Handler getHandler() {
1350 return mHandler;
1351 }
1352
Joe Onorato808182d2010-07-09 18:52:06 -04001353 View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
1354 public void onFocusChange(View v, boolean hasFocus) {
1355 // Because 'v' is a ViewGroup, all its children will be (un)selected
1356 // too, which allows marqueeing to work.
1357 v.setSelected(hasFocus);
1358 }
1359 };
1360
Daniel Sandler08d05e32012-08-08 16:39:54 -04001361 void makeExpandedVisible(boolean revealAfterDraw) {
Joe Onorato808182d2010-07-09 18:52:06 -04001362 if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
1363 if (mExpandedVisible) {
1364 return;
1365 }
Jim Millera073e572012-05-23 17:03:27 -07001366
Joe Onorato808182d2010-07-09 18:52:06 -04001367 mExpandedVisible = true;
Daniel Sandlere5011a32012-06-11 16:07:52 -04001368 mPile.setLayoutTransitionsEnabled(true);
John Spurlockd5ef5462012-06-13 11:19:51 -04001369 if (mNavigationBarView != null)
1370 mNavigationBarView.setSlippery(true);
Joe Onorato808182d2010-07-09 18:52:06 -04001371
Daniel Sandlere5011a32012-06-11 16:07:52 -04001372 updateCarrierLabelVisibility(true);
Daniel Sandler3d32a242012-06-05 13:44:14 -04001373
Joe Onorato808182d2010-07-09 18:52:06 -04001374 updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
Daniel Sandlera310af82012-04-24 01:20:13 -04001375
1376 // Expand the window to encompass the full screen in anticipation of the drag.
1377 // This is only possible to do atomically because the status bar is at the top of the screen!
1378 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
Daniel Sandler4391b0b2012-05-10 13:15:26 -04001379 lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
1380 lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
Daniel Sandler21b274e2012-05-02 15:07:51 -04001381 lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
Jeff Brown98365d72012-08-19 20:30:52 -07001382 mWindowManager.updateViewLayout(mStatusBarWindow, lp);
Daniel Sandlera310af82012-04-24 01:20:13 -04001383
John Spurlock804df702012-06-01 15:34:27 -04001384 // Updating the window layout will force an expensive traversal/redraw.
1385 // Kick off the reveal animation after this is complete to avoid animation latency.
1386 if (revealAfterDraw) {
Daniel Sandler08d05e32012-08-08 16:39:54 -04001387// mHandler.post(mStartRevealAnimation);
John Spurlock804df702012-06-01 15:34:27 -04001388 }
1389
Daniel Sandlera310af82012-04-24 01:20:13 -04001390 visibilityChanged(true);
Joe Onorato808182d2010-07-09 18:52:06 -04001391 }
1392
Daniel Sandler11cf1782012-09-27 14:03:08 -04001393 public void animateCollapsePanels() {
1394 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
Michael Jurka3b1fc472011-06-13 10:54:40 -07001395 }
1396
Daniel Sandler11cf1782012-09-27 14:03:08 -04001397 public void animateCollapsePanels(int flags) {
Joe Onorato808182d2010-07-09 18:52:06 -04001398 if (SPEW) {
Daniel Sandler198a0302012-08-17 16:04:31 -04001399 Slog.d(TAG, "animateCollapse():"
Joe Onorato808182d2010-07-09 18:52:06 -04001400 + " mExpandedVisible=" + mExpandedVisible
Jim Miller9a720f52012-05-30 03:19:43 -07001401 + " flags=" + flags);
Joe Onorato808182d2010-07-09 18:52:06 -04001402 }
1403
Jim Miller9a720f52012-05-30 03:19:43 -07001404 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
Michael Jurka3b1fc472011-06-13 10:54:40 -07001405 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
1406 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
1407 }
Jim Miller9a720f52012-05-30 03:19:43 -07001408
1409 if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
1410 mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
1411 mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
1412 }
Michael Jurka3b1fc472011-06-13 10:54:40 -07001413
Daniel Sandlerac47ff72012-10-23 10:41:44 -04001414 mStatusBarWindow.cancelExpandHelper();
Daniel Sandler08d05e32012-08-08 16:39:54 -04001415 mStatusBarView.collapseAllPanels(true);
Joe Onorato808182d2010-07-09 18:52:06 -04001416 }
1417
Daniel Sandler101784e2012-10-15 13:39:38 -04001418 public ViewPropertyAnimator setVisibilityWhenDone(
1419 final ViewPropertyAnimator a, final View v, final int vis) {
1420 a.setListener(new AnimatorListenerAdapter() {
1421 @Override
1422 public void onAnimationEnd(Animator animation) {
1423 v.setVisibility(vis);
1424 a.setListener(null); // oneshot
1425 }
1426 });
1427 return a;
1428 }
1429
1430 public Animator setVisibilityWhenDone(
1431 final Animator a, final View v, final int vis) {
1432 a.addListener(new AnimatorListenerAdapter() {
1433 @Override
1434 public void onAnimationEnd(Animator animation) {
1435 v.setVisibility(vis);
1436 }
1437 });
1438 return a;
1439 }
1440
1441 public Animator interpolator(TimeInterpolator ti, Animator a) {
1442 a.setInterpolator(ti);
1443 return a;
1444 }
1445
1446 public Animator startDelay(int d, Animator a) {
1447 a.setStartDelay(d);
1448 return a;
1449 }
1450
1451 public Animator start(Animator a) {
1452 a.start();
1453 return a;
1454 }
1455
1456 final TimeInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
1457 final TimeInterpolator mDecelerateInterpolator = new DecelerateInterpolator();
1458 final int FLIP_DURATION_OUT = 125;
1459 final int FLIP_DURATION_IN = 225;
1460 final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT);
1461
1462 Animator mScrollViewAnim, mFlipSettingsViewAnim, mNotificationButtonAnim,
1463 mSettingsButtonAnim, mClearButtonAnim;
1464
Daniel Sandler08d05e32012-08-08 16:39:54 -04001465 @Override
Daniel Sandler11cf1782012-09-27 14:03:08 -04001466 public void animateExpandNotificationsPanel() {
Daniel Sandlere7237fc2012-08-14 16:08:27 -04001467 if (SPEW) Slog.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
Joe Onorato808182d2010-07-09 18:52:06 -04001468 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
1469 return ;
1470 }
Joe Onorato808182d2010-07-09 18:52:06 -04001471
Daniel Sandler08d05e32012-08-08 16:39:54 -04001472 mNotificationPanel.expand();
Daniel Sandler040c2e42012-10-17 00:56:33 -04001473 if (mHasFlipSettings && mScrollView.getVisibility() != View.VISIBLE) {
1474 flipToNotifications();
Daniel Sandler101784e2012-10-15 13:39:38 -04001475 }
Joe Onorato808182d2010-07-09 18:52:06 -04001476
1477 if (false) postStartTracing();
1478 }
1479
Daniel Sandler040c2e42012-10-17 00:56:33 -04001480 public void flipToNotifications() {
1481 if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
1482 if (mScrollViewAnim != null) mScrollViewAnim.cancel();
1483 if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
1484 if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
1485 if (mClearButtonAnim != null) mClearButtonAnim.cancel();
1486
1487 mScrollView.setVisibility(View.VISIBLE);
1488 mScrollViewAnim = start(
1489 startDelay(FLIP_DURATION_OUT,
1490 interpolator(mDecelerateInterpolator,
1491 ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 0f, 1f)
1492 .setDuration(FLIP_DURATION_IN)
1493 )));
1494 mFlipSettingsViewAnim = start(
1495 setVisibilityWhenDone(
1496 interpolator(mAccelerateInterpolator,
1497 ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 1f, 0f)
1498 )
1499 .setDuration(FLIP_DURATION_OUT),
1500 mFlipSettingsView, View.INVISIBLE));
1501 mNotificationButtonAnim = start(
1502 setVisibilityWhenDone(
1503 ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
1504 .setDuration(FLIP_DURATION),
1505 mNotificationButton, View.INVISIBLE));
1506 mSettingsButton.setVisibility(View.VISIBLE);
1507 mSettingsButtonAnim = start(
1508 ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
1509 .setDuration(FLIP_DURATION));
1510 mClearButton.setVisibility(View.VISIBLE);
1511 mClearButton.setAlpha(0f);
1512 setAreThereNotifications(); // this will show/hide the button as necessary
1513 mNotificationPanel.postDelayed(new Runnable() {
1514 public void run() {
1515 updateCarrierLabelVisibility(false);
1516 }
1517 }, FLIP_DURATION - 150);
1518 }
1519
Svetoslav Ganove20a1772012-09-25 16:07:46 -07001520 @Override
Daniel Sandler11cf1782012-09-27 14:03:08 -04001521 public void animateExpandSettingsPanel() {
Svetoslav Ganove20a1772012-09-25 16:07:46 -07001522 if (SPEW) Slog.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
1523 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
1524 return;
1525 }
1526
Daniel Sandlera8ef3b02012-11-29 15:52:39 -05001527 // Settings are not available in setup
1528 if (!mUserSetup) return;
1529
Daniel Sandler101784e2012-10-15 13:39:38 -04001530 if (mHasFlipSettings) {
1531 mNotificationPanel.expand();
1532 if (mFlipSettingsView.getVisibility() != View.VISIBLE) {
Daniel Sandler040c2e42012-10-17 00:56:33 -04001533 flipToSettings();
Daniel Sandler101784e2012-10-15 13:39:38 -04001534 }
1535 } else if (mSettingsPanel != null) {
1536 mSettingsPanel.expand();
1537 }
Svetoslav Ganove20a1772012-09-25 16:07:46 -07001538
1539 if (false) postStartTracing();
1540 }
1541
Daniel Sandler040c2e42012-10-17 00:56:33 -04001542 public void switchToSettings() {
Daniel Sandlera8ef3b02012-11-29 15:52:39 -05001543 // Settings are not available in setup
1544 if (!mUserSetup) return;
1545
Daniel Sandler040c2e42012-10-17 00:56:33 -04001546 mFlipSettingsView.setScaleX(1f);
1547 mFlipSettingsView.setVisibility(View.VISIBLE);
1548 mSettingsButton.setVisibility(View.GONE);
1549 mScrollView.setVisibility(View.GONE);
Daniel Sandler720a34d2012-10-18 11:44:04 -04001550 mScrollView.setScaleX(0f);
Daniel Sandler040c2e42012-10-17 00:56:33 -04001551 mNotificationButton.setVisibility(View.VISIBLE);
1552 mNotificationButton.setAlpha(1f);
1553 mClearButton.setVisibility(View.GONE);
1554 }
1555
1556 public void flipToSettings() {
Daniel Sandlera8ef3b02012-11-29 15:52:39 -05001557 // Settings are not available in setup
1558 if (!mUserSetup) return;
1559
Daniel Sandler040c2e42012-10-17 00:56:33 -04001560 if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
1561 if (mScrollViewAnim != null) mScrollViewAnim.cancel();
1562 if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
1563 if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
1564 if (mClearButtonAnim != null) mClearButtonAnim.cancel();
1565
1566 mFlipSettingsView.setVisibility(View.VISIBLE);
1567 mFlipSettingsView.setScaleX(0f);
1568 mFlipSettingsViewAnim = start(
1569 startDelay(FLIP_DURATION_OUT,
1570 interpolator(mDecelerateInterpolator,
1571 ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 0f, 1f)
1572 .setDuration(FLIP_DURATION_IN)
1573 )));
1574 mScrollViewAnim = start(
1575 setVisibilityWhenDone(
1576 interpolator(mAccelerateInterpolator,
1577 ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 1f, 0f)
1578 )
1579 .setDuration(FLIP_DURATION_OUT),
1580 mScrollView, View.INVISIBLE));
1581 mSettingsButtonAnim = start(
1582 setVisibilityWhenDone(
1583 ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
1584 .setDuration(FLIP_DURATION),
1585 mScrollView, View.INVISIBLE));
1586 mNotificationButton.setVisibility(View.VISIBLE);
1587 mNotificationButtonAnim = start(
1588 ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
1589 .setDuration(FLIP_DURATION));
1590 mClearButtonAnim = start(
1591 setVisibilityWhenDone(
1592 ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
1593 .setDuration(FLIP_DURATION),
1594 mClearButton, View.INVISIBLE));
1595 mNotificationPanel.postDelayed(new Runnable() {
1596 public void run() {
1597 updateCarrierLabelVisibility(false);
1598 }
1599 }, FLIP_DURATION - 150);
1600 }
1601
1602 public void flipPanels() {
1603 if (mHasFlipSettings) {
1604 if (mFlipSettingsView.getVisibility() != View.VISIBLE) {
1605 flipToSettings();
1606 } else {
1607 flipToNotifications();
1608 }
1609 }
1610 }
1611
Svetoslav Ganove20a1772012-09-25 16:07:46 -07001612 public void animateCollapseQuickSettings() {
1613 mStatusBarView.collapseAllPanels(true);
1614 }
1615
Daniel Sandler6e2810b2012-10-17 09:40:09 -04001616 void makeExpandedInvisibleSoon() {
1617 mHandler.postDelayed(new Runnable() { public void run() { makeExpandedInvisible(); }}, 50);
1618 }
1619
Daniel Sandler08d05e32012-08-08 16:39:54 -04001620 void makeExpandedInvisible() {
Daniel Sandlere7237fc2012-08-14 16:08:27 -04001621 if (SPEW) Slog.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
Joe Onorato808182d2010-07-09 18:52:06 -04001622 + " mExpandedVisible=" + mExpandedVisible);
1623
1624 if (!mExpandedVisible) {
1625 return;
1626 }
Daniel Sandlered930e52012-07-03 14:31:22 -04001627
Daniel Sandlerc38bbc32012-10-05 12:21:38 -04001628 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
1629 mStatusBarView.collapseAllPanels(/*animate=*/ false);
Daniel Sandlered930e52012-07-03 14:31:22 -04001630
Daniel Sandler040c2e42012-10-17 00:56:33 -04001631 if (mHasFlipSettings) {
1632 // reset things to their proper state
Daniel Sandler50bc4f52012-10-22 14:47:55 -04001633 if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
1634 if (mScrollViewAnim != null) mScrollViewAnim.cancel();
1635 if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
1636 if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
1637 if (mClearButtonAnim != null) mClearButtonAnim.cancel();
1638
Daniel Sandler040c2e42012-10-17 00:56:33 -04001639 mScrollView.setScaleX(1f);
1640 mScrollView.setVisibility(View.VISIBLE);
1641 mSettingsButton.setAlpha(1f);
1642 mSettingsButton.setVisibility(View.VISIBLE);
1643 mNotificationPanel.setVisibility(View.GONE);
1644 mFlipSettingsView.setVisibility(View.GONE);
1645 mNotificationButton.setVisibility(View.GONE);
1646 setAreThereNotifications(); // show the clear button
1647 }
1648
Joe Onorato808182d2010-07-09 18:52:06 -04001649 mExpandedVisible = false;
Daniel Sandlere5011a32012-06-11 16:07:52 -04001650 mPile.setLayoutTransitionsEnabled(false);
John Spurlockd5ef5462012-06-13 11:19:51 -04001651 if (mNavigationBarView != null)
1652 mNavigationBarView.setSlippery(false);
Joe Onorato808182d2010-07-09 18:52:06 -04001653 visibilityChanged(false);
Daniel Sandlera310af82012-04-24 01:20:13 -04001654
1655 // Shrink the window to the size of the status bar only
1656 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
1657 lp.height = getStatusBarHeight();
Daniel Sandler4391b0b2012-05-10 13:15:26 -04001658 lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
1659 lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
Jeff Brown98365d72012-08-19 20:30:52 -07001660 mWindowManager.updateViewLayout(mStatusBarWindow, lp);
Joe Onorato808182d2010-07-09 18:52:06 -04001661
1662 if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
1663 setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
1664 }
Joe Onorato808182d2010-07-09 18:52:06 -04001665
Daniel Sandler469e96e2012-05-04 15:56:19 -04001666 // Close any "App info" popups that might have snuck on-screen
1667 dismissPopups();
1668
Chet Haase2f2022a2011-10-11 06:41:59 -07001669 if (mPostCollapseCleanup != null) {
1670 mPostCollapseCleanup.run();
1671 mPostCollapseCleanup = null;
1672 }
Joe Onorato808182d2010-07-09 18:52:06 -04001673 }
1674
Romain Guy54ab3472012-06-14 12:52:53 -07001675 /**
1676 * Enables or disables layers on the children of the notifications pile.
1677 *
1678 * When layers are enabled, this method attempts to enable layers for the minimal
1679 * number of children. Only children visible when the notification area is fully
1680 * expanded will receive a layer. The technique used in this method might cause
1681 * more children than necessary to get a layer (at most one extra child with the
1682 * current UI.)
1683 *
1684 * @param layerType {@link View#LAYER_TYPE_NONE} or {@link View#LAYER_TYPE_HARDWARE}
1685 */
1686 private void setPileLayers(int layerType) {
1687 final int count = mPile.getChildCount();
1688
1689 switch (layerType) {
1690 case View.LAYER_TYPE_NONE:
1691 for (int i = 0; i < count; i++) {
1692 mPile.getChildAt(i).setLayerType(layerType, null);
1693 }
1694 break;
1695 case View.LAYER_TYPE_HARDWARE:
1696 final int[] location = new int[2];
1697 mNotificationPanel.getLocationInWindow(location);
1698
1699 final int left = location[0];
1700 final int top = location[1];
1701 final int right = left + mNotificationPanel.getWidth();
1702 final int bottom = top + getExpandedViewMaxHeight();
1703
1704 final Rect childBounds = new Rect();
1705
1706 for (int i = 0; i < count; i++) {
1707 final View view = mPile.getChildAt(i);
1708 view.getLocationInWindow(location);
1709
1710 childBounds.set(location[0], location[1],
1711 location[0] + view.getWidth(), location[1] + view.getHeight());
1712
1713 if (childBounds.intersects(left, top, right, bottom)) {
1714 view.setLayerType(layerType, null);
1715 }
1716 }
1717
1718 break;
1719 }
1720 }
1721
Daniel Sandlerb17a7262012-10-05 14:32:50 -04001722 public boolean isClinging() {
1723 return mCling != null && mCling.getVisibility() == View.VISIBLE;
1724 }
1725
1726 public void hideCling() {
1727 if (isClinging()) {
1728 mCling.animate().alpha(0f).setDuration(250).start();
1729 mCling.setVisibility(View.GONE);
1730 mSuppressStatusBarDrags = false;
1731 }
1732 }
1733
1734 public void showCling() {
Daniel Sandler118f4842012-10-07 20:38:39 -04001735 // lazily inflate this to accommodate orientation change
1736 final ViewStub stub = (ViewStub) mStatusBarWindow.findViewById(R.id.status_bar_cling_stub);
1737 if (stub == null) {
1738 mClingShown = true;
1739 return; // no clings on this device
1740 }
1741
Daniel Sandlerb17a7262012-10-05 14:32:50 -04001742 mSuppressStatusBarDrags = true;
1743
1744 mHandler.postDelayed(new Runnable() {
1745 @Override
1746 public void run() {
Daniel Sandlerb17a7262012-10-05 14:32:50 -04001747 mCling = (ViewGroup) stub.inflate();
Daniel Sandler118f4842012-10-07 20:38:39 -04001748
Daniel Sandlerb17a7262012-10-05 14:32:50 -04001749 mCling.setOnTouchListener(new View.OnTouchListener() {
1750 @Override
1751 public boolean onTouch(View v, MotionEvent event) {
1752 return true; // e eats everything
1753 }});
1754 mCling.findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
1755 @Override
1756 public void onClick(View v) {
1757 hideCling();
1758 }});
1759
1760 mCling.setAlpha(0f);
1761 mCling.setVisibility(View.VISIBLE);
1762 mCling.animate().alpha(1f);
1763
1764 mClingShown = true;
1765 SharedPreferences.Editor editor = Prefs.edit(mContext);
1766 editor.putBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, true);
1767 editor.apply();
1768
1769 makeExpandedVisible(true); // enforce visibility in case the shade is still animating closed
1770 animateExpandNotificationsPanel();
1771
1772 mSuppressStatusBarDrags = false;
1773 }
1774 }, 500);
1775
1776 animateExpandNotificationsPanel();
1777 }
1778
1779 public boolean interceptTouchEvent(MotionEvent event) {
Chris Wren64161cc2012-12-17 16:49:30 -05001780 if (DEBUG_GESTURES) {
1781 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
1782 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
1783 event.getActionMasked(), (int) event.getX(), (int) event.getY(), mDisabled);
1784 }
1785
1786 }
1787
Joe Onorato808182d2010-07-09 18:52:06 -04001788 if (SPEW) {
1789 Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
John Spurlock804df702012-06-01 15:34:27 -04001790 + mDisabled + " mTracking=" + mTracking);
Daniel Sandler96e61c3c82011-08-04 22:49:06 -04001791 } else if (CHATTY) {
Daniel Sandlerfe172cc2011-09-12 13:47:25 -04001792 if (event.getAction() != MotionEvent.ACTION_MOVE) {
Daniel Sandler96e61c3c82011-08-04 22:49:06 -04001793 Slog.d(TAG, String.format(
Daniel Sandlerfe172cc2011-09-12 13:47:25 -04001794 "panel: %s at (%f, %f) mDisabled=0x%08x",
1795 MotionEvent.actionToString(event.getAction()),
Daniel Sandler96e61c3c82011-08-04 22:49:06 -04001796 event.getRawX(), event.getRawY(), mDisabled));
1797 }
Joe Onorato808182d2010-07-09 18:52:06 -04001798 }
1799
Daniel Sandler151f00d2012-10-02 22:33:08 -04001800 if (DEBUG_GESTURES) {
1801 mGestureRec.add(event);
1802 }
Daniel Sandler33805342012-07-23 15:45:12 -04001803
Daniel Sandlerb17a7262012-10-05 14:32:50 -04001804 // Cling (first-run help) handling.
1805 // The cling is supposed to show the first time you drag, or even tap, the status bar.
1806 // It should show the notification panel, then fade in after half a second, giving you
1807 // an explanation of what just happened, as well as teach you how to access quick
1808 // settings (another drag). The user can dismiss the cling by clicking OK or by
1809 // dragging quick settings into view.
1810 final int act = event.getActionMasked();
1811 if (mSuppressStatusBarDrags) {
1812 return true;
1813 } else if (act == MotionEvent.ACTION_UP && !mClingShown) {
1814 showCling();
1815 } else {
1816 hideCling();
1817 }
1818
Joe Onorato808182d2010-07-09 18:52:06 -04001819 return false;
1820 }
1821
Daniel Sandler08d05e32012-08-08 16:39:54 -04001822 public GestureRecorder getGestureRecorder() {
1823 return mGestureRec;
Jeff Brown911fe302011-09-12 14:21:17 -07001824 }
1825
Daniel Sandler60ee2562011-07-22 12:34:33 -04001826 @Override // CommandQueue
Daniel Sandler328310c2011-09-23 15:56:52 -04001827 public void setNavigationIconHints(int hints) {
1828 if (hints == mNavigationIconHints) return;
1829
1830 mNavigationIconHints = hints;
1831
1832 if (mNavigationBarView != null) {
1833 mNavigationBarView.setNavigationIconHints(hints);
1834 }
1835 }
1836
1837 @Override // CommandQueue
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001838 public void setSystemUiVisibility(int vis, int mask) {
1839 final int oldVal = mSystemUiVisibility;
1840 final int newVal = (oldVal&~mask) | (vis&mask);
1841 final int diff = newVal ^ oldVal;
Daniel Sandlere137a1e2011-08-17 16:47:19 -04001842
1843 if (diff != 0) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001844 mSystemUiVisibility = newVal;
Daniel Sandler60ee2562011-07-22 12:34:33 -04001845
Daniel Sandlere137a1e2011-08-17 16:47:19 -04001846 if (0 != (diff & View.SYSTEM_UI_FLAG_LOW_PROFILE)) {
1847 final boolean lightsOut = (0 != (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE));
1848 if (lightsOut) {
Daniel Sandler11cf1782012-09-27 14:03:08 -04001849 animateCollapsePanels();
Daniel Sandlerd7e96862012-04-26 01:10:29 -04001850 if (mTicking) {
Daniel Sandlerf59a90c2012-09-28 15:33:14 -04001851 haltTicker();
Daniel Sandlerd7e96862012-04-26 01:10:29 -04001852 }
Daniel Sandlere137a1e2011-08-17 16:47:19 -04001853 }
Jim Millera073e572012-05-23 17:03:27 -07001854
Daniel Sandler69314e72011-08-20 00:31:08 -04001855 if (mNavigationBarView != null) {
1856 mNavigationBarView.setLowProfile(lightsOut);
1857 }
Jim Millera073e572012-05-23 17:03:27 -07001858
Daniel Sandlerd7e96862012-04-26 01:10:29 -04001859 setStatusBarLowProfile(lightsOut);
Daniel Sandler60ee2562011-07-22 12:34:33 -04001860 }
1861
1862 notifyUiVisibilityChanged();
Joe Onorato93056472010-09-10 10:30:46 -04001863 }
Daniel Sandler1d4d30a2011-04-28 12:35:29 -04001864 }
1865
Daniel Sandlerd7e96862012-04-26 01:10:29 -04001866 private void setStatusBarLowProfile(boolean lightsOut) {
1867 if (mLightsOutAnimation == null) {
Daniel Sandler825b3302012-10-01 15:22:36 -04001868 final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area);
1869 final View systemIcons = mStatusBarView.findViewById(R.id.statusIcons);
1870 final View signal = mStatusBarView.findViewById(R.id.signal_cluster);
1871 final View battery = mStatusBarView.findViewById(R.id.battery);
1872 final View clock = mStatusBarView.findViewById(R.id.clock);
Jim Millera073e572012-05-23 17:03:27 -07001873
Daniel Sandler825b3302012-10-01 15:22:36 -04001874 final AnimatorSet lightsOutAnim = new AnimatorSet();
1875 lightsOutAnim.playTogether(
1876 ObjectAnimator.ofFloat(notifications, View.ALPHA, 0),
1877 ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 0),
1878 ObjectAnimator.ofFloat(signal, View.ALPHA, 0),
1879 ObjectAnimator.ofFloat(battery, View.ALPHA, 0.5f),
1880 ObjectAnimator.ofFloat(clock, View.ALPHA, 0.5f)
1881 );
1882 lightsOutAnim.setDuration(750);
1883
1884 final AnimatorSet lightsOnAnim = new AnimatorSet();
1885 lightsOnAnim.playTogether(
1886 ObjectAnimator.ofFloat(notifications, View.ALPHA, 1),
1887 ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 1),
1888 ObjectAnimator.ofFloat(signal, View.ALPHA, 1),
1889 ObjectAnimator.ofFloat(battery, View.ALPHA, 1),
1890 ObjectAnimator.ofFloat(clock, View.ALPHA, 1)
1891 );
1892 lightsOnAnim.setDuration(250);
1893
1894 mLightsOutAnimation = lightsOutAnim;
1895 mLightsOnAnimation = lightsOnAnim;
Daniel Sandlerd7e96862012-04-26 01:10:29 -04001896 }
Jim Millera073e572012-05-23 17:03:27 -07001897
Daniel Sandlerd7e96862012-04-26 01:10:29 -04001898 mLightsOutAnimation.cancel();
1899 mLightsOnAnimation.cancel();
1900
1901 final Animator a = lightsOut ? mLightsOutAnimation : mLightsOnAnimation;
1902 a.start();
1903
1904 setAreThereNotifications();
1905 }
1906
1907 private boolean areLightsOn() {
1908 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
1909 }
Jim Millera073e572012-05-23 17:03:27 -07001910
Daniel Sandler60ee2562011-07-22 12:34:33 -04001911 public void setLightsOn(boolean on) {
1912 Log.v(TAG, "setLightsOn(" + on + ")");
1913 if (on) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001914 setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
Daniel Sandler60ee2562011-07-22 12:34:33 -04001915 } else {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001916 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
Daniel Sandler60ee2562011-07-22 12:34:33 -04001917 }
1918 }
1919
1920 private void notifyUiVisibilityChanged() {
Daniel Sandler1d4d30a2011-04-28 12:35:29 -04001921 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001922 mWindowManagerService.statusBarVisibilityChanged(mSystemUiVisibility);
Daniel Sandler1d4d30a2011-04-28 12:35:29 -04001923 } catch (RemoteException ex) {
1924 }
Joe Onorato93056472010-09-10 10:30:46 -04001925 }
1926
Daniel Sandler5c8da942011-06-28 00:29:04 -04001927 public void topAppWindowChanged(boolean showMenu) {
1928 if (DEBUG) {
1929 Slog.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
1930 }
1931 if (mNavigationBarView != null) {
Daniel Sandlerf1ebcee2011-09-15 16:02:56 -04001932 mNavigationBarView.setMenuVisibility(showMenu);
Daniel Sandler5c8da942011-06-28 00:29:04 -04001933 }
1934
1935 // See above re: lights-out policy for legacy apps.
1936 if (showMenu) setLightsOn(true);
1937 }
1938
Daniel Sandler328310c2011-09-23 15:56:52 -04001939 @Override
1940 public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
1941 boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS)
1942 || ((vis & InputMethodService.IME_VISIBLE) != 0);
1943
1944 mCommandQueue.setNavigationIconHints(
1945 altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
1946 : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
Daniel Sandler101784e2012-10-15 13:39:38 -04001947 if (mQS != null) mQS.setImeWindowStatus(vis > 0);
Daniel Sandler328310c2011-09-23 15:56:52 -04001948 }
1949
Jeff Brown2992ea72011-01-28 22:04:14 -08001950 @Override
Winson Chung43229d72012-09-12 18:04:18 -07001951 public void setHardKeyboardStatus(boolean available, boolean enabled) {}
Daniel Sandlere02d8082010-10-08 15:13:22 -04001952
Chris Wren0c8275b2012-05-08 13:36:48 -04001953 @Override
1954 protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
Daniel Sandlerd7e96862012-04-26 01:10:29 -04001955 // no ticking in lights-out mode
1956 if (!areLightsOn()) return;
Jim Millera073e572012-05-23 17:03:27 -07001957
Daniel Sandler26cda272012-05-22 15:44:08 -04001958 // no ticking in Setup
1959 if (!isDeviceProvisioned()) return;
1960
John Spurlock61e36832012-09-10 09:43:27 -04001961 // not for you
1962 if (!notificationIsForCurrentUser(n)) return;
1963
Joe Onorato808182d2010-07-09 18:52:06 -04001964 // Show the ticker if one is requested. Also don't do this
1965 // until status bar window is attached to the window manager,
1966 // because... well, what's the point otherwise? And trying to
1967 // run a ticker without being attached will crash!
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04001968 if (n.getNotification().tickerText != null && mStatusBarWindow.getWindowToken() != null) {
Joe Onorato808182d2010-07-09 18:52:06 -04001969 if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
1970 | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
1971 mTicker.addEntry(n);
1972 }
1973 }
1974 }
1975
Joe Onorato808182d2010-07-09 18:52:06 -04001976 private class MyTicker extends Ticker {
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001977 MyTicker(Context context, View sb) {
Joe Onorato808182d2010-07-09 18:52:06 -04001978 super(context, sb);
1979 }
1980
1981 @Override
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001982 public void tickerStarting() {
Joe Onorato808182d2010-07-09 18:52:06 -04001983 mTicking = true;
Daniel Sandler173bae22012-09-25 14:37:42 -04001984 mStatusBarContents.setVisibility(View.GONE);
Joe Onorato808182d2010-07-09 18:52:06 -04001985 mTickerView.setVisibility(View.VISIBLE);
1986 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
Daniel Sandler173bae22012-09-25 14:37:42 -04001987 mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
Joe Onorato808182d2010-07-09 18:52:06 -04001988 }
1989
1990 @Override
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001991 public void tickerDone() {
Daniel Sandler173bae22012-09-25 14:37:42 -04001992 mStatusBarContents.setVisibility(View.VISIBLE);
Joe Onorato808182d2010-07-09 18:52:06 -04001993 mTickerView.setVisibility(View.GONE);
Daniel Sandler173bae22012-09-25 14:37:42 -04001994 mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
Joe Onorato808182d2010-07-09 18:52:06 -04001995 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
1996 mTickingDoneListener));
Joe Onorato808182d2010-07-09 18:52:06 -04001997 }
1998
Daniel Sandlerdfa08db2010-08-05 16:18:42 -04001999 public void tickerHalting() {
Daniel Sandler173bae22012-09-25 14:37:42 -04002000 mStatusBarContents.setVisibility(View.VISIBLE);
Joe Onorato808182d2010-07-09 18:52:06 -04002001 mTickerView.setVisibility(View.GONE);
Daniel Sandler173bae22012-09-25 14:37:42 -04002002 mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
Daniel Sandlerf59a90c2012-09-28 15:33:14 -04002003 // we do not animate the ticker away at this point, just get rid of it (b/6992707)
Joe Onorato808182d2010-07-09 18:52:06 -04002004 }
2005 }
2006
2007 Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
2008 public void onAnimationEnd(Animation animation) {
2009 mTicking = false;
2010 }
2011 public void onAnimationRepeat(Animation animation) {
2012 }
2013 public void onAnimationStart(Animation animation) {
2014 }
2015 };
2016
2017 private Animation loadAnim(int id, Animation.AnimationListener listener) {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04002018 Animation anim = AnimationUtils.loadAnimation(mContext, id);
Joe Onorato808182d2010-07-09 18:52:06 -04002019 if (listener != null) {
2020 anim.setAnimationListener(listener);
2021 }
2022 return anim;
2023 }
2024
Daniel Sandler48852952011-12-01 14:34:23 -05002025 public static String viewInfo(View v) {
2026 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
2027 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
Joe Onorato808182d2010-07-09 18:52:06 -04002028 }
2029
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04002030 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Joe Onorato808182d2010-07-09 18:52:06 -04002031 synchronized (mQueueLock) {
2032 pw.println("Current Status Bar state:");
Daniel Sandlere7237fc2012-08-14 16:08:27 -04002033 pw.println(" mExpandedVisible=" + mExpandedVisible
Daniel Sandlerfdbac772012-07-03 14:30:10 -04002034 + ", mTrackingPosition=" + mTrackingPosition);
Joe Onorato808182d2010-07-09 18:52:06 -04002035 pw.println(" mTicking=" + mTicking);
2036 pw.println(" mTracking=" + mTracking);
Daniel Sandler36412a72011-08-04 09:35:13 -04002037 pw.println(" mDisplayMetrics=" + mDisplayMetrics);
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04002038 pw.println(" mPile: " + viewInfo(mPile));
Joe Onorato808182d2010-07-09 18:52:06 -04002039 pw.println(" mTickerView: " + viewInfo(mTickerView));
2040 pw.println(" mScrollView: " + viewInfo(mScrollView)
2041 + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
Joe Onorato808182d2010-07-09 18:52:06 -04002042 }
Joe Onorato808182d2010-07-09 18:52:06 -04002043
Daniel Sandler48852952011-12-01 14:34:23 -05002044 pw.print(" mNavigationBarView=");
2045 if (mNavigationBarView == null) {
2046 pw.println("null");
2047 } else {
2048 mNavigationBarView.dump(fd, pw, args);
2049 }
2050
Daniel Sandler37a38aa2013-02-13 17:15:57 -05002051 pw.println(" Panels: ");
2052 if (mNotificationPanel != null) {
2053 pw.println(" mNotificationPanel=" +
2054 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
2055 pw.print (" ");
2056 mNotificationPanel.dump(fd, pw, args);
2057 }
2058 if (mSettingsPanel != null) {
2059 pw.println(" mSettingsPanel=" +
2060 mSettingsPanel + " params=" + mSettingsPanel.getLayoutParams().debug(""));
2061 pw.print (" ");
2062 mSettingsPanel.dump(fd, pw, args);
2063 }
2064
Daniel Sandler7579bca2011-08-18 15:47:26 -04002065 if (DUMPTRUCK) {
2066 synchronized (mNotificationData) {
2067 int N = mNotificationData.size();
2068 pw.println(" notification icons: " + N);
2069 for (int i=0; i<N; i++) {
2070 NotificationData.Entry e = mNotificationData.get(i);
2071 pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon);
2072 StatusBarNotification n = e.notification;
Daniel Sandler4f91efd2013-04-25 16:38:41 -04002073 pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " score=" + n.getScore());
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04002074 pw.println(" notification=" + n.getNotification());
2075 pw.println(" tickerText=\"" + n.getNotification().tickerText + "\"");
Daniel Sandler7579bca2011-08-18 15:47:26 -04002076 }
2077 }
2078
2079 int N = mStatusIcons.getChildCount();
2080 pw.println(" system icons: " + N);
2081 for (int i=0; i<N; i++) {
2082 StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
2083 pw.println(" [" + i + "] icon=" + ic);
2084 }
Jim Miller5e6af442011-12-02 18:24:26 -08002085
Daniel Sandler89d97132011-09-08 15:31:57 -04002086 if (false) {
2087 pw.println("see the logcat for a dump of the views we have created.");
2088 // must happen on ui thread
2089 mHandler.post(new Runnable() {
2090 public void run() {
2091 mStatusBarView.getLocationOnScreen(mAbsPos);
2092 Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
2093 + ") " + mStatusBarView.getWidth() + "x"
Daniel Sandlera310af82012-04-24 01:20:13 -04002094 + getStatusBarHeight());
Daniel Sandler89d97132011-09-08 15:31:57 -04002095 mStatusBarView.debug();
Daniel Sandler89d97132011-09-08 15:31:57 -04002096 }
2097 });
2098 }
Joe Onorato808182d2010-07-09 18:52:06 -04002099 }
Daniel Sandler89d97132011-09-08 15:31:57 -04002100
Daniel Sandler151f00d2012-10-02 22:33:08 -04002101 if (DEBUG_GESTURES) {
2102 pw.print(" status bar gestures: ");
2103 mGestureRec.dump(fd, pw, args);
2104 }
Daniel Sandler33805342012-07-23 15:45:12 -04002105
Daniel Sandler89d97132011-09-08 15:31:57 -04002106 mNetworkController.dump(fd, pw, args);
Joe Onorato808182d2010-07-09 18:52:06 -04002107 }
2108
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -05002109 @Override
2110 public void createAndAddWindows() {
2111 addStatusBarWindow();
Joe Onorato808182d2010-07-09 18:52:06 -04002112 }
Jim Millere898ac52012-04-06 17:10:57 -07002113
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -05002114 private void addStatusBarWindow() {
2115 // Put up the view
2116 final int height = getStatusBarHeight();
Joe Onorato808182d2010-07-09 18:52:06 -04002117
Daniel Sandlera310af82012-04-24 01:20:13 -04002118 // Now that the status bar window encompasses the sliding panel and its
2119 // translucent backdrop, the entire thing is made TRANSLUCENT and is
2120 // hardware-accelerated.
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -05002121 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
2122 ViewGroup.LayoutParams.MATCH_PARENT,
2123 height,
2124 WindowManager.LayoutParams.TYPE_STATUS_BAR,
2125 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
2126 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
2127 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
Daniel Sandlera310af82012-04-24 01:20:13 -04002128 PixelFormat.TRANSLUCENT);
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -05002129
Romain Guy0901fda2012-05-22 21:10:57 -07002130 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -05002131
2132 lp.gravity = getStatusBarGravity();
2133 lp.setTitle("StatusBar");
2134 lp.packageName = mContext.getPackageName();
Jim Millere898ac52012-04-06 17:10:57 -07002135
Daniel Sandlera310af82012-04-24 01:20:13 -04002136 makeStatusBarView();
Jeff Brown98365d72012-08-19 20:30:52 -07002137 mWindowManager.addView(mStatusBarWindow, lp);
Joe Onorato808182d2010-07-09 18:52:06 -04002138 }
2139
Joe Onorato808182d2010-07-09 18:52:06 -04002140 void setNotificationIconVisibility(boolean visible, int anim) {
2141 int old = mNotificationIcons.getVisibility();
2142 int v = visible ? View.VISIBLE : View.INVISIBLE;
2143 if (old != v) {
2144 mNotificationIcons.setVisibility(v);
2145 mNotificationIcons.startAnimation(loadAnim(anim, null));
2146 }
2147 }
2148
Dianne Hackborn1dacf272011-08-02 15:01:22 -07002149 void updateExpandedInvisiblePosition() {
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -05002150 mTrackingPosition = -mDisplayMetrics.heightPixels;
Dianne Hackborn1dacf272011-08-02 15:01:22 -07002151 }
2152
Daniel Sandler1fac1fd2012-04-30 12:07:30 -04002153 static final float saturate(float a) {
2154 return a < 0f ? 0f : (a > 1f ? 1f : a);
2155 }
2156
Chris Wren8fd12652012-05-09 21:25:57 -04002157 @Override
2158 protected int getExpandedViewMaxHeight() {
Daniel Sandler21b274e2012-05-02 15:07:51 -04002159 return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx;
2160 }
2161
Chris Wren0c8275b2012-05-08 13:36:48 -04002162 @Override
Daniel Sandler08d05e32012-08-08 16:39:54 -04002163 public void updateExpandedViewPos(int thingy) {
Daniel Sandler08d05e32012-08-08 16:39:54 -04002164 if (DEBUG) Slog.v(TAG, "updateExpandedViewPos");
Daniel Sandlere680f542012-09-28 12:22:27 -04002165
2166 // on larger devices, the notification panel is propped open a bit
2167 mNotificationPanel.setMinimumHeight(
2168 (int)(mNotificationPanelMinHeightFrac * mCurrentDisplaySize.y));
2169
Daniel Sandler21b274e2012-05-02 15:07:51 -04002170 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
Daniel Sandler21b274e2012-05-02 15:07:51 -04002171 lp.gravity = mNotificationPanelGravity;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -07002172 lp.setMarginStart(mNotificationPanelMarginPx);
Daniel Sandler21b274e2012-05-02 15:07:51 -04002173 mNotificationPanel.setLayoutParams(lp);
Daniel Sandlere680f542012-09-28 12:22:27 -04002174
Daniel Sandlere111ad32012-10-13 15:17:45 -04002175 if (mSettingsPanel != null) {
2176 lp = (FrameLayout.LayoutParams) mSettingsPanel.getLayoutParams();
2177 lp.gravity = mSettingsPanelGravity;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -07002178 lp.setMarginEnd(mNotificationPanelMarginPx);
Daniel Sandlere111ad32012-10-13 15:17:45 -04002179 mSettingsPanel.setLayoutParams(lp);
2180 }
Daniel Sandlerbf526d12012-09-04 22:56:44 -04002181
2182 updateCarrierLabelVisibility(false);
Joe Onorato808182d2010-07-09 18:52:06 -04002183 }
2184
Daniel Sandler747a9e92012-08-10 16:39:19 -04002185 // called by makeStatusbar and also by PhoneStatusBarView
Dianne Hackborn1dacf272011-08-02 15:01:22 -07002186 void updateDisplaySize() {
Daniel Sandler36412a72011-08-04 09:35:13 -04002187 mDisplay.getMetrics(mDisplayMetrics);
Daniel Sandler151f00d2012-10-02 22:33:08 -04002188 if (DEBUG_GESTURES) {
2189 mGestureRec.tag("display",
2190 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
2191 }
Dianne Hackborn1dacf272011-08-02 15:01:22 -07002192 }
2193
Joe Onorato808182d2010-07-09 18:52:06 -04002194 private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
2195 public void onClick(View v) {
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002196 synchronized (mNotificationData) {
Chet Haase2f2022a2011-10-11 06:41:59 -07002197 // animate-swipe all dismissable notifications, then animate the shade closed
2198 int numChildren = mPile.getChildCount();
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002199
Chet Haase2f2022a2011-10-11 06:41:59 -07002200 int scrollTop = mScrollView.getScrollY();
2201 int scrollBottom = scrollTop + mScrollView.getHeight();
2202 final ArrayList<View> snapshot = new ArrayList<View>(numChildren);
2203 for (int i=0; i<numChildren; i++) {
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002204 final View child = mPile.getChildAt(i);
Chet Haase2f2022a2011-10-11 06:41:59 -07002205 if (mPile.canChildBeDismissed(child) && child.getBottom() > scrollTop &&
2206 child.getTop() < scrollBottom) {
2207 snapshot.add(child);
2208 }
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002209 }
Craig Mautner93a035c2012-04-09 15:23:59 -07002210 if (snapshot.isEmpty()) {
Daniel Sandler11cf1782012-09-27 14:03:08 -04002211 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
Craig Mautner93a035c2012-04-09 15:23:59 -07002212 return;
2213 }
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002214 new Thread(new Runnable() {
2215 @Override
2216 public void run() {
Chet Haase2f2022a2011-10-11 06:41:59 -07002217 // Decrease the delay for every row we animate to give the sense of
2218 // accelerating the swipes
2219 final int ROW_DELAY_DECREMENT = 10;
2220 int currentDelay = 140;
2221 int totalDelay = 0;
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002222
Chet Haase2f2022a2011-10-11 06:41:59 -07002223 // Set the shade-animating state to avoid doing other work during
2224 // all of these animations. In particular, avoid layout and
2225 // redrawing when collapsing the shade.
2226 mPile.setViewRemoval(false);
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002227
Chet Haase2f2022a2011-10-11 06:41:59 -07002228 mPostCollapseCleanup = new Runnable() {
Craig Mautner93a035c2012-04-09 15:23:59 -07002229 @Override
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002230 public void run() {
Daniel Sandlere7237fc2012-08-14 16:08:27 -04002231 if (DEBUG) {
2232 Slog.v(TAG, "running post-collapse cleanup");
2233 }
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002234 try {
Chet Haase2f2022a2011-10-11 06:41:59 -07002235 mPile.setViewRemoval(true);
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002236 mBarService.onClearAllNotifications();
Chet Haase2f2022a2011-10-11 06:41:59 -07002237 } catch (Exception ex) { }
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002238 }
Chet Haase2f2022a2011-10-11 06:41:59 -07002239 };
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002240
Chet Haase2f2022a2011-10-11 06:41:59 -07002241 View sampleView = snapshot.get(0);
2242 int width = sampleView.getWidth();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -07002243 final int dir = sampleView.isLayoutRtl() ? -1 : +1;
2244 final int velocity = dir * width * 8; // 1000/8 = 125 ms duration
Craig Mautner93a035c2012-04-09 15:23:59 -07002245 for (final View _v : snapshot) {
Chet Haase2f2022a2011-10-11 06:41:59 -07002246 mHandler.postDelayed(new Runnable() {
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002247 @Override
2248 public void run() {
Chet Haase2f2022a2011-10-11 06:41:59 -07002249 mPile.dismissRowAnimated(_v, velocity);
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002250 }
Chet Haase2f2022a2011-10-11 06:41:59 -07002251 }, totalDelay);
2252 currentDelay = Math.max(50, currentDelay - ROW_DELAY_DECREMENT);
2253 totalDelay += currentDelay;
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002254 }
Chet Haase2f2022a2011-10-11 06:41:59 -07002255 // Delay the collapse animation until after all swipe animations have
2256 // finished. Provide some buffer because there may be some extra delay
2257 // before actually starting each swipe animation. Ideally, we'd
2258 // synchronize the end of those animations with the start of the collaps
2259 // exactly.
2260 mHandler.postDelayed(new Runnable() {
Craig Mautner93a035c2012-04-09 15:23:59 -07002261 @Override
Chet Haase2f2022a2011-10-11 06:41:59 -07002262 public void run() {
Daniel Sandler11cf1782012-09-27 14:03:08 -04002263 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
Chet Haase2f2022a2011-10-11 06:41:59 -07002264 }
2265 }, totalDelay + 225);
Daniel Sandler8ba33c92011-10-04 21:49:30 -04002266 }
2267 }).start();
Joe Onorato808182d2010-07-09 18:52:06 -04002268 }
Joe Onorato808182d2010-07-09 18:52:06 -04002269 }
2270 };
2271
Daniel Sandler3679bf52012-10-16 21:30:28 -04002272 public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
2273 if (onlyProvisioned && !isDeviceProvisioned()) return;
2274 try {
2275 // Dismiss the lock screen when Settings starts.
2276 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
2277 } catch (RemoteException e) {
2278 }
2279 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2280 mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
2281 animateCollapsePanels();
2282 }
2283
Daniel Sandlerd3090562011-08-09 00:28:44 -04002284 private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
2285 public void onClick(View v) {
Daniel Sandlere111ad32012-10-13 15:17:45 -04002286 if (mHasSettingsPanel) {
2287 animateExpandSettingsPanel();
2288 } else {
Daniel Sandler3679bf52012-10-16 21:30:28 -04002289 startActivityDismissingKeyguard(
2290 new Intent(android.provider.Settings.ACTION_SETTINGS), true);
Daniel Sandlere111ad32012-10-13 15:17:45 -04002291 }
Daniel Sandlerd3090562011-08-09 00:28:44 -04002292 }
2293 };
2294
Daniel Sandler3679bf52012-10-16 21:30:28 -04002295 private View.OnClickListener mClockClickListener = new View.OnClickListener() {
2296 public void onClick(View v) {
2297 startActivityDismissingKeyguard(
2298 new Intent(Intent.ACTION_QUICK_CLOCK), true); // have fun, everyone
2299 }
2300 };
2301
Daniel Sandler101784e2012-10-15 13:39:38 -04002302 private View.OnClickListener mNotificationButtonListener = new View.OnClickListener() {
2303 public void onClick(View v) {
2304 animateExpandNotificationsPanel();
2305 }
2306 };
2307
Joe Onorato808182d2010-07-09 18:52:06 -04002308 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
2309 public void onReceive(Context context, Intent intent) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002310 if (DEBUG) Slog.v(TAG, "onReceive: " + intent);
Joe Onorato808182d2010-07-09 18:52:06 -04002311 String action = intent.getAction();
Daniel Sandlered930e52012-07-03 14:31:22 -04002312 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
Jim Miller9a720f52012-05-30 03:19:43 -07002313 int flags = CommandQueue.FLAG_EXCLUDE_NONE;
Michael Jurka3b1fc472011-06-13 10:54:40 -07002314 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
Daniel Sandleredbdd3a2011-06-21 12:57:08 -04002315 String reason = intent.getStringExtra("reason");
Jim Miller9a720f52012-05-30 03:19:43 -07002316 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
2317 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
Michael Jurka3b1fc472011-06-13 10:54:40 -07002318 }
2319 }
Daniel Sandler11cf1782012-09-27 14:03:08 -04002320 animateCollapsePanels(flags);
Joe Onorato808182d2010-07-09 18:52:06 -04002321 }
Daniel Sandlered930e52012-07-03 14:31:22 -04002322 else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
2323 // no waiting!
Daniel Sandler08d05e32012-08-08 16:39:54 -04002324 makeExpandedInvisible();
John Spurlock1bbd49d2012-10-19 11:09:32 -04002325 notifyNavigationBarScreenOn(false);
Daniel Sandlered930e52012-07-03 14:31:22 -04002326 }
Joe Onorato808182d2010-07-09 18:52:06 -04002327 else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
Daniel Sandler7f3cf952012-08-31 14:57:09 -04002328 if (DEBUG) {
2329 Slog.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
2330 }
Daniel Sandlere680f542012-09-28 12:22:27 -04002331 mDisplay.getSize(mCurrentDisplaySize);
2332
Joe Onorato808182d2010-07-09 18:52:06 -04002333 updateResources();
Daniel Sandler21b274e2012-05-02 15:07:51 -04002334 repositionNavigationBar();
2335 updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
Daniel Sandler7f3cf952012-08-31 14:57:09 -04002336 updateShowSearchHoldoff();
2337 }
2338 else if (Intent.ACTION_SCREEN_ON.equals(action)) {
2339 // work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018)
2340 repositionNavigationBar();
John Spurlock1bbd49d2012-10-19 11:09:32 -04002341 notifyNavigationBarScreenOn(true);
Joe Onorato808182d2010-07-09 18:52:06 -04002342 }
2343 }
2344 };
2345
Daniel Sandlerb9301c32012-08-14 15:08:24 -04002346 @Override
2347 public void userSwitched(int newUserId) {
2348 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
Daniel Sandler11cf1782012-09-27 14:03:08 -04002349 animateCollapsePanels();
Daniel Sandlerb9301c32012-08-14 15:08:24 -04002350 updateNotificationIcons();
John Spurlock919adac2012-10-02 16:41:12 -04002351 resetUserSetupObserver();
Daniel Sandlerb9301c32012-08-14 15:08:24 -04002352 }
John Spurlock919adac2012-10-02 16:41:12 -04002353
2354 private void resetUserSetupObserver() {
2355 mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver);
2356 mUserSetupObserver.onChange(false);
2357 mContext.getContentResolver().registerContentObserver(
2358 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true,
2359 mUserSetupObserver,
2360 mCurrentUserId);
2361 }
2362
Joe Onorato808182d2010-07-09 18:52:06 -04002363 private void setIntruderAlertVisibility(boolean vis) {
Daniel Sandler6b318802012-04-13 14:05:19 -04002364 if (!ENABLE_INTRUDERS) return;
Daniel Sandlerfa7887b2012-03-26 09:43:31 -04002365 if (DEBUG) {
2366 Slog.v(TAG, (vis ? "showing" : "hiding") + " intruder alert window");
2367 }
Joe Onorato808182d2010-07-09 18:52:06 -04002368 mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
2369 }
2370
Daniel Sandlerfa7887b2012-03-26 09:43:31 -04002371 public void dismissIntruder() {
2372 if (mCurrentlyIntrudingNotification == null) return;
2373
2374 try {
2375 mBarService.onNotificationClear(
Daniel Sandler4f91efd2013-04-25 16:38:41 -04002376 mCurrentlyIntrudingNotification.getPackageName(),
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -04002377 mCurrentlyIntrudingNotification.getTag(),
2378 mCurrentlyIntrudingNotification.getId());
Daniel Sandlerfa7887b2012-03-26 09:43:31 -04002379 } catch (android.os.RemoteException ex) {
2380 // oh well
2381 }
2382 }
Jim Millere898ac52012-04-06 17:10:57 -07002383
Joe Onorato808182d2010-07-09 18:52:06 -04002384 /**
2385 * Reload some of our resources when the configuration changes.
2386 *
2387 * We don't reload everything when the configuration changes -- we probably
2388 * should, but getting that smooth is tough. Someday we'll fix that. In the
2389 * meantime, just update the things that we know change.
2390 */
2391 void updateResources() {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04002392 final Context context = mContext;
2393 final Resources res = context.getResources();
Joe Onorato808182d2010-07-09 18:52:06 -04002394
Daniel Sandler1347c302011-08-01 16:47:53 -04002395 if (mClearButton instanceof TextView) {
2396 ((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button));
2397 }
Winson Chungd63c59782012-09-05 17:34:41 -07002398
2399 // Update the QuickSettings container
Daniel Sandler101784e2012-10-15 13:39:38 -04002400 if (mQS != null) mQS.updateResources();
Winson Chungd63c59782012-09-05 17:34:41 -07002401
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04002402 loadDimens();
2403 }
Jim Miller5e6af442011-12-02 18:24:26 -08002404
Daniel Sandler7c3e39d2011-07-29 16:30:49 -04002405 protected void loadDimens() {
2406 final Resources res = mContext.getResources();
2407
2408 mNaturalBarHeight = res.getDimensionPixelSize(
2409 com.android.internal.R.dimen.status_bar_height);
2410
2411 int newIconSize = res.getDimensionPixelSize(
2412 com.android.internal.R.dimen.status_bar_icon_size);
2413 int newIconHPadding = res.getDimensionPixelSize(
2414 R.dimen.status_bar_icon_padding);
2415
2416 if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
2417// Slog.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
2418 mIconHPadding = newIconHPadding;
2419 mIconSize = newIconSize;
2420 //reloadAllNotificationIcons(); // reload the tray
2421 }
2422
Joe Onorato808182d2010-07-09 18:52:06 -04002423 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
2424
Daniel Sandlerdc940ea2011-08-25 14:35:53 -07002425 mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity);
2426 mSelfCollapseVelocityPx = res.getDimension(R.dimen.self_collapse_velocity);
2427 mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity);
2428 mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity);
2429
2430 mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1);
2431 mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1);
2432
2433 mExpandAccelPx = res.getDimension(R.dimen.expand_accel);
2434 mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel);
2435
2436 mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity);
Jim Millera073e572012-05-23 17:03:27 -07002437
Daniel Sandlere5011a32012-06-11 16:07:52 -04002438 mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
2439
Daniel Sandler21b274e2012-05-02 15:07:51 -04002440 mNotificationPanelMarginBottomPx
2441 = (int) res.getDimension(R.dimen.notification_panel_margin_bottom);
Daniel Sandler8e72c9e2012-08-15 00:09:26 -04002442 mNotificationPanelMarginPx
Daniel Sandler21b274e2012-05-02 15:07:51 -04002443 = (int) res.getDimension(R.dimen.notification_panel_margin_left);
2444 mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
2445 if (mNotificationPanelGravity <= 0) {
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -07002446 mNotificationPanelGravity = Gravity.START | Gravity.TOP;
Daniel Sandler8e72c9e2012-08-15 00:09:26 -04002447 }
2448 mSettingsPanelGravity = res.getInteger(R.integer.settings_panel_layout_gravity);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -07002449 Log.d(TAG, "mSettingsPanelGravity = " + mSettingsPanelGravity);
Daniel Sandler8e72c9e2012-08-15 00:09:26 -04002450 if (mSettingsPanelGravity <= 0) {
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -07002451 mSettingsPanelGravity = Gravity.END | Gravity.TOP;
Daniel Sandler21b274e2012-05-02 15:07:51 -04002452 }
Daniel Sandler3d32a242012-06-05 13:44:14 -04002453
2454 mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
Daniel Sandlerbf526d12012-09-04 22:56:44 -04002455 mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height);
Daniel Sandlerdc940ea2011-08-25 14:35:53 -07002456
Daniel Sandlere680f542012-09-28 12:22:27 -04002457 mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1);
2458 if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) {
2459 mNotificationPanelMinHeightFrac = 0f;
John Spurlock804df702012-06-01 15:34:27 -04002460 }
Daniel Sandlere680f542012-09-28 12:22:27 -04002461
2462 if (false) Slog.v(TAG, "updateResources");
John Spurlock804df702012-06-01 15:34:27 -04002463 }
2464
Joe Onorato808182d2010-07-09 18:52:06 -04002465 //
2466 // tracing
2467 //
2468
2469 void postStartTracing() {
2470 mHandler.postDelayed(mStartTracing, 3000);
2471 }
2472
2473 void vibrate() {
Joe Onoratof3c3c4f2010-10-21 11:09:02 -04002474 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
2475 Context.VIBRATOR_SERVICE);
Joe Onorato808182d2010-07-09 18:52:06 -04002476 vib.vibrate(250);
2477 }
2478
2479 Runnable mStartTracing = new Runnable() {
2480 public void run() {
2481 vibrate();
2482 SystemClock.sleep(250);
2483 Slog.d(TAG, "startTracing");
2484 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
2485 mHandler.postDelayed(mStopTracing, 10000);
2486 }
2487 };
2488
2489 Runnable mStopTracing = new Runnable() {
2490 public void run() {
2491 android.os.Debug.stopMethodTracing();
2492 Slog.d(TAG, "stopTracing");
2493 vibrate();
2494 }
2495 };
Chris Wren0c8275b2012-05-08 13:36:48 -04002496
2497 @Override
2498 protected void haltTicker() {
2499 mTicker.halt();
2500 }
Jim Miller670d9dd2012-05-12 13:28:26 -07002501
2502 @Override
Jim Millerb4238e02012-05-14 15:26:20 -07002503 protected boolean shouldDisableNavbarGestures() {
Daniel Sandlerd5483c32012-10-19 16:44:15 -04002504 return !isDeviceProvisioned()
2505 || mExpandedVisible
2506 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
Jim Miller670d9dd2012-05-12 13:28:26 -07002507 }
Joe Onorato808182d2010-07-09 18:52:06 -04002508
Romain Guy648342f2012-05-25 10:44:45 -07002509 private static class FastColorDrawable extends Drawable {
2510 private final int mColor;
2511
2512 public FastColorDrawable(int color) {
2513 mColor = 0xff000000 | color;
2514 }
2515
2516 @Override
2517 public void draw(Canvas canvas) {
2518 canvas.drawColor(mColor, PorterDuff.Mode.SRC);
2519 }
2520
2521 @Override
2522 public void setAlpha(int alpha) {
2523 }
2524
2525 @Override
2526 public void setColorFilter(ColorFilter cf) {
2527 }
2528
2529 @Override
2530 public int getOpacity() {
2531 return PixelFormat.OPAQUE;
2532 }
2533
2534 @Override
2535 public void setBounds(int left, int top, int right, int bottom) {
2536 }
2537
2538 @Override
2539 public void setBounds(Rect bounds) {
2540 }
2541 }
2542}