2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.systemui.statusbar.phone;
20 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
21 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
22 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
23 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
24 import static android.app.StatusBarManager.windowStateToString;
25 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
26 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
27 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
28 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
29 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
30 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
31 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
33 import android.animation.Animator;
34 import android.animation.AnimatorListenerAdapter;
35 import android.annotation.NonNull;
36 import android.app.ActivityManager;
37 import android.app.ActivityManagerNative;
38 import android.app.IActivityManager;
39 import android.app.Notification;
40 import android.app.PendingIntent;
41 import android.app.StatusBarManager;
42 import android.content.BroadcastReceiver;
43 import android.content.ComponentCallbacks2;
44 import android.content.Context;
45 import android.content.Intent;
46 import android.content.IntentFilter;
47 import android.content.res.Configuration;
48 import android.content.res.Resources;
49 import android.database.ContentObserver;
50 import android.graphics.Bitmap;
51 import android.graphics.Canvas;
52 import android.graphics.ColorFilter;
53 import android.graphics.PixelFormat;
54 import android.graphics.Point;
55 import android.graphics.PointF;
56 import android.graphics.PorterDuff;
57 import android.graphics.PorterDuffXfermode;
58 import android.graphics.Rect;
59 import android.graphics.drawable.ColorDrawable;
60 import android.graphics.drawable.Drawable;
61 import android.inputmethodservice.InputMethodService;
62 import android.media.AudioAttributes;
63 import android.media.MediaMetadata;
64 import android.media.session.MediaController;
65 import android.media.session.MediaSession;
66 import android.media.session.MediaSessionManager;
67 import android.media.session.PlaybackState;
68 import android.os.AsyncTask;
69 import android.os.Bundle;
70 import android.os.Handler;
71 import android.os.HandlerThread;
72 import android.os.IBinder;
73 import android.os.Message;
74 import android.os.PowerManager;
75 import android.os.Process;
76 import android.os.RemoteException;
77 import android.os.SystemClock;
78 import android.os.UserHandle;
79 import android.os.UserManager;
80 import android.provider.Settings;
81 import android.service.notification.NotificationListenerService;
82 import android.service.notification.NotificationListenerService.RankingMap;
83 import android.service.notification.StatusBarNotification;
84 import android.util.ArraySet;
85 import android.util.DisplayMetrics;
86 import android.util.EventLog;
87 import android.util.Log;
88 import android.view.Display;
89 import android.view.Gravity;
90 import android.view.KeyEvent;
91 import android.view.LayoutInflater;
92 import android.view.MotionEvent;
93 import android.view.VelocityTracker;
94 import android.view.View;
95 import android.view.ViewGroup;
96 import android.view.ViewGroup.LayoutParams;
97 import android.view.ViewStub;
98 import android.view.WindowManager;
99 import android.view.WindowManagerGlobal;
100 import android.view.accessibility.AccessibilityEvent;
101 import android.view.animation.AccelerateDecelerateInterpolator;
102 import android.view.animation.AccelerateInterpolator;
103 import android.view.animation.Interpolator;
104 import android.view.animation.LinearInterpolator;
105 import android.view.animation.PathInterpolator;
106 import android.widget.ImageView;
107 import android.widget.TextView;
109 import com.android.internal.statusbar.StatusBarIcon;
110 import com.android.keyguard.KeyguardHostView.OnDismissAction;
111 import com.android.keyguard.ViewMediatorCallback;
112 import com.android.systemui.BatteryMeterView;
113 import com.android.systemui.DemoMode;
114 import com.android.systemui.EventLogConstants;
115 import com.android.systemui.EventLogTags;
116 import com.android.systemui.R;
117 import com.android.systemui.doze.DozeHost;
118 import com.android.systemui.doze.DozeLog;
119 import com.android.systemui.keyguard.KeyguardViewMediator;
120 import com.android.systemui.qs.QSPanel;
121 import com.android.systemui.recents.ScreenPinningRequest;
122 import com.android.systemui.statusbar.ActivatableNotificationView;
123 import com.android.systemui.statusbar.BackDropView;
124 import com.android.systemui.statusbar.BaseStatusBar;
125 import com.android.systemui.statusbar.CommandQueue;
126 import com.android.systemui.statusbar.DismissView;
127 import com.android.systemui.statusbar.DragDownHelper;
128 import com.android.systemui.statusbar.EmptyShadeView;
129 import com.android.systemui.statusbar.ExpandableNotificationRow;
130 import com.android.systemui.statusbar.GestureRecorder;
131 import com.android.systemui.statusbar.KeyguardIndicationController;
132 import com.android.systemui.statusbar.NotificationData;
133 import com.android.systemui.statusbar.NotificationData.Entry;
134 import com.android.systemui.statusbar.NotificationOverflowContainer;
135 import com.android.systemui.statusbar.ScrimView;
136 import com.android.systemui.statusbar.SignalClusterView;
137 import com.android.systemui.statusbar.SpeedBumpView;
138 import com.android.systemui.statusbar.StatusBarIconView;
139 import com.android.systemui.statusbar.StatusBarState;
140 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
141 import com.android.systemui.statusbar.policy.AccessibilityController;
142 import com.android.systemui.statusbar.policy.BatteryController;
143 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
144 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
145 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
146 import com.android.systemui.statusbar.policy.CastControllerImpl;
147 import com.android.systemui.statusbar.policy.FlashlightController;
148 import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
149 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
150 import com.android.systemui.statusbar.policy.KeyButtonView;
151 import com.android.systemui.statusbar.policy.KeyguardMonitor;
152 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
153 import com.android.systemui.statusbar.policy.LocationControllerImpl;
154 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
155 import com.android.systemui.statusbar.policy.NextAlarmController;
156 import com.android.systemui.statusbar.policy.PreviewInflater;
157 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
158 import com.android.systemui.statusbar.policy.SecurityControllerImpl;
159 import com.android.systemui.statusbar.policy.UserInfoController;
160 import com.android.systemui.statusbar.policy.UserSwitcherController;
161 import com.android.systemui.statusbar.policy.ZenModeController;
162 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
163 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
164 import com.android.systemui.statusbar.stack.StackViewState;
165 import com.android.systemui.volume.VolumeComponent;
167 import java.io.FileDescriptor;
168 import java.io.PrintWriter;
169 import java.util.ArrayList;
170 import java.util.Collection;
171 import java.util.Collections;
172 import java.util.HashMap;
173 import java.util.List;
174 import java.util.Map;
176 public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
177 DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener {
178 static final String TAG = "PhoneStatusBar";
179 public static final boolean DEBUG = BaseStatusBar.DEBUG;
180 public static final boolean SPEW = false;
181 public static final boolean DUMPTRUCK = true; // extra dumpsys info
182 public static final boolean DEBUG_GESTURES = false;
183 public static final boolean DEBUG_MEDIA = false;
184 public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
186 public static final boolean DEBUG_WINDOW_STATE = false;
188 // additional instrumentation for testing purposes; intended to be left on during development
189 public static final boolean CHATTY = DEBUG;
191 public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
193 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
194 private static final int MSG_CLOSE_PANELS = 1001;
195 private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
196 private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
197 // 1020-1040 reserved for BaseStatusBar
199 // Time after we abort the launch transition.
200 private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
202 private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
204 private static final int STATUS_OR_NAV_TRANSIENT =
205 View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
206 private static final long AUTOHIDE_TIMEOUT_MS = 3000;
208 /** The minimum delay in ms between reports of notification visibility. */
209 private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
212 * The delay to reset the hint text when the hint animation is finished running.
214 private static final int HINT_RESET_DELAY_MS = 1200;
216 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
217 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
218 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
221 public static final int FADE_KEYGUARD_START_DELAY = 100;
222 public static final int FADE_KEYGUARD_DURATION = 300;
224 /** Allow some time inbetween the long press for back and recents. */
225 private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
227 PhoneStatusBarPolicy mIconPolicy;
229 // These are no longer handled by the policy, because we need custom strategies for them
230 BluetoothControllerImpl mBluetoothController;
231 SecurityControllerImpl mSecurityController;
232 BatteryController mBatteryController;
233 LocationControllerImpl mLocationController;
234 NetworkControllerImpl mNetworkController;
235 HotspotControllerImpl mHotspotController;
236 RotationLockControllerImpl mRotationLockController;
237 UserInfoController mUserInfoController;
238 ZenModeController mZenModeController;
239 CastControllerImpl mCastController;
240 VolumeComponent mVolumeComponent;
241 KeyguardUserSwitcher mKeyguardUserSwitcher;
242 FlashlightController mFlashlightController;
243 UserSwitcherController mUserSwitcherController;
244 NextAlarmController mNextAlarmController;
245 KeyguardMonitor mKeyguardMonitor;
246 BrightnessMirrorController mBrightnessMirrorController;
247 AccessibilityController mAccessibilityController;
249 int mNaturalBarHeight = -1;
252 Point mCurrentDisplaySize = new Point();
254 StatusBarWindowView mStatusBarWindow;
255 PhoneStatusBarView mStatusBarView;
256 private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
257 private StatusBarWindowManager mStatusBarWindowManager;
258 private UnlockMethodCache mUnlockMethodCache;
259 private DozeServiceHost mDozeServiceHost;
260 private boolean mScreenOnComingFromTouch;
261 private PointF mScreenOnTouchLocation;
264 Object mQueueLock = new Object();
266 StatusBarIconController mIconController;
268 // expanded notifications
269 NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
270 View mExpandedContents;
271 TextView mNotificationPanelDebugText;
274 private QSPanel mQSPanel;
277 StatusBarHeaderView mHeader;
278 KeyguardStatusBarView mKeyguardStatusBar;
279 View mKeyguardStatusView;
280 KeyguardBottomAreaView mKeyguardBottomArea;
281 boolean mLeaveOpenOnKeyguardHide;
282 KeyguardIndicationController mKeyguardIndicationController;
284 private boolean mKeyguardFadingAway;
285 private long mKeyguardFadingAwayDelay;
286 private long mKeyguardFadingAwayDuration;
288 int mKeyguardMaxNotificationCount;
290 boolean mExpandedVisible;
292 private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
295 int mTrackingPosition; // the position of the top of the tracking view.
297 // Tracking finger for opening/closing.
298 int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
300 VelocityTracker mVelocityTracker;
302 int[] mAbsPos = new int[2];
303 ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
305 // for disabling the status bar
308 // tracking calls to View.setSystemUiVisibility()
309 int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
311 DisplayMetrics mDisplayMetrics = new DisplayMetrics();
313 // XXX: gesture research
314 private final GestureRecorder mGestureRec = DEBUG_GESTURES
315 ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
318 private ScreenPinningRequest mScreenPinningRequest;
320 private int mNavigationIconHints = 0;
321 private HandlerThread mHandlerThread;
323 // ensure quick settings is disabled until the current user makes it through the setup wizard
324 private boolean mUserSetup = false;
325 private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
327 public void onChange(boolean selfChange) {
328 final boolean userSetup = 0 != Settings.Secure.getIntForUser(
329 mContext.getContentResolver(),
330 Settings.Secure.USER_SETUP_COMPLETE,
333 if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
334 "selfChange=%s userSetup=%s mUserSetup=%s",
335 selfChange, userSetup, mUserSetup));
337 if (userSetup != mUserSetup) {
338 mUserSetup = userSetup;
339 if (!mUserSetup && mStatusBarView != null)
340 animateCollapseQuickSettings();
345 final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
347 public void onChange(boolean selfChange) {
348 boolean wasUsing = mUseHeadsUp;
349 mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts
350 && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
351 mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
352 Settings.Global.HEADS_UP_OFF);
353 mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt(
354 mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0);
355 Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
356 if (wasUsing != mUseHeadsUp) {
358 Log.d(TAG, "dismissing any existing heads up notification on disable event");
359 setHeadsUpVisibility(false);
360 mHeadsUpNotificationView.releaseImmediately();
369 private int mInteractingWindows;
370 private boolean mAutohideSuspended;
371 private int mStatusBarMode;
372 private int mNavigationBarMode;
374 private ViewMediatorCallback mKeyguardViewMediatorCallback;
375 private ScrimController mScrimController;
376 private DozeScrimController mDozeScrimController;
378 private final Runnable mAutohide = new Runnable() {
381 int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
382 if (mSystemUiVisibility != requested) {
383 notifyUiVisibilityChanged(requested);
387 private boolean mWaitingForKeyguardExit;
388 private boolean mDozing;
389 private boolean mScrimSrcModeEnabled;
391 private Interpolator mLinearInterpolator = new LinearInterpolator();
392 private Interpolator mBackdropInterpolator = new AccelerateDecelerateInterpolator();
393 public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
394 public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
396 private BackDropView mBackdrop;
397 private ImageView mBackdropFront, mBackdropBack;
398 private PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
399 private PorterDuffXfermode mSrcOverXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
401 private MediaSessionManager mMediaSessionManager;
402 private MediaController mMediaController;
403 private String mMediaNotificationKey;
404 private MediaMetadata mMediaMetadata;
405 private MediaController.Callback mMediaListener
406 = new MediaController.Callback() {
408 public void onPlaybackStateChanged(PlaybackState state) {
409 super.onPlaybackStateChanged(state);
410 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state);
414 public void onMetadataChanged(MediaMetadata metadata) {
415 super.onMetadataChanged(metadata);
416 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
417 mMediaMetadata = metadata;
418 updateMediaMetaData(true);
422 private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
423 new OnChildLocationsChangedListener() {
425 public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) {
430 private int mDisabledUnmodified;
432 /** Keys of notifications currently visible to the user. */
433 private final ArraySet<String> mCurrentlyVisibleNotifications = new ArraySet<String>();
434 private long mLastVisibilityReportUptimeMs;
436 private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
438 private int mDrawCount;
439 private Runnable mLaunchTransitionEndRunnable;
440 private boolean mLaunchTransitionFadingAway;
441 private ExpandableNotificationRow mDraggedDownRow;
443 // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
444 private int mLastLoggedStateFingerprint;
446 private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD
447 | StackViewState.LOCATION_TOP_STACK_PEEKING
448 | StackViewState.LOCATION_MAIN_AREA
449 | StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
451 private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
452 new OnChildLocationsChangedListener() {
454 public void onChildLocationsChanged(
455 NotificationStackScrollLayout stackScrollLayout) {
456 if (mHandler.hasCallbacks(mVisibilityReporter)) {
457 // Visibilities will be reported when the existing
458 // callback is executed.
461 // Calculate when we're allowed to run the visibility
462 // reporter. Note that this timestamp might already have
463 // passed. That's OK, the callback will just be executed
465 long nextReportUptimeMs =
466 mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS;
467 mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs);
471 // Tracks notifications currently visible in mNotificationStackScroller and
472 // emits visibility events via NoMan on changes.
473 private final Runnable mVisibilityReporter = new Runnable() {
474 private final ArrayList<String> mTmpNewlyVisibleNotifications = new ArrayList<String>();
475 private final ArrayList<String> mTmpCurrentlyVisibleNotifications = new ArrayList<String>();
479 mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
481 // 1. Loop over mNotificationData entries:
482 // A. Keep list of visible notifications.
483 // B. Keep list of previously hidden, now visible notifications.
484 // 2. Compute no-longer visible notifications by removing currently
485 // visible notifications from the set of previously visible
487 // 3. Report newly visible and no-longer visible notifications.
488 // 4. Keep currently visible notifications for next report.
489 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
490 int N = activeNotifications.size();
491 for (int i = 0; i < N; i++) {
492 Entry entry = activeNotifications.get(i);
493 String key = entry.notification.getKey();
494 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(key);
495 boolean currentlyVisible =
496 (mStackScroller.getChildLocation(entry.row) & VISIBLE_LOCATIONS) != 0;
497 if (currentlyVisible) {
498 // Build new set of visible notifications.
499 mTmpCurrentlyVisibleNotifications.add(key);
501 if (!previouslyVisible && currentlyVisible) {
502 mTmpNewlyVisibleNotifications.add(key);
505 ArraySet<String> noLongerVisibleNotifications = mCurrentlyVisibleNotifications;
506 noLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
508 logNotificationVisibilityChanges(
509 mTmpNewlyVisibleNotifications, noLongerVisibleNotifications);
511 mCurrentlyVisibleNotifications.clear();
512 mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
514 mTmpNewlyVisibleNotifications.clear();
515 mTmpCurrentlyVisibleNotifications.clear();
519 private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
521 public void onClick(View v) {
522 goToLockedShade(null);
525 private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap
529 public void start() {
530 mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
531 .getDefaultDisplay();
533 mScrimSrcModeEnabled = mContext.getResources().getBoolean(
534 R.bool.config_status_bar_scrim_behind_use_src);
536 super.start(); // calls createAndAddWindows()
539 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
540 // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
545 // Lastly, call to the icon policy to install/update all the icons.
546 mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController);
547 mSettingsObserver.onChange(false); // set up
549 mHeadsUpObserver.onChange(true); // set up
550 if (ENABLE_HEADS_UP) {
551 mContext.getContentResolver().registerContentObserver(
552 Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true,
554 mContext.getContentResolver().registerContentObserver(
555 Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
558 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
559 mUnlockMethodCache.addListener(this);
562 mDozeServiceHost = new DozeServiceHost();
563 putComponent(DozeHost.class, mDozeServiceHost);
564 putComponent(PhoneStatusBar.class, this);
566 setControllerUsers();
568 notifyUserAboutHiddenNotifications();
570 mScreenPinningRequest = new ScreenPinningRequest(mContext);
573 // ================================================================================
574 // Constructing the view
575 // ================================================================================
576 protected PhoneStatusBarView makeStatusBarView() {
577 final Context context = mContext;
579 Resources res = context.getResources();
581 updateDisplaySize(); // populates mDisplayMetrics
584 mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
585 R.layout.super_status_bar, null);
586 mStatusBarWindow.mService = this;
587 mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
589 public boolean onTouch(View v, MotionEvent event) {
590 checkUserAutohide(v, event);
591 if (event.getAction() == MotionEvent.ACTION_DOWN) {
592 if (mExpandedVisible) {
593 animateCollapsePanels();
596 return mStatusBarWindow.onTouchEvent(event);
599 mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
600 mStatusBarView.setBar(this);
602 PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
603 mStatusBarView.setPanelHolder(holder);
605 mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
606 R.id.notification_panel);
607 mNotificationPanel.setStatusBar(this);
609 if (!ActivityManager.isHighEndGfx()) {
610 mStatusBarWindow.setBackground(null);
611 mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
612 R.color.notification_panel_solid_background)));
614 if (ENABLE_HEADS_UP) {
615 mHeadsUpNotificationView =
616 (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up, null);
617 mHeadsUpNotificationView.setVisibility(View.GONE);
618 mHeadsUpNotificationView.setBar(this);
620 if (MULTIUSER_DEBUG) {
621 mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
622 R.id.header_debug_info);
623 mNotificationPanelDebugText.setVisibility(View.VISIBLE);
626 updateShowSearchHoldoff();
629 boolean showNav = mWindowManagerService.hasNavigationBar();
630 if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
633 (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
635 mNavigationBarView.setDisabledFlags(mDisabled);
636 mNavigationBarView.setBar(this);
637 mNavigationBarView.setOnVerticalChangedListener(
638 new NavigationBarView.OnVerticalChangedListener() {
640 public void onVerticalChanged(boolean isVertical) {
641 if (mSearchPanelView != null) {
642 mSearchPanelView.setHorizontal(isVertical);
644 mNotificationPanel.setQsScrimEnabled(!isVertical);
647 mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
649 public boolean onTouch(View v, MotionEvent event) {
650 checkUserAutohide(v, event);
654 } catch (RemoteException ex) {
655 // no window manager? good luck with that
658 // figure out which pixel-format to use for the status bar.
659 mPixelFormat = PixelFormat.OPAQUE;
661 mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
662 R.id.notification_stack_scroller);
663 mStackScroller.setLongPressListener(getNotificationLongClicker());
664 mStackScroller.setPhoneStatusBar(this);
665 mStackScroller.setGroupManager(mGroupManager);
666 mGroupManager.setOnGroupChangeListener(mStackScroller);
668 mKeyguardIconOverflowContainer =
669 (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
670 R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
671 mKeyguardIconOverflowContainer.setOnActivatedListener(this);
672 mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
673 mStackScroller.addView(mKeyguardIconOverflowContainer);
675 SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
676 R.layout.status_bar_notification_speed_bump, mStackScroller, false);
677 mStackScroller.setSpeedBumpView(speedBump);
678 mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
679 R.layout.status_bar_no_notifications, mStackScroller, false);
680 mStackScroller.setEmptyShadeView(mEmptyShadeView);
681 mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
682 R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
683 mDismissView.setOnButtonClickListener(new View.OnClickListener() {
685 public void onClick(View v) {
686 clearAllNotifications();
689 mStackScroller.setDismissView(mDismissView);
690 mExpandedContents = mStackScroller;
692 mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
693 mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
694 mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
696 ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
697 ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
698 mScrimController = new ScrimController(scrimBehind, scrimInFront, mScrimSrcModeEnabled);
699 mScrimController.setBackDropView(mBackdrop);
700 mStatusBarView.setScrimController(mScrimController);
701 mDozeScrimController = new DozeScrimController(mScrimController, context);
703 mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
704 mHeader.setActivityStarter(this);
705 mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
706 mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
707 mKeyguardBottomArea =
708 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
709 mKeyguardBottomArea.setActivityStarter(this);
710 mKeyguardIndicationController = new KeyguardIndicationController(mContext,
711 (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
712 R.id.keyguard_indication_text));
713 mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
715 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
717 // set the inital view visibility
718 setAreThereNotifications();
720 mIconController = new StatusBarIconController(
721 mContext, mStatusBarView, mKeyguardStatusBar, this);
723 // Background thread for any controllers that need it.
724 mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
725 mHandlerThread.start();
728 mLocationController = new LocationControllerImpl(mContext); // will post a notification
729 mBatteryController = new BatteryController(mContext);
730 mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
732 public void onPowerSaveChanged() {
733 mHandler.post(mCheckBarModes);
734 if (mDozeServiceHost != null) {
735 mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave());
739 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
743 mNetworkController = new NetworkControllerImpl(mContext);
744 mHotspotController = new HotspotControllerImpl(mContext);
745 mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());
746 mSecurityController = new SecurityControllerImpl(mContext);
747 if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
748 mRotationLockController = new RotationLockControllerImpl(mContext);
750 mUserInfoController = new UserInfoController(mContext);
751 mVolumeComponent = getComponent(VolumeComponent.class);
752 if (mVolumeComponent != null) {
753 mZenModeController = mVolumeComponent.getZenController();
755 mCastController = new CastControllerImpl(mContext);
756 final SignalClusterView signalCluster =
757 (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
758 final SignalClusterView signalClusterKeyguard =
759 (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
760 final SignalClusterView signalClusterQs =
761 (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
762 mNetworkController.addSignalCluster(signalCluster);
763 mNetworkController.addSignalCluster(signalClusterKeyguard);
764 mNetworkController.addSignalCluster(signalClusterQs);
765 signalCluster.setSecurityController(mSecurityController);
766 signalCluster.setNetworkController(mNetworkController);
767 signalClusterKeyguard.setSecurityController(mSecurityController);
768 signalClusterKeyguard.setNetworkController(mNetworkController);
769 signalClusterQs.setSecurityController(mSecurityController);
770 signalClusterQs.setNetworkController(mNetworkController);
771 final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
773 mNetworkController.addEmergencyListener(new NetworkControllerImpl.EmergencyListener() {
775 public void setEmergencyCallsOnly(boolean emergencyOnly) {
776 mHeader.setShowEmergencyCallsOnly(emergencyOnly);
781 mFlashlightController = new FlashlightController(mContext);
782 mKeyguardBottomArea.setFlashlightController(mFlashlightController);
783 mKeyguardBottomArea.setPhoneStatusBar(this);
784 mAccessibilityController = new AccessibilityController(mContext);
785 mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
786 mNextAlarmController = new NextAlarmController(mContext);
787 mKeyguardMonitor = new KeyguardMonitor();
788 if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) {
789 mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor);
791 mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
792 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
793 mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
796 // Set up the quick settings tile panel
797 mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
798 if (mQSPanel != null) {
799 final QSTileHost qsh = new QSTileHost(mContext, this,
800 mBluetoothController, mLocationController, mRotationLockController,
801 mNetworkController, mZenModeController, mHotspotController,
802 mCastController, mFlashlightController,
803 mUserSwitcherController, mKeyguardMonitor,
804 mSecurityController);
805 mQSPanel.setHost(qsh);
806 mQSPanel.setTiles(qsh.getTiles());
807 mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
808 mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
809 mHeader.setQSPanel(mQSPanel);
810 qsh.setCallback(new QSTileHost.Callback() {
812 public void onTilesChanged() {
813 mQSPanel.setTiles(qsh.getTiles());
818 // User info. Trigger first load.
819 mHeader.setUserInfoController(mUserInfoController);
820 mKeyguardStatusBar.setUserInfoController(mUserInfoController);
821 mUserInfoController.reloadUserInfo();
823 mHeader.setBatteryController(mBatteryController);
824 ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
826 mKeyguardStatusBar.setBatteryController(mBatteryController);
827 mHeader.setNextAlarmController(mNextAlarmController);
829 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
830 mBroadcastReceiver.onReceive(mContext,
831 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
833 // receive broadcasts
834 IntentFilter filter = new IntentFilter();
835 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
836 filter.addAction(Intent.ACTION_SCREEN_OFF);
837 filter.addAction(Intent.ACTION_SCREEN_ON);
838 if (DEBUG_MEDIA_FAKE_ARTWORK) {
839 filter.addAction("fake_artwork");
841 filter.addAction(ACTION_DEMO);
842 context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
844 // listen for USER_SETUP_COMPLETE setting (per-user)
845 resetUserSetupObserver();
847 return mStatusBarView;
850 private void clearAllNotifications() {
852 // animate-swipe all dismissable notifications, then animate the shade closed
853 int numChildren = mStackScroller.getChildCount();
855 final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren);
856 for (int i = 0; i < numChildren; i++) {
857 final View child = mStackScroller.getChildAt(i);
858 if (child instanceof ExpandableNotificationRow) {
859 if (mStackScroller.canChildBeDismissed(child)) {
860 if (child.getVisibility() == View.VISIBLE) {
861 viewsToHide.add(child);
864 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
865 List<ExpandableNotificationRow> children = row.getNotificationChildren();
866 if (row.areChildrenExpanded() && children != null) {
867 for (ExpandableNotificationRow childRow : children) {
868 if (childRow.getVisibility() == View.VISIBLE) {
869 viewsToHide.add(childRow);
875 if (viewsToHide.isEmpty()) {
876 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
880 addPostCollapseAction(new Runnable() {
884 mBarService.onClearAllNotifications(mCurrentUserId);
885 } catch (Exception ex) { }
889 performDismissAllAnimations(viewsToHide);
893 private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
894 Runnable animationFinishAction = new Runnable() {
897 mStackScroller.post(new Runnable() {
900 mStackScroller.setDismissAllInProgress(false);
903 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
907 // let's disable our normal animations
908 mStackScroller.setDismissAllInProgress(true);
910 // Decrease the delay for every row we animate to give the sense of
911 // accelerating the swipes
912 int rowDelayDecrement = 10;
913 int currentDelay = 140;
914 int totalDelay = 180;
915 int numItems = hideAnimatedList.size();
916 for (int i = numItems - 1; i >= 0; i--) {
917 View view = hideAnimatedList.get(i);
918 Runnable endRunnable = null;
920 endRunnable = animationFinishAction;
922 mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260);
923 currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
924 totalDelay += currentDelay;
929 protected void setZenMode(int mode) {
930 super.setZenMode(mode);
931 if (mIconPolicy != null) {
932 mIconPolicy.setZenMode(mode);
936 private void startKeyguard() {
937 KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
938 mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
939 mStatusBarWindow, mStatusBarWindowManager, mScrimController);
940 mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
944 protected View getStatusBarView() {
945 return mStatusBarView;
948 public StatusBarWindowView getStatusBarWindow() {
949 return mStatusBarWindow;
953 protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
954 boolean opaque = false;
955 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
956 LayoutParams.MATCH_PARENT,
957 LayoutParams.MATCH_PARENT,
958 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
959 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
960 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
961 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
962 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
963 if (ActivityManager.isHighEndGfx()) {
964 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
966 lp.gravity = Gravity.BOTTOM | Gravity.START;
967 lp.setTitle("SearchPanel");
968 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
969 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
974 protected void updateSearchPanel() {
975 super.updateSearchPanel();
976 if (mNavigationBarView != null) {
977 mNavigationBarView.setDelegateView(mSearchPanelView);
982 public void showSearchPanel() {
983 super.showSearchPanel();
984 mHandler.removeCallbacks(mShowSearchPanel);
986 // we want to freeze the sysui state wherever it is
987 mSearchPanelView.setSystemUiVisibility(mSystemUiVisibility);
989 if (mNavigationBarView != null) {
990 WindowManager.LayoutParams lp =
991 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
992 lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
993 mWindowManager.updateViewLayout(mNavigationBarView, lp);
998 public void hideSearchPanel() {
999 super.hideSearchPanel();
1000 if (mNavigationBarView != null) {
1001 WindowManager.LayoutParams lp =
1002 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
1003 lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
1004 mWindowManager.updateViewLayout(mNavigationBarView, lp);
1008 public int getStatusBarHeight() {
1009 if (mNaturalBarHeight < 0) {
1010 final Resources res = mContext.getResources();
1012 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
1014 return mNaturalBarHeight;
1017 private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
1018 public void onClick(View v) {
1024 private long mLastLockToAppLongPress;
1025 private View.OnLongClickListener mLongPressBackRecentsListener =
1026 new View.OnLongClickListener() {
1028 public boolean onLongClick(View v) {
1029 handleLongPressBackRecents(v);
1034 private int mShowSearchHoldoff = 0;
1035 private Runnable mShowSearchPanel = new Runnable() {
1042 View.OnTouchListener mHomeActionListener = new View.OnTouchListener() {
1043 public boolean onTouch(View v, MotionEvent event) {
1044 switch(event.getAction()) {
1045 case MotionEvent.ACTION_DOWN:
1046 if (!shouldDisableNavbarGestures()) {
1047 mHandler.removeCallbacks(mShowSearchPanel);
1048 mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
1052 case MotionEvent.ACTION_UP:
1053 case MotionEvent.ACTION_CANCEL:
1054 mHandler.removeCallbacks(mShowSearchPanel);
1062 private void awakenDreams() {
1063 if (mDreamManager != null) {
1065 mDreamManager.awaken();
1066 } catch (RemoteException e) {
1067 // fine, stay asleep then
1072 private void prepareNavigationBarView() {
1073 mNavigationBarView.reorient();
1075 mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
1076 mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
1077 mNavigationBarView.getRecentsButton().setLongClickable(true);
1078 mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);
1079 mNavigationBarView.getBackButton().setLongClickable(true);
1080 mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
1081 mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
1082 updateSearchPanel();
1085 // For small-screen devices (read: phones) that lack hardware navigation buttons
1086 private void addNavigationBar() {
1087 if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
1088 if (mNavigationBarView == null) return;
1090 prepareNavigationBarView();
1092 mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
1095 private void repositionNavigationBar() {
1096 if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
1098 prepareNavigationBarView();
1100 mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams());
1103 private void notifyNavigationBarScreenOn(boolean screenOn) {
1104 if (mNavigationBarView == null) return;
1105 mNavigationBarView.notifyScreenOn(screenOn);
1108 private WindowManager.LayoutParams getNavigationBarLayoutParams() {
1109 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
1110 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
1111 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
1113 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
1114 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1115 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
1116 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
1117 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
1118 PixelFormat.TRANSLUCENT);
1119 // this will allow the navbar to run in an overlay on devices that support this
1120 if (ActivityManager.isHighEndGfx()) {
1121 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
1124 lp.setTitle("NavigationBar");
1125 lp.windowAnimations = 0;
1129 private void addHeadsUpView() {
1130 int headsUpHeight = mContext.getResources()
1131 .getDimensionPixelSize(R.dimen.heads_up_window_height);
1132 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
1133 LayoutParams.MATCH_PARENT, headsUpHeight,
1134 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar!
1135 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
1136 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
1137 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
1138 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1139 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
1140 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
1141 PixelFormat.TRANSLUCENT);
1142 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
1143 lp.gravity = Gravity.TOP;
1144 lp.setTitle("Heads Up");
1145 lp.packageName = mContext.getPackageName();
1146 lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp;
1148 mWindowManager.addView(mHeadsUpNotificationView, lp);
1151 private void removeHeadsUpView() {
1152 mWindowManager.removeView(mHeadsUpNotificationView);
1155 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
1156 mIconController.addSystemIcon(slot, index, viewIndex, icon);
1159 public void updateIcon(String slot, int index, int viewIndex,
1160 StatusBarIcon old, StatusBarIcon icon) {
1161 mIconController.updateSystemIcon(slot, index, viewIndex, old, icon);
1164 public void removeIcon(String slot, int index, int viewIndex) {
1165 mIconController.removeSystemIcon(slot, index, viewIndex);
1168 public UserHandle getCurrentUserHandle() {
1169 return new UserHandle(mCurrentUserId);
1173 public void addNotification(StatusBarNotification notification, RankingMap ranking,
1175 if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
1176 if (mUseHeadsUp && shouldInterrupt(notification)) {
1177 if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
1178 Entry interruptionCandidate = oldEntry;
1179 if (interruptionCandidate == null) {
1180 final StatusBarIconView iconView = createIcon(notification);
1181 if (iconView == null) {
1184 interruptionCandidate = new Entry(notification, iconView);
1186 ViewGroup holder = mHeadsUpNotificationView.getHolder();
1187 if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
1188 // 1. Populate mHeadsUpNotificationView
1189 mHeadsUpNotificationView.showNotification(interruptionCandidate);
1191 // do not show the notification in the shade, yet.
1196 Entry shadeEntry = createNotificationViews(notification);
1197 if (shadeEntry == null) {
1201 if (notification.getNotification().fullScreenIntent != null) {
1202 // Stop screensaver if the notification has a full-screen intent.
1203 // (like an incoming phone call)
1206 // not immersive & a full-screen alert should be shown
1207 if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
1209 EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
1210 notification.getKey());
1211 notification.getNotification().fullScreenIntent.send();
1212 } catch (PendingIntent.CanceledException e) {
1215 addNotificationViews(shadeEntry, ranking);
1216 // Recalculate the position of the sliding windows and the titles.
1217 setAreThereNotifications();
1220 public void displayNotificationFromHeadsUp(Entry shadeEntry) {
1222 // The notification comes from the headsup, let's inflate the normal layout again
1223 inflateViews(shadeEntry, mStackScroller);
1224 shadeEntry.setInterruption();
1225 shadeEntry.row.setHeadsUp(false);
1227 addNotificationViews(shadeEntry, null);
1228 // Recalculate the position of the sliding windows and the titles.
1229 setAreThereNotifications();
1233 protected void updateNotificationRanking(RankingMap ranking) {
1234 mNotificationData.updateRanking(ranking);
1235 updateNotifications();
1239 public void removeNotification(String key, RankingMap ranking) {
1240 if (ENABLE_HEADS_UP) {
1241 mHeadsUpNotificationView.removeNotification(key);
1244 StatusBarNotification old = removeNotificationViews(key, ranking);
1245 if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
1248 if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
1249 && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
1250 if (mState == StatusBarState.SHADE) {
1251 animateCollapsePanels();
1252 } else if (mState == StatusBarState.SHADE_LOCKED) {
1257 setAreThereNotifications();
1261 protected void refreshLayout(int layoutDirection) {
1262 if (mNavigationBarView != null) {
1263 mNavigationBarView.setLayoutDirection(layoutDirection);
1267 private void updateShowSearchHoldoff() {
1268 mShowSearchHoldoff = mContext.getResources().getInteger(
1269 R.integer.config_show_search_delay);
1272 private void updateNotificationShade() {
1273 if (mStackScroller == null) return;
1275 // Do not modify the notifications during collapse.
1276 if (isCollapsing()) {
1277 addPostCollapseAction(new Runnable() {
1280 updateNotificationShade();
1286 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1287 ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
1288 final int N = activeNotifications.size();
1289 for (int i=0; i<N; i++) {
1290 Entry ent = activeNotifications.get(i);
1291 int vis = ent.notification.getNotification().visibility;
1293 // Display public version of the notification if we need to redact.
1294 final boolean hideSensitive =
1295 !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
1296 boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE;
1297 boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
1298 boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
1299 boolean showingPublic = sensitive && isLockscreenPublicMode();
1300 ent.row.setSensitive(sensitive);
1301 if (ent.autoRedacted && ent.legacy) {
1302 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
1303 // for legacy auto redacted notifications.
1304 if (showingPublic) {
1305 ent.row.setShowingLegacyBackground(false);
1307 ent.row.setShowingLegacyBackground(true);
1310 if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
1311 ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
1312 ent.row.getStatusBarNotification());
1313 List<ExpandableNotificationRow> orderedChildren =
1314 mTmpChildOrderMap.get(summary);
1315 if (orderedChildren == null) {
1316 orderedChildren = new ArrayList<>();
1317 mTmpChildOrderMap.put(summary, orderedChildren);
1319 orderedChildren.add(ent.row);
1321 toShow.add(ent.row);
1326 ArrayList<View> toRemove = new ArrayList<>();
1327 for (int i=0; i< mStackScroller.getChildCount(); i++) {
1328 View child = mStackScroller.getChildAt(i);
1329 if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
1330 toRemove.add(child);
1334 for (View remove : toRemove) {
1335 mStackScroller.removeView(remove);
1337 for (int i=0; i<toShow.size(); i++) {
1338 View v = toShow.get(i);
1339 if (v.getParent() == null) {
1340 mStackScroller.addView(v);
1344 // So after all this work notifications still aren't sorted correctly.
1345 // Let's do that now by advancing through toShow and mStackScroller in
1346 // lock-step, making sure mStackScroller matches what we see in toShow.
1348 for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1349 View child = mStackScroller.getChildAt(i);
1350 if (!(child instanceof ExpandableNotificationRow)) {
1351 // We don't care about non-notification views.
1355 ExpandableNotificationRow targetChild = toShow.get(j);
1356 if (child != targetChild) {
1357 // Oops, wrong notification at this position. Put the right one
1358 // here and advance both lists.
1359 mStackScroller.changeViewPosition(targetChild, i);
1365 // lets handle the child notifications now
1366 updateNotificationShadeForChildren();
1368 // clear the map again for the next usage
1369 mTmpChildOrderMap.clear();
1374 updateEmptyShadeView();
1376 // Disable QS if device not provisioned.
1377 // If the user switcher is simple then disable QS during setup because
1378 // the user intends to use the lock screen user switcher, QS in not needed.
1379 mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
1380 && (mUserSetup || mUserSwitcherController == null
1381 || !mUserSwitcherController.isSimpleUserSwitcher()));
1382 mShadeUpdates.check();
1385 private void updateNotificationShadeForChildren() {
1386 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
1387 boolean orderChanged = false;
1388 for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1389 View view = mStackScroller.getChildAt(i);
1390 if (!(view instanceof ExpandableNotificationRow)) {
1391 // We don't care about non-notification views.
1395 ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
1396 List<ExpandableNotificationRow> children = parent.getNotificationChildren();
1397 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
1399 // lets first remove all undesired children
1400 if (children != null) {
1402 for (ExpandableNotificationRow childRow : children) {
1403 if (orderedChildren == null || !orderedChildren.contains(childRow)) {
1404 toRemove.add(childRow);
1407 for (ExpandableNotificationRow remove : toRemove) {
1408 parent.removeChildNotification(remove);
1409 mStackScroller.notifyGroupChildRemoved(remove);
1413 // We now add all the children which are not in there already
1414 for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
1416 ExpandableNotificationRow childView = orderedChildren.get(childIndex);
1417 if (children == null || !children.contains(childView)) {
1418 parent.addChildNotification(childView, childIndex);
1419 mStackScroller.notifyGroupChildAdded(childView);
1423 // Finally after removing and adding has been beformed we can apply the order.
1424 orderChanged |= parent.applyChildOrder(orderedChildren);
1427 mStackScroller.generateChildOrderChangedEvent();
1431 private boolean packageHasVisibilityOverride(String key) {
1432 return mNotificationData.getVisibilityOverride(key)
1433 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
1436 private void updateClearAll() {
1437 boolean showDismissView =
1438 mState != StatusBarState.KEYGUARD &&
1439 mNotificationData.hasActiveClearableNotifications();
1440 mStackScroller.updateDismissView(showDismissView);
1443 private void updateEmptyShadeView() {
1444 boolean showEmptyShade =
1445 mState != StatusBarState.KEYGUARD &&
1446 mNotificationData.getActiveNotifications().size() == 0;
1447 mNotificationPanel.setShadeEmpty(showEmptyShade);
1450 private void updateSpeedbump() {
1451 int speedbumpIndex = -1;
1452 int currentIndex = 0;
1453 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1454 final int N = activeNotifications.size();
1455 for (int i = 0; i < N; i++) {
1456 Entry entry = activeNotifications.get(i);
1457 boolean isChild = !isTopLevelChild(entry);
1461 if (entry.row.getVisibility() != View.GONE &&
1462 mNotificationData.isAmbient(entry.key)) {
1463 speedbumpIndex = currentIndex;
1468 mStackScroller.updateSpeedBumpIndex(speedbumpIndex);
1471 public static boolean isTopLevelChild(Entry entry) {
1472 return entry.row.getParent() instanceof NotificationStackScrollLayout;
1476 protected void updateNotifications() {
1477 mNotificationData.filterAndSort();
1479 updateNotificationShade();
1480 mIconController.updateNotificationIcons(mNotificationData);
1484 protected void updateRowStates() {
1485 super.updateRowStates();
1486 mNotificationPanel.notifyVisibleChildrenChanged();
1490 protected void setAreThereNotifications() {
1493 final boolean clearable = hasActiveNotifications() &&
1494 mNotificationData.hasActiveClearableNotifications();
1495 Log.d(TAG, "setAreThereNotifications: N=" +
1496 mNotificationData.getActiveNotifications().size() + " any=" +
1497 hasActiveNotifications() + " clearable=" + clearable);
1500 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
1501 final boolean showDot = hasActiveNotifications() && !areLightsOn();
1502 if (showDot != (nlo.getAlpha() == 1.0f)) {
1505 nlo.setVisibility(View.VISIBLE);
1509 .setDuration(showDot?750:250)
1510 .setInterpolator(new AccelerateInterpolator(2.0f))
1511 .setListener(showDot ? null : new AnimatorListenerAdapter() {
1513 public void onAnimationEnd(Animator _a) {
1514 nlo.setVisibility(View.GONE);
1520 findAndUpdateMediaNotifications();
1523 public void findAndUpdateMediaNotifications() {
1524 boolean metaDataChanged = false;
1526 synchronized (mNotificationData) {
1527 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1528 final int N = activeNotifications.size();
1529 Entry mediaNotification = null;
1530 MediaController controller = null;
1531 for (int i = 0; i < N; i++) {
1532 final Entry entry = activeNotifications.get(i);
1533 if (isMediaNotification(entry)) {
1534 final MediaSession.Token token = entry.notification.getNotification().extras
1535 .getParcelable(Notification.EXTRA_MEDIA_SESSION);
1536 if (token != null) {
1537 controller = new MediaController(mContext, token);
1538 if (controller != null) {
1539 // we've got a live one, here
1540 mediaNotification = entry;
1546 if (mediaNotification == null) {
1547 // Still nothing? OK, let's just look for live media sessions and see if they match
1548 // one of our notifications. This will catch apps that aren't (yet!) using media
1551 if (mMediaSessionManager != null) {
1552 final List<MediaController> sessions
1553 = mMediaSessionManager.getActiveSessionsForUser(
1555 UserHandle.USER_ALL);
1557 for (MediaController aController : sessions) {
1558 if (aController == null) continue;
1559 final PlaybackState state = aController.getPlaybackState();
1560 if (state == null) continue;
1561 switch (state.getState()) {
1562 case PlaybackState.STATE_STOPPED:
1563 case PlaybackState.STATE_ERROR:
1566 // now to see if we have one like this
1567 final String pkg = aController.getPackageName();
1569 for (int i = 0; i < N; i++) {
1570 final Entry entry = activeNotifications.get(i);
1571 if (entry.notification.getPackageName().equals(pkg)) {
1573 Log.v(TAG, "DEBUG_MEDIA: found controller matching "
1574 + entry.notification.getKey());
1576 controller = aController;
1577 mediaNotification = entry;
1586 if (!sameSessions(mMediaController, controller)) {
1587 // We have a new media session
1589 if (mMediaController != null) {
1590 // something old was playing
1591 Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
1592 + mMediaController);
1593 mMediaController.unregisterCallback(mMediaListener);
1595 mMediaController = controller;
1597 if (mMediaController != null) {
1598 mMediaController.registerCallback(mMediaListener);
1599 mMediaMetadata = mMediaController.getMetadata();
1601 Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: "
1605 final String notificationKey = mediaNotification == null
1607 : mediaNotification.notification.getKey();
1609 if (notificationKey == null || !notificationKey.equals(mMediaNotificationKey)) {
1610 // we have a new notification!
1612 Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
1613 + notificationKey + " controller=" + controller);
1615 mMediaNotificationKey = notificationKey;
1618 mMediaMetadata = null;
1619 mMediaNotificationKey = null;
1622 metaDataChanged = true;
1624 // Media session unchanged
1627 Log.v(TAG, "DEBUG_MEDIA: Continuing media notification: key=" + mMediaNotificationKey);
1632 updateMediaMetaData(metaDataChanged);
1635 private boolean sameSessions(MediaController a, MediaController b) {
1636 if (a == b) return true;
1637 if (a == null) return false;
1638 return a.controlsSameSession(b);
1642 * Hide the album artwork that is fading out and release its bitmap.
1644 private Runnable mHideBackdropFront = new Runnable() {
1648 Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
1650 mBackdropFront.setVisibility(View.INVISIBLE);
1651 mBackdropFront.animate().cancel();
1652 mBackdropFront.setImageDrawable(null);
1657 * Refresh or remove lockscreen artwork from media metadata.
1659 public void updateMediaMetaData(boolean metaDataChanged) {
1660 if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) return;
1662 if (mBackdrop == null) return; // called too early
1665 Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey
1666 + " metadata=" + mMediaMetadata
1667 + " metaDataChanged=" + metaDataChanged
1668 + " state=" + mState);
1671 Bitmap artworkBitmap = null;
1672 if (mMediaMetadata != null) {
1673 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
1674 if (artworkBitmap == null) {
1675 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
1676 // might still be null
1680 final boolean hasArtwork = artworkBitmap != null;
1682 if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
1683 && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
1684 // time to show some art!
1685 if (mBackdrop.getVisibility() != View.VISIBLE) {
1686 mBackdrop.setVisibility(View.VISIBLE);
1687 mBackdrop.animate().alpha(1f);
1688 metaDataChanged = true;
1690 Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
1693 if (metaDataChanged) {
1694 if (mBackdropBack.getDrawable() != null) {
1695 Drawable drawable = mBackdropBack.getDrawable();
1696 mBackdropFront.setImageDrawable(drawable);
1697 if (mScrimSrcModeEnabled) {
1698 mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode);
1700 mBackdropFront.setAlpha(1f);
1701 mBackdropFront.setVisibility(View.VISIBLE);
1703 mBackdropFront.setVisibility(View.INVISIBLE);
1706 if (DEBUG_MEDIA_FAKE_ARTWORK) {
1707 final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
1708 Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
1709 mBackdropBack.setBackgroundColor(0xFFFFFFFF);
1710 mBackdropBack.setImageDrawable(new ColorDrawable(c));
1712 mBackdropBack.setImageBitmap(artworkBitmap);
1714 if (mScrimSrcModeEnabled) {
1715 mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
1718 if (mBackdropFront.getVisibility() == View.VISIBLE) {
1720 Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
1721 + mBackdropFront.getDrawable()
1723 + mBackdropBack.getDrawable());
1725 mBackdropFront.animate()
1727 .alpha(0f).withEndAction(mHideBackdropFront);
1731 // need to hide the album art, either because we are unlocked or because
1732 // the metadata isn't there to support it
1733 if (mBackdrop.getVisibility() != View.GONE) {
1735 Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
1739 .setInterpolator(mBackdropInterpolator)
1742 .withEndAction(new Runnable() {
1745 mBackdrop.setVisibility(View.GONE);
1746 mBackdropFront.animate().cancel();
1747 mBackdropBack.animate().cancel();
1748 mHandler.post(mHideBackdropFront);
1751 if (mKeyguardFadingAway) {
1754 // Make it disappear faster, as the focus should be on the activity behind.
1755 .setDuration(mKeyguardFadingAwayDuration / 2)
1756 .setStartDelay(mKeyguardFadingAwayDelay)
1757 .setInterpolator(mLinearInterpolator)
1764 private int adjustDisableFlags(int state) {
1765 if (!mLaunchTransitionFadingAway
1766 && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
1767 state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
1768 state |= StatusBarManager.DISABLE_SYSTEM_INFO;
1774 * State is one or more of the DISABLE constants from StatusBarManager.
1776 public void disable(int state, boolean animate) {
1777 mDisabledUnmodified = state;
1778 state = adjustDisableFlags(state);
1779 final int old = mDisabled;
1780 final int diff = state ^ old;
1784 Log.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)",
1788 StringBuilder flagdbg = new StringBuilder();
1789 flagdbg.append("disable: < ");
1790 flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
1791 flagdbg.append(((diff & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
1792 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
1793 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
1794 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
1795 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
1796 flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
1797 flagdbg.append(((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
1798 flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
1799 flagdbg.append(((diff & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
1800 flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
1801 flagdbg.append(((diff & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
1802 flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
1803 flagdbg.append(((diff & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
1804 flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
1805 flagdbg.append(((diff & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
1806 flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
1807 flagdbg.append(((diff & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
1808 flagdbg.append(">");
1809 Log.d(TAG, flagdbg.toString());
1811 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
1812 if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
1813 mIconController.hideSystemIconArea(animate);
1815 mIconController.showSystemIconArea(animate);
1819 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
1820 boolean visible = (state & StatusBarManager.DISABLE_CLOCK) == 0;
1821 mIconController.setClockVisibility(visible);
1823 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
1824 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
1825 animateCollapsePanels();
1829 if ((diff & (StatusBarManager.DISABLE_HOME
1830 | StatusBarManager.DISABLE_RECENT
1831 | StatusBarManager.DISABLE_BACK
1832 | StatusBarManager.DISABLE_SEARCH)) != 0) {
1833 // the nav bar will take care of these
1834 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state);
1836 if ((state & StatusBarManager.DISABLE_RECENT) != 0) {
1837 // close recents if it's visible
1838 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
1839 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
1843 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
1844 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
1845 mIconController.hideNotificationIconArea(animate);
1847 mIconController.showNotificationIconArea(animate);
1851 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
1852 mDisableNotificationAlerts =
1853 (state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
1854 mHeadsUpObserver.onChange(true);
1859 protected BaseStatusBar.H createHandler() {
1860 return new PhoneStatusBar.H();
1864 public void startActivity(Intent intent, boolean dismissShade) {
1865 startActivityDismissingKeyguard(intent, false, dismissShade);
1868 public void setQsExpanded(boolean expanded) {
1869 mStatusBarWindowManager.setQsExpanded(expanded);
1872 public boolean isGoingToNotificationShade() {
1873 return mLeaveOpenOnKeyguardHide;
1876 public boolean isQsExpanded() {
1877 return mNotificationPanel.isQsExpanded();
1880 public boolean isScreenOnComingFromTouch() {
1881 return mScreenOnComingFromTouch;
1884 public boolean isFalsingThresholdNeeded() {
1885 boolean onKeyguard = getBarState() == StatusBarState.KEYGUARD;
1886 boolean isCurrentlyInsecure = mUnlockMethodCache.isCurrentlyInsecure();
1887 return onKeyguard && (isCurrentlyInsecure || mDozing || mScreenOnComingFromTouch);
1890 public boolean isDozing() {
1894 @Override // NotificationData.Environment
1895 public String getCurrentMediaNotificationKey() {
1896 return mMediaNotificationKey;
1899 public boolean isScrimSrcModeEnabled() {
1900 return mScrimSrcModeEnabled;
1904 * To be called when there's a state change in StatusBarKeyguardViewManager.
1906 public void onKeyguardViewManagerStatesUpdated() {
1907 logStateToEventlog();
1910 @Override // UnlockMethodCache.OnUnlockMethodChangedListener
1911 public void onUnlockMethodStateChanged() {
1912 logStateToEventlog();
1916 * All changes to the status bar and notifications funnel through here and are batched.
1918 private class H extends BaseStatusBar.H {
1919 public void handleMessage(Message m) {
1920 super.handleMessage(m);
1922 case MSG_OPEN_NOTIFICATION_PANEL:
1923 animateExpandNotificationsPanel();
1925 case MSG_OPEN_SETTINGS_PANEL:
1926 animateExpandSettingsPanel();
1928 case MSG_CLOSE_PANELS:
1929 animateCollapsePanels();
1931 case MSG_SHOW_HEADS_UP:
1932 setHeadsUpVisibility(true);
1934 case MSG_ESCALATE_HEADS_UP:
1936 case MSG_HIDE_HEADS_UP:
1937 mHeadsUpNotificationView.releaseImmediately();
1938 setHeadsUpVisibility(false);
1940 case MSG_LAUNCH_TRANSITION_TIMEOUT:
1941 onLaunchTransitionTimeout();
1948 public void scheduleHeadsUpDecay(long delay) {
1949 mHandler.removeMessages(MSG_HIDE_HEADS_UP);
1950 if (mHeadsUpNotificationView.isClearable()) {
1951 mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, delay);
1956 public void scheduleHeadsUpOpen() {
1957 mHandler.removeMessages(MSG_HIDE_HEADS_UP);
1958 mHandler.removeMessages(MSG_SHOW_HEADS_UP);
1959 mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
1963 public void scheduleHeadsUpClose() {
1964 mHandler.removeMessages(MSG_HIDE_HEADS_UP);
1965 if (mHeadsUpNotificationView.getVisibility() != View.GONE) {
1966 mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
1971 public void scheduleHeadsUpEscalation() {
1972 mHandler.removeMessages(MSG_HIDE_HEADS_UP);
1973 mHandler.removeMessages(MSG_ESCALATE_HEADS_UP);
1974 mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
1977 /** if the interrupting notification had a fullscreen intent, fire it now. */
1978 private void escalateHeadsUp() {
1979 if (mHeadsUpNotificationView.getEntry() != null) {
1980 final StatusBarNotification sbn = mHeadsUpNotificationView.getEntry().notification;
1981 mHeadsUpNotificationView.releaseImmediately();
1982 final Notification notification = sbn.getNotification();
1983 if (notification.fullScreenIntent != null) {
1985 Log.d(TAG, "converting a heads up to fullScreen");
1987 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
1989 notification.fullScreenIntent.send();
1990 } catch (PendingIntent.CanceledException e) {
1996 boolean panelsEnabled() {
1997 return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0;
2000 void makeExpandedVisible(boolean force) {
2001 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
2002 if (!force && (mExpandedVisible || !panelsEnabled())) {
2006 mExpandedVisible = true;
2007 if (mNavigationBarView != null)
2008 mNavigationBarView.setSlippery(true);
2010 // Expand the window to encompass the full screen in anticipation of the drag.
2011 // This is only possible to do atomically because the status bar is at the top of the screen!
2012 mStatusBarWindowManager.setStatusBarExpanded(true);
2013 mStatusBarView.setFocusable(false);
2015 visibilityChanged(true);
2016 mWaitingForKeyguardExit = false;
2017 disable(mDisabledUnmodified, !force /* animate */);
2018 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2021 public void animateCollapsePanels() {
2022 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
2025 private final Runnable mAnimateCollapsePanels = new Runnable() {
2028 animateCollapsePanels();
2032 public void postAnimateCollapsePanels() {
2033 mHandler.post(mAnimateCollapsePanels);
2036 public void animateCollapsePanels(int flags) {
2037 animateCollapsePanels(flags, false /* force */);
2040 public void animateCollapsePanels(int flags, boolean force) {
2042 (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
2043 runPostCollapseRunnables();
2047 Log.d(TAG, "animateCollapse():"
2048 + " mExpandedVisible=" + mExpandedVisible
2049 + " flags=" + flags);
2052 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
2053 if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
2054 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
2055 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
2059 if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
2060 mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
2061 mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
2064 if (mStatusBarWindow != null) {
2065 // release focus immediately to kick off focus change transition
2066 mStatusBarWindowManager.setStatusBarFocusable(false);
2068 mStatusBarWindow.cancelExpandHelper();
2069 mStatusBarView.collapseAllPanels(true);
2073 private void runPostCollapseRunnables() {
2074 int size = mPostCollapseRunnables.size();
2075 for (int i = 0; i < size; i++) {
2076 mPostCollapseRunnables.get(i).run();
2078 mPostCollapseRunnables.clear();
2081 Animator mScrollViewAnim, mClearButtonAnim;
2084 public void animateExpandNotificationsPanel() {
2085 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2086 if (!panelsEnabled()) {
2090 mNotificationPanel.expand();
2092 if (false) postStartTracing();
2096 public void animateExpandSettingsPanel() {
2097 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2098 if (!panelsEnabled()) {
2102 // Settings are not available in setup
2103 if (!mUserSetup) return;
2105 mNotificationPanel.expandWithQs();
2107 if (false) postStartTracing();
2110 public void animateCollapseQuickSettings() {
2111 if (mState == StatusBarState.SHADE) {
2112 mStatusBarView.collapseAllPanels(true);
2116 void makeExpandedInvisible() {
2117 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
2118 + " mExpandedVisible=" + mExpandedVisible);
2120 if (!mExpandedVisible || mStatusBarWindow == null) {
2124 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
2125 mStatusBarView.collapseAllPanels(/*animate=*/ false);
2127 // reset things to their proper state
2128 mStackScroller.setVisibility(View.VISIBLE);
2129 mNotificationPanel.setVisibility(View.GONE);
2131 mNotificationPanel.closeQs();
2133 mExpandedVisible = false;
2134 if (mNavigationBarView != null)
2135 mNavigationBarView.setSlippery(false);
2136 visibilityChanged(false);
2138 // Shrink the window to the size of the status bar only
2139 mStatusBarWindowManager.setStatusBarExpanded(false);
2140 mStatusBarView.setFocusable(true);
2142 // Close any "App info" popups that might have snuck on-screen
2145 runPostCollapseRunnables();
2146 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2148 disable(mDisabledUnmodified, true /* animate */);
2150 // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
2151 // the bouncer appear animation.
2152 if (!mStatusBarKeyguardViewManager.isShowing()) {
2153 WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
2157 public boolean interceptTouchEvent(MotionEvent event) {
2158 if (DEBUG_GESTURES) {
2159 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
2160 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
2161 event.getActionMasked(), (int) event.getX(), (int) event.getY(), mDisabled);
2167 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
2168 + mDisabled + " mTracking=" + mTracking);
2169 } else if (CHATTY) {
2170 if (event.getAction() != MotionEvent.ACTION_MOVE) {
2171 Log.d(TAG, String.format(
2172 "panel: %s at (%f, %f) mDisabled=0x%08x",
2173 MotionEvent.actionToString(event.getAction()),
2174 event.getRawX(), event.getRawY(), mDisabled));
2178 if (DEBUG_GESTURES) {
2179 mGestureRec.add(event);
2182 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
2183 final boolean upOrCancel =
2184 event.getAction() == MotionEvent.ACTION_UP ||
2185 event.getAction() == MotionEvent.ACTION_CANCEL;
2186 if (upOrCancel && !mExpandedVisible) {
2187 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2189 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2195 public GestureRecorder getGestureRecorder() {
2199 private void setNavigationIconHints(int hints) {
2200 if (hints == mNavigationIconHints) return;
2202 mNavigationIconHints = hints;
2204 if (mNavigationBarView != null) {
2205 mNavigationBarView.setNavigationIconHints(hints);
2210 @Override // CommandQueue
2211 public void setWindowState(int window, int state) {
2212 boolean showing = state == WINDOW_STATE_SHOWING;
2213 if (mStatusBarWindow != null
2214 && window == StatusBarManager.WINDOW_STATUS_BAR
2215 && mStatusBarWindowState != state) {
2216 mStatusBarWindowState = state;
2217 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
2218 if (!showing && mState == StatusBarState.SHADE) {
2219 mStatusBarView.collapseAllPanels(false);
2222 if (mNavigationBarView != null
2223 && window == StatusBarManager.WINDOW_NAVIGATION_BAR
2224 && mNavigationBarWindowState != state) {
2225 mNavigationBarWindowState = state;
2226 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
2230 @Override // CommandQueue
2231 public void buzzBeepBlinked() {
2232 if (mDozeServiceHost != null) {
2233 mDozeServiceHost.fireBuzzBeepBlinked();
2238 public void notificationLightOff() {
2239 if (mDozeServiceHost != null) {
2240 mDozeServiceHost.fireNotificationLight(false);
2245 public void notificationLightPulse(int argb, int onMillis, int offMillis) {
2246 if (mDozeServiceHost != null) {
2247 mDozeServiceHost.fireNotificationLight(true);
2251 @Override // CommandQueue
2252 public void setSystemUiVisibility(int vis, int mask) {
2253 final int oldVal = mSystemUiVisibility;
2254 final int newVal = (oldVal&~mask) | (vis&mask);
2255 final int diff = newVal ^ oldVal;
2256 if (DEBUG) Log.d(TAG, String.format(
2257 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
2258 Integer.toHexString(vis), Integer.toHexString(mask),
2259 Integer.toHexString(oldVal), Integer.toHexString(newVal),
2260 Integer.toHexString(diff)));
2262 // we never set the recents bit via this method, so save the prior state to prevent
2263 // clobbering the bit below
2264 final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0;
2266 mSystemUiVisibility = newVal;
2268 // update low profile
2269 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
2270 final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0;
2272 animateCollapsePanels();
2275 setAreThereNotifications();
2278 // update status bar mode
2279 final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
2280 View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT);
2282 // update navigation bar mode
2283 final int nbMode = mNavigationBarView == null ? -1 : computeBarMode(
2284 oldVal, newVal, mNavigationBarView.getBarTransitions(),
2285 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT);
2286 final boolean sbModeChanged = sbMode != -1;
2287 final boolean nbModeChanged = nbMode != -1;
2288 boolean checkBarModes = false;
2289 if (sbModeChanged && sbMode != mStatusBarMode) {
2290 mStatusBarMode = sbMode;
2291 checkBarModes = true;
2293 if (nbModeChanged && nbMode != mNavigationBarMode) {
2294 mNavigationBarMode = nbMode;
2295 checkBarModes = true;
2297 if (checkBarModes) {
2300 if (sbModeChanged || nbModeChanged) {
2301 // update transient bar autohide
2302 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
2310 if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
2311 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
2313 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
2314 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
2317 if ((diff & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 || sbModeChanged) {
2318 boolean isTransparentBar = (mStatusBarMode == MODE_TRANSPARENT
2319 || mStatusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
2320 boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
2321 boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
2323 mIconController.setIconsDark(allowLight && light);
2325 // restore the recents bit
2326 if (wasRecentsVisible) {
2327 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
2330 // send updated sysui visibility to window manager
2331 notifyUiVisibilityChanged(mSystemUiVisibility);
2335 private int computeBarMode(int oldVis, int newVis, BarTransitions transitions,
2336 int transientFlag, int translucentFlag) {
2337 final int oldMode = barMode(oldVis, transientFlag, translucentFlag);
2338 final int newMode = barMode(newVis, transientFlag, translucentFlag);
2339 if (oldMode == newMode) {
2340 return -1; // no mode change
2345 private int barMode(int vis, int transientFlag, int translucentFlag) {
2346 int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_TRANSPARENT;
2347 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
2348 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
2349 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
2350 : (vis & View.SYSTEM_UI_TRANSPARENT) != 0 ? MODE_TRANSPARENT
2351 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
2355 private void checkBarModes() {
2356 if (mDemoMode) return;
2357 checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions());
2358 if (mNavigationBarView != null) {
2359 checkBarMode(mNavigationBarMode,
2360 mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
2364 private void checkBarMode(int mode, int windowState, BarTransitions transitions) {
2365 final boolean powerSave = mBatteryController.isPowerSave();
2366 final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN
2368 if (powerSave && getBarState() == StatusBarState.SHADE) {
2369 mode = MODE_WARNING;
2371 transitions.transitionTo(mode, anim);
2374 private void finishBarAnimations() {
2375 mStatusBarView.getBarTransitions().finishAnimations();
2376 if (mNavigationBarView != null) {
2377 mNavigationBarView.getBarTransitions().finishAnimations();
2381 private final Runnable mCheckBarModes = new Runnable() {
2389 public void setInteracting(int barWindow, boolean interacting) {
2390 final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting;
2391 mInteractingWindows = interacting
2392 ? (mInteractingWindows | barWindow)
2393 : (mInteractingWindows & ~barWindow);
2394 if (mInteractingWindows != 0) {
2397 resumeSuspendedAutohide();
2399 // manually dismiss the volume panel when interacting with the nav bar
2400 if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
2401 if (mVolumeComponent != null) {
2402 mVolumeComponent.dismissNow();
2408 private void resumeSuspendedAutohide() {
2409 if (mAutohideSuspended) {
2411 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
2415 private void suspendAutohide() {
2416 mHandler.removeCallbacks(mAutohide);
2417 mHandler.removeCallbacks(mCheckBarModes);
2418 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
2421 private void cancelAutohide() {
2422 mAutohideSuspended = false;
2423 mHandler.removeCallbacks(mAutohide);
2426 private void scheduleAutohide() {
2428 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
2431 private void checkUserAutohide(View v, MotionEvent event) {
2432 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed
2433 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
2434 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars
2440 private void userAutohide() {
2442 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
2445 private boolean areLightsOn() {
2446 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
2449 public void setLightsOn(boolean on) {
2450 Log.v(TAG, "setLightsOn(" + on + ")");
2452 setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
2454 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
2458 private void notifyUiVisibilityChanged(int vis) {
2460 mWindowManagerService.statusBarVisibilityChanged(vis);
2461 } catch (RemoteException ex) {
2465 public void topAppWindowChanged(boolean showMenu) {
2467 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
2469 if (mNavigationBarView != null) {
2470 mNavigationBarView.setMenuVisibility(showMenu);
2473 // See above re: lights-out policy for legacy apps.
2474 if (showMenu) setLightsOn(true);
2478 public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
2479 boolean showImeSwitcher) {
2480 boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
2481 int flags = mNavigationIconHints;
2482 if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
2483 flags |= NAVIGATION_HINT_BACK_ALT;
2485 flags &= ~NAVIGATION_HINT_BACK_ALT;
2487 if (showImeSwitcher) {
2488 flags |= NAVIGATION_HINT_IME_SHOWN;
2490 flags &= ~NAVIGATION_HINT_IME_SHOWN;
2493 setNavigationIconHints(flags);
2496 public static String viewInfo(View v) {
2497 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
2498 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
2501 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2502 synchronized (mQueueLock) {
2503 pw.println("Current Status Bar state:");
2504 pw.println(" mExpandedVisible=" + mExpandedVisible
2505 + ", mTrackingPosition=" + mTrackingPosition);
2506 pw.println(" mTracking=" + mTracking);
2507 pw.println(" mDisplayMetrics=" + mDisplayMetrics);
2508 pw.println(" mStackScroller: " + viewInfo(mStackScroller));
2509 pw.println(" mStackScroller: " + viewInfo(mStackScroller)
2510 + " scroll " + mStackScroller.getScrollX()
2511 + "," + mStackScroller.getScrollY());
2514 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
2515 pw.print(" mStatusBarWindowState=");
2516 pw.println(windowStateToString(mStatusBarWindowState));
2517 pw.print(" mStatusBarMode=");
2518 pw.println(BarTransitions.modeToString(mStatusBarMode));
2519 pw.print(" mDozing="); pw.println(mDozing);
2520 pw.print(" mZenMode=");
2521 pw.println(Settings.Global.zenModeToString(mZenMode));
2522 pw.print(" mUseHeadsUp=");
2523 pw.println(mUseHeadsUp);
2524 pw.print(" interrupting package: ");
2525 pw.println(hunStateToString(mHeadsUpNotificationView.getEntry()));
2526 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
2527 if (mNavigationBarView != null) {
2528 pw.print(" mNavigationBarWindowState=");
2529 pw.println(windowStateToString(mNavigationBarWindowState));
2530 pw.print(" mNavigationBarMode=");
2531 pw.println(BarTransitions.modeToString(mNavigationBarMode));
2532 dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
2535 pw.print(" mNavigationBarView=");
2536 if (mNavigationBarView == null) {
2539 mNavigationBarView.dump(fd, pw, args);
2542 pw.print(" mMediaSessionManager=");
2543 pw.println(mMediaSessionManager);
2544 pw.print(" mMediaNotificationKey=");
2545 pw.println(mMediaNotificationKey);
2546 pw.print(" mMediaController=");
2547 pw.print(mMediaController);
2548 if (mMediaController != null) {
2549 pw.print(" state=" + mMediaController.getPlaybackState());
2552 pw.print(" mMediaMetadata=");
2553 pw.print(mMediaMetadata);
2554 if (mMediaMetadata != null) {
2555 pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE));
2559 pw.println(" Panels: ");
2560 if (mNotificationPanel != null) {
2561 pw.println(" mNotificationPanel=" +
2562 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
2564 mNotificationPanel.dump(fd, pw, args);
2570 synchronized (mNotificationData) {
2571 mNotificationData.dump(pw, " ");
2574 mIconController.dump(pw);
2577 pw.println("see the logcat for a dump of the views we have created.");
2578 // must happen on ui thread
2579 mHandler.post(new Runnable() {
2581 mStatusBarView.getLocationOnScreen(mAbsPos);
2582 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
2583 + ") " + mStatusBarView.getWidth() + "x"
2584 + getStatusBarHeight());
2585 mStatusBarView.debug();
2591 if (DEBUG_GESTURES) {
2592 pw.print(" status bar gestures: ");
2593 mGestureRec.dump(fd, pw, args);
2596 if (mNetworkController != null) {
2597 mNetworkController.dump(fd, pw, args);
2599 if (mBluetoothController != null) {
2600 mBluetoothController.dump(fd, pw, args);
2602 if (mCastController != null) {
2603 mCastController.dump(fd, pw, args);
2605 if (mUserSwitcherController != null) {
2606 mUserSwitcherController.dump(fd, pw, args);
2608 if (mBatteryController != null) {
2609 mBatteryController.dump(fd, pw, args);
2611 if (mNextAlarmController != null) {
2612 mNextAlarmController.dump(fd, pw, args);
2614 if (mSecurityController != null) {
2615 mSecurityController.dump(fd, pw, args);
2617 if (mHeadsUpNotificationView != null) {
2618 mHeadsUpNotificationView.dump(fd, pw, args);
2620 pw.println(" mHeadsUpNotificationView: null");
2623 pw.println("SharedPreferences:");
2624 for (Map.Entry<String, ?> entry : mContext.getSharedPreferences(mContext.getPackageName(),
2625 Context.MODE_PRIVATE).getAll().entrySet()) {
2626 pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
2630 private String hunStateToString(Entry entry) {
2631 if (entry == null) return "null";
2632 if (entry.notification == null) return "corrupt";
2633 return entry.notification.getPackageName();
2636 private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
2637 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode=");
2638 pw.println(BarTransitions.modeToString(transitions.getMode()));
2642 public void createAndAddWindows() {
2643 addStatusBarWindow();
2646 private void addStatusBarWindow() {
2647 makeStatusBarView();
2648 mStatusBarWindowManager = new StatusBarWindowManager(mContext);
2649 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
2652 // called by makeStatusbar and also by PhoneStatusBarView
2653 void updateDisplaySize() {
2654 mDisplay.getMetrics(mDisplayMetrics);
2655 mDisplay.getSize(mCurrentDisplaySize);
2656 if (DEBUG_GESTURES) {
2657 mGestureRec.tag("display",
2658 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
2662 float getDisplayDensity() {
2663 return mDisplayMetrics.density;
2666 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
2667 final boolean dismissShade) {
2668 if (onlyProvisioned && !isDeviceProvisioned()) return;
2670 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
2671 mContext, intent, mCurrentUserId);
2672 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
2673 dismissKeyguardThenExecute(new OnDismissAction() {
2675 public boolean onDismiss() {
2676 AsyncTask.execute(new Runnable() {
2679 if (keyguardShowing && !afterKeyguardGone) {
2680 ActivityManagerNative.getDefault()
2681 .keyguardWaitingForActivityDrawn();
2684 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2685 mContext.startActivityAsUser(
2686 intent, new UserHandle(UserHandle.USER_CURRENT));
2687 overrideActivityPendingAppTransition(
2688 keyguardShowing && !afterKeyguardGone);
2689 } catch (RemoteException e) {
2694 animateCollapsePanels(
2695 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
2699 }, afterKeyguardGone);
2702 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
2703 public void onReceive(Context context, Intent intent) {
2704 if (DEBUG) Log.v(TAG, "onReceive: " + intent);
2705 String action = intent.getAction();
2706 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
2707 if (isCurrentProfile(getSendingUserId())) {
2708 int flags = CommandQueue.FLAG_EXCLUDE_NONE;
2709 String reason = intent.getStringExtra("reason");
2710 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
2711 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
2713 animateCollapsePanels(flags);
2716 else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
2718 notifyNavigationBarScreenOn(false);
2719 notifyHeadsUpScreenOn(false);
2720 finishBarAnimations();
2721 resetUserExpandedStates();
2723 else if (Intent.ACTION_SCREEN_ON.equals(action)) {
2725 notifyNavigationBarScreenOn(true);
2727 else if (ACTION_DEMO.equals(action)) {
2728 Bundle bundle = intent.getExtras();
2729 if (bundle != null) {
2730 String command = bundle.getString("command", "").trim().toLowerCase();
2731 if (command.length() > 0) {
2733 dispatchDemoCommand(command, bundle);
2734 } catch (Throwable t) {
2735 Log.w(TAG, "Error running demo command, intent=" + intent, t);
2739 } else if ("fake_artwork".equals(action)) {
2740 if (DEBUG_MEDIA_FAKE_ARTWORK) {
2741 updateMediaMetaData(true);
2747 private void resetUserExpandedStates() {
2748 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
2749 final int notificationCount = activeNotifications.size();
2750 for (int i = 0; i < notificationCount; i++) {
2751 NotificationData.Entry entry = activeNotifications.get(i);
2752 if (entry.row != null) {
2753 entry.row.resetUserExpansion();
2759 protected void dismissKeyguardThenExecute(final OnDismissAction action,
2760 boolean afterKeyguardGone) {
2761 if (mStatusBarKeyguardViewManager.isShowing()) {
2762 mStatusBarKeyguardViewManager.dismissWithAction(action, afterKeyguardGone);
2768 // SystemUIService notifies SystemBars of configuration changes, which then calls down here
2770 protected void onConfigurationChanged(Configuration newConfig) {
2771 super.onConfigurationChanged(newConfig); // calls refreshLayout
2774 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
2776 updateDisplaySize(); // populates mDisplayMetrics
2779 repositionNavigationBar();
2780 updateShowSearchHoldoff();
2782 mIconController.updateResources();
2783 mScreenPinningRequest.onConfigurationChanged();
2787 public void userSwitched(int newUserId) {
2788 super.userSwitched(newUserId);
2789 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
2790 animateCollapsePanels();
2792 updateNotifications();
2793 resetUserSetupObserver();
2794 setControllerUsers();
2797 private void setControllerUsers() {
2798 if (mZenModeController != null) {
2799 mZenModeController.setUserId(mCurrentUserId);
2803 private void resetUserSetupObserver() {
2804 mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver);
2805 mUserSetupObserver.onChange(false);
2806 mContext.getContentResolver().registerContentObserver(
2807 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true,
2808 mUserSetupObserver, mCurrentUserId);
2811 private void setHeadsUpVisibility(boolean vis) {
2812 if (!ENABLE_HEADS_UP) return;
2813 if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window");
2814 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_STATUS,
2815 vis ? mHeadsUpNotificationView.getKey() : "",
2817 mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
2821 * Reload some of our resources when the configuration changes.
2823 * We don't reload everything when the configuration changes -- we probably
2824 * should, but getting that smooth is tough. Someday we'll fix that. In the
2825 * meantime, just update the things that we know change.
2827 void updateResources() {
2828 // Update the quick setting tiles
2829 if (mQSPanel != null) {
2830 mQSPanel.updateResources();
2835 if (mNotificationPanel != null) {
2836 mNotificationPanel.updateResources();
2838 if (mHeadsUpNotificationView != null) {
2839 mHeadsUpNotificationView.updateResources();
2841 if (mBrightnessMirrorController != null) {
2842 mBrightnessMirrorController.updateResources();
2846 protected void loadDimens() {
2847 final Resources res = mContext.getResources();
2849 mNaturalBarHeight = res.getDimensionPixelSize(
2850 com.android.internal.R.dimen.status_bar_height);
2852 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
2854 mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
2855 mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
2857 mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count);
2859 if (DEBUG) Log.v(TAG, "updateResources");
2862 // Visibility reporting
2865 protected void handleVisibleToUserChanged(boolean visibleToUser) {
2866 if (visibleToUser) {
2867 super.handleVisibleToUserChanged(visibleToUser);
2868 startNotificationLogging();
2870 stopNotificationLogging();
2871 super.handleVisibleToUserChanged(visibleToUser);
2875 private void stopNotificationLogging() {
2876 // Report all notifications as invisible and turn down the
2878 if (!mCurrentlyVisibleNotifications.isEmpty()) {
2879 logNotificationVisibilityChanges(
2880 Collections.<String>emptyList(), mCurrentlyVisibleNotifications);
2881 mCurrentlyVisibleNotifications.clear();
2883 mHandler.removeCallbacks(mVisibilityReporter);
2884 mStackScroller.setChildLocationsChangedListener(null);
2887 private void startNotificationLogging() {
2888 mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
2889 // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
2890 // cause the scroller to emit child location events. Hence generate
2891 // one ourselves to guarantee that we're reporting visible
2893 // (Note that in cases where the scroller does emit events, this
2894 // additional event doesn't break anything.)
2895 mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller);
2898 private void logNotificationVisibilityChanges(
2899 Collection<String> newlyVisible, Collection<String> noLongerVisible) {
2900 if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
2903 String[] newlyVisibleAr = newlyVisible.toArray(new String[newlyVisible.size()]);
2904 String[] noLongerVisibleAr = noLongerVisible.toArray(new String[noLongerVisible.size()]);
2906 mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
2907 } catch (RemoteException e) {
2914 private void logStateToEventlog() {
2915 boolean isShowing = mStatusBarKeyguardViewManager.isShowing();
2916 boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();
2917 boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
2918 boolean isSecure = mUnlockMethodCache.isMethodSecure();
2919 boolean isCurrentlyInsecure = mUnlockMethodCache.isCurrentlyInsecure();
2920 int stateFingerprint = getLoggingFingerprint(mState,
2925 isCurrentlyInsecure);
2926 if (stateFingerprint != mLastLoggedStateFingerprint) {
2927 EventLogTags.writeSysuiStatusBarState(mState,
2930 isBouncerShowing ? 1 : 0,
2932 isCurrentlyInsecure ? 1 : 0);
2933 mLastLoggedStateFingerprint = stateFingerprint;
2938 * Returns a fingerprint of fields logged to eventlog
2940 private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing,
2941 boolean keyguardOccluded, boolean bouncerShowing, boolean secure,
2942 boolean currentlyInsecure) {
2943 // Reserve 8 bits for statusBarState. We'll never go higher than
2944 // that, right? Riiiight.
2945 return (statusBarState & 0xFF)
2946 | ((keyguardShowing ? 1 : 0) << 8)
2947 | ((keyguardOccluded ? 1 : 0) << 9)
2948 | ((bouncerShowing ? 1 : 0) << 10)
2949 | ((secure ? 1 : 0) << 11)
2950 | ((currentlyInsecure ? 1 : 0) << 12);
2957 void postStartTracing() {
2958 mHandler.postDelayed(mStartTracing, 3000);
2962 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
2963 Context.VIBRATOR_SERVICE);
2964 vib.vibrate(250, VIBRATION_ATTRIBUTES);
2967 Runnable mStartTracing = new Runnable() {
2970 SystemClock.sleep(250);
2971 Log.d(TAG, "startTracing");
2972 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
2973 mHandler.postDelayed(mStopTracing, 10000);
2977 Runnable mStopTracing = new Runnable() {
2979 android.os.Debug.stopMethodTracing();
2980 Log.d(TAG, "stopTracing");
2986 protected boolean shouldDisableNavbarGestures() {
2987 return !isDeviceProvisioned()
2989 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
2992 public void postStartSettingsActivity(final Intent intent, int delay) {
2993 mHandler.postDelayed(new Runnable() {
2996 handleStartSettingsActivity(intent, true /*onlyProvisioned*/);
3001 private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) {
3002 startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
3005 private static class FastColorDrawable extends Drawable {
3006 private final int mColor;
3008 public FastColorDrawable(int color) {
3009 mColor = 0xff000000 | color;
3013 public void draw(Canvas canvas) {
3014 canvas.drawColor(mColor, PorterDuff.Mode.SRC);
3018 public void setAlpha(int alpha) {
3022 public void setColorFilter(ColorFilter colorFilter) {
3026 public int getOpacity() {
3027 return PixelFormat.OPAQUE;
3031 public void setBounds(int left, int top, int right, int bottom) {
3035 public void setBounds(Rect bounds) {
3040 public void destroy() {
3042 if (mStatusBarWindow != null) {
3043 mWindowManager.removeViewImmediate(mStatusBarWindow);
3044 mStatusBarWindow = null;
3046 if (mNavigationBarView != null) {
3047 mWindowManager.removeViewImmediate(mNavigationBarView);
3048 mNavigationBarView = null;
3050 if (mHandlerThread != null) {
3051 mHandlerThread.quitSafely();
3052 mHandlerThread = null;
3054 mContext.unregisterReceiver(mBroadcastReceiver);
3057 private boolean mDemoModeAllowed;
3058 private boolean mDemoMode;
3061 public void dispatchDemoCommand(String command, Bundle args) {
3062 if (!mDemoModeAllowed) {
3063 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
3064 "sysui_demo_allowed", 0) != 0;
3066 if (!mDemoModeAllowed) return;
3067 if (command.equals(COMMAND_ENTER)) {
3069 } else if (command.equals(COMMAND_EXIT)) {
3072 } else if (!mDemoMode) {
3073 // automatically enter demo mode on first demo command
3074 dispatchDemoCommand(COMMAND_ENTER, new Bundle());
3076 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT);
3077 if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) {
3078 mVolumeComponent.dispatchDemoCommand(command, args);
3080 if (modeChange || command.equals(COMMAND_CLOCK)) {
3081 dispatchDemoCommandToView(command, args, R.id.clock);
3083 if (modeChange || command.equals(COMMAND_BATTERY)) {
3084 dispatchDemoCommandToView(command, args, R.id.battery);
3086 if (modeChange || command.equals(COMMAND_STATUS)) {
3087 mIconController.dispatchDemoCommand(command, args);
3090 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
3091 mNetworkController.dispatchDemoCommand(command, args);
3093 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) {
3094 View notifications = mStatusBarView == null ? null
3095 : mStatusBarView.findViewById(R.id.notification_icon_area);
3096 if (notifications != null) {
3097 String visible = args.getString("visible");
3098 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE;
3099 notifications.setVisibility(vis);
3102 if (command.equals(COMMAND_BARS)) {
3103 String mode = args.getString("mode");
3104 int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
3105 "translucent".equals(mode) ? MODE_TRANSLUCENT :
3106 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
3107 "transparent".equals(mode) ? MODE_TRANSPARENT :
3108 "warning".equals(mode) ? MODE_WARNING :
3110 if (barMode != -1) {
3111 boolean animate = true;
3112 if (mStatusBarView != null) {
3113 mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
3115 if (mNavigationBarView != null) {
3116 mNavigationBarView.getBarTransitions().transitionTo(barMode, animate);
3122 private void dispatchDemoCommandToView(String command, Bundle args, int id) {
3123 if (mStatusBarView == null) return;
3124 View v = mStatusBarView.findViewById(id);
3125 if (v instanceof DemoMode) {
3126 ((DemoMode)v).dispatchDemoCommand(command, args);
3131 * @return The {@link StatusBarState} the status bar is in.
3133 public int getBarState() {
3137 public void showKeyguard() {
3138 if (mLaunchTransitionFadingAway) {
3139 mNotificationPanel.animate().cancel();
3140 mNotificationPanel.setAlpha(1f);
3141 runLaunchTransitionEndRunnable();
3142 mLaunchTransitionFadingAway = false;
3144 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3145 setBarState(StatusBarState.KEYGUARD);
3146 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
3147 if (!mScreenOnFromKeyguard) {
3149 // If the screen is off already, we need to disable touch events because these might
3150 // collapse the panel after we expanded it, and thus we would end up with a blank
3152 mNotificationPanel.setTouchDisabled(true);
3154 instantExpandNotificationsPanel();
3155 mLeaveOpenOnKeyguardHide = false;
3156 if (mDraggedDownRow != null) {
3157 mDraggedDownRow.setUserLocked(false);
3158 mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */);
3159 mDraggedDownRow = null;
3163 public boolean isCollapsing() {
3164 return mNotificationPanel.isCollapsing();
3167 public void addPostCollapseAction(Runnable r) {
3168 mPostCollapseRunnables.add(r);
3171 public boolean isInLaunchTransition() {
3172 return mNotificationPanel.isLaunchTransitionRunning()
3173 || mNotificationPanel.isLaunchTransitionFinished();
3177 * Fades the content of the keyguard away after the launch transition is done.
3179 * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
3181 * @param endRunnable the runnable to be run when the transition is done
3183 public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
3184 Runnable endRunnable) {
3185 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3186 mLaunchTransitionEndRunnable = endRunnable;
3187 Runnable hideRunnable = new Runnable() {
3190 mLaunchTransitionFadingAway = true;
3191 if (beforeFading != null) {
3194 mNotificationPanel.setAlpha(1);
3195 mNotificationPanel.animate()
3197 .setStartDelay(FADE_KEYGUARD_START_DELAY)
3198 .setDuration(FADE_KEYGUARD_DURATION)
3200 .withEndAction(new Runnable() {
3203 mNotificationPanel.setAlpha(1);
3204 runLaunchTransitionEndRunnable();
3205 mLaunchTransitionFadingAway = false;
3208 mIconController.appTransitionStarting(SystemClock.uptimeMillis(),
3209 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
3212 if (mNotificationPanel.isLaunchTransitionRunning()) {
3213 mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
3220 * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
3221 * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
3222 * because the launched app crashed or something else went wrong.
3224 public void startLaunchTransitionTimeout() {
3225 mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT,
3226 LAUNCH_TRANSITION_TIMEOUT_MS);
3229 private void onLaunchTransitionTimeout() {
3230 Log.w(TAG, "Launch transition: Timeout!");
3231 mNotificationPanel.resetViews();
3234 private void runLaunchTransitionEndRunnable() {
3235 if (mLaunchTransitionEndRunnable != null) {
3236 Runnable r = mLaunchTransitionEndRunnable;
3238 // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again,
3239 // which would lead to infinite recursion. Protect against it.
3240 mLaunchTransitionEndRunnable = null;
3246 * @return true if we would like to stay in the shade, false if it should go away entirely
3248 public boolean hideKeyguard() {
3249 boolean staying = mLeaveOpenOnKeyguardHide;
3250 setBarState(StatusBarState.SHADE);
3251 if (mLeaveOpenOnKeyguardHide) {
3252 mLeaveOpenOnKeyguardHide = false;
3253 mNotificationPanel.animateToFullShade(calculateGoingToFullShadeDelay());
3254 if (mDraggedDownRow != null) {
3255 mDraggedDownRow.setUserLocked(false);
3256 mDraggedDownRow = null;
3259 instantCollapseNotificationPanel();
3261 updateKeyguardState(staying, false /* fromShadeLocked */);
3263 // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
3264 // visibilities so next time we open the panel we know the correct height already.
3265 if (mQSPanel != null) {
3266 mQSPanel.refreshAllTiles();
3268 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3272 public long calculateGoingToFullShadeDelay() {
3273 return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
3277 * Notifies the status bar that Keyguard is going away very soon.
3279 public void keyguardGoingAway() {
3281 // Treat Keyguard exit animation as an app transition to achieve nice transition for status
3283 mIconController.appTransitionPending();
3287 * Notifies the status bar the Keyguard is fading away with the specified timings.
3289 * @param startTime the start time of the animations in uptime millis
3290 * @param delay the precalculated animation delay in miliseconds
3291 * @param fadeoutDuration the duration of the exit animation, in milliseconds
3293 public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
3294 mKeyguardFadingAway = true;
3295 mKeyguardFadingAwayDelay = delay;
3296 mKeyguardFadingAwayDuration = fadeoutDuration;
3297 mWaitingForKeyguardExit = false;
3298 mIconController.appTransitionStarting(
3299 startTime + fadeoutDuration
3300 - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION,
3301 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
3302 disable(mDisabledUnmodified, true /* animate */);
3305 public boolean isKeyguardFadingAway() {
3306 return mKeyguardFadingAway;
3310 * Notifies that the Keyguard fading away animation is done.
3312 public void finishKeyguardFadingAway() {
3313 mKeyguardFadingAway = false;
3316 private void updatePublicMode() {
3317 setLockscreenPublicMode(
3318 mStatusBarKeyguardViewManager.isShowing() && mStatusBarKeyguardViewManager
3319 .isSecure(mCurrentUserId));
3322 private void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
3323 if (mState == StatusBarState.KEYGUARD) {
3324 mKeyguardIndicationController.setVisible(true);
3325 mNotificationPanel.resetViews();
3326 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
3328 mKeyguardIndicationController.setVisible(false);
3329 mKeyguardUserSwitcher.setKeyguard(false,
3330 goingToFullShade || mState == StatusBarState.SHADE_LOCKED || fromShadeLocked);
3332 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
3333 mScrimController.setKeyguardShowing(true);
3335 mScrimController.setKeyguardShowing(false);
3337 mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
3338 updateDozingState();
3340 updateStackScrollerState(goingToFullShade);
3341 updateNotifications();
3343 updateMediaMetaData(false);
3344 mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
3345 mStatusBarKeyguardViewManager.isSecure());
3348 private void updateDozingState() {
3349 if (mState != StatusBarState.KEYGUARD && !mNotificationPanel.isDozing()) {
3352 boolean animate = !mDozing && mDozeScrimController.isPulsing();
3353 mNotificationPanel.setDozing(mDozing, animate);
3354 mStackScroller.setDark(mDozing, animate, mScreenOnTouchLocation);
3355 mScrimController.setDozing(mDozing);
3356 mDozeScrimController.setDozing(mDozing, animate);
3359 public void updateStackScrollerState(boolean goingToFullShade) {
3360 if (mStackScroller == null) return;
3361 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
3362 mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
3363 mStackScroller.setDimmed(onKeyguard, false /* animate */);
3364 mStackScroller.setExpandingEnabled(!onKeyguard);
3365 ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
3366 mStackScroller.setActivatedChild(null);
3367 if (activatedChild != null) {
3368 activatedChild.makeInactive(false /* animate */);
3372 public void userActivity() {
3373 if (mState == StatusBarState.KEYGUARD) {
3374 mKeyguardViewMediatorCallback.userActivity();
3378 public boolean interceptMediaKey(KeyEvent event) {
3379 return mState == StatusBarState.KEYGUARD
3380 && mStatusBarKeyguardViewManager.interceptMediaKey(event);
3383 public boolean onMenuPressed() {
3384 return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed();
3387 public boolean onBackPressed() {
3388 if (mStatusBarKeyguardViewManager.onBackPressed()) {
3391 if (mNotificationPanel.isQsExpanded()) {
3392 if (mNotificationPanel.isQsDetailShowing()) {
3393 mNotificationPanel.closeQsDetail();
3395 mNotificationPanel.animateCloseQs();
3399 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
3400 animateCollapsePanels();
3406 public boolean onSpacePressed() {
3407 if (mScreenOn != null && mScreenOn
3408 && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
3409 animateCollapsePanels(
3410 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
3416 private void showBouncer() {
3417 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
3418 mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
3419 mStatusBarKeyguardViewManager.dismiss();
3423 private void instantExpandNotificationsPanel() {
3425 // Make our window larger and the panel expanded.
3426 makeExpandedVisible(true);
3427 mNotificationPanel.instantExpand();
3430 private void instantCollapseNotificationPanel() {
3431 mNotificationPanel.instantCollapse();
3435 public void onActivated(ActivatableNotificationView view) {
3436 EventLogTags.writeSysuiLockscreenGesture(
3437 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE,
3438 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
3439 mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
3440 ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
3441 if (previousView != null) {
3442 previousView.makeInactive(true /* animate */);
3444 mStackScroller.setActivatedChild(view);
3448 * @param state The {@link StatusBarState} to set.
3450 public void setBarState(int state) {
3451 // If we're visible and switched to SHADE_LOCKED (the user dragged
3452 // down on the lockscreen), clear notification LED, vibration,
3454 // Other transitions are covered in handleVisibleToUserChanged().
3455 if (state != mState && mVisible && state == StatusBarState.SHADE_LOCKED) {
3457 mBarService.clearNotificationEffects();
3458 } catch (RemoteException e) {
3463 mGroupManager.setStatusBarState(state);
3464 mStatusBarWindowManager.setStatusBarState(state);
3468 public void onActivationReset(ActivatableNotificationView view) {
3469 if (view == mStackScroller.getActivatedChild()) {
3470 mKeyguardIndicationController.hideTransientIndication();
3471 mStackScroller.setActivatedChild(null);
3475 public void onTrackingStarted() {
3476 runPostCollapseRunnables();
3479 public void onClosingFinished() {
3480 runPostCollapseRunnables();
3483 public void onUnlockHintStarted() {
3484 mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
3487 public void onHintFinished() {
3488 // Delay the reset a bit so the user can read the text.
3489 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
3492 public void onCameraHintStarted() {
3493 mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
3496 public void onPhoneHintStarted() {
3497 mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
3500 public void onTrackingStopped(boolean expand) {
3501 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
3502 if (!expand && !mUnlockMethodCache.isCurrentlyInsecure()) {
3509 protected int getMaxKeyguardNotifications() {
3510 return mKeyguardMaxNotificationCount;
3513 public NavigationBarView getNavigationBarView() {
3514 return mNavigationBarView;
3517 // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
3520 public boolean onDraggedDown(View startingChild, int dragLengthY) {
3521 if (hasActiveNotifications()) {
3522 EventLogTags.writeSysuiLockscreenGesture(
3523 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE,
3524 (int) (dragLengthY / mDisplayMetrics.density),
3525 0 /* velocityDp - N/A */);
3527 // We have notifications, go to locked shade.
3528 goToLockedShade(startingChild);
3532 // No notifications - abort gesture.
3538 public void onDragDownReset() {
3539 mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
3543 public void onThresholdReached() {
3544 mStackScroller.setDimmed(false /* dimmed */, true /* animate */);
3548 public void onTouchSlopExceeded() {
3549 mStackScroller.removeLongPressCallback();
3553 public void setEmptyDragAmount(float amount) {
3554 mNotificationPanel.setEmptyDragAmount(amount);
3558 * If secure with redaction: Show bouncer, go to unlocked shade.
3560 * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
3562 * @param expandView The view to expand after going to the shade.
3564 public void goToLockedShade(View expandView) {
3565 ExpandableNotificationRow row = null;
3566 if (expandView instanceof ExpandableNotificationRow) {
3567 row = (ExpandableNotificationRow) expandView;
3568 row.setUserExpanded(true);
3570 boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
3571 || !mShowLockscreenNotifications;
3572 if (isLockscreenPublicMode() && fullShadeNeedsBouncer) {
3573 mLeaveOpenOnKeyguardHide = true;
3575 mDraggedDownRow = row;
3577 mNotificationPanel.animateToFullShade(0 /* delay */);
3578 setBarState(StatusBarState.SHADE_LOCKED);
3579 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
3581 row.setUserLocked(false);
3587 * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
3589 public void goToKeyguard() {
3590 if (mState == StatusBarState.SHADE_LOCKED) {
3591 mStackScroller.onGoToKeyguard();
3592 setBarState(StatusBarState.KEYGUARD);
3593 updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/);
3597 public long getKeyguardFadingAwayDelay() {
3598 return mKeyguardFadingAwayDelay;
3601 public long getKeyguardFadingAwayDuration() {
3602 return mKeyguardFadingAwayDuration;
3606 public void setBouncerShowing(boolean bouncerShowing) {
3607 super.setBouncerShowing(bouncerShowing);
3608 disable(mDisabledUnmodified, true /* animate */);
3611 public void onScreenTurnedOff() {
3612 mScreenOnFromKeyguard = false;
3613 mScreenOnComingFromTouch = false;
3614 mScreenOnTouchLocation = null;
3615 mStackScroller.setAnimationsEnabled(false);
3616 updateVisibleToUser();
3619 public void onScreenTurnedOn() {
3620 mScreenOnFromKeyguard = true;
3621 mStackScroller.setAnimationsEnabled(true);
3622 mNotificationPanel.onScreenTurnedOn();
3623 mNotificationPanel.setTouchDisabled(false);
3624 updateVisibleToUser();
3628 * This handles long-press of both back and recents. They are
3629 * handled together to capture them both being long-pressed
3630 * at the same time to exit screen pinning (lock task).
3632 * When accessibility mode is on, only a long-press from recents
3633 * is required to exit.
3635 * In all other circumstances we try to pass through long-press events
3636 * for Back, so that apps can still use it. Which can be from two things.
3637 * 1) Not currently in screen pinning (lock task).
3638 * 2) Back is long-pressed without recents.
3640 private void handleLongPressBackRecents(View v) {
3642 boolean sendBackLongPress = false;
3643 IActivityManager activityManager = ActivityManagerNative.getDefault();
3644 boolean isAccessiblityEnabled = mAccessibilityManager.isEnabled();
3645 if (activityManager.isInLockTaskMode() && !isAccessiblityEnabled) {
3646 long time = System.currentTimeMillis();
3647 // If we recently long-pressed the other button then they were
3648 // long-pressed 'together'
3649 if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
3650 activityManager.stopLockTaskModeOnCurrent();
3651 // When exiting refresh disabled flags.
3652 mNavigationBarView.setDisabledFlags(mDisabled, true);
3653 } else if ((v.getId() == R.id.back)
3654 && !mNavigationBarView.getRecentsButton().isPressed()) {
3655 // If we aren't pressing recents right now then they presses
3656 // won't be together, so send the standard long-press action.
3657 sendBackLongPress = true;
3659 mLastLockToAppLongPress = time;
3661 // If this is back still need to handle sending the long-press event.
3662 if (v.getId() == R.id.back) {
3663 sendBackLongPress = true;
3664 } else if (isAccessiblityEnabled && activityManager.isInLockTaskMode()) {
3665 // When in accessibility mode a long press that is recents (not back)
3666 // should stop lock task.
3667 activityManager.stopLockTaskModeOnCurrent();
3668 // When exiting refresh disabled flags.
3669 mNavigationBarView.setDisabledFlags(mDisabled, true);
3672 if (sendBackLongPress) {
3673 KeyButtonView keyButtonView = (KeyButtonView) v;
3674 keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
3675 keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
3677 } catch (RemoteException e) {
3678 Log.d(TAG, "Unable to reach activity manager", e);
3685 protected void showRecents(boolean triggeredFromAltTab) {
3686 // Set the recents visibility flag
3687 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
3688 notifyUiVisibilityChanged(mSystemUiVisibility);
3689 super.showRecents(triggeredFromAltTab);
3693 protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
3694 // Unset the recents visibility flag
3695 mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
3696 notifyUiVisibilityChanged(mSystemUiVisibility);
3697 super.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
3701 protected void toggleRecents() {
3702 // Toggle the recents visibility flag
3703 mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE;
3704 notifyUiVisibilityChanged(mSystemUiVisibility);
3705 super.toggleRecents();
3709 public void onVisibilityChanged(boolean visible) {
3710 // Update the recents visibility flag
3712 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
3714 mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
3716 notifyUiVisibilityChanged(mSystemUiVisibility);
3720 public void showScreenPinningRequest() {
3721 if (mKeyguardMonitor.isShowing()) {
3722 // Don't allow apps to trigger this from keyguard.
3725 // Show screen pinning request, since this comes from an app, show 'no thanks', button.
3726 showScreenPinningRequest(true);
3729 public void showScreenPinningRequest(boolean allowCancel) {
3730 mScreenPinningRequest.showPrompt(allowCancel);
3733 public boolean hasActiveNotifications() {
3734 return !mNotificationData.getActiveNotifications().isEmpty();
3737 public void wakeUpIfDozing(long time, MotionEvent event) {
3738 if (mDozing && mDozeScrimController.isPulsing()) {
3739 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
3741 mScreenOnComingFromTouch = true;
3742 mScreenOnTouchLocation = new PointF(event.getX(), event.getY());
3743 mNotificationPanel.setTouchDisabled(false);
3748 public void appTransitionPending() {
3750 // Use own timings when Keyguard is going away, see keyguardGoingAway and
3751 // setKeyguardFadingAway
3752 if (!mKeyguardFadingAway) {
3753 mIconController.appTransitionPending();
3758 public void appTransitionCancelled() {
3759 mIconController.appTransitionCancelled();
3763 public void appTransitionStarting(long startTime, long duration) {
3765 // Use own timings when Keyguard is going away, see keyguardGoingAway and
3766 // setKeyguardFadingAway
3767 if (!mKeyguardFadingAway) {
3768 mIconController.appTransitionStarting(startTime, duration);
3772 private final class ShadeUpdates {
3773 private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
3774 private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
3776 public void check() {
3777 mNewVisibleNotifications.clear();
3778 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
3779 for (int i = 0; i < activeNotifications.size(); i++) {
3780 final Entry entry = activeNotifications.get(i);
3781 final boolean visible = entry.row != null
3782 && entry.row.getVisibility() == View.VISIBLE;
3784 mNewVisibleNotifications.add(entry.key + entry.notification.getPostTime());
3787 final boolean updates = !mVisibleNotifications.containsAll(mNewVisibleNotifications);
3788 mVisibleNotifications.clear();
3789 mVisibleNotifications.addAll(mNewVisibleNotifications);
3791 // We have new notifications
3792 if (updates && mDozeServiceHost != null) {
3793 mDozeServiceHost.fireNewNotifications();
3798 private final class DozeServiceHost implements DozeHost {
3799 // Amount of time to allow to update the time shown on the screen before releasing
3800 // the wakelock. This timeout is design to compensate for the fact that we don't
3801 // currently have a way to know when time display contents have actually been
3802 // refreshed once we've finished rendering a new frame.
3803 private static final long PROCESSING_TIME = 500;
3805 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
3806 private final H mHandler = new H();
3808 // Keeps the last reported state by fireNotificationLight.
3809 private boolean mNotificationLightOn;
3812 public String toString() {
3813 return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
3816 public void firePowerSaveChanged(boolean active) {
3817 for (Callback callback : mCallbacks) {
3818 callback.onPowerSaveChanged(active);
3822 public void fireBuzzBeepBlinked() {
3823 for (Callback callback : mCallbacks) {
3824 callback.onBuzzBeepBlinked();
3828 public void fireNotificationLight(boolean on) {
3829 mNotificationLightOn = on;
3830 for (Callback callback : mCallbacks) {
3831 callback.onNotificationLight(on);
3835 public void fireNewNotifications() {
3836 for (Callback callback : mCallbacks) {
3837 callback.onNewNotifications();
3842 public void addCallback(@NonNull Callback callback) {
3843 mCallbacks.add(callback);
3847 public void removeCallback(@NonNull Callback callback) {
3848 mCallbacks.remove(callback);
3852 public void startDozing(@NonNull Runnable ready) {
3853 mHandler.obtainMessage(H.MSG_START_DOZING, ready).sendToTarget();
3857 public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
3858 mHandler.obtainMessage(H.MSG_PULSE_WHILE_DOZING, reason, 0, callback).sendToTarget();
3862 public void stopDozing() {
3863 mHandler.obtainMessage(H.MSG_STOP_DOZING).sendToTarget();
3867 public boolean isPowerSaveActive() {
3868 return mBatteryController != null && mBatteryController.isPowerSave();
3872 public boolean isNotificationLightOn() {
3873 return mNotificationLightOn;
3876 private void handleStartDozing(@NonNull Runnable ready) {
3879 DozeLog.traceDozing(mContext, mDozing);
3880 updateDozingState();
3885 private void handlePulseWhileDozing(@NonNull PulseCallback callback, int reason) {
3886 mDozeScrimController.pulse(callback, reason);
3889 private void handleStopDozing() {
3892 DozeLog.traceDozing(mContext, mDozing);
3893 updateDozingState();
3897 private final class H extends Handler {
3898 private static final int MSG_START_DOZING = 1;
3899 private static final int MSG_PULSE_WHILE_DOZING = 2;
3900 private static final int MSG_STOP_DOZING = 3;
3903 public void handleMessage(Message msg) {
3905 case MSG_START_DOZING:
3906 handleStartDozing((Runnable) msg.obj);
3908 case MSG_PULSE_WHILE_DOZING:
3909 handlePulseWhileDozing((PulseCallback) msg.obj, msg.arg1);
3911 case MSG_STOP_DOZING: