StatusBar.java revision e5b770e47d44a40d412c7d42010b2cf67920d9e3
10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2010 The Android Open Source Project
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.systemui.statusbar.phone;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.app.StatusBarManager.windowStateToString;
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static com.android.systemui.statusbar.notification.NotificationInflater.InflationExceptionHandler;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.animation.Animator;
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.animation.AnimatorListenerAdapter;
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.annotation.NonNull;
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.ActivityManager;
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.ActivityOptions;
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.Notification;
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.NotificationManager;
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent;
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.StatusBarManager;
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.admin.DevicePolicyManager;
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.BroadcastReceiver;
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ComponentCallbacks2;
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ComponentName;
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Context;
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Intent;
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.IntentFilter;
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.IntentSender;
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.IPackageManager;
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.PackageManager;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Configuration;
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Resources;
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.database.ContentObserver;
570825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.Bitmap;
580825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.Canvas;
590825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.ColorFilter;
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.PixelFormat;
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.Point;
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.PointF;
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.PorterDuff;
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.PorterDuffXfermode;
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.Rect;
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.drawable.BitmapDrawable;
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.drawable.ColorDrawable;
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.drawable.Drawable;
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.media.AudioAttributes;
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.media.MediaMetadata;
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.media.session.MediaController;
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.media.session.MediaSession;
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.media.session.MediaSessionManager;
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.media.session.PlaybackState;
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.metrics.LogMaker;
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.net.Uri;
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.AsyncTask;
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Bundle;
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.IBinder;
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message;
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.PowerManager;
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.RemoteException;
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.ServiceManager;
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.SystemClock;
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.SystemProperties;
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Trace;
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.UserHandle;
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.UserManager;
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Vibrator;
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.provider.Settings;
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.service.notification.NotificationListenerService.RankingMap;
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.service.notification.StatusBarNotification;
930825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.ArraySet;
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.DisplayMetrics;
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.EventLog;
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.Log;
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.Display;
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.KeyEvent;
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.LayoutInflater;
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.MotionEvent;
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.ThreadedRenderer;
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.View;
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.ViewGroup;
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.ViewParent;
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.ViewStub;
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.ViewTreeObserver;
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.WindowManager;
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.WindowManagerGlobal;
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.animation.AccelerateInterpolator;
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.animation.Interpolator;
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.widget.DateTimeView;
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.widget.ImageView;
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.widget.TextView;
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.logging.MetricsLogger;
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.logging.nano.MetricsProto.MetricsEvent;
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.statusbar.NotificationVisibility;
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.statusbar.StatusBarIcon;
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.util.NotificationMessagingUtil;
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.keyguard.KeyguardHostView.OnDismissAction;
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.keyguard.KeyguardStatusView;
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.keyguard.KeyguardUpdateMonitor;
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.keyguard.KeyguardUpdateMonitorCallback;
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.keyguard.ViewMediatorCallback;
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.ActivityStarterDelegate;
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.DemoMode;
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.Dependency;
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.EventLogTags;
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.Interpolators;
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.Prefs;
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.R;
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.SystemUIFactory;
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.assist.AssistManager;
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.classifier.FalsingLog;
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.classifier.FalsingManager;
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.doze.DozeHost;
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.doze.DozeLog;
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.fragments.FragmentHostManager;
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.fragments.PluginFragmentListener;
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.keyguard.KeyguardViewMediator;
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.plugins.qs.QS;
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.plugins.ActivityStarter;
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeOption;
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.qs.QSFragment;
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.qs.QSPanel;
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.qs.QSTileHost;
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.recents.ScreenPinningRequest;
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.recents.events.EventBus;
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.recents.events.activity.UndockingTaskEvent;
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.stackdivider.Divider;
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.stackdivider.WindowManagerProxy;
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.ActivatableNotificationView;
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.BackDropView;
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.CommandQueue;
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.DismissView;
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.DragDownHelper;
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.EmptyShadeView;
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.ExpandableNotificationRow;
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.GestureRecorder;
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.KeyboardShortcuts;
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.KeyguardIndicationController;
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.NotificationData;
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.NotificationData.Entry;
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.NotificationGuts;
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.NotificationInfo;
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.NotificationShelf;
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.NotificationSnooze;
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.RemoteInputController;
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.ScrimView;
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.SignalClusterView;
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.StatusBarState;
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.notification.InflationException;
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.notification.VisualStabilityManager;
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.BatteryController;
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.BrightnessMirrorController;
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.ConfigurationController;
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.DarkIconDispatcher;
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.DeviceProvisionedController;
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.HeadsUpManager;
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.KeyguardMonitor;
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.NetworkController;
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.PreviewInflater;
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.UserInfoController;
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.UserInfoControllerImpl;
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.UserSwitcherController;
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.util.leak.LeakDetector;
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.volume.VolumeComponent;
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.io.FileDescriptor;
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.io.PrintWriter;
2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.io.StringWriter;
2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Collection;
2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Collections;
2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap;
2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.List;
2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Map;
2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.ActivityManager.StackId;
2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.INotificationManager;
2150825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.KeyguardManager;
2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.NotificationChannel;
2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.RemoteInput;
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.TaskStackBuilder;
2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.ApplicationInfo;
2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.PackageManager.NameNotFoundException;
2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.UserInfo;
2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Build;
2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler;
2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.service.dreams.DreamService;
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.service.dreams.IDreamManager;
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.service.notification.NotificationListenerService;
2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.service.vr.IVrManager;
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.service.vr.IVrStateCallbacks;
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.TextUtils;
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.Slog;
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.SparseArray;
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.SparseBooleanArray;
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.IWindowManager;
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.ViewAnimationUtils;
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.accessibility.AccessibilityManager;
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.widget.RemoteViews;
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.widget.Toast;
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.statusbar.IStatusBarService;
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.widget.LockPatternUtils;
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.DejankUtils;
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.RecentsComponent;
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.SwipeHelper;
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.SystemUI;
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeGutsContent;
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.recents.Recents;
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.policy.RemoteInputView;
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.statusbar.stack.StackStateAnimator;
2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.systemui.util.NotificationChannels;
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashSet;
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Locale;
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Set;
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Stack;
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic class StatusBar extends SystemUI implements DemoMode,
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        OnHeadsUpChangedListener, VisualStabilityManager.Callback, SnoozeListener,
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ExpandableNotificationRow.OnExpandClickListener {
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean MULTIUSER_DEBUG = false;
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean ENABLE_REMOTE_INPUT =
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SystemProperties.getBoolean("debug.enable_remote_input", true);
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean ENABLE_CHILD_NOTIFICATIONS
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            = SystemProperties.getBoolean("debug.child_notifs", true);
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean FORCE_REMOTE_INPUT_HISTORY =
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SystemProperties.getBoolean("debug.force_remoteinput_history", false);
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int MSG_SHOW_RECENT_APPS = 1019;
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int MSG_HIDE_RECENT_APPS = 1020;
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final boolean ENABLE_HEADS_UP = true;
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // Must match constant in Settings. Used to highlight preferences when linking to Settings.
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // Should match the values in PhoneWindowManager
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String BANNER_ACTION_CANCEL =
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "com.android.systemui.statusbar.banner_action_cancel";
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String BANNER_ACTION_SETUP =
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "com.android.systemui.statusbar.banner_action_setup";
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final String TAG = "StatusBar";
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean DEBUG = false;
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean SPEW = false;
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean DUMPTRUCK = true; // extra dumpsys info
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean DEBUG_GESTURES = false;
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean DEBUG_MEDIA = false;
3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean DEBUG_WINDOW_STATE = false;
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // additional instrumentation for testing purposes; intended to be left on during development
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean CHATTY = DEBUG;
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final String ACTION_FAKE_ARTWORK = "fake_artwork";
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MSG_CLOSE_PANELS = 1001;
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // 1020-1040 reserved for BaseStatusBar
3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // Time after we abort the launch transition.
3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int STATUS_OR_NAV_TRANSIENT =
3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final long AUTOHIDE_TIMEOUT_MS = 3000;
3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** The minimum delay in ms between reports of notification visibility. */
3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The delay to reset the hint text when the hint animation is finished running.
3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int HINT_RESET_DELAY_MS = 1200;
3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            .build();
3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int FADE_KEYGUARD_START_DELAY = 100;
3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int FADE_KEYGUARD_DURATION = 300;
3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** If true, the system is in the half-boot-to-decryption-screen state.
3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Prudently disable QS and notifications.  */
3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final boolean ONLY_CORE_APPS;
3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** If true, the lockscreen will show a distinct wallpaper */
3540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
3550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* If true, the device supports freeform window management.
3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * This affects the status bar UI. */
3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final boolean FREEFORM_WINDOW_MANAGEMENT;
3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * How long to wait before auto-dismissing a notification that was kept for remote input, and
3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel
3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * these given that they technically don't exist anymore. We wait a bit in case the app issues
3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * an update.
3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * won't draw anything and uninitialized memory will show through
3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * libhwui.
3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final float SRC_MIN_ALPHA = 0.002f;
3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static {
3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean onlyCoreApps;
3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean freeformWindowManagement;
3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            IPackageManager packageManager =
3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            onlyCoreApps = packageManager.isOnlyCoreApps();
3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            freeformWindowManagement = packageManager.hasSystemFeature(
3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, 0);
3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (RemoteException e) {
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            onlyCoreApps = false;
3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            freeformWindowManagement = false;
3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ONLY_CORE_APPS = onlyCoreApps;
3900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement;
3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The {@link StatusBarState} of the status bar.
3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected int mState;
3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mBouncerShowing;
3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mShowLockscreenNotifications;
3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mAllowLockscreenRemoteInput;
4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    PhoneStatusBarPolicy mIconPolicy;
4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    VolumeComponent mVolumeComponent;
4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    BrightnessMirrorController mBrightnessMirrorController;
4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected FingerprintUnlockController mFingerprintUnlockController;
4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    LightBarController mLightBarController;
4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected LockscreenWallpaper mLockscreenWallpaper;
4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    int mNaturalBarHeight = -1;
4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    Point mCurrentDisplaySize = new Point();
4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected StatusBarWindowView mStatusBarWindow;
4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected PhoneStatusBarView mStatusBarView;
4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected StatusBarWindowManager mStatusBarWindowManager;
4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected UnlockMethodCache mUnlockMethodCache;
4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private DozeServiceHost mDozeServiceHost;
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mWakeUpComingFromTouch;
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private PointF mWakeUpTouchLocation;
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mScreenTurningOn;
4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    int mPixelFormat;
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    Object mQueueLock = new Object();
4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected StatusBarIconController mIconController;
4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // expanded notifications
4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    View mExpandedContents;
4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    TextView mNotificationPanelDebugText;
4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // settings
4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private QSPanel mQSPanel;
4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // top bar
4370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected KeyguardStatusBarView mKeyguardStatusBar;
4380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    KeyguardStatusView mKeyguardStatusView;
4390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    KeyguardBottomAreaView mKeyguardBottomArea;
4400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    boolean mLeaveOpenOnKeyguardHide;
4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    KeyguardIndicationController mKeyguardIndicationController;
4420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // Keyguard is going away soon.
4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mKeyguardGoingAway;
4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // Keyguard is actually fading away now.
4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mKeyguardFadingAway;
4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected long mKeyguardFadingAwayDelay;
4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected long mKeyguardFadingAwayDuration;
4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // RemoteInputView to be activated after unlock
4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private View mPendingRemoteInputView;
4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private View mPendingWorkRemoteInputView;
4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private View mReportRejectedTouch;
4550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    int mMaxAllowedKeyguardNotifications;
4570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    boolean mExpandedVisible;
4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // the tracker view
4610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    int mTrackingPosition; // the position of the top of the tracking view.
4620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // Tracking finger for opening/closing.
4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    boolean mTracking;
4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    int[] mAbsPos = new int[2];
4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // for disabling the status bar
4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    int mDisabled1 = 0;
4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    int mDisabled2 = 0;
4720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // tracking calls to View.setSystemUiVisibility()
4740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
4750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final Rect mLastFullscreenStackBounds = new Rect();
4760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final Rect mLastDockedStackBounds = new Rect();
4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // last value sent to window manager
4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    DisplayMetrics mDisplayMetrics = new DisplayMetrics();
4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // XXX: gesture research
4840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final GestureRecorder mGestureRec = DEBUG_GESTURES
4850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
4860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        : null;
4870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private ScreenPinningRequest mScreenPinningRequest;
4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // ensure quick settings is disabled until the current user makes it through the setup wizard
4910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mUserSetup = false;
4920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onUserSetupChanged() {
4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            final boolean userSetup = mDeviceProvisionedController.isUserSetup(
4960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mDeviceProvisionedController.getCurrentUser());
4970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    "userSetup=%s mUserSetup=%s", userSetup, mUserSetup));
4990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (userSetup != mUserSetup) {
5010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mUserSetup = userSetup;
5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (!mUserSetup && mStatusBarView != null)
5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    animateCollapseQuickSettings();
5040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (mKeyguardBottomArea != null) {
5050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
5060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
5070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                updateQsExpansionEnabled();
5080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    };
5110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected H mHandler = createHandler();
5130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
5140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
5150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onChange(boolean selfChange) {
5160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean wasUsing = mUseHeadsUp;
5170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts
5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
5200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Settings.Global.HEADS_UP_OFF);
5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt(
5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0);
5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (wasUsing != mUseHeadsUp) {
5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (!mUseHeadsUp) {
5260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Log.d(TAG, "dismissing any existing heads up notification on disable event");
5270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mHeadsUpManager.releaseAllImmediately();
5280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
5290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    };
5320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mInteractingWindows;
5340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mAutohideSuspended;
5350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mStatusBarMode;
5360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mMaxKeyguardNotifications;
5370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private ViewMediatorCallback mKeyguardViewMediatorCallback;
5390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected ScrimController mScrimController;
5400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected DozeScrimController mDozeScrimController;
5410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final Runnable mAutohide = new Runnable() {
5430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
5440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void run() {
5450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
5460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (mSystemUiVisibility != requested) {
5470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                notifyUiVisibilityChanged(requested);
5480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }};
5500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mWaitingForKeyguardExit;
5520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mDozing;
5530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mDozingRequested;
5540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mScrimSrcModeEnabled;
5550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final Interpolator ALPHA_IN = Interpolators.ALPHA_IN;
5570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT;
5580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected BackDropView mBackdrop;
5600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected ImageView mBackdropFront, mBackdropBack;
5610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
5620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected PorterDuffXfermode mSrcOverXferMode =
5630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
5640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private MediaSessionManager mMediaSessionManager;
5660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private MediaController mMediaController;
5670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private String mMediaNotificationKey;
5680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private MediaMetadata mMediaMetadata;
5690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private MediaController.Callback mMediaListener
5700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            = new MediaController.Callback() {
5710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
5720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onPlaybackStateChanged(PlaybackState state) {
5730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            super.onPlaybackStateChanged(state);
5740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state);
5750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (state != null) {
5760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (!isPlaybackActive(state.getState())) {
5770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    clearCurrentMediaNotification();
5780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    updateMediaMetaData(true, true);
5790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
5800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
5840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onMetadataChanged(MediaMetadata metadata) {
5850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            super.onMetadataChanged(metadata);
5860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
5870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mMediaMetadata = metadata;
5880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            updateMediaMetaData(true, true);
5890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    };
5910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
592    private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
593            new OnChildLocationsChangedListener() {
594        @Override
595        public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) {
596            userActivity();
597        }
598    };
599
600    private int mDisabledUnmodified1;
601    private int mDisabledUnmodified2;
602
603    /** Keys of notifications currently visible to the user. */
604    private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
605            new ArraySet<>();
606    private long mLastVisibilityReportUptimeMs;
607
608    private Runnable mLaunchTransitionEndRunnable;
609    protected boolean mLaunchTransitionFadingAway;
610    private ExpandableNotificationRow mDraggedDownRow;
611    private boolean mLaunchCameraOnScreenTurningOn;
612    private boolean mLaunchCameraOnFinishedGoingToSleep;
613    private int mLastCameraLaunchSource;
614    private PowerManager.WakeLock mGestureWakeLock;
615    private Vibrator mVibrator;
616    private long[] mCameraLaunchGestureVibePattern;
617
618    private final int[] mTmpInt2 = new int[2];
619
620    // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
621    private int mLastLoggedStateFingerprint;
622
623    /**
624     * If set, the device has started going to sleep but isn't fully non-interactive yet.
625     */
626    protected boolean mStartedGoingToSleep;
627
628    private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
629            new OnChildLocationsChangedListener() {
630                @Override
631                public void onChildLocationsChanged(
632                        NotificationStackScrollLayout stackScrollLayout) {
633                    if (mHandler.hasCallbacks(mVisibilityReporter)) {
634                        // Visibilities will be reported when the existing
635                        // callback is executed.
636                        return;
637                    }
638                    // Calculate when we're allowed to run the visibility
639                    // reporter. Note that this timestamp might already have
640                    // passed. That's OK, the callback will just be executed
641                    // ASAP.
642                    long nextReportUptimeMs =
643                            mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS;
644                    mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs);
645                }
646            };
647
648    // Tracks notifications currently visible in mNotificationStackScroller and
649    // emits visibility events via NoMan on changes.
650    private final Runnable mVisibilityReporter = new Runnable() {
651        private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications =
652                new ArraySet<>();
653        private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications =
654                new ArraySet<>();
655        private final ArraySet<NotificationVisibility> mTmpNoLongerVisibleNotifications =
656                new ArraySet<>();
657
658        @Override
659        public void run() {
660            mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
661            final String mediaKey = getCurrentMediaNotificationKey();
662
663            // 1. Loop over mNotificationData entries:
664            //   A. Keep list of visible notifications.
665            //   B. Keep list of previously hidden, now visible notifications.
666            // 2. Compute no-longer visible notifications by removing currently
667            //    visible notifications from the set of previously visible
668            //    notifications.
669            // 3. Report newly visible and no-longer visible notifications.
670            // 4. Keep currently visible notifications for next report.
671            ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
672            int N = activeNotifications.size();
673            for (int i = 0; i < N; i++) {
674                Entry entry = activeNotifications.get(i);
675                String key = entry.notification.getKey();
676                boolean isVisible = mStackScroller.isInVisibleLocation(entry.row);
677                NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible);
678                boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj);
679                if (isVisible) {
680                    // Build new set of visible notifications.
681                    mTmpCurrentlyVisibleNotifications.add(visObj);
682                    if (!previouslyVisible) {
683                        mTmpNewlyVisibleNotifications.add(visObj);
684                    }
685                } else {
686                    // release object
687                    visObj.recycle();
688                }
689            }
690            mTmpNoLongerVisibleNotifications.addAll(mCurrentlyVisibleNotifications);
691            mTmpNoLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
692
693            logNotificationVisibilityChanges(
694                    mTmpNewlyVisibleNotifications, mTmpNoLongerVisibleNotifications);
695
696            recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
697            mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
698
699            recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
700            mTmpCurrentlyVisibleNotifications.clear();
701            mTmpNewlyVisibleNotifications.clear();
702            mTmpNoLongerVisibleNotifications.clear();
703        }
704    };
705
706    private NotificationMessagingUtil mMessagingUtil;
707    private KeyguardUserSwitcher mKeyguardUserSwitcher;
708    private UserSwitcherController mUserSwitcherController;
709    private NetworkController mNetworkController;
710    private KeyguardMonitorImpl mKeyguardMonitor;
711    private BatteryController mBatteryController;
712    private boolean mPanelExpanded;
713    private LogMaker mStatusBarStateLog;
714    private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
715    private NotificationIconAreaController mNotificationIconAreaController;
716    private ConfigurationListener mConfigurationListener;
717    private InflationExceptionHandler mInflationExceptionHandler = this::handleInflationException;
718
719    private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
720        final int N = array.size();
721        for (int i = 0 ; i < N; i++) {
722            array.valueAt(i).recycle();
723        }
724        array.clear();
725    }
726
727    private final View.OnClickListener mGoToLockedShadeListener = v -> {
728        if (mState == StatusBarState.KEYGUARD) {
729            wakeUpIfDozing(SystemClock.uptimeMillis(), v);
730            goToLockedShade(null);
731        }
732    };
733    private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap
734            = new HashMap<>();
735    private RankingMap mLatestRankingMap;
736    private boolean mNoAnimationOnNextBarModeChange;
737    private FalsingManager mFalsingManager;
738
739    private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
740        @Override
741        public void onDreamingStateChanged(boolean dreaming) {
742            if (dreaming) {
743                maybeEscalateHeadsUp();
744            }
745        }
746    };
747
748    private NavigationBarFragment mNavigationBar;
749    private View mNavigationBarView;
750
751    @Override
752    public void start() {
753        mNetworkController = Dependency.get(NetworkController.class);
754        mUserSwitcherController = Dependency.get(UserSwitcherController.class);
755        mKeyguardMonitor = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
756        mBatteryController = Dependency.get(BatteryController.class);
757        mAssistManager = Dependency.get(AssistManager.class);
758        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
759
760        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
761        mDisplay = mWindowManager.getDefaultDisplay();
762        updateDisplaySize();
763        mScrimSrcModeEnabled = mContext.getResources().getBoolean(
764                R.bool.config_status_bar_scrim_behind_use_src);
765
766        DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
767        putComponent(StatusBar.class, this);
768
769        // start old BaseStatusBar.start().
770        mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
771        mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
772                Context.DEVICE_POLICY_SERVICE);
773
774        mNotificationData = new NotificationData(this);
775        mMessagingUtil = new NotificationMessagingUtil(mContext);
776
777        mAccessibilityManager = (AccessibilityManager)
778                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
779
780        mDreamManager = IDreamManager.Stub.asInterface(
781                ServiceManager.checkService(DreamService.DREAM_SERVICE));
782        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
783
784        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
785        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
786        mContext.getContentResolver().registerContentObserver(
787                Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
788                mSettingsObserver);
789        mContext.getContentResolver().registerContentObserver(
790                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
791                mLockscreenSettingsObserver,
792                UserHandle.USER_ALL);
793        if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
794            mContext.getContentResolver().registerContentObserver(
795                    Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
796                    false,
797                    mSettingsObserver,
798                    UserHandle.USER_ALL);
799        }
800
801        mContext.getContentResolver().registerContentObserver(
802                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
803                true,
804                mLockscreenSettingsObserver,
805                UserHandle.USER_ALL);
806
807        mBarService = IStatusBarService.Stub.asInterface(
808                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
809
810        mRecents = getComponent(Recents.class);
811
812        final Configuration currentConfig = mContext.getResources().getConfiguration();
813        mLocale = currentConfig.locale;
814        mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
815
816        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
817        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
818        mLockPatternUtils = new LockPatternUtils(mContext);
819
820        // Connect in to the status bar manager service
821        mCommandQueue = getComponent(CommandQueue.class);
822        mCommandQueue.addCallbacks(this);
823
824        int[] switches = new int[9];
825        ArrayList<IBinder> binders = new ArrayList<IBinder>();
826        ArrayList<String> iconSlots = new ArrayList<>();
827        ArrayList<StatusBarIcon> icons = new ArrayList<>();
828        Rect fullscreenStackBounds = new Rect();
829        Rect dockedStackBounds = new Rect();
830        try {
831            mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
832                    fullscreenStackBounds, dockedStackBounds);
833        } catch (RemoteException ex) {
834            // If the system process isn't there we're doomed anyway.
835        }
836
837        createAndAddWindows();
838
839        mSettingsObserver.onChange(false); // set up
840        mCommandQueue.disable(switches[0], switches[6], false /* animate */);
841        setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
842                fullscreenStackBounds, dockedStackBounds);
843        topAppWindowChanged(switches[2] != 0);
844        // StatusBarManagerService has a back up of IME token and it's restored here.
845        setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
846
847        // Set up the initial icon state
848        int N = iconSlots.size();
849        int viewIndex = 0;
850        for (int i=0; i < N; i++) {
851            mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
852        }
853
854        // Set up the initial notification state.
855        try {
856            mNotificationListener.registerAsSystemService(mContext,
857                    new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
858                    UserHandle.USER_ALL);
859        } catch (RemoteException e) {
860            Log.e(TAG, "Unable to register notification listener", e);
861        }
862
863
864        if (DEBUG) {
865            Log.d(TAG, String.format(
866                    "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
867                   icons.size(),
868                   switches[0],
869                   switches[1],
870                   switches[2],
871                   switches[3]
872                   ));
873        }
874
875        mCurrentUserId = ActivityManager.getCurrentUser();
876        setHeadsUpUser(mCurrentUserId);
877
878        IntentFilter filter = new IntentFilter();
879        filter.addAction(Intent.ACTION_USER_SWITCHED);
880        filter.addAction(Intent.ACTION_USER_ADDED);
881        filter.addAction(Intent.ACTION_USER_PRESENT);
882        mContext.registerReceiver(mBaseBroadcastReceiver, filter);
883
884        IntentFilter internalFilter = new IntentFilter();
885        internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
886        internalFilter.addAction(BANNER_ACTION_CANCEL);
887        internalFilter.addAction(BANNER_ACTION_SETUP);
888        mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
889
890        IntentFilter allUsersFilter = new IntentFilter();
891        allUsersFilter.addAction(
892                DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
893        allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
894        mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
895                null, null);
896        updateCurrentProfilesCache();
897
898        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
899                Context.VR_SERVICE));
900        try {
901            vrManager.registerListener(mVrStateCallbacks);
902        } catch (RemoteException e) {
903            Slog.e(TAG, "Failed to register VR mode state listener: " + e);
904        }
905
906        mNonBlockablePkgs = new HashSet<String>();
907        Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
908                com.android.internal.R.array.config_nonBlockableNotificationPackages));
909        // end old BaseStatusBar.start().
910
911        mMediaSessionManager
912                = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
913        // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
914        // in session state
915
916        // Lastly, call to the icon policy to install/update all the icons.
917        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
918        mSettingsObserver.onChange(false); // set up
919
920        mHeadsUpObserver.onChange(true); // set up
921        if (ENABLE_HEADS_UP) {
922            mContext.getContentResolver().registerContentObserver(
923                    Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true,
924                    mHeadsUpObserver);
925            mContext.getContentResolver().registerContentObserver(
926                    Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
927                    mHeadsUpObserver);
928        }
929        mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
930        mUnlockMethodCache.addListener(this);
931        startKeyguard();
932
933        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
934        mDozeServiceHost = new DozeServiceHost();
935        putComponent(DozeHost.class, mDozeServiceHost);
936
937        notifyUserAboutHiddenNotifications();
938
939        mScreenPinningRequest = new ScreenPinningRequest(mContext);
940        mFalsingManager = FalsingManager.getInstance(mContext);
941
942        Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
943
944        mConfigurationListener = new ConfigurationListener() {
945            @Override
946            public void onConfigChanged(Configuration newConfig) {
947                StatusBar.this.onConfigurationChanged(newConfig);
948            }
949
950            @Override
951            public void onDensityOrFontScaleChanged() {
952                StatusBar.this.onDensityOrFontScaleChanged();
953            }
954        };
955        Dependency.get(ConfigurationController.class).addCallback(mConfigurationListener);
956    }
957
958    protected void createIconController() {
959    }
960
961    // ================================================================================
962    // Constructing the view
963    // ================================================================================
964    protected void makeStatusBarView() {
965        final Context context = mContext;
966        updateDisplaySize(); // populates mDisplayMetrics
967        updateResources();
968
969        inflateStatusBarWindow(context);
970        mStatusBarWindow.setService(this);
971        mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
972
973        // TODO: Deal with the ugliness that comes from having some of the statusbar broken out
974        // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
975        mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
976                R.id.notification_panel);
977        mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
978                R.id.notification_stack_scroller);
979        mNotificationPanel.setStatusBar(this);
980        mNotificationPanel.setGroupManager(mGroupManager);
981        mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
982
983        mNotificationIconAreaController = SystemUIFactory.getInstance()
984                .createNotificationIconAreaController(context, this);
985        inflateShelf();
986        mNotificationIconAreaController.setupShelf(mNotificationShelf);
987        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
988        FragmentHostManager.get(mStatusBarWindow)
989                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
990                    CollapsedStatusBarFragment statusBarFragment = (CollapsedStatusBarFragment) fragment;
991                    statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
992                    mStatusBarView = (PhoneStatusBarView) fragment.getView();
993                    mStatusBarView.setBar(this);
994                    mStatusBarView.setPanel(mNotificationPanel);
995                    mStatusBarView.setScrimController(mScrimController);
996                    setAreThereNotifications();
997                }).getFragmentManager()
998                .beginTransaction()
999                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(), CollapsedStatusBarFragment.TAG)
1000                .commit();
1001        Dependency.get(StatusBarIconController.class).addIconGroup(
1002                new IconManager((ViewGroup) mKeyguardStatusBar.findViewById(R.id.statusIcons)));
1003        mIconController = Dependency.get(StatusBarIconController.class);
1004
1005        if (!ActivityManager.isHighEndGfx()) {
1006            mStatusBarWindow.setBackground(null);
1007            mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
1008                    R.color.notification_panel_solid_background)));
1009        }
1010
1011        mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager);
1012        mHeadsUpManager.setBar(this);
1013        mHeadsUpManager.addListener(this);
1014        mHeadsUpManager.addListener(mNotificationPanel);
1015        mHeadsUpManager.addListener(mGroupManager);
1016        mHeadsUpManager.addListener(mVisualStabilityManager);
1017        mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
1018        mNotificationData.setHeadsUpManager(mHeadsUpManager);
1019        mGroupManager.setHeadsUpManager(mHeadsUpManager);
1020        mHeadsUpManager.setVisualStabilityManager(mVisualStabilityManager);
1021
1022        if (MULTIUSER_DEBUG) {
1023            mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
1024                    R.id.header_debug_info);
1025            mNotificationPanelDebugText.setVisibility(View.VISIBLE);
1026        }
1027
1028        try {
1029            boolean showNav = mWindowManagerService.hasNavigationBar();
1030            if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
1031            if (showNav) {
1032                createNavigationBar();
1033            }
1034        } catch (RemoteException ex) {
1035            // no window manager? good luck with that
1036        }
1037
1038        // figure out which pixel-format to use for the status bar.
1039        mPixelFormat = PixelFormat.OPAQUE;
1040
1041        mStackScroller.setLongPressListener(getNotificationLongClicker());
1042        mStackScroller.setStatusBar(this);
1043        mStackScroller.setGroupManager(mGroupManager);
1044        mStackScroller.setHeadsUpManager(mHeadsUpManager);
1045        mGroupManager.setOnGroupChangeListener(mStackScroller);
1046        mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
1047
1048        inflateEmptyShadeView();
1049        inflateDismissView();
1050        mExpandedContents = mStackScroller;
1051
1052        mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
1053        mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
1054        mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
1055
1056        if (ENABLE_LOCKSCREEN_WALLPAPER) {
1057            mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
1058        }
1059
1060        mKeyguardStatusView =
1061                (KeyguardStatusView) mStatusBarWindow.findViewById(R.id.keyguard_status_view);
1062        mKeyguardBottomArea =
1063                (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
1064        mKeyguardIndicationController =
1065                SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
1066                (ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
1067                mKeyguardBottomArea.getLockIcon());
1068        mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
1069
1070        // set the initial view visibility
1071        setAreThereNotifications();
1072
1073        // TODO: Find better place for this callback.
1074        mBatteryController.addCallback(new BatteryStateChangeCallback() {
1075            @Override
1076            public void onPowerSaveChanged(boolean isPowerSave) {
1077                mHandler.post(mCheckBarModes);
1078                if (mDozeServiceHost != null) {
1079                    mDozeServiceHost.firePowerSaveChanged(isPowerSave);
1080                }
1081            }
1082
1083            @Override
1084            public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
1085                // noop
1086            }
1087        });
1088
1089        mLightBarController = new LightBarController();
1090        if (mNavigationBar != null) {
1091            mNavigationBar.setLightBarController(mLightBarController);
1092        }
1093
1094        ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
1095        ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
1096        View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
1097        mScrimController = SystemUIFactory.getInstance().createScrimController(mLightBarController,
1098                scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper);
1099        if (mScrimSrcModeEnabled) {
1100            Runnable runnable = new Runnable() {
1101                @Override
1102                public void run() {
1103                    boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
1104                    mScrimController.setDrawBehindAsSrc(asSrc);
1105                    mStackScroller.setDrawBackgroundAsSrc(asSrc);
1106                }
1107            };
1108            mBackdrop.setOnVisibilityChangedRunnable(runnable);
1109            runnable.run();
1110        }
1111        mHeadsUpManager.addListener(mScrimController);
1112        mStackScroller.setScrimController(mScrimController);
1113        mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller,
1114                mNotificationPanel);
1115
1116        // Other icons
1117        mVolumeComponent = getComponent(VolumeComponent.class);
1118
1119        initEmergencyCryptkeeperText();
1120
1121        mKeyguardBottomArea.setStatusBar(this);
1122        mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
1123        if (UserManager.get(mContext).isUserSwitcherEnabled()) {
1124            createUserSwitcher();
1125        }
1126
1127        // Set up the quick settings tile panel
1128        View container = mStatusBarWindow.findViewById(R.id.qs_frame);
1129        if (container != null) {
1130            FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
1131            fragmentHostManager.getFragmentManager().beginTransaction()
1132                    .replace(R.id.qs_frame, new QSFragment(), QS.TAG)
1133                    .commit();
1134            new PluginFragmentListener(container, QS.TAG, QSFragment.class, QS.class)
1135                    .startListening();
1136            final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
1137                    mIconController);
1138            mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
1139            fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
1140                QS qs = (QS) f;
1141                if (qs instanceof QSFragment) {
1142                    ((QSFragment) qs).setHost(qsh);
1143                    mQSPanel = ((QSFragment) qs).getQsPanel();
1144                    mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
1145                    mKeyguardStatusBar.setQSPanel(mQSPanel);
1146                }
1147            });
1148        }
1149
1150        mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
1151        if (mReportRejectedTouch != null) {
1152            updateReportRejectedTouchVisibility();
1153            mReportRejectedTouch.setOnClickListener(v -> {
1154                Uri session = mFalsingManager.reportRejectedTouch();
1155                if (session == null) { return; }
1156
1157                StringWriter message = new StringWriter();
1158                message.write("Build info: ");
1159                message.write(SystemProperties.get("ro.build.description"));
1160                message.write("\nSerial number: ");
1161                message.write(SystemProperties.get("ro.serialno"));
1162                message.write("\n");
1163
1164                PrintWriter falsingPw = new PrintWriter(message);
1165                FalsingLog.dump(falsingPw);
1166                falsingPw.flush();
1167
1168                startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND)
1169                                .setType("*/*")
1170                                .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report")
1171                                .putExtra(Intent.EXTRA_STREAM, session)
1172                                .putExtra(Intent.EXTRA_TEXT, message.toString()),
1173                        "Share rejected touch report")
1174                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
1175                        true /* onlyProvisioned */, true /* dismissShade */);
1176            });
1177        }
1178
1179
1180        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
1181        if (!pm.isScreenOn()) {
1182            mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
1183        }
1184        mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
1185                "GestureWakeLock");
1186        mVibrator = mContext.getSystemService(Vibrator.class);
1187        int[] pattern = mContext.getResources().getIntArray(
1188                R.array.config_cameraLaunchGestureVibePattern);
1189        mCameraLaunchGestureVibePattern = new long[pattern.length];
1190        for (int i = 0; i < pattern.length; i++) {
1191            mCameraLaunchGestureVibePattern[i] = pattern[i];
1192        }
1193
1194        // receive broadcasts
1195        IntentFilter filter = new IntentFilter();
1196        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1197        filter.addAction(Intent.ACTION_SCREEN_OFF);
1198        filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
1199        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
1200
1201        IntentFilter demoFilter = new IntentFilter();
1202        if (DEBUG_MEDIA_FAKE_ARTWORK) {
1203            demoFilter.addAction(ACTION_FAKE_ARTWORK);
1204        }
1205        demoFilter.addAction(ACTION_DEMO);
1206        context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
1207                android.Manifest.permission.DUMP, null);
1208
1209        // listen for USER_SETUP_COMPLETE setting (per-user)
1210        mDeviceProvisionedController.addCallback(mUserSetupObserver);
1211        mUserSetupObserver.onUserSetupChanged();
1212
1213        // disable profiling bars, since they overlap and clutter the output on app windows
1214        ThreadedRenderer.overrideProperty("disableProfileBars", "true");
1215
1216        // Private API call to make the shadows look better for Recents
1217        ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
1218    }
1219
1220    protected void createNavigationBar() {
1221        mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
1222            mNavigationBar = (NavigationBarFragment) fragment;
1223            if (mLightBarController != null) {
1224                mNavigationBar.setLightBarController(mLightBarController);
1225            }
1226            mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
1227        });
1228    }
1229
1230    private void initEmergencyCryptkeeperText() {
1231        View emergencyViewStub = mStatusBarWindow.findViewById(R.id.emergency_cryptkeeper_text);
1232        if (mNetworkController.hasEmergencyCryptKeeperText()) {
1233            if (emergencyViewStub != null) {
1234                ((ViewStub) emergencyViewStub).inflate();
1235            }
1236            mNetworkController.addCallback(new NetworkController.SignalCallback() {
1237                @Override
1238                public void setIsAirplaneMode(NetworkController.IconState icon) {
1239                    recomputeDisableFlags(true /* animate */);
1240                }
1241            });
1242        } else if (emergencyViewStub != null) {
1243            ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
1244            parent.removeView(emergencyViewStub);
1245        }
1246    }
1247
1248    /**
1249     * Returns the {@link android.view.View.OnTouchListener} that will be invoked when the
1250     * background window of the status bar is clicked.
1251     */
1252    protected View.OnTouchListener getStatusBarWindowTouchListener() {
1253        return (v, event) -> {
1254            checkUserAutohide(v, event);
1255            checkRemoteInputOutside(event);
1256            if (event.getAction() == MotionEvent.ACTION_DOWN) {
1257                if (mExpandedVisible) {
1258                    animateCollapsePanels();
1259                }
1260            }
1261            return mStatusBarWindow.onTouchEvent(event);
1262        };
1263    }
1264
1265    private void inflateShelf() {
1266        mNotificationShelf =
1267                (NotificationShelf) LayoutInflater.from(mContext).inflate(
1268                        R.layout.status_bar_notification_shelf, mStackScroller, false);
1269        mNotificationShelf.setOnActivatedListener(this);
1270        mStackScroller.setShelf(mNotificationShelf);
1271        mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
1272        mNotificationShelf.setStatusBarState(mState);
1273    }
1274
1275    protected void onDensityOrFontScaleChanged() {
1276        // start old BaseStatusBar.onDensityOrFontScaleChanged().
1277        ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1278        for (int i = 0; i < activeNotifications.size(); i++) {
1279            Entry entry = activeNotifications.get(i);
1280            boolean exposedGuts = mNotificationGutsExposed != null
1281                    && entry.row.getGuts() == mNotificationGutsExposed;
1282            entry.row.onDensityOrFontScaleChanged();
1283            if (exposedGuts) {
1284                mNotificationGutsExposed = entry.row.getGuts();
1285                bindGuts(entry.row, mGutsMenuItem);
1286            }
1287        }
1288        // end old BaseStatusBar.onDensityOrFontScaleChanged().
1289        mScrimController.onDensityOrFontScaleChanged();
1290        // TODO: Remove this.
1291        if (mStatusBarView != null) mStatusBarView.onDensityOrFontScaleChanged();
1292        if (mBrightnessMirrorController != null) {
1293            mBrightnessMirrorController.onDensityOrFontScaleChanged();
1294        }
1295        inflateSignalClusters();
1296        mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
1297        inflateDismissView();
1298        updateClearAll();
1299        inflateEmptyShadeView();
1300        updateEmptyShadeView();
1301        mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
1302        // TODO: Bring these out of StatusBar.
1303        ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
1304                .onDensityOrFontScaleChanged();
1305        Dependency.get(UserSwitcherController.class).onDensityOrFontScaleChanged();
1306        if (mKeyguardUserSwitcher != null) {
1307            mKeyguardUserSwitcher.onDensityOrFontScaleChanged();
1308        }
1309    }
1310
1311    private void inflateSignalClusters() {
1312        reinflateSignalCluster(mKeyguardStatusBar);
1313    }
1314
1315    public static SignalClusterView reinflateSignalCluster(View view) {
1316        Context context = view.getContext();
1317        SignalClusterView signalCluster =
1318                (SignalClusterView) view.findViewById(R.id.signal_cluster);
1319        if (signalCluster != null) {
1320            ViewParent parent = signalCluster.getParent();
1321            if (parent instanceof ViewGroup) {
1322                ViewGroup viewParent = (ViewGroup) parent;
1323                int index = viewParent.indexOfChild(signalCluster);
1324                viewParent.removeView(signalCluster);
1325                SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(context)
1326                        .inflate(R.layout.signal_cluster_view, viewParent, false);
1327                ViewGroup.MarginLayoutParams layoutParams =
1328                        (ViewGroup.MarginLayoutParams) viewParent.getLayoutParams();
1329                layoutParams.setMarginsRelative(
1330                        context.getResources().getDimensionPixelSize(
1331                                R.dimen.signal_cluster_margin_start),
1332                        0, 0, 0);
1333                newCluster.setLayoutParams(layoutParams);
1334                viewParent.addView(newCluster, index);
1335                return newCluster;
1336            }
1337            return signalCluster;
1338        }
1339        return null;
1340    }
1341
1342    private void inflateEmptyShadeView() {
1343        mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
1344                R.layout.status_bar_no_notifications, mStackScroller, false);
1345        mStackScroller.setEmptyShadeView(mEmptyShadeView);
1346    }
1347
1348    private void inflateDismissView() {
1349        mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
1350                R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
1351        mDismissView.setOnButtonClickListener(new View.OnClickListener() {
1352            @Override
1353            public void onClick(View v) {
1354                MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES);
1355                clearAllNotifications();
1356            }
1357        });
1358        mStackScroller.setDismissView(mDismissView);
1359    }
1360
1361    protected void createUserSwitcher() {
1362        mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
1363                (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
1364                mKeyguardStatusBar, mNotificationPanel);
1365    }
1366
1367    protected void inflateStatusBarWindow(Context context) {
1368        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
1369                R.layout.super_status_bar, null);
1370    }
1371
1372    public void clearAllNotifications() {
1373
1374        // animate-swipe all dismissable notifications, then animate the shade closed
1375        int numChildren = mStackScroller.getChildCount();
1376
1377        final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren);
1378        for (int i = 0; i < numChildren; i++) {
1379            final View child = mStackScroller.getChildAt(i);
1380            if (child instanceof ExpandableNotificationRow) {
1381                if (mStackScroller.canChildBeDismissed(child)) {
1382                    if (child.getVisibility() == View.VISIBLE) {
1383                        viewsToHide.add(child);
1384                    }
1385                }
1386                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1387                List<ExpandableNotificationRow> children = row.getNotificationChildren();
1388                if (row.areChildrenExpanded() && children != null) {
1389                    for (ExpandableNotificationRow childRow : children) {
1390                        if (mStackScroller.canChildBeDismissed(childRow)) {
1391                            if (childRow.getVisibility() == View.VISIBLE) {
1392                                viewsToHide.add(childRow);
1393                            }
1394                        }
1395                    }
1396                }
1397            }
1398        }
1399        if (viewsToHide.isEmpty()) {
1400            animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1401            return;
1402        }
1403
1404        addPostCollapseAction(new Runnable() {
1405            @Override
1406            public void run() {
1407                mStackScroller.setDismissAllInProgress(false);
1408                try {
1409                    mBarService.onClearAllNotifications(mCurrentUserId);
1410                } catch (Exception ex) { }
1411            }
1412        });
1413
1414        performDismissAllAnimations(viewsToHide);
1415
1416    }
1417
1418    private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
1419        Runnable animationFinishAction = new Runnable() {
1420            @Override
1421            public void run() {
1422                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1423            }
1424        };
1425
1426        // let's disable our normal animations
1427        mStackScroller.setDismissAllInProgress(true);
1428
1429        // Decrease the delay for every row we animate to give the sense of
1430        // accelerating the swipes
1431        int rowDelayDecrement = 10;
1432        int currentDelay = 140;
1433        int totalDelay = 180;
1434        int numItems = hideAnimatedList.size();
1435        for (int i = numItems - 1; i >= 0; i--) {
1436            View view = hideAnimatedList.get(i);
1437            Runnable endRunnable = null;
1438            if (i == 0) {
1439                endRunnable = animationFinishAction;
1440            }
1441            mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260);
1442            currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
1443            totalDelay += currentDelay;
1444        }
1445    }
1446
1447    protected void setZenMode(int mode) {
1448        // start old BaseStatusBar.setZenMode().
1449        if (isDeviceProvisioned()) {
1450            mZenMode = mode;
1451            updateNotifications();
1452        }
1453        // end old BaseStatusBar.setZenMode().
1454    }
1455
1456    protected void startKeyguard() {
1457        Trace.beginSection("StatusBar#startKeyguard");
1458        KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
1459        mFingerprintUnlockController = new FingerprintUnlockController(mContext,
1460                mDozeScrimController, keyguardViewMediator,
1461                mScrimController, this, UnlockMethodCache.getInstance(mContext));
1462        mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
1463                getBouncerContainer(), mScrimController,
1464                mFingerprintUnlockController);
1465        mKeyguardIndicationController.setStatusBarKeyguardViewManager(
1466                mStatusBarKeyguardViewManager);
1467        mKeyguardIndicationController.setUserInfoController(
1468                Dependency.get(UserInfoController.class));
1469        mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1470        mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
1471
1472        mRemoteInputController.addCallback(new RemoteInputController.Callback() {
1473            @Override
1474            public void onRemoteInputSent(Entry entry) {
1475                if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) {
1476                    removeNotification(entry.key, null);
1477                } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) {
1478                    // We're currently holding onto this notification, but from the apps point of
1479                    // view it is already canceled, so we'll need to cancel it on the apps behalf
1480                    // after sending - unless the app posts an update in the mean time, so wait a
1481                    // bit.
1482                    mHandler.postDelayed(() -> {
1483                        if (mRemoteInputEntriesToRemoveOnCollapse.remove(entry)) {
1484                            removeNotification(entry.key, null);
1485                        }
1486                    }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
1487                }
1488            }
1489        });
1490
1491        mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
1492        mLightBarController.setFingerprintUnlockController(mFingerprintUnlockController);
1493        Trace.endSection();
1494    }
1495
1496    protected View getStatusBarView() {
1497        return mStatusBarView;
1498    }
1499
1500    public StatusBarWindowView getStatusBarWindow() {
1501        return mStatusBarWindow;
1502    }
1503
1504    protected ViewGroup getBouncerContainer() {
1505        return mStatusBarWindow;
1506    }
1507
1508    public int getStatusBarHeight() {
1509        if (mNaturalBarHeight < 0) {
1510            final Resources res = mContext.getResources();
1511            mNaturalBarHeight =
1512                    res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
1513        }
1514        return mNaturalBarHeight;
1515    }
1516
1517    protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
1518        if (mRecents == null) {
1519            return false;
1520        }
1521        int dockSide = WindowManagerProxy.getInstance().getDockSide();
1522        if (dockSide == WindowManager.DOCKED_INVALID) {
1523            return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
1524                    ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
1525        } else {
1526            Divider divider = getComponent(Divider.class);
1527            if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
1528                // Undocking from the minimized state is not supported
1529                return false;
1530            } else {
1531                EventBus.getDefault().send(new UndockingTaskEvent());
1532                if (metricsUndockAction != -1) {
1533                    MetricsLogger.action(mContext, metricsUndockAction);
1534                }
1535            }
1536        }
1537        return true;
1538    }
1539
1540    void awakenDreams() {
1541        if (mDreamManager != null) {
1542            try {
1543                mDreamManager.awaken();
1544            } catch (RemoteException e) {
1545                // fine, stay asleep then
1546            }
1547        }
1548    }
1549
1550    public UserHandle getCurrentUserHandle() {
1551        return new UserHandle(mCurrentUserId);
1552    }
1553
1554    public void addNotification(StatusBarNotification notification, RankingMap ranking,
1555            Entry oldEntry) throws InflationException {
1556        if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
1557
1558        mNotificationData.updateRanking(ranking);
1559        Entry shadeEntry = createNotificationViews(notification);
1560        boolean isHeadsUped = shouldPeek(shadeEntry);
1561        if (isHeadsUped) {
1562            mHeadsUpManager.showNotification(shadeEntry);
1563            // Mark as seen immediately
1564            setNotificationShown(notification);
1565        }
1566
1567        if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
1568            if (shouldSuppressFullScreenIntent(notification.getKey())) {
1569                if (DEBUG) {
1570                    Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
1571                }
1572            } else if (mNotificationData.getImportance(notification.getKey())
1573                    < NotificationManager.IMPORTANCE_HIGH) {
1574                if (DEBUG) {
1575                    Log.d(TAG, "No Fullscreen intent: not important enough: "
1576                            + notification.getKey());
1577                }
1578            } else {
1579                // Stop screensaver if the notification has a full-screen intent.
1580                // (like an incoming phone call)
1581                awakenDreams();
1582
1583                // not immersive & a full-screen alert should be shown
1584                if (DEBUG)
1585                    Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
1586                try {
1587                    EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
1588                            notification.getKey());
1589                    notification.getNotification().fullScreenIntent.send();
1590                    shadeEntry.notifyFullScreenIntentLaunched();
1591                    MetricsLogger.count(mContext, "note_fullscreen", 1);
1592                } catch (PendingIntent.CanceledException e) {
1593                }
1594            }
1595        }
1596        addNotificationViews(shadeEntry, ranking);
1597        // Recalculate the position of the sliding windows and the titles.
1598        setAreThereNotifications();
1599    }
1600
1601    public void handleInflationException(StatusBarNotification notification, InflationException e) {
1602        handleNotificationError(notification, e.getMessage());
1603    }
1604
1605    private boolean shouldSuppressFullScreenIntent(String key) {
1606        if (isDeviceInVrMode()) {
1607            return true;
1608        }
1609
1610        if (mPowerManager.isInteractive()) {
1611            return mNotificationData.shouldSuppressScreenOn(key);
1612        } else {
1613            return mNotificationData.shouldSuppressScreenOff(key);
1614        }
1615    }
1616
1617    protected void updateNotificationRanking(RankingMap ranking) {
1618        mNotificationData.updateRanking(ranking);
1619        updateNotifications();
1620    }
1621
1622    public void removeNotification(String key, RankingMap ranking) {
1623        boolean deferRemoval = false;
1624        if (mHeadsUpManager.isHeadsUp(key)) {
1625            // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
1626            // sending look longer than it takes.
1627            // Also we should not defer the removal if reordering isn't allowed since otherwise
1628            // some notifications can't disappear before the panel is closed.
1629            boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key)
1630                    && !FORCE_REMOTE_INPUT_HISTORY
1631                    || !mVisualStabilityManager.isReorderingAllowed();
1632            deferRemoval = !mHeadsUpManager.removeNotification(key,  ignoreEarliestRemovalTime);
1633        }
1634        if (key.equals(mMediaNotificationKey)) {
1635            clearCurrentMediaNotification();
1636            updateMediaMetaData(true, true);
1637        }
1638        if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
1639            Entry entry = mNotificationData.get(key);
1640            StatusBarNotification sbn = entry.notification;
1641
1642            Notification.Builder b = Notification.Builder
1643                    .recoverBuilder(mContext, sbn.getNotification().clone());
1644            CharSequence[] oldHistory = sbn.getNotification().extras
1645                    .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
1646            CharSequence[] newHistory;
1647            if (oldHistory == null) {
1648                newHistory = new CharSequence[1];
1649            } else {
1650                newHistory = new CharSequence[oldHistory.length + 1];
1651                for (int i = 0; i < oldHistory.length; i++) {
1652                    newHistory[i + 1] = oldHistory[i];
1653                }
1654            }
1655            newHistory[0] = String.valueOf(entry.remoteInputText);
1656            b.setRemoteInputHistory(newHistory);
1657
1658            Notification newNotification = b.build();
1659
1660            // Undo any compatibility view inflation
1661            newNotification.contentView = sbn.getNotification().contentView;
1662            newNotification.bigContentView = sbn.getNotification().bigContentView;
1663            newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
1664
1665            StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
1666                    sbn.getOpPkg(),
1667                    sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1668                    newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
1669            boolean updated = false;
1670            try {
1671                updateNotification(newSbn, null);
1672                updated = true;
1673            } catch (InflationException e) {
1674                deferRemoval = false;
1675            }
1676            if (updated) {
1677                mKeysKeptForRemoteInput.add(entry.key);
1678                return;
1679            }
1680        }
1681        if (deferRemoval) {
1682            mLatestRankingMap = ranking;
1683            mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
1684            return;
1685        }
1686        Entry entry = mNotificationData.get(key);
1687
1688        if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
1689                && (entry.row != null && !entry.row.isDismissed())) {
1690            mLatestRankingMap = ranking;
1691            mRemoteInputEntriesToRemoveOnCollapse.add(entry);
1692            return;
1693        }
1694
1695        if (entry != null && entry.row != null) {
1696            entry.row.setRemoved();
1697            mStackScroller.cleanUpViewState(entry.row);
1698        }
1699        // Let's remove the children if this was a summary
1700        handleGroupSummaryRemoved(key, ranking);
1701        StatusBarNotification old = removeNotificationViews(key, ranking);
1702        if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
1703
1704        if (old != null) {
1705            if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
1706                    && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
1707                if (mState == StatusBarState.SHADE) {
1708                    animateCollapsePanels();
1709                } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) {
1710                    goToKeyguard();
1711                }
1712            }
1713        }
1714        setAreThereNotifications();
1715    }
1716
1717    /**
1718     * Ensures that the group children are cancelled immediately when the group summary is cancelled
1719     * instead of waiting for the notification manager to send all cancels. Otherwise this could
1720     * lead to flickers.
1721     *
1722     * This also ensures that the animation looks nice and only consists of a single disappear
1723     * animation instead of multiple.
1724     *
1725     * @param key the key of the notification was removed
1726     * @param ranking the current ranking
1727     */
1728    private void handleGroupSummaryRemoved(String key,
1729            RankingMap ranking) {
1730        Entry entry = mNotificationData.get(key);
1731        if (entry != null && entry.row != null
1732                && entry.row.isSummaryWithChildren()) {
1733            if (entry.notification.getOverrideGroupKey() != null && !entry.row.isDismissed()) {
1734                // We don't want to remove children for autobundled notifications as they are not
1735                // always cancelled. We only remove them if they were dismissed by the user.
1736                return;
1737            }
1738            List<ExpandableNotificationRow> notificationChildren =
1739                    entry.row.getNotificationChildren();
1740            ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
1741            for (int i = 0; i < notificationChildren.size(); i++) {
1742                ExpandableNotificationRow row = notificationChildren.get(i);
1743                if ((row.getStatusBarNotification().getNotification().flags
1744                        & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
1745                    // the child is a forground service notification which we can't remove!
1746                    continue;
1747                }
1748                toRemove.add(row);
1749                toRemove.get(i).setKeepInParent(true);
1750                // we need to set this state earlier as otherwise we might generate some weird
1751                // animations
1752                toRemove.get(i).setRemoved();
1753            }
1754        }
1755    }
1756
1757    protected void performRemoveNotification(StatusBarNotification n) {
1758        Entry entry = mNotificationData.get(n.getKey());
1759        if (mRemoteInputController.isRemoteInputActive(entry)) {
1760            mRemoteInputController.removeRemoteInput(entry, null);
1761        }
1762        // start old BaseStatusBar.performRemoveNotification.
1763        final String pkg = n.getPackageName();
1764        final String tag = n.getTag();
1765        final int id = n.getId();
1766        final int userId = n.getUserId();
1767        try {
1768            mBarService.onNotificationClear(pkg, tag, id, userId);
1769            if (FORCE_REMOTE_INPUT_HISTORY
1770                    && mKeysKeptForRemoteInput.contains(n.getKey())) {
1771                mKeysKeptForRemoteInput.remove(n.getKey());
1772            }
1773            removeNotification(n.getKey(), null);
1774
1775        } catch (RemoteException ex) {
1776            // system process is dead if we're here.
1777        }
1778        // end old BaseStatusBar.performRemoveNotification.
1779    }
1780
1781    private void updateNotificationShade() {
1782        if (mStackScroller == null) return;
1783
1784        // Do not modify the notifications during collapse.
1785        if (isCollapsing()) {
1786            addPostCollapseAction(new Runnable() {
1787                @Override
1788                public void run() {
1789                    updateNotificationShade();
1790                }
1791            });
1792            return;
1793        }
1794
1795        ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1796        ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
1797        final int N = activeNotifications.size();
1798        for (int i=0; i<N; i++) {
1799            Entry ent = activeNotifications.get(i);
1800            if (ent.row.isDismissed() || ent.row.isRemoved()) {
1801                // we don't want to update removed notifications because they could
1802                // temporarily become children if they were isolated before.
1803                continue;
1804            }
1805            int vis = ent.notification.getNotification().visibility;
1806            int userId = ent.notification.getUserId();
1807
1808            // Display public version of the notification if we need to redact.
1809            boolean deviceSensitive = (isLockscreenPublicMode(mCurrentUserId)
1810                    && !userAllowsPrivateNotificationsInPublic(mCurrentUserId));
1811            boolean userSensitive = deviceSensitive || (isLockscreenPublicMode(userId)
1812                    && !userAllowsPrivateNotificationsInPublic(userId));
1813            boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE;
1814            boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
1815            boolean sensitive = (sensitiveNote && userSensitive) || sensitivePackage;
1816            boolean showingPublic = sensitive && isLockscreenPublicMode(userId);
1817            if (showingPublic) {
1818                updatePublicContentView(ent, ent.notification);
1819            }
1820            ent.row.setSensitive(sensitive, deviceSensitive);
1821            if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
1822                ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
1823                        ent.row.getStatusBarNotification());
1824                List<ExpandableNotificationRow> orderedChildren =
1825                        mTmpChildOrderMap.get(summary);
1826                if (orderedChildren == null) {
1827                    orderedChildren = new ArrayList<>();
1828                    mTmpChildOrderMap.put(summary, orderedChildren);
1829                }
1830                orderedChildren.add(ent.row);
1831            } else {
1832                toShow.add(ent.row);
1833            }
1834
1835        }
1836
1837        ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
1838        for (int i=0; i< mStackScroller.getChildCount(); i++) {
1839            View child = mStackScroller.getChildAt(i);
1840            if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
1841                toRemove.add((ExpandableNotificationRow) child);
1842            }
1843        }
1844
1845        for (ExpandableNotificationRow remove : toRemove) {
1846            if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) {
1847                // we are only transfering this notification to its parent, don't generate an animation
1848                mStackScroller.setChildTransferInProgress(true);
1849            }
1850            if (remove.isSummaryWithChildren()) {
1851                remove.removeAllChildren();
1852            }
1853            mStackScroller.removeView(remove);
1854            mStackScroller.setChildTransferInProgress(false);
1855        }
1856
1857        removeNotificationChildren();
1858
1859        for (int i=0; i<toShow.size(); i++) {
1860            View v = toShow.get(i);
1861            if (v.getParent() == null) {
1862                mVisualStabilityManager.notifyViewAddition(v);
1863                mStackScroller.addView(v);
1864            }
1865        }
1866
1867        addNotificationChildrenAndSort();
1868
1869        // So after all this work notifications still aren't sorted correctly.
1870        // Let's do that now by advancing through toShow and mStackScroller in
1871        // lock-step, making sure mStackScroller matches what we see in toShow.
1872        int j = 0;
1873        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1874            View child = mStackScroller.getChildAt(i);
1875            if (!(child instanceof ExpandableNotificationRow)) {
1876                // We don't care about non-notification views.
1877                continue;
1878            }
1879
1880            ExpandableNotificationRow targetChild = toShow.get(j);
1881            if (child != targetChild) {
1882                // Oops, wrong notification at this position. Put the right one
1883                // here and advance both lists.
1884                if (mVisualStabilityManager.canReorderNotification(targetChild)) {
1885                    mStackScroller.changeViewPosition(targetChild, i);
1886                } else {
1887                    mVisualStabilityManager.addReorderingAllowedCallback(this);
1888                }
1889            }
1890            j++;
1891
1892        }
1893
1894        mVisualStabilityManager.onReorderingFinished();
1895        // clear the map again for the next usage
1896        mTmpChildOrderMap.clear();
1897
1898        updateRowStates();
1899        updateSpeedBumpIndex();
1900        updateClearAll();
1901        updateEmptyShadeView();
1902
1903        updateQsExpansionEnabled();
1904
1905        // Let's also update the icons
1906        mNotificationIconAreaController.updateNotificationIcons(mNotificationData);
1907    }
1908
1909    /**
1910     * Disable QS if device not provisioned.
1911     * If the user switcher is simple then disable QS during setup because
1912     * the user intends to use the lock screen user switcher, QS in not needed.
1913     */
1914    private void updateQsExpansionEnabled() {
1915        mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
1916                && (mUserSetup || mUserSwitcherController == null
1917                        || !mUserSwitcherController.isSimpleUserSwitcher())
1918                && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
1919                && !ONLY_CORE_APPS);
1920    }
1921
1922    private void addNotificationChildrenAndSort() {
1923        // Let's now add all notification children which are missing
1924        boolean orderChanged = false;
1925        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1926            View view = mStackScroller.getChildAt(i);
1927            if (!(view instanceof ExpandableNotificationRow)) {
1928                // We don't care about non-notification views.
1929                continue;
1930            }
1931
1932            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
1933            List<ExpandableNotificationRow> children = parent.getNotificationChildren();
1934            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
1935
1936            for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
1937                    childIndex++) {
1938                ExpandableNotificationRow childView = orderedChildren.get(childIndex);
1939                if (children == null || !children.contains(childView)) {
1940                    if (childView.getParent() != null) {
1941                        Log.wtf(TAG, "trying to add a notification child that already has " +
1942                                "a parent. class:" + childView.getParent().getClass() +
1943                                "\n child: " + childView);
1944                        // This shouldn't happen. We can recover by removing it though.
1945                        ((ViewGroup) childView.getParent()).removeView(childView);
1946                    }
1947                    mVisualStabilityManager.notifyViewAddition(childView);
1948                    parent.addChildNotification(childView, childIndex);
1949                    mStackScroller.notifyGroupChildAdded(childView);
1950                }
1951            }
1952
1953            // Finally after removing and adding has been beformed we can apply the order.
1954            orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager, this);
1955        }
1956        if (orderChanged) {
1957            mStackScroller.generateChildOrderChangedEvent();
1958        }
1959    }
1960
1961    private void removeNotificationChildren() {
1962        // First let's remove all children which don't belong in the parents
1963        ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
1964        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1965            View view = mStackScroller.getChildAt(i);
1966            if (!(view instanceof ExpandableNotificationRow)) {
1967                // We don't care about non-notification views.
1968                continue;
1969            }
1970
1971            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
1972            List<ExpandableNotificationRow> children = parent.getNotificationChildren();
1973            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
1974
1975            if (children != null) {
1976                toRemove.clear();
1977                for (ExpandableNotificationRow childRow : children) {
1978                    if ((orderedChildren == null
1979                            || !orderedChildren.contains(childRow))
1980                            && !childRow.keepInParent()) {
1981                        toRemove.add(childRow);
1982                    }
1983                }
1984                for (ExpandableNotificationRow remove : toRemove) {
1985                    parent.removeChildNotification(remove);
1986                    if (mNotificationData.get(remove.getStatusBarNotification().getKey()) == null) {
1987                        // We only want to add an animation if the view is completely removed
1988                        // otherwise it's just a transfer
1989                        mStackScroller.notifyGroupChildRemoved(remove,
1990                                parent.getChildrenContainer());
1991                    }
1992                }
1993            }
1994        }
1995    }
1996
1997    public void addQsTile(ComponentName tile) {
1998        mQSPanel.getHost().addTile(tile);
1999    }
2000
2001    public void remQsTile(ComponentName tile) {
2002        mQSPanel.getHost().removeTile(tile);
2003    }
2004
2005    public void clickTile(ComponentName tile) {
2006        mQSPanel.clickTile(tile);
2007    }
2008
2009    private boolean packageHasVisibilityOverride(String key) {
2010        return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE;
2011    }
2012
2013    private void updateClearAll() {
2014        boolean showDismissView =
2015                mState != StatusBarState.KEYGUARD &&
2016               hasActiveClearableNotifications();
2017        mStackScroller.updateDismissView(showDismissView);
2018    }
2019
2020    /**
2021     * Return whether there are any clearable notifications
2022     */
2023    private boolean hasActiveClearableNotifications() {
2024        int childCount = mStackScroller.getChildCount();
2025        for (int i = 0; i < childCount; i++) {
2026            View child = mStackScroller.getChildAt(i);
2027            if (!(child instanceof ExpandableNotificationRow)) {
2028                continue;
2029            }
2030            if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
2031                    return true;
2032            }
2033        }
2034        return false;
2035    }
2036
2037    private void updateEmptyShadeView() {
2038        boolean showEmptyShadeView =
2039                mState != StatusBarState.KEYGUARD &&
2040                        mNotificationData.getActiveNotifications().size() == 0;
2041        mNotificationPanel.showEmptyShadeView(showEmptyShadeView);
2042    }
2043
2044    private void updateSpeedBumpIndex() {
2045        int speedBumpIndex = 0;
2046        int currentIndex = 0;
2047        final int N = mStackScroller.getChildCount();
2048        for (int i = 0; i < N; i++) {
2049            View view = mStackScroller.getChildAt(i);
2050            if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) {
2051                continue;
2052            }
2053            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2054            currentIndex++;
2055            if (!mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) {
2056                speedBumpIndex = currentIndex;
2057            }
2058        }
2059        boolean noAmbient = speedBumpIndex == N;
2060        mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient);
2061    }
2062
2063    public static boolean isTopLevelChild(Entry entry) {
2064        return entry.row.getParent() instanceof NotificationStackScrollLayout;
2065    }
2066
2067    protected void updateNotifications() {
2068        mNotificationData.filterAndSort();
2069
2070        updateNotificationShade();
2071    }
2072
2073    public void requestNotificationUpdate() {
2074        updateNotifications();
2075    }
2076
2077    protected void setAreThereNotifications() {
2078
2079        if (SPEW) {
2080            final boolean clearable = hasActiveNotifications() &&
2081                    hasActiveClearableNotifications();
2082            Log.d(TAG, "setAreThereNotifications: N=" +
2083                    mNotificationData.getActiveNotifications().size() + " any=" +
2084                    hasActiveNotifications() + " clearable=" + clearable);
2085        }
2086
2087        if (mStatusBarView != null) {
2088            final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
2089            final boolean showDot = hasActiveNotifications() && !areLightsOn();
2090            if (showDot != (nlo.getAlpha() == 1.0f)) {
2091                if (showDot) {
2092                    nlo.setAlpha(0f);
2093                    nlo.setVisibility(View.VISIBLE);
2094                }
2095                nlo.animate()
2096                        .alpha(showDot ? 1 : 0)
2097                        .setDuration(showDot ? 750 : 250)
2098                        .setInterpolator(new AccelerateInterpolator(2.0f))
2099                        .setListener(showDot ? null : new AnimatorListenerAdapter() {
2100                            @Override
2101                            public void onAnimationEnd(Animator _a) {
2102                                nlo.setVisibility(View.GONE);
2103                            }
2104                        })
2105                        .start();
2106            }
2107        }
2108
2109        findAndUpdateMediaNotifications();
2110    }
2111
2112    public void findAndUpdateMediaNotifications() {
2113        boolean metaDataChanged = false;
2114
2115        synchronized (mNotificationData) {
2116            ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
2117            final int N = activeNotifications.size();
2118
2119            // Promote the media notification with a controller in 'playing' state, if any.
2120            Entry mediaNotification = null;
2121            MediaController controller = null;
2122            for (int i = 0; i < N; i++) {
2123                final Entry entry = activeNotifications.get(i);
2124                if (isMediaNotification(entry)) {
2125                    final MediaSession.Token token =
2126                            entry.notification.getNotification().extras
2127                            .getParcelable(Notification.EXTRA_MEDIA_SESSION);
2128                    if (token != null) {
2129                        MediaController aController = new MediaController(mContext, token);
2130                        if (PlaybackState.STATE_PLAYING ==
2131                                getMediaControllerPlaybackState(aController)) {
2132                            if (DEBUG_MEDIA) {
2133                                Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
2134                                        + entry.notification.getKey());
2135                            }
2136                            mediaNotification = entry;
2137                            controller = aController;
2138                            break;
2139                        }
2140                    }
2141                }
2142            }
2143            if (mediaNotification == null) {
2144                // Still nothing? OK, let's just look for live media sessions and see if they match
2145                // one of our notifications. This will catch apps that aren't (yet!) using media
2146                // notifications.
2147
2148                if (mMediaSessionManager != null) {
2149                    final List<MediaController> sessions
2150                            = mMediaSessionManager.getActiveSessionsForUser(
2151                                    null,
2152                                    UserHandle.USER_ALL);
2153
2154                    for (MediaController aController : sessions) {
2155                        if (PlaybackState.STATE_PLAYING ==
2156                                getMediaControllerPlaybackState(aController)) {
2157                            // now to see if we have one like this
2158                            final String pkg = aController.getPackageName();
2159
2160                            for (int i = 0; i < N; i++) {
2161                                final Entry entry = activeNotifications.get(i);
2162                                if (entry.notification.getPackageName().equals(pkg)) {
2163                                    if (DEBUG_MEDIA) {
2164                                        Log.v(TAG, "DEBUG_MEDIA: found controller matching "
2165                                            + entry.notification.getKey());
2166                                    }
2167                                    controller = aController;
2168                                    mediaNotification = entry;
2169                                    break;
2170                                }
2171                            }
2172                        }
2173                    }
2174                }
2175            }
2176
2177            if (controller != null && !sameSessions(mMediaController, controller)) {
2178                // We have a new media session
2179                clearCurrentMediaNotification();
2180                mMediaController = controller;
2181                mMediaController.registerCallback(mMediaListener);
2182                mMediaMetadata = mMediaController.getMetadata();
2183                if (DEBUG_MEDIA) {
2184                    Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: "
2185                            + mMediaMetadata);
2186                }
2187
2188                if (mediaNotification != null) {
2189                    mMediaNotificationKey = mediaNotification.notification.getKey();
2190                    if (DEBUG_MEDIA) {
2191                        Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
2192                                + mMediaNotificationKey + " controller=" + mMediaController);
2193                    }
2194                }
2195                metaDataChanged = true;
2196            }
2197        }
2198
2199        if (metaDataChanged) {
2200            updateNotifications();
2201        }
2202        updateMediaMetaData(metaDataChanged, true);
2203    }
2204
2205    private int getMediaControllerPlaybackState(MediaController controller) {
2206        if (controller != null) {
2207            final PlaybackState playbackState = controller.getPlaybackState();
2208            if (playbackState != null) {
2209                return playbackState.getState();
2210            }
2211        }
2212        return PlaybackState.STATE_NONE;
2213    }
2214
2215    private boolean isPlaybackActive(int state) {
2216        if (state != PlaybackState.STATE_STOPPED
2217                && state != PlaybackState.STATE_ERROR
2218                && state != PlaybackState.STATE_NONE) {
2219            return true;
2220        }
2221        return false;
2222    }
2223
2224    private void clearCurrentMediaNotification() {
2225        mMediaNotificationKey = null;
2226        mMediaMetadata = null;
2227        if (mMediaController != null) {
2228            if (DEBUG_MEDIA) {
2229                Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
2230                        + mMediaController.getPackageName());
2231            }
2232            mMediaController.unregisterCallback(mMediaListener);
2233        }
2234        mMediaController = null;
2235    }
2236
2237    private boolean sameSessions(MediaController a, MediaController b) {
2238        if (a == b) return true;
2239        if (a == null) return false;
2240        return a.controlsSameSession(b);
2241    }
2242
2243    /**
2244     * Hide the album artwork that is fading out and release its bitmap.
2245     */
2246    protected Runnable mHideBackdropFront = new Runnable() {
2247        @Override
2248        public void run() {
2249            if (DEBUG_MEDIA) {
2250                Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
2251            }
2252            mBackdropFront.setVisibility(View.INVISIBLE);
2253            mBackdropFront.animate().cancel();
2254            mBackdropFront.setImageDrawable(null);
2255        }
2256    };
2257
2258    /**
2259     * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
2260     */
2261    public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
2262        Trace.beginSection("StatusBar#updateMediaMetaData");
2263        if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
2264            Trace.endSection();
2265            return;
2266        }
2267
2268        if (mBackdrop == null) {
2269            Trace.endSection();
2270            return; // called too early
2271        }
2272
2273        if (mLaunchTransitionFadingAway) {
2274            mBackdrop.setVisibility(View.INVISIBLE);
2275            Trace.endSection();
2276            return;
2277        }
2278
2279        if (DEBUG_MEDIA) {
2280            Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey
2281                    + " metadata=" + mMediaMetadata
2282                    + " metaDataChanged=" + metaDataChanged
2283                    + " state=" + mState);
2284        }
2285
2286        Drawable artworkDrawable = null;
2287        if (mMediaMetadata != null) {
2288            Bitmap artworkBitmap = null;
2289            artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
2290            if (artworkBitmap == null) {
2291                artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
2292                // might still be null
2293            }
2294            if (artworkBitmap != null) {
2295                artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
2296            }
2297        }
2298        boolean allowWhenShade = false;
2299        if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
2300            Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
2301            if (lockWallpaper != null) {
2302                artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
2303                        mBackdropBack.getResources(), lockWallpaper);
2304                // We're in the SHADE mode on the SIM screen - yet we still need to show
2305                // the lockscreen wallpaper in that mode.
2306                allowWhenShade = mStatusBarKeyguardViewManager != null
2307                        && mStatusBarKeyguardViewManager.isShowing();
2308            }
2309        }
2310
2311        boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null
2312                && mStatusBarKeyguardViewManager.isOccluded();
2313
2314        final boolean hasArtwork = artworkDrawable != null;
2315
2316        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
2317                && (mState != StatusBarState.SHADE || allowWhenShade)
2318                && mFingerprintUnlockController.getMode()
2319                        != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
2320                && !hideBecauseOccluded) {
2321            // time to show some art!
2322            if (mBackdrop.getVisibility() != View.VISIBLE) {
2323                mBackdrop.setVisibility(View.VISIBLE);
2324                if (allowEnterAnimation) {
2325                    mBackdrop.setAlpha(SRC_MIN_ALPHA);
2326                    mBackdrop.animate().alpha(1f);
2327                } else {
2328                    mBackdrop.animate().cancel();
2329                    mBackdrop.setAlpha(1f);
2330                }
2331                mStatusBarWindowManager.setBackdropShowing(true);
2332                metaDataChanged = true;
2333                if (DEBUG_MEDIA) {
2334                    Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
2335                }
2336            }
2337            if (metaDataChanged) {
2338                if (mBackdropBack.getDrawable() != null) {
2339                    Drawable drawable =
2340                            mBackdropBack.getDrawable().getConstantState()
2341                                    .newDrawable(mBackdropFront.getResources()).mutate();
2342                    mBackdropFront.setImageDrawable(drawable);
2343                    if (mScrimSrcModeEnabled) {
2344                        mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode);
2345                    }
2346                    mBackdropFront.setAlpha(1f);
2347                    mBackdropFront.setVisibility(View.VISIBLE);
2348                } else {
2349                    mBackdropFront.setVisibility(View.INVISIBLE);
2350                }
2351
2352                if (DEBUG_MEDIA_FAKE_ARTWORK) {
2353                    final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
2354                    Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
2355                    mBackdropBack.setBackgroundColor(0xFFFFFFFF);
2356                    mBackdropBack.setImageDrawable(new ColorDrawable(c));
2357                } else {
2358                    mBackdropBack.setImageDrawable(artworkDrawable);
2359                }
2360                if (mScrimSrcModeEnabled) {
2361                    mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
2362                }
2363
2364                if (mBackdropFront.getVisibility() == View.VISIBLE) {
2365                    if (DEBUG_MEDIA) {
2366                        Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
2367                                + mBackdropFront.getDrawable()
2368                                + " to "
2369                                + mBackdropBack.getDrawable());
2370                    }
2371                    mBackdropFront.animate()
2372                            .setDuration(250)
2373                            .alpha(0f).withEndAction(mHideBackdropFront);
2374                }
2375            }
2376        } else {
2377            // need to hide the album art, either because we are unlocked or because
2378            // the metadata isn't there to support it
2379            if (mBackdrop.getVisibility() != View.GONE) {
2380                if (DEBUG_MEDIA) {
2381                    Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
2382                }
2383                if (mFingerprintUnlockController.getMode()
2384                        == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
2385                        || hideBecauseOccluded) {
2386
2387                    // We are unlocking directly - no animation!
2388                    mBackdrop.setVisibility(View.GONE);
2389                    mBackdropBack.setImageDrawable(null);
2390                    mStatusBarWindowManager.setBackdropShowing(false);
2391                } else {
2392                    mStatusBarWindowManager.setBackdropShowing(false);
2393                    mBackdrop.animate()
2394                            .alpha(SRC_MIN_ALPHA)
2395                            .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
2396                            .setDuration(300)
2397                            .setStartDelay(0)
2398                            .withEndAction(new Runnable() {
2399                                @Override
2400                                public void run() {
2401                                    mBackdrop.setVisibility(View.GONE);
2402                                    mBackdropFront.animate().cancel();
2403                                    mBackdropBack.setImageDrawable(null);
2404                                    mHandler.post(mHideBackdropFront);
2405                                }
2406                            });
2407                    if (mKeyguardFadingAway) {
2408                        mBackdrop.animate()
2409                                // Make it disappear faster, as the focus should be on the activity
2410                                // behind.
2411                                .setDuration(mKeyguardFadingAwayDuration / 2)
2412                                .setStartDelay(mKeyguardFadingAwayDelay)
2413                                .setInterpolator(Interpolators.LINEAR)
2414                                .start();
2415                    }
2416                }
2417            }
2418        }
2419        Trace.endSection();
2420    }
2421
2422    private void updateReportRejectedTouchVisibility() {
2423        if (mReportRejectedTouch == null) {
2424            return;
2425        }
2426        mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD
2427                && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
2428    }
2429
2430    /**
2431     * State is one or more of the DISABLE constants from StatusBarManager.
2432     */
2433    @Override
2434    public void disable(int state1, int state2, boolean animate) {
2435        animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
2436        mDisabledUnmodified1 = state1;
2437        mDisabledUnmodified2 = state2;
2438        final int old1 = mDisabled1;
2439        final int diff1 = state1 ^ old1;
2440        mDisabled1 = state1;
2441
2442        final int old2 = mDisabled2;
2443        final int diff2 = state2 ^ old2;
2444        mDisabled2 = state2;
2445
2446        if (DEBUG) {
2447            Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
2448                old1, state1, diff1));
2449            Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
2450                old2, state2, diff2));
2451        }
2452
2453        StringBuilder flagdbg = new StringBuilder();
2454        flagdbg.append("disable: < ");
2455        flagdbg.append(((state1 & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
2456        flagdbg.append(((diff1  & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
2457        flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
2458        flagdbg.append(((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
2459        flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
2460        flagdbg.append(((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
2461        flagdbg.append(((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
2462        flagdbg.append(((diff1  & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
2463        flagdbg.append(((state1 & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
2464        flagdbg.append(((diff1  & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
2465        flagdbg.append(((state1 & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
2466        flagdbg.append(((diff1  & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
2467        flagdbg.append(((state1 & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
2468        flagdbg.append(((diff1  & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
2469        flagdbg.append(((state1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
2470        flagdbg.append(((diff1  & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
2471        flagdbg.append(((state1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
2472        flagdbg.append(((diff1  & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
2473        flagdbg.append(((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "QUICK_SETTINGS"
2474                : "quick_settings");
2475        flagdbg.append(((diff2  & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "* " : " ");
2476        flagdbg.append(">");
2477        Log.d(TAG, flagdbg.toString());
2478
2479        if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
2480            if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
2481                animateCollapsePanels();
2482            }
2483        }
2484
2485        if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
2486            if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
2487                // close recents if it's visible
2488                mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
2489                mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
2490            }
2491        }
2492
2493        if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
2494            mDisableNotificationAlerts =
2495                    (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
2496            mHeadsUpObserver.onChange(true);
2497        }
2498
2499        if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
2500            updateQsExpansionEnabled();
2501        }
2502    }
2503
2504    /**
2505     * Reapplies the disable flags as last requested by StatusBarManager.
2506     *
2507     * This needs to be called if state used by {@link #adjustDisableFlags} changes.
2508     */
2509    public void recomputeDisableFlags(boolean animate) {
2510        mCommandQueue.recomputeDisableFlags(animate);
2511    }
2512
2513    protected H createHandler() {
2514        return new StatusBar.H();
2515    }
2516
2517    @Override
2518    public void startActivity(Intent intent, boolean dismissShade) {
2519        startActivityDismissingKeyguard(intent, false, dismissShade);
2520    }
2521
2522    @Override
2523    public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
2524        startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade);
2525    }
2526
2527    @Override
2528    public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
2529        startActivityDismissingKeyguard(intent, false, dismissShade, callback);
2530    }
2531
2532    public void setQsExpanded(boolean expanded) {
2533        mStatusBarWindowManager.setQsExpanded(expanded);
2534        mKeyguardStatusView.setImportantForAccessibility(expanded
2535                ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
2536                : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
2537    }
2538
2539    public boolean isGoingToNotificationShade() {
2540        return mLeaveOpenOnKeyguardHide;
2541    }
2542
2543    public boolean isWakeUpComingFromTouch() {
2544        return mWakeUpComingFromTouch;
2545    }
2546
2547    public boolean isFalsingThresholdNeeded() {
2548        return getBarState() == StatusBarState.KEYGUARD;
2549    }
2550
2551    public boolean isDozing() {
2552        return mDozing;
2553    }
2554
2555    @Override  // NotificationData.Environment
2556    public String getCurrentMediaNotificationKey() {
2557        return mMediaNotificationKey;
2558    }
2559
2560    public boolean isScrimSrcModeEnabled() {
2561        return mScrimSrcModeEnabled;
2562    }
2563
2564    /**
2565     * To be called when there's a state change in StatusBarKeyguardViewManager.
2566     */
2567    public void onKeyguardViewManagerStatesUpdated() {
2568        logStateToEventlog();
2569    }
2570
2571    @Override  // UnlockMethodCache.OnUnlockMethodChangedListener
2572    public void onUnlockMethodStateChanged() {
2573        logStateToEventlog();
2574    }
2575
2576    @Override
2577    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
2578        if (inPinnedMode) {
2579            mStatusBarWindowManager.setHeadsUpShowing(true);
2580            mStatusBarWindowManager.setForceStatusBarVisible(true);
2581            if (mNotificationPanel.isFullyCollapsed()) {
2582                // We need to ensure that the touchable region is updated before the window will be
2583                // resized, in order to not catch any touches. A layout will ensure that
2584                // onComputeInternalInsets will be called and after that we can resize the layout. Let's
2585                // make sure that the window stays small for one frame until the touchableRegion is set.
2586                mNotificationPanel.requestLayout();
2587                mStatusBarWindowManager.setForceWindowCollapsed(true);
2588                mNotificationPanel.post(new Runnable() {
2589                    @Override
2590                    public void run() {
2591                        mStatusBarWindowManager.setForceWindowCollapsed(false);
2592                    }
2593                });
2594            }
2595        } else {
2596            if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) {
2597                // We are currently tracking or is open and the shade doesn't need to be kept
2598                // open artificially.
2599                mStatusBarWindowManager.setHeadsUpShowing(false);
2600            } else {
2601                // we need to keep the panel open artificially, let's wait until the animation
2602                // is finished.
2603                mHeadsUpManager.setHeadsUpGoingAway(true);
2604                mStackScroller.runAfterAnimationFinished(new Runnable() {
2605                    @Override
2606                    public void run() {
2607                        if (!mHeadsUpManager.hasPinnedHeadsUp()) {
2608                            mStatusBarWindowManager.setHeadsUpShowing(false);
2609                            mHeadsUpManager.setHeadsUpGoingAway(false);
2610                        }
2611                        removeRemoteInputEntriesKeptUntilCollapsed();
2612                    }
2613                });
2614            }
2615        }
2616    }
2617
2618    @Override
2619    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
2620        dismissVolumeDialog();
2621    }
2622
2623    @Override
2624    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
2625    }
2626
2627    @Override
2628    public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
2629        if (!isHeadsUp && mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
2630            removeNotification(entry.key, mLatestRankingMap);
2631            mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
2632            if (mHeadsUpEntriesToRemoveOnSwitch.isEmpty()) {
2633                mLatestRankingMap = null;
2634            }
2635        } else {
2636            updateNotificationRanking(null);
2637            if (isHeadsUp) {
2638                mDozeServiceHost.fireNotificationHeadsUp();
2639            }
2640        }
2641
2642    }
2643
2644    protected void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
2645            boolean alertAgain) {
2646        final boolean wasHeadsUp = isHeadsUp(key);
2647        if (wasHeadsUp) {
2648            if (!shouldPeek) {
2649                // We don't want this to be interrupting anymore, lets remove it
2650                mHeadsUpManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
2651            } else {
2652                mHeadsUpManager.updateNotification(entry, alertAgain);
2653            }
2654        } else if (shouldPeek && alertAgain) {
2655            // This notification was updated to be a heads-up, show it!
2656            mHeadsUpManager.showNotification(entry);
2657        }
2658    }
2659
2660    protected void setHeadsUpUser(int newUserId) {
2661        if (mHeadsUpManager != null) {
2662            mHeadsUpManager.setUser(newUserId);
2663        }
2664    }
2665
2666    public boolean isHeadsUp(String key) {
2667        return mHeadsUpManager.isHeadsUp(key);
2668    }
2669
2670    protected boolean isSnoozedPackage(StatusBarNotification sbn) {
2671        return mHeadsUpManager.isSnoozed(sbn.getPackageName());
2672    }
2673
2674    public boolean isKeyguardCurrentlySecure() {
2675        return !mUnlockMethodCache.canSkipBouncer();
2676    }
2677
2678    public void setPanelExpanded(boolean isExpanded) {
2679        mPanelExpanded = isExpanded;
2680        mStatusBarWindowManager.setPanelExpanded(isExpanded);
2681        mVisualStabilityManager.setPanelExpanded(isExpanded);
2682        if (isExpanded && getBarState() != StatusBarState.KEYGUARD) {
2683            if (DEBUG) {
2684                Log.v(TAG, "clearing notification effects from setPanelExpanded");
2685            }
2686            clearNotificationEffects();
2687        }
2688
2689        if (!isExpanded) {
2690            removeRemoteInputEntriesKeptUntilCollapsed();
2691        }
2692    }
2693
2694    private void removeRemoteInputEntriesKeptUntilCollapsed() {
2695        for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) {
2696            Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i);
2697            mRemoteInputController.removeRemoteInput(entry, null);
2698            removeNotification(entry.key, mLatestRankingMap);
2699        }
2700        mRemoteInputEntriesToRemoveOnCollapse.clear();
2701    }
2702
2703    public void onScreenTurnedOff() {
2704        mFalsingManager.onScreenOff();
2705    }
2706
2707    public NotificationStackScrollLayout getNotificationScrollLayout() {
2708        return mStackScroller;
2709    }
2710
2711    public boolean isPulsing() {
2712        return mDozeScrimController.isPulsing();
2713    }
2714
2715    @Override
2716    public void onReorderingAllowed() {
2717        updateNotifications();
2718    }
2719
2720    public boolean isLaunchTransitionFadingAway() {
2721        return mLaunchTransitionFadingAway;
2722    }
2723
2724    public boolean hideStatusBarIconsWhenExpanded() {
2725        return mNotificationPanel.hideStatusBarIconsWhenExpanded();
2726    }
2727
2728    /**
2729     * All changes to the status bar and notifications funnel through here and are batched.
2730     */
2731    protected class H extends Handler {
2732        @Override
2733        public void handleMessage(Message m) {
2734            switch (m.what) {
2735                case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
2736                    toggleKeyboardShortcuts(m.arg1);
2737                    break;
2738                case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
2739                    dismissKeyboardShortcuts();
2740                    break;
2741                // End old BaseStatusBar.H handling.
2742                case MSG_OPEN_NOTIFICATION_PANEL:
2743                    animateExpandNotificationsPanel();
2744                    break;
2745                case MSG_OPEN_SETTINGS_PANEL:
2746                    animateExpandSettingsPanel((String) m.obj);
2747                    break;
2748                case MSG_CLOSE_PANELS:
2749                    animateCollapsePanels();
2750                    break;
2751                case MSG_LAUNCH_TRANSITION_TIMEOUT:
2752                    onLaunchTransitionTimeout();
2753                    break;
2754            }
2755        }
2756    }
2757
2758    public void maybeEscalateHeadsUp() {
2759        Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries();
2760        for (HeadsUpManager.HeadsUpEntry entry : entries) {
2761            final StatusBarNotification sbn = entry.entry.notification;
2762            final Notification notification = sbn.getNotification();
2763            if (notification.fullScreenIntent != null) {
2764                if (DEBUG) {
2765                    Log.d(TAG, "converting a heads up to fullScreen");
2766                }
2767                try {
2768                    EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
2769                            sbn.getKey());
2770                    notification.fullScreenIntent.send();
2771                    entry.entry.notifyFullScreenIntentLaunched();
2772                } catch (PendingIntent.CanceledException e) {
2773                }
2774            }
2775        }
2776        mHeadsUpManager.releaseAllImmediately();
2777    }
2778
2779    /**
2780     * Called for system navigation gestures. First action opens the panel, second opens
2781     * settings. Down action closes the entire panel.
2782     */
2783    @Override
2784    public void handleSystemNavigationKey(int key) {
2785        if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key);
2786        if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
2787                || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
2788            return;
2789        }
2790
2791        // Panels are not available in setup
2792        if (!mUserSetup) return;
2793
2794        if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
2795            MetricsLogger.action(mContext, MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
2796            mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
2797        } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
2798            MetricsLogger.action(mContext, MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
2799            if (mNotificationPanel.isFullyCollapsed()) {
2800                mNotificationPanel.expand(true /* animate */);
2801                MetricsLogger.count(mContext, NotificationPanelView.COUNTER_PANEL_OPEN, 1);
2802            } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
2803                mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */);
2804                MetricsLogger.count(mContext, NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
2805            }
2806        }
2807
2808    }
2809
2810    boolean panelsEnabled() {
2811        return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0 && !ONLY_CORE_APPS;
2812    }
2813
2814    void makeExpandedVisible(boolean force) {
2815        if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
2816        if (!force && (mExpandedVisible || !panelsEnabled())) {
2817            return;
2818        }
2819
2820        mExpandedVisible = true;
2821
2822        // Expand the window to encompass the full screen in anticipation of the drag.
2823        // This is only possible to do atomically because the status bar is at the top of the screen!
2824        mStatusBarWindowManager.setPanelVisible(true);
2825
2826        visibilityChanged(true);
2827        mWaitingForKeyguardExit = false;
2828        recomputeDisableFlags(!force /* animate */);
2829        setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2830    }
2831
2832    public void animateCollapsePanels() {
2833        animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
2834    }
2835
2836    private final Runnable mAnimateCollapsePanels = new Runnable() {
2837        @Override
2838        public void run() {
2839            animateCollapsePanels();
2840        }
2841    };
2842
2843    public void postAnimateCollapsePanels() {
2844        mHandler.post(mAnimateCollapsePanels);
2845    }
2846
2847    public void postAnimateOpenPanels() {
2848        mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
2849    }
2850
2851    @Override
2852    public void animateCollapsePanels(int flags) {
2853        animateCollapsePanels(flags, false /* force */, false /* delayed */,
2854                1.0f /* speedUpFactor */);
2855    }
2856
2857    public void animateCollapsePanels(int flags, boolean force) {
2858        animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
2859    }
2860
2861    public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
2862        animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
2863    }
2864
2865    public void animateCollapsePanels(int flags, boolean force, boolean delayed,
2866            float speedUpFactor) {
2867        if (!force && mState != StatusBarState.SHADE) {
2868            runPostCollapseRunnables();
2869            return;
2870        }
2871        if (SPEW) {
2872            Log.d(TAG, "animateCollapse():"
2873                    + " mExpandedVisible=" + mExpandedVisible
2874                    + " flags=" + flags);
2875        }
2876
2877        if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
2878            if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
2879                mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
2880                mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
2881            }
2882        }
2883
2884        if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) {
2885            // release focus immediately to kick off focus change transition
2886            mStatusBarWindowManager.setStatusBarFocusable(false);
2887
2888            mStatusBarWindow.cancelExpandHelper();
2889            mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
2890        }
2891    }
2892
2893    private void runPostCollapseRunnables() {
2894        ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables);
2895        mPostCollapseRunnables.clear();
2896        int size = clonedList.size();
2897        for (int i = 0; i < size; i++) {
2898            clonedList.get(i).run();
2899        }
2900        mStatusBarKeyguardViewManager.readyForKeyguardDone();
2901    }
2902
2903    @Override
2904    public void animateExpandNotificationsPanel() {
2905        if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2906        if (!panelsEnabled()) {
2907            return ;
2908        }
2909
2910        mNotificationPanel.expand(true /* animate */);
2911
2912        if (false) postStartTracing();
2913    }
2914
2915    @Override
2916    public void animateExpandSettingsPanel(String subPanel) {
2917        if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2918        if (!panelsEnabled()) {
2919            return;
2920        }
2921
2922        // Settings are not available in setup
2923        if (!mUserSetup) return;
2924
2925
2926        if (subPanel != null) {
2927            mQSPanel.openDetails(subPanel);
2928        }
2929        mNotificationPanel.expandWithQs();
2930
2931        if (false) postStartTracing();
2932    }
2933
2934    public void animateCollapseQuickSettings() {
2935        if (mState == StatusBarState.SHADE) {
2936            mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
2937        }
2938    }
2939
2940    void makeExpandedInvisible() {
2941        if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
2942                + " mExpandedVisible=" + mExpandedVisible);
2943
2944        if (!mExpandedVisible || mStatusBarWindow == null) {
2945            return;
2946        }
2947
2948        // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
2949        mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
2950                1.0f /* speedUpFactor */);
2951
2952        mNotificationPanel.closeQs();
2953
2954        mExpandedVisible = false;
2955        visibilityChanged(false);
2956
2957        // Shrink the window to the size of the status bar only
2958        mStatusBarWindowManager.setPanelVisible(false);
2959        mStatusBarWindowManager.setForceStatusBarVisible(false);
2960
2961        // Close any "App info" popups that might have snuck on-screen
2962        dismissPopups();
2963
2964        runPostCollapseRunnables();
2965        setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2966        showBouncerIfKeyguard();
2967        recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
2968
2969        // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
2970        // the bouncer appear animation.
2971        if (!mStatusBarKeyguardViewManager.isShowing()) {
2972            WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
2973        }
2974    }
2975
2976    public boolean interceptTouchEvent(MotionEvent event) {
2977        if (DEBUG_GESTURES) {
2978            if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
2979                EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
2980                        event.getActionMasked(), (int) event.getX(), (int) event.getY(),
2981                        mDisabled1, mDisabled2);
2982            }
2983
2984        }
2985
2986        if (SPEW) {
2987            Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1="
2988                + mDisabled1 + " mDisabled2=" + mDisabled2 + " mTracking=" + mTracking);
2989        } else if (CHATTY) {
2990            if (event.getAction() != MotionEvent.ACTION_MOVE) {
2991                Log.d(TAG, String.format(
2992                            "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x",
2993                            MotionEvent.actionToString(event.getAction()),
2994                            event.getRawX(), event.getRawY(), mDisabled1, mDisabled2));
2995            }
2996        }
2997
2998        if (DEBUG_GESTURES) {
2999            mGestureRec.add(event);
3000        }
3001
3002        if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
3003            final boolean upOrCancel =
3004                    event.getAction() == MotionEvent.ACTION_UP ||
3005                    event.getAction() == MotionEvent.ACTION_CANCEL;
3006            if (upOrCancel && !mExpandedVisible) {
3007                setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
3008            } else {
3009                setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
3010            }
3011        }
3012        return false;
3013    }
3014
3015    public GestureRecorder getGestureRecorder() {
3016        return mGestureRec;
3017    }
3018
3019    public FingerprintUnlockController getFingerprintUnlockController() {
3020        return mFingerprintUnlockController;
3021    }
3022
3023    @Override // CommandQueue
3024    public void setWindowState(int window, int state) {
3025        boolean showing = state == WINDOW_STATE_SHOWING;
3026        if (mStatusBarWindow != null
3027                && window == StatusBarManager.WINDOW_STATUS_BAR
3028                && mStatusBarWindowState != state) {
3029            mStatusBarWindowState = state;
3030            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
3031            if (!showing && mState == StatusBarState.SHADE) {
3032                mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
3033                        1.0f /* speedUpFactor */);
3034            }
3035        }
3036    }
3037
3038    @Override // CommandQueue
3039    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
3040            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
3041        final int oldVal = mSystemUiVisibility;
3042        final int newVal = (oldVal&~mask) | (vis&mask);
3043        final int diff = newVal ^ oldVal;
3044        if (DEBUG) Log.d(TAG, String.format(
3045                "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
3046                Integer.toHexString(vis), Integer.toHexString(mask),
3047                Integer.toHexString(oldVal), Integer.toHexString(newVal),
3048                Integer.toHexString(diff)));
3049        boolean sbModeChanged = false;
3050        if (diff != 0) {
3051            mSystemUiVisibility = newVal;
3052
3053            // update low profile
3054            if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
3055                setAreThereNotifications();
3056            }
3057
3058            // ready to unhide
3059            if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
3060                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
3061                mNoAnimationOnNextBarModeChange = true;
3062            }
3063
3064            // update status bar mode
3065            final int sbMode = computeStatusBarMode(oldVal, newVal);
3066
3067            sbModeChanged = sbMode != -1;
3068            if (sbModeChanged && sbMode != mStatusBarMode) {
3069                if (sbMode != mStatusBarMode) {
3070                    mStatusBarMode = sbMode;
3071                    checkBarModes();
3072                }
3073                touchAutoHide();
3074            }
3075
3076            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
3077                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
3078            }
3079
3080            // send updated sysui visibility to window manager
3081            notifyUiVisibilityChanged(mSystemUiVisibility);
3082        }
3083
3084        mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
3085                mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
3086    }
3087
3088    void touchAutoHide() {
3089        // update transient bar autohide
3090        if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null
3091                && mNavigationBar.isSemiTransparent())) {
3092            scheduleAutohide();
3093        } else {
3094            cancelAutohide();
3095        }
3096    }
3097
3098    protected int computeStatusBarMode(int oldVal, int newVal) {
3099        return computeBarMode(oldVal, newVal, View.STATUS_BAR_TRANSIENT,
3100                View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT);
3101    }
3102
3103    protected BarTransitions getStatusBarTransitions() {
3104        return mStatusBarView.getBarTransitions();
3105    }
3106
3107    protected int computeBarMode(int oldVis, int newVis,
3108            int transientFlag, int translucentFlag, int transparentFlag) {
3109        final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag);
3110        final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag);
3111        if (oldMode == newMode) {
3112            return -1; // no mode change
3113        }
3114        return newMode;
3115    }
3116
3117    private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
3118        int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
3119        return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
3120                : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
3121                : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
3122                : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
3123                : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
3124                : MODE_OPAQUE;
3125    }
3126
3127    void checkBarModes() {
3128        if (mDemoMode) return;
3129        if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
3130                getStatusBarTransitions());
3131        if (mNavigationBar != null) mNavigationBar.checkNavBarModes();
3132        mNoAnimationOnNextBarModeChange = false;
3133    }
3134
3135    // Called by NavigationBarFragment
3136    void setQsScrimEnabled(boolean scrimEnabled) {
3137        mNotificationPanel.setQsScrimEnabled(scrimEnabled);
3138    }
3139
3140    void checkBarMode(int mode, int windowState, BarTransitions transitions) {
3141        final boolean powerSave = mBatteryController.isPowerSave();
3142        final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
3143                && windowState != WINDOW_STATE_HIDDEN && !powerSave;
3144        if (powerSave && getBarState() == StatusBarState.SHADE) {
3145            mode = MODE_WARNING;
3146        }
3147        transitions.transitionTo(mode, anim);
3148    }
3149
3150    private void finishBarAnimations() {
3151        if (mStatusBarView != null) {
3152            mStatusBarView.getBarTransitions().finishAnimations();
3153        }
3154        if (mNavigationBar != null) {
3155            mNavigationBar.finishBarAnimations();
3156        }
3157    }
3158
3159    private final Runnable mCheckBarModes = new Runnable() {
3160        @Override
3161        public void run() {
3162            checkBarModes();
3163        }
3164    };
3165
3166    public void setInteracting(int barWindow, boolean interacting) {
3167        final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting;
3168        mInteractingWindows = interacting
3169                ? (mInteractingWindows | barWindow)
3170                : (mInteractingWindows & ~barWindow);
3171        if (mInteractingWindows != 0) {
3172            suspendAutohide();
3173        } else {
3174            resumeSuspendedAutohide();
3175        }
3176        // manually dismiss the volume panel when interacting with the nav bar
3177        if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
3178            dismissVolumeDialog();
3179        }
3180        checkBarModes();
3181    }
3182
3183    private void dismissVolumeDialog() {
3184        if (mVolumeComponent != null) {
3185            mVolumeComponent.dismissNow();
3186        }
3187    }
3188
3189    private void resumeSuspendedAutohide() {
3190        if (mAutohideSuspended) {
3191            scheduleAutohide();
3192            mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
3193        }
3194    }
3195
3196    private void suspendAutohide() {
3197        mHandler.removeCallbacks(mAutohide);
3198        mHandler.removeCallbacks(mCheckBarModes);
3199        mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
3200    }
3201
3202    private void cancelAutohide() {
3203        mAutohideSuspended = false;
3204        mHandler.removeCallbacks(mAutohide);
3205    }
3206
3207    private void scheduleAutohide() {
3208        cancelAutohide();
3209        mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
3210    }
3211
3212    void checkUserAutohide(View v, MotionEvent event) {
3213        if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
3214                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
3215                && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
3216                && !mRemoteInputController.isRemoteInputActive()) { // not due to typing in IME
3217            userAutohide();
3218        }
3219    }
3220
3221    private void checkRemoteInputOutside(MotionEvent event) {
3222        if (event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
3223                && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
3224                && mRemoteInputController.isRemoteInputActive()) {
3225            mRemoteInputController.closeRemoteInputs();
3226        }
3227    }
3228
3229    private void userAutohide() {
3230        cancelAutohide();
3231        mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
3232    }
3233
3234    private boolean areLightsOn() {
3235        return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
3236    }
3237
3238    public void setLightsOn(boolean on) {
3239        Log.v(TAG, "setLightsOn(" + on + ")");
3240        if (on) {
3241            setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
3242                    mLastFullscreenStackBounds, mLastDockedStackBounds);
3243        } else {
3244            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
3245                    View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
3246                    mLastDockedStackBounds);
3247        }
3248    }
3249
3250    private void notifyUiVisibilityChanged(int vis) {
3251        try {
3252            if (mLastDispatchedSystemUiVisibility != vis) {
3253                mWindowManagerService.statusBarVisibilityChanged(vis);
3254                mLastDispatchedSystemUiVisibility = vis;
3255            }
3256        } catch (RemoteException ex) {
3257        }
3258    }
3259
3260    @Override
3261    public void topAppWindowChanged(boolean showMenu) {
3262        if (SPEW) {
3263            Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
3264        }
3265
3266        // See above re: lights-out policy for legacy apps.
3267        if (showMenu) setLightsOn(true);
3268    }
3269
3270    public static String viewInfo(View v) {
3271        return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
3272                + ") " + v.getWidth() + "x" + v.getHeight() + "]";
3273    }
3274
3275    @Override
3276    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3277        synchronized (mQueueLock) {
3278            pw.println("Current Status Bar state:");
3279            pw.println("  mExpandedVisible=" + mExpandedVisible
3280                    + ", mTrackingPosition=" + mTrackingPosition);
3281            pw.println("  mTracking=" + mTracking);
3282            pw.println("  mDisplayMetrics=" + mDisplayMetrics);
3283            pw.println("  mStackScroller: " + viewInfo(mStackScroller));
3284            pw.println("  mStackScroller: " + viewInfo(mStackScroller)
3285                    + " scroll " + mStackScroller.getScrollX()
3286                    + "," + mStackScroller.getScrollY());
3287        }
3288
3289        pw.print("  mInteractingWindows="); pw.println(mInteractingWindows);
3290        pw.print("  mStatusBarWindowState=");
3291        pw.println(windowStateToString(mStatusBarWindowState));
3292        pw.print("  mStatusBarMode=");
3293        pw.println(BarTransitions.modeToString(mStatusBarMode));
3294        pw.print("  mDozing="); pw.println(mDozing);
3295        pw.print("  mZenMode=");
3296        pw.println(Settings.Global.zenModeToString(mZenMode));
3297        pw.print("  mUseHeadsUp=");
3298        pw.println(mUseHeadsUp);
3299        dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
3300
3301        pw.print("  mMediaSessionManager=");
3302        pw.println(mMediaSessionManager);
3303        pw.print("  mMediaNotificationKey=");
3304        pw.println(mMediaNotificationKey);
3305        pw.print("  mMediaController=");
3306        pw.print(mMediaController);
3307        if (mMediaController != null) {
3308            pw.print(" state=" + mMediaController.getPlaybackState());
3309        }
3310        pw.println();
3311        pw.print("  mMediaMetadata=");
3312        pw.print(mMediaMetadata);
3313        if (mMediaMetadata != null) {
3314            pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE));
3315        }
3316        pw.println();
3317
3318        pw.println("  Panels: ");
3319        if (mNotificationPanel != null) {
3320            pw.println("    mNotificationPanel=" +
3321                mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
3322            pw.print  ("      ");
3323            mNotificationPanel.dump(fd, pw, args);
3324        }
3325
3326        DozeLog.dump(pw);
3327
3328        if (DUMPTRUCK) {
3329            synchronized (mNotificationData) {
3330                mNotificationData.dump(pw, "  ");
3331            }
3332
3333            if (false) {
3334                pw.println("see the logcat for a dump of the views we have created.");
3335                // must happen on ui thread
3336                mHandler.post(new Runnable() {
3337                        @Override
3338                        public void run() {
3339                            mStatusBarView.getLocationOnScreen(mAbsPos);
3340                            Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
3341                                    + ") " + mStatusBarView.getWidth() + "x"
3342                                    + getStatusBarHeight());
3343                            mStatusBarView.debug();
3344                        }
3345                    });
3346            }
3347        }
3348
3349        if (DEBUG_GESTURES) {
3350            pw.print("  status bar gestures: ");
3351            mGestureRec.dump(fd, pw, args);
3352        }
3353
3354        if (mHeadsUpManager != null) {
3355            mHeadsUpManager.dump(fd, pw, args);
3356        } else {
3357            pw.println("  mHeadsUpManager: null");
3358        }
3359        if (mGroupManager != null) {
3360            mGroupManager.dump(fd, pw, args);
3361        } else {
3362            pw.println("  mGroupManager: null");
3363        }
3364
3365        mLightBarController.dump(fd, pw, args);
3366
3367        if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
3368            KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
3369        }
3370
3371        FalsingManager.getInstance(mContext).dump(pw);
3372        FalsingLog.dump(pw);
3373
3374        pw.println("SharedPreferences:");
3375        for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
3376            pw.print("  "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
3377        }
3378    }
3379
3380    static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
3381        pw.print("  "); pw.print(var); pw.print(".BarTransitions.mMode=");
3382        pw.println(BarTransitions.modeToString(transitions.getMode()));
3383    }
3384
3385    public void createAndAddWindows() {
3386        addStatusBarWindow();
3387    }
3388
3389    private void addStatusBarWindow() {
3390        makeStatusBarView();
3391        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
3392        mRemoteInputController = new RemoteInputController(mHeadsUpManager);
3393        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
3394    }
3395
3396    // called by makeStatusbar and also by PhoneStatusBarView
3397    void updateDisplaySize() {
3398        mDisplay.getMetrics(mDisplayMetrics);
3399        mDisplay.getSize(mCurrentDisplaySize);
3400        if (DEBUG_GESTURES) {
3401            mGestureRec.tag("display",
3402                    String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
3403        }
3404    }
3405
3406    float getDisplayDensity() {
3407        return mDisplayMetrics.density;
3408    }
3409
3410    public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
3411            boolean dismissShade) {
3412        startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, null /* callback */);
3413    }
3414
3415    public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
3416            final boolean dismissShade, final Callback callback) {
3417        if (onlyProvisioned && !isDeviceProvisioned()) return;
3418
3419        final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
3420                mContext, intent, mCurrentUserId);
3421        Runnable runnable = new Runnable() {
3422            @Override
3423            public void run() {
3424                mAssistManager.hideAssist();
3425                intent.setFlags(
3426                        Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
3427                int result = ActivityManager.START_CANCELED;
3428                ActivityOptions options = new ActivityOptions(getActivityOptions());
3429                if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
3430                    // Normally an activity will set it's requested rotation
3431                    // animation on its window. However when launching an activity
3432                    // causes the orientation to change this is too late. In these cases
3433                    // the default animation is used. This doesn't look good for
3434                    // the camera (as it rotates the camera contents out of sync
3435                    // with physical reality). So, we ask the WindowManager to
3436                    // force the crossfade animation if an orientation change
3437                    // happens to occur during the launch.
3438                    options.setRotationAnimationHint(
3439                            WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
3440                }
3441                try {
3442                    result = ActivityManager.getService().startActivityAsUser(
3443                            null, mContext.getBasePackageName(),
3444                            intent,
3445                            intent.resolveTypeIfNeeded(mContext.getContentResolver()),
3446                            null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
3447                            options.toBundle(), UserHandle.CURRENT.getIdentifier());
3448                } catch (RemoteException e) {
3449                    Log.w(TAG, "Unable to start activity", e);
3450                }
3451                if (callback != null) {
3452                    callback.onActivityStarted(result);
3453                }
3454            }
3455        };
3456        Runnable cancelRunnable = new Runnable() {
3457            @Override
3458            public void run() {
3459                if (callback != null) {
3460                    callback.onActivityStarted(ActivityManager.START_CANCELED);
3461                }
3462            }
3463        };
3464        executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
3465                afterKeyguardGone, true /* deferred */);
3466    }
3467
3468    public void readyForKeyguardDone() {
3469        mStatusBarKeyguardViewManager.readyForKeyguardDone();
3470    }
3471
3472    public void executeRunnableDismissingKeyguard(final Runnable runnable,
3473            final Runnable cancelAction,
3474            final boolean dismissShade,
3475            final boolean afterKeyguardGone,
3476            final boolean deferred) {
3477        dismissKeyguardThenExecute(() -> {
3478            if (runnable != null) {
3479                if (mStatusBarKeyguardViewManager.isShowing()
3480                        && mStatusBarKeyguardViewManager.isOccluded()) {
3481                    mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
3482                } else {
3483                    AsyncTask.execute(runnable);
3484                }
3485            }
3486            if (dismissShade) {
3487                if (mExpandedVisible) {
3488                    animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
3489                            true /* delayed*/);
3490                } else {
3491
3492                    // Do it after DismissAction has been processed to conserve the needed ordering.
3493                    mHandler.post(this::runPostCollapseRunnables);
3494                }
3495            }
3496            return deferred;
3497        }, cancelAction, afterKeyguardGone);
3498    }
3499
3500    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
3501        @Override
3502        public void onReceive(Context context, Intent intent) {
3503            if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3504            String action = intent.getAction();
3505            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
3506                KeyboardShortcuts.dismiss();
3507                if (mRemoteInputController != null) {
3508                    mRemoteInputController.closeRemoteInputs();
3509                }
3510                if (isCurrentProfile(getSendingUserId())) {
3511                    int flags = CommandQueue.FLAG_EXCLUDE_NONE;
3512                    String reason = intent.getStringExtra("reason");
3513                    if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
3514                        flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
3515                    }
3516                    animateCollapsePanels(flags);
3517                }
3518            }
3519            else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
3520                notifyHeadsUpScreenOff();
3521                finishBarAnimations();
3522                resetUserExpandedStates();
3523            }
3524            else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
3525                mQSPanel.showDeviceMonitoringDialog();
3526            }
3527        }
3528    };
3529
3530    private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
3531        @Override
3532        public void onReceive(Context context, Intent intent) {
3533            if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3534            String action = intent.getAction();
3535            if (ACTION_DEMO.equals(action)) {
3536                Bundle bundle = intent.getExtras();
3537                if (bundle != null) {
3538                    String command = bundle.getString("command", "").trim().toLowerCase();
3539                    if (command.length() > 0) {
3540                        try {
3541                            dispatchDemoCommand(command, bundle);
3542                        } catch (Throwable t) {
3543                            Log.w(TAG, "Error running demo command, intent=" + intent, t);
3544                        }
3545                    }
3546                }
3547            } else if (ACTION_FAKE_ARTWORK.equals(action)) {
3548                if (DEBUG_MEDIA_FAKE_ARTWORK) {
3549                    updateMediaMetaData(true, true);
3550                }
3551            }
3552        }
3553    };
3554
3555    public void resetUserExpandedStates() {
3556        ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
3557        final int notificationCount = activeNotifications.size();
3558        for (int i = 0; i < notificationCount; i++) {
3559            NotificationData.Entry entry = activeNotifications.get(i);
3560            if (entry.row != null) {
3561                entry.row.resetUserExpansion();
3562            }
3563        }
3564    }
3565
3566    protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
3567        dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
3568    }
3569
3570    private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
3571            boolean afterKeyguardGone) {
3572        if (mStatusBarKeyguardViewManager.isShowing()) {
3573            mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
3574                    afterKeyguardGone);
3575        } else {
3576            action.onDismiss();
3577        }
3578    }
3579
3580    // SystemUIService notifies SystemBars of configuration changes, which then calls down here
3581    @Override
3582    protected void onConfigurationChanged(Configuration newConfig) {
3583        updateResources();
3584        updateDisplaySize(); // populates mDisplayMetrics
3585
3586        if (DEBUG) {
3587            Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
3588        }
3589
3590        updateRowStates();
3591        mScreenPinningRequest.onConfigurationChanged();
3592    }
3593
3594    public void userSwitched(int newUserId) {
3595        // Begin old BaseStatusBar.userSwitched
3596        setHeadsUpUser(newUserId);
3597        // End old BaseStatusBar.userSwitched
3598        if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
3599        animateCollapsePanels();
3600        updatePublicMode();
3601        updateNotifications();
3602        clearCurrentMediaNotification();
3603        setLockscreenUser(newUserId);
3604    }
3605
3606    protected void setLockscreenUser(int newUserId) {
3607        mLockscreenWallpaper.setCurrentUser(newUserId);
3608        mScrimController.setCurrentUser(newUserId);
3609        updateMediaMetaData(true, false);
3610    }
3611
3612    /**
3613     * Reload some of our resources when the configuration changes.
3614     *
3615     * We don't reload everything when the configuration changes -- we probably
3616     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
3617     * meantime, just update the things that we know change.
3618     */
3619    void updateResources() {
3620        // Update the quick setting tiles
3621        if (mQSPanel != null) {
3622            mQSPanel.updateResources();
3623        }
3624
3625        loadDimens();
3626
3627        if (mNotificationPanel != null) {
3628            mNotificationPanel.updateResources();
3629        }
3630        if (mBrightnessMirrorController != null) {
3631            mBrightnessMirrorController.updateResources();
3632        }
3633    }
3634
3635    protected void loadDimens() {
3636        final Resources res = mContext.getResources();
3637
3638        int oldBarHeight = mNaturalBarHeight;
3639        mNaturalBarHeight = res.getDimensionPixelSize(
3640                com.android.internal.R.dimen.status_bar_height);
3641        if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) {
3642            mStatusBarWindowManager.setBarHeight(mNaturalBarHeight);
3643        }
3644        mMaxAllowedKeyguardNotifications = res.getInteger(
3645                R.integer.keyguard_max_notification_count);
3646
3647        if (DEBUG) Log.v(TAG, "defineSlots");
3648    }
3649
3650    // Visibility reporting
3651
3652    protected void handleVisibleToUserChanged(boolean visibleToUser) {
3653        if (visibleToUser) {
3654            handleVisibleToUserChangedImpl(visibleToUser);
3655            startNotificationLogging();
3656        } else {
3657            stopNotificationLogging();
3658            handleVisibleToUserChangedImpl(visibleToUser);
3659        }
3660    }
3661
3662    /**
3663     * The LEDs are turned off when the notification panel is shown, even just a little bit.
3664     * See also StatusBar.setPanelExpanded for another place where we attempt to do this.
3665     */
3666    // Old BaseStatusBar.handleVisibileToUserChanged
3667    private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
3668        try {
3669            if (visibleToUser) {
3670                boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
3671                boolean clearNotificationEffects =
3672                        !isPanelFullyCollapsed() &&
3673                        (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
3674                int notificationLoad = mNotificationData.getActiveNotifications().size();
3675                if (pinnedHeadsUp && isPanelFullyCollapsed())  {
3676                    notificationLoad = 1;
3677                } else {
3678                    MetricsLogger.histogram(mContext, "note_load", notificationLoad);
3679                }
3680                mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
3681            } else {
3682                mBarService.onPanelHidden();
3683            }
3684        } catch (RemoteException ex) {
3685            // Won't fail unless the world has ended.
3686        }
3687    }
3688
3689    private void stopNotificationLogging() {
3690        // Report all notifications as invisible and turn down the
3691        // reporter.
3692        if (!mCurrentlyVisibleNotifications.isEmpty()) {
3693            logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(),
3694                    mCurrentlyVisibleNotifications);
3695            recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
3696        }
3697        mHandler.removeCallbacks(mVisibilityReporter);
3698        mStackScroller.setChildLocationsChangedListener(null);
3699    }
3700
3701    private void startNotificationLogging() {
3702        mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
3703        // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
3704        // cause the scroller to emit child location events. Hence generate
3705        // one ourselves to guarantee that we're reporting visible
3706        // notifications.
3707        // (Note that in cases where the scroller does emit events, this
3708        // additional event doesn't break anything.)
3709        mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller);
3710    }
3711
3712    private void logNotificationVisibilityChanges(
3713            Collection<NotificationVisibility> newlyVisible,
3714            Collection<NotificationVisibility> noLongerVisible) {
3715        if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
3716            return;
3717        }
3718        NotificationVisibility[] newlyVisibleAr =
3719                newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]);
3720        NotificationVisibility[] noLongerVisibleAr =
3721                noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]);
3722        try {
3723            mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
3724        } catch (RemoteException e) {
3725            // Ignore.
3726        }
3727
3728        final int N = newlyVisible.size();
3729        if (N > 0) {
3730            String[] newlyVisibleKeyAr = new String[N];
3731            for (int i = 0; i < N; i++) {
3732                newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
3733            }
3734
3735            setNotificationsShown(newlyVisibleKeyAr);
3736        }
3737    }
3738
3739    public void onKeyguardOccludedChanged(boolean keyguardOccluded) {
3740        mNavigationBar.onKeyguardOccludedChanged(keyguardOccluded);
3741    }
3742
3743    // State logging
3744
3745    private void logStateToEventlog() {
3746        boolean isShowing = mStatusBarKeyguardViewManager.isShowing();
3747        boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();
3748        boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
3749        boolean isSecure = mUnlockMethodCache.isMethodSecure();
3750        boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer();
3751        int stateFingerprint = getLoggingFingerprint(mState,
3752                isShowing,
3753                isOccluded,
3754                isBouncerShowing,
3755                isSecure,
3756                canSkipBouncer);
3757        if (stateFingerprint != mLastLoggedStateFingerprint) {
3758            if (mStatusBarStateLog == null) {
3759                mStatusBarStateLog = new LogMaker(MetricsEvent.VIEW_UNKNOWN);
3760            }
3761            MetricsLogger.action(mStatusBarStateLog
3762                    .setCategory(isBouncerShowing ? MetricsEvent.BOUNCER : MetricsEvent.LOCKSCREEN)
3763                    .setType(isShowing ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
3764                    .setSubtype(isSecure ? 1 : 0));
3765            EventLogTags.writeSysuiStatusBarState(mState,
3766                    isShowing ? 1 : 0,
3767                    isOccluded ? 1 : 0,
3768                    isBouncerShowing ? 1 : 0,
3769                    isSecure ? 1 : 0,
3770                    canSkipBouncer ? 1 : 0);
3771            mLastLoggedStateFingerprint = stateFingerprint;
3772        }
3773    }
3774
3775    /**
3776     * Returns a fingerprint of fields logged to eventlog
3777     */
3778    private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing,
3779            boolean keyguardOccluded, boolean bouncerShowing, boolean secure,
3780            boolean currentlyInsecure) {
3781        // Reserve 8 bits for statusBarState. We'll never go higher than
3782        // that, right? Riiiight.
3783        return (statusBarState & 0xFF)
3784                | ((keyguardShowing   ? 1 : 0) <<  8)
3785                | ((keyguardOccluded  ? 1 : 0) <<  9)
3786                | ((bouncerShowing    ? 1 : 0) << 10)
3787                | ((secure            ? 1 : 0) << 11)
3788                | ((currentlyInsecure ? 1 : 0) << 12);
3789    }
3790
3791    //
3792    // tracing
3793    //
3794
3795    void postStartTracing() {
3796        mHandler.postDelayed(mStartTracing, 3000);
3797    }
3798
3799    void vibrate() {
3800        android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
3801                Context.VIBRATOR_SERVICE);
3802        vib.vibrate(250, VIBRATION_ATTRIBUTES);
3803    }
3804
3805    Runnable mStartTracing = new Runnable() {
3806        @Override
3807        public void run() {
3808            vibrate();
3809            SystemClock.sleep(250);
3810            Log.d(TAG, "startTracing");
3811            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
3812            mHandler.postDelayed(mStopTracing, 10000);
3813        }
3814    };
3815
3816    Runnable mStopTracing = new Runnable() {
3817        @Override
3818        public void run() {
3819            android.os.Debug.stopMethodTracing();
3820            Log.d(TAG, "stopTracing");
3821            vibrate();
3822        }
3823    };
3824
3825    @Override
3826    public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
3827        mHandler.post(() -> {
3828            mLeaveOpenOnKeyguardHide = true;
3829            executeRunnableDismissingKeyguard(() -> mHandler.post(runnable), null, false, false,
3830                    false);
3831        });
3832    }
3833
3834    @Override
3835    public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
3836        mHandler.post(() -> startPendingIntentDismissingKeyguard(intent));
3837    }
3838
3839    @Override
3840    public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
3841        mHandler.postDelayed(() ->
3842                handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/), delay);
3843    }
3844
3845    private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
3846        startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
3847    }
3848
3849    private static class FastColorDrawable extends Drawable {
3850        private final int mColor;
3851
3852        public FastColorDrawable(int color) {
3853            mColor = 0xff000000 | color;
3854        }
3855
3856        @Override
3857        public void draw(Canvas canvas) {
3858            canvas.drawColor(mColor, PorterDuff.Mode.SRC);
3859        }
3860
3861        @Override
3862        public void setAlpha(int alpha) {
3863        }
3864
3865        @Override
3866        public void setColorFilter(ColorFilter colorFilter) {
3867        }
3868
3869        @Override
3870        public int getOpacity() {
3871            return PixelFormat.OPAQUE;
3872        }
3873
3874        @Override
3875        public void setBounds(int left, int top, int right, int bottom) {
3876        }
3877
3878        @Override
3879        public void setBounds(Rect bounds) {
3880        }
3881    }
3882
3883    public void destroy() {
3884        // Begin old BaseStatusBar.destroy().
3885        mContext.unregisterReceiver(mBaseBroadcastReceiver);
3886        try {
3887            mNotificationListener.unregisterAsSystemService();
3888        } catch (RemoteException e) {
3889            // Ignore.
3890        }
3891        mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
3892        // End old BaseStatusBar.destroy().
3893        if (mStatusBarWindow != null) {
3894            mWindowManager.removeViewImmediate(mStatusBarWindow);
3895            mStatusBarWindow = null;
3896        }
3897        if (mNavigationBarView != null) {
3898            mWindowManager.removeViewImmediate(mNavigationBarView);
3899            mNavigationBarView = null;
3900        }
3901        mContext.unregisterReceiver(mBroadcastReceiver);
3902        mContext.unregisterReceiver(mDemoReceiver);
3903        mAssistManager.destroy();
3904
3905        if (mQSPanel != null && mQSPanel.getHost() != null) {
3906            mQSPanel.getHost().destroy();
3907        }
3908        Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
3909        mDeviceProvisionedController.removeCallback(mUserSetupObserver);
3910        Dependency.get(ConfigurationController.class).removeCallback(mConfigurationListener);
3911    }
3912
3913    private boolean mDemoModeAllowed;
3914    private boolean mDemoMode;
3915
3916    @Override
3917    public void dispatchDemoCommand(String command, Bundle args) {
3918        if (!mDemoModeAllowed) {
3919            mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
3920                    DEMO_MODE_ALLOWED, 0) != 0;
3921        }
3922        if (!mDemoModeAllowed) return;
3923        if (command.equals(COMMAND_ENTER)) {
3924            mDemoMode = true;
3925        } else if (command.equals(COMMAND_EXIT)) {
3926            mDemoMode = false;
3927            checkBarModes();
3928        } else if (!mDemoMode) {
3929            // automatically enter demo mode on first demo command
3930            dispatchDemoCommand(COMMAND_ENTER, new Bundle());
3931        }
3932        boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT);
3933        if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) {
3934            mVolumeComponent.dispatchDemoCommand(command, args);
3935        }
3936        if (modeChange || command.equals(COMMAND_CLOCK)) {
3937            dispatchDemoCommandToView(command, args, R.id.clock);
3938        }
3939        if (modeChange || command.equals(COMMAND_BATTERY)) {
3940            mBatteryController.dispatchDemoCommand(command, args);
3941        }
3942        if (modeChange || command.equals(COMMAND_STATUS)) {
3943            ((StatusBarIconControllerImpl) mIconController).dispatchDemoCommand(command, args);
3944        }
3945        if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
3946            mNetworkController.dispatchDemoCommand(command, args);
3947        }
3948        if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) {
3949            View notifications = mStatusBarView == null ? null
3950                    : mStatusBarView.findViewById(R.id.notification_icon_area);
3951            if (notifications != null) {
3952                String visible = args.getString("visible");
3953                int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE;
3954                notifications.setVisibility(vis);
3955            }
3956        }
3957        if (command.equals(COMMAND_BARS)) {
3958            String mode = args.getString("mode");
3959            int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
3960                    "translucent".equals(mode) ? MODE_TRANSLUCENT :
3961                    "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
3962                    "transparent".equals(mode) ? MODE_TRANSPARENT :
3963                    "warning".equals(mode) ? MODE_WARNING :
3964                    -1;
3965            if (barMode != -1) {
3966                boolean animate = true;
3967                if (mStatusBarView != null) {
3968                    mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
3969                }
3970                if (mNavigationBar != null) {
3971                    mNavigationBar.getBarTransitions().transitionTo(barMode, animate);
3972                }
3973            }
3974        }
3975    }
3976
3977    private void dispatchDemoCommandToView(String command, Bundle args, int id) {
3978        if (mStatusBarView == null) return;
3979        View v = mStatusBarView.findViewById(id);
3980        if (v instanceof DemoMode) {
3981            ((DemoMode)v).dispatchDemoCommand(command, args);
3982        }
3983    }
3984
3985    /**
3986     * @return The {@link StatusBarState} the status bar is in.
3987     */
3988    public int getBarState() {
3989        return mState;
3990    }
3991
3992    public boolean isPanelFullyCollapsed() {
3993        return mNotificationPanel.isFullyCollapsed();
3994    }
3995
3996    public void showKeyguard() {
3997        if (mLaunchTransitionFadingAway) {
3998            mNotificationPanel.animate().cancel();
3999            onLaunchTransitionFadingEnded();
4000        }
4001        mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
4002        if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
4003            setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER);
4004        } else {
4005            setBarState(StatusBarState.KEYGUARD);
4006        }
4007        updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
4008        if (!mDeviceInteractive) {
4009
4010            // If the screen is off already, we need to disable touch events because these might
4011            // collapse the panel after we expanded it, and thus we would end up with a blank
4012            // Keyguard.
4013            mNotificationPanel.setTouchDisabled(true);
4014        }
4015        if (mState == StatusBarState.KEYGUARD) {
4016            instantExpandNotificationsPanel();
4017        } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
4018            instantCollapseNotificationPanel();
4019        }
4020        mLeaveOpenOnKeyguardHide = false;
4021        if (mDraggedDownRow != null) {
4022            mDraggedDownRow.setUserLocked(false);
4023            mDraggedDownRow.notifyHeightChanged(false  /* needsAnimation */);
4024            mDraggedDownRow = null;
4025        }
4026        mPendingRemoteInputView = null;
4027        mAssistManager.onLockscreenShown();
4028    }
4029
4030    private void onLaunchTransitionFadingEnded() {
4031        mNotificationPanel.setAlpha(1.0f);
4032        mNotificationPanel.onAffordanceLaunchEnded();
4033        releaseGestureWakeLock();
4034        runLaunchTransitionEndRunnable();
4035        mLaunchTransitionFadingAway = false;
4036        mScrimController.forceHideScrims(false /* hide */);
4037        updateMediaMetaData(true /* metaDataChanged */, true);
4038    }
4039
4040    public boolean isCollapsing() {
4041        return mNotificationPanel.isCollapsing();
4042    }
4043
4044    public void addPostCollapseAction(Runnable r) {
4045        mPostCollapseRunnables.add(r);
4046    }
4047
4048    public boolean isInLaunchTransition() {
4049        return mNotificationPanel.isLaunchTransitionRunning()
4050                || mNotificationPanel.isLaunchTransitionFinished();
4051    }
4052
4053    /**
4054     * Fades the content of the keyguard away after the launch transition is done.
4055     *
4056     * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
4057     *                     starts
4058     * @param endRunnable the runnable to be run when the transition is done
4059     */
4060    public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
4061            Runnable endRunnable) {
4062        mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
4063        mLaunchTransitionEndRunnable = endRunnable;
4064        Runnable hideRunnable = new Runnable() {
4065            @Override
4066            public void run() {
4067                mLaunchTransitionFadingAway = true;
4068                if (beforeFading != null) {
4069                    beforeFading.run();
4070                }
4071                mScrimController.forceHideScrims(true /* hide */);
4072                updateMediaMetaData(false, true);
4073                mNotificationPanel.setAlpha(1);
4074                mStackScroller.setParentNotFullyVisible(true);
4075                mNotificationPanel.animate()
4076                        .alpha(0)
4077                        .setStartDelay(FADE_KEYGUARD_START_DELAY)
4078                        .setDuration(FADE_KEYGUARD_DURATION)
4079                        .withLayer()
4080                        .withEndAction(new Runnable() {
4081                            @Override
4082                            public void run() {
4083                                onLaunchTransitionFadingEnded();
4084                            }
4085                        });
4086                mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(),
4087                        LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
4088            }
4089        };
4090        if (mNotificationPanel.isLaunchTransitionRunning()) {
4091            mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
4092        } else {
4093            hideRunnable.run();
4094        }
4095    }
4096
4097    /**
4098     * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
4099     * fading.
4100     */
4101    public void fadeKeyguardWhilePulsing() {
4102        mNotificationPanel.animate()
4103                .alpha(0f)
4104                .setStartDelay(0)
4105                .setDuration(FADE_KEYGUARD_DURATION_PULSING)
4106                .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR)
4107                .start();
4108    }
4109
4110    /**
4111     * Plays the animation when an activity that was occluding Keyguard goes away.
4112     */
4113    public void animateKeyguardUnoccluding() {
4114        mScrimController.animateKeyguardUnoccluding(500);
4115        mNotificationPanel.setExpandedFraction(0f);
4116        animateExpandNotificationsPanel();
4117    }
4118
4119    /**
4120     * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
4121     * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
4122     * because the launched app crashed or something else went wrong.
4123     */
4124    public void startLaunchTransitionTimeout() {
4125        mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT,
4126                LAUNCH_TRANSITION_TIMEOUT_MS);
4127    }
4128
4129    private void onLaunchTransitionTimeout() {
4130        Log.w(TAG, "Launch transition: Timeout!");
4131        mNotificationPanel.onAffordanceLaunchEnded();
4132        releaseGestureWakeLock();
4133        mNotificationPanel.resetViews();
4134    }
4135
4136    private void runLaunchTransitionEndRunnable() {
4137        if (mLaunchTransitionEndRunnable != null) {
4138            Runnable r = mLaunchTransitionEndRunnable;
4139
4140            // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again,
4141            // which would lead to infinite recursion. Protect against it.
4142            mLaunchTransitionEndRunnable = null;
4143            r.run();
4144        }
4145    }
4146
4147    /**
4148     * @return true if we would like to stay in the shade, false if it should go away entirely
4149     */
4150    public boolean hideKeyguard() {
4151        Trace.beginSection("StatusBar#hideKeyguard");
4152        boolean staying = mLeaveOpenOnKeyguardHide;
4153        setBarState(StatusBarState.SHADE);
4154        View viewToClick = null;
4155        if (mLeaveOpenOnKeyguardHide) {
4156            mLeaveOpenOnKeyguardHide = false;
4157            long delay = calculateGoingToFullShadeDelay();
4158            mNotificationPanel.animateToFullShade(delay);
4159            if (mDraggedDownRow != null) {
4160                mDraggedDownRow.setUserLocked(false);
4161                mDraggedDownRow = null;
4162            }
4163            viewToClick = mPendingRemoteInputView;
4164            mPendingRemoteInputView = null;
4165
4166            // Disable layout transitions in navbar for this transition because the load is just
4167            // too heavy for the CPU and GPU on any device.
4168            if (mNavigationBar != null) {
4169                mNavigationBar.disableAnimationsDuringHide(delay);
4170            }
4171        } else if (!mNotificationPanel.isCollapsing()) {
4172            instantCollapseNotificationPanel();
4173        }
4174        updateKeyguardState(staying, false /* fromShadeLocked */);
4175
4176        if (viewToClick != null && viewToClick.isAttachedToWindow()) {
4177            viewToClick.callOnClick();
4178        }
4179
4180        // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
4181        // visibilities so next time we open the panel we know the correct height already.
4182        if (mQSPanel != null) {
4183            mQSPanel.refreshAllTiles();
4184        }
4185        mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
4186        releaseGestureWakeLock();
4187        mNotificationPanel.onAffordanceLaunchEnded();
4188        mNotificationPanel.animate().cancel();
4189        mNotificationPanel.setAlpha(1f);
4190        Trace.endSection();
4191        return staying;
4192    }
4193
4194    private void releaseGestureWakeLock() {
4195        if (mGestureWakeLock.isHeld()) {
4196            mGestureWakeLock.release();
4197        }
4198    }
4199
4200    public long calculateGoingToFullShadeDelay() {
4201        return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
4202    }
4203
4204    /**
4205     * Notifies the status bar that Keyguard is going away very soon.
4206     */
4207    public void keyguardGoingAway() {
4208
4209        // Treat Keyguard exit animation as an app transition to achieve nice transition for status
4210        // bar.
4211        mKeyguardGoingAway = true;
4212        mKeyguardMonitor.notifyKeyguardGoingAway(true);
4213        mCommandQueue.appTransitionPending(true);
4214    }
4215
4216    /**
4217     * Notifies the status bar the Keyguard is fading away with the specified timings.
4218     *
4219     * @param startTime the start time of the animations in uptime millis
4220     * @param delay the precalculated animation delay in miliseconds
4221     * @param fadeoutDuration the duration of the exit animation, in milliseconds
4222     */
4223    public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
4224        mKeyguardFadingAway = true;
4225        mKeyguardFadingAwayDelay = delay;
4226        mKeyguardFadingAwayDuration = fadeoutDuration;
4227        mWaitingForKeyguardExit = false;
4228        mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
4229                        - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
4230                LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
4231        recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
4232        mCommandQueue.appTransitionStarting(
4233                    startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
4234                    LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
4235        mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
4236    }
4237
4238    public boolean isKeyguardFadingAway() {
4239        return mKeyguardFadingAway;
4240    }
4241
4242    /**
4243     * Notifies that the Keyguard fading away animation is done.
4244     */
4245    public void finishKeyguardFadingAway() {
4246        mKeyguardFadingAway = false;
4247        mKeyguardGoingAway = false;
4248        mKeyguardMonitor.notifyKeyguardDoneFading();
4249    }
4250
4251    public void stopWaitingForKeyguardExit() {
4252        mWaitingForKeyguardExit = false;
4253    }
4254
4255    private void updatePublicMode() {
4256        final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
4257        final boolean devicePublic = showingKeyguard
4258                && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId);
4259
4260        // Look for public mode users. Users are considered public in either case of:
4261        //   - device keyguard is shown in secure mode;
4262        //   - profile is locked with a work challenge.
4263        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
4264            final int userId = mCurrentProfiles.valueAt(i).id;
4265            boolean isProfilePublic = devicePublic;
4266            if (!devicePublic && userId != mCurrentUserId) {
4267                if (mStatusBarKeyguardViewManager.isSecure(userId)) {
4268                    isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
4269                }
4270            }
4271            setLockscreenPublicMode(isProfilePublic, userId);
4272        }
4273    }
4274
4275    protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
4276        Trace.beginSection("StatusBar#updateKeyguardState");
4277        if (mState == StatusBarState.KEYGUARD) {
4278            mKeyguardIndicationController.setVisible(true);
4279            mNotificationPanel.resetViews();
4280            if (mKeyguardUserSwitcher != null) {
4281                mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
4282            }
4283            mStatusBarView.removePendingHideExpandedRunnables();
4284        } else {
4285            mKeyguardIndicationController.setVisible(false);
4286            if (mKeyguardUserSwitcher != null) {
4287                mKeyguardUserSwitcher.setKeyguard(false,
4288                        goingToFullShade ||
4289                        mState == StatusBarState.SHADE_LOCKED ||
4290                        fromShadeLocked);
4291            }
4292        }
4293        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4294            mScrimController.setKeyguardShowing(true);
4295        } else {
4296            mScrimController.setKeyguardShowing(false);
4297        }
4298        mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
4299        updateDozingState();
4300        updatePublicMode();
4301        updateStackScrollerState(goingToFullShade, fromShadeLocked);
4302        updateNotifications();
4303        checkBarModes();
4304        updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
4305        mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
4306                mStatusBarKeyguardViewManager.isSecure(),
4307                mStatusBarKeyguardViewManager.isOccluded());
4308        Trace.endSection();
4309    }
4310
4311    private void updateDozingState() {
4312        Trace.beginSection("StatusBar#updateDozingState");
4313        boolean animate = !mDozing && mDozeScrimController.isPulsing();
4314        mNotificationPanel.setDozing(mDozing, animate);
4315        mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
4316        mScrimController.setDozing(mDozing);
4317        mKeyguardIndicationController.setDozing(mDozing);
4318
4319        // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock
4320        // for pulsing so the Keyguard fade-out animation scrim can take over.
4321        mDozeScrimController.setDozing(mDozing &&
4322                mFingerprintUnlockController.getMode()
4323                        != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
4324        updateRowStates();
4325        Trace.endSection();
4326    }
4327
4328    public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
4329        if (mStackScroller == null) return;
4330        boolean onKeyguard = mState == StatusBarState.KEYGUARD;
4331        boolean publicMode = isAnyProfilePublicMode();
4332        mStackScroller.setHideSensitive(publicMode, goingToFullShade);
4333        mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
4334        mStackScroller.setExpandingEnabled(!onKeyguard);
4335        ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
4336        mStackScroller.setActivatedChild(null);
4337        if (activatedChild != null) {
4338            activatedChild.makeInactive(false /* animate */);
4339        }
4340    }
4341
4342    public void userActivity() {
4343        if (mState == StatusBarState.KEYGUARD) {
4344            mKeyguardViewMediatorCallback.userActivity();
4345        }
4346    }
4347
4348    public boolean interceptMediaKey(KeyEvent event) {
4349        return mState == StatusBarState.KEYGUARD
4350                && mStatusBarKeyguardViewManager.interceptMediaKey(event);
4351    }
4352
4353    protected boolean shouldUnlockOnMenuPressed() {
4354        return mDeviceInteractive && mState != StatusBarState.SHADE
4355            && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed();
4356    }
4357
4358    public boolean onMenuPressed() {
4359        if (shouldUnlockOnMenuPressed()) {
4360            animateCollapsePanels(
4361                    CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
4362            return true;
4363        }
4364        return false;
4365    }
4366
4367    public void endAffordanceLaunch() {
4368        releaseGestureWakeLock();
4369        mNotificationPanel.onAffordanceLaunchEnded();
4370    }
4371
4372    public boolean onBackPressed() {
4373        if (mStatusBarKeyguardViewManager.onBackPressed()) {
4374            return true;
4375        }
4376        if (mNotificationPanel.isQsExpanded()) {
4377            if (mNotificationPanel.isQsDetailShowing()) {
4378                mNotificationPanel.closeQsDetail();
4379            } else {
4380                mNotificationPanel.animateCloseQs();
4381            }
4382            return true;
4383        }
4384        if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
4385            animateCollapsePanels();
4386            return true;
4387        }
4388        if (mKeyguardUserSwitcher.hideIfNotSimple(true)) {
4389            return true;
4390        }
4391        return false;
4392    }
4393
4394    public boolean onSpacePressed() {
4395        if (mDeviceInteractive && mState != StatusBarState.SHADE) {
4396            animateCollapsePanels(
4397                    CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
4398            return true;
4399        }
4400        return false;
4401    }
4402
4403    private void showBouncerIfKeyguard() {
4404        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4405            showBouncer();
4406        }
4407    }
4408
4409    protected void showBouncer() {
4410        mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
4411        mStatusBarKeyguardViewManager.dismiss();
4412    }
4413
4414    private void instantExpandNotificationsPanel() {
4415
4416        // Make our window larger and the panel expanded.
4417        makeExpandedVisible(true);
4418        mNotificationPanel.expand(false /* animate */);
4419    }
4420
4421    private void instantCollapseNotificationPanel() {
4422        mNotificationPanel.instantCollapse();
4423    }
4424
4425    @Override
4426    public void onActivated(ActivatableNotificationView view) {
4427        mLockscreenGestureLogger.write(
4428                MetricsEvent.ACTION_LS_NOTE,
4429                0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
4430        mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
4431        ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
4432        if (previousView != null) {
4433            previousView.makeInactive(true /* animate */);
4434        }
4435        mStackScroller.setActivatedChild(view);
4436    }
4437
4438    /**
4439     * @param state The {@link StatusBarState} to set.
4440     */
4441    public void setBarState(int state) {
4442        // If we're visible and switched to SHADE_LOCKED (the user dragged
4443        // down on the lockscreen), clear notification LED, vibration,
4444        // ringing.
4445        // Other transitions are covered in handleVisibleToUserChanged().
4446        if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED
4447                || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) {
4448            clearNotificationEffects();
4449        }
4450        if (state == StatusBarState.KEYGUARD) {
4451            removeRemoteInputEntriesKeptUntilCollapsed();
4452            maybeEscalateHeadsUp();
4453        }
4454        mState = state;
4455        mGroupManager.setStatusBarState(state);
4456        mHeadsUpManager.setStatusBarState(state);
4457        mFalsingManager.setStatusBarState(state);
4458        mStatusBarWindowManager.setStatusBarState(state);
4459        mStackScroller.setStatusBarState(state);
4460        updateReportRejectedTouchVisibility();
4461        updateDozing();
4462        mNotificationShelf.setStatusBarState(state);
4463    }
4464
4465    @Override
4466    public void onActivationReset(ActivatableNotificationView view) {
4467        if (view == mStackScroller.getActivatedChild()) {
4468            mKeyguardIndicationController.hideTransientIndication();
4469            mStackScroller.setActivatedChild(null);
4470        }
4471    }
4472
4473    public void onTrackingStarted() {
4474        runPostCollapseRunnables();
4475    }
4476
4477    public void onClosingFinished() {
4478        runPostCollapseRunnables();
4479        if (!isPanelFullyCollapsed()) {
4480            // if we set it not to be focusable when collapsing, we have to undo it when we aborted
4481            // the closing
4482            mStatusBarWindowManager.setStatusBarFocusable(true);
4483        }
4484    }
4485
4486    public void onUnlockHintStarted() {
4487        mFalsingManager.onUnlockHintStarted();
4488        mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
4489    }
4490
4491    public void onHintFinished() {
4492        // Delay the reset a bit so the user can read the text.
4493        mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
4494    }
4495
4496    public void onCameraHintStarted() {
4497        mFalsingManager.onCameraHintStarted();
4498        mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
4499    }
4500
4501    public void onVoiceAssistHintStarted() {
4502        mFalsingManager.onLeftAffordanceHintStarted();
4503        mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
4504    }
4505
4506    public void onPhoneHintStarted() {
4507        mFalsingManager.onLeftAffordanceHintStarted();
4508        mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
4509    }
4510
4511    public void onTrackingStopped(boolean expand) {
4512        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4513            if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
4514                showBouncerIfKeyguard();
4515            }
4516        }
4517    }
4518
4519    protected int getMaxKeyguardNotifications(boolean recompute) {
4520        if (recompute) {
4521            mMaxKeyguardNotifications = Math.max(1,
4522                    mNotificationPanel.computeMaxKeyguardNotifications(
4523                            mMaxAllowedKeyguardNotifications));
4524            return mMaxKeyguardNotifications;
4525        }
4526        return mMaxKeyguardNotifications;
4527    }
4528
4529    public int getMaxKeyguardNotifications() {
4530        return getMaxKeyguardNotifications(false /* recompute */);
4531    }
4532
4533    // TODO: Figure out way to remove this.
4534    public NavigationBarView getNavigationBarView() {
4535        return (NavigationBarView) mNavigationBar.getView();
4536    }
4537
4538    // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
4539
4540
4541    /* Only ever called as a consequence of a lockscreen expansion gesture. */
4542    @Override
4543    public boolean onDraggedDown(View startingChild, int dragLengthY) {
4544        if (hasActiveNotifications() && (!isDozing() || isPulsing())) {
4545            mLockscreenGestureLogger.write(
4546                    MetricsEvent.ACTION_LS_SHADE,
4547                    (int) (dragLengthY / mDisplayMetrics.density),
4548                    0 /* velocityDp - N/A */);
4549
4550            // We have notifications, go to locked shade.
4551            goToLockedShade(startingChild);
4552            if (startingChild instanceof ExpandableNotificationRow) {
4553                ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
4554                row.onExpandedByGesture(true /* drag down is always an open */);
4555            }
4556            return true;
4557        } else {
4558            // abort gesture.
4559            return false;
4560        }
4561    }
4562
4563    @Override
4564    public void onDragDownReset() {
4565        mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
4566        mStackScroller.resetScrollPosition();
4567    }
4568
4569    @Override
4570    public void onCrossedThreshold(boolean above) {
4571        mStackScroller.setDimmed(!above /* dimmed */, true /* animate */);
4572    }
4573
4574    @Override
4575    public void onTouchSlopExceeded() {
4576        mStackScroller.removeLongPressCallback();
4577    }
4578
4579    @Override
4580    public void setEmptyDragAmount(float amount) {
4581        mNotificationPanel.setEmptyDragAmount(amount);
4582    }
4583
4584    /**
4585     * If secure with redaction: Show bouncer, go to unlocked shade.
4586     *
4587     * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
4588     *
4589     * @param expandView The view to expand after going to the shade.
4590     */
4591    public void goToLockedShade(View expandView) {
4592        int userId = mCurrentUserId;
4593        ExpandableNotificationRow row = null;
4594        if (expandView instanceof ExpandableNotificationRow) {
4595            row = (ExpandableNotificationRow) expandView;
4596            row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
4597            // Indicate that the group expansion is changing at this time -- this way the group
4598            // and children backgrounds / divider animations will look correct.
4599            row.setGroupExpansionChanging(true);
4600            if (row.getStatusBarNotification() != null) {
4601                userId = row.getStatusBarNotification().getUserId();
4602            }
4603        }
4604        boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
4605                || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
4606        if (isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
4607            mLeaveOpenOnKeyguardHide = true;
4608            showBouncerIfKeyguard();
4609            mDraggedDownRow = row;
4610            mPendingRemoteInputView = null;
4611        } else {
4612            mNotificationPanel.animateToFullShade(0 /* delay */);
4613            setBarState(StatusBarState.SHADE_LOCKED);
4614            updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
4615        }
4616    }
4617
4618    public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
4619        mLeaveOpenOnKeyguardHide = true;
4620        dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
4621    }
4622
4623    protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
4624        mLeaveOpenOnKeyguardHide = true;
4625        showBouncer();
4626        mPendingRemoteInputView = clicked;
4627    }
4628
4629    protected void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
4630            View clickedView) {
4631        if (isKeyguardShowing()) {
4632            onLockedRemoteInput(row, clickedView);
4633        } else {
4634            row.setUserExpanded(true);
4635            row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
4636        }
4637    }
4638
4639    protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
4640            String notificationKey) {
4641        // Clear pending remote view, as we do not want to trigger pending remote input view when
4642        // it's called by other code
4643        mPendingWorkRemoteInputView = null;
4644        // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
4645        final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
4646                null, userId);
4647        if (newIntent == null) {
4648            return false;
4649        }
4650        final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
4651        callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
4652        callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
4653        callBackIntent.setPackage(mContext.getPackageName());
4654
4655        PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
4656                mContext,
4657                0,
4658                callBackIntent,
4659                PendingIntent.FLAG_CANCEL_CURRENT |
4660                        PendingIntent.FLAG_ONE_SHOT |
4661                        PendingIntent.FLAG_IMMUTABLE);
4662        newIntent.putExtra(
4663                Intent.EXTRA_INTENT,
4664                callBackPendingIntent.getIntentSender());
4665        try {
4666            ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
4667                    null /*options*/);
4668        } catch (RemoteException ex) {
4669            // ignore
4670        }
4671        return true;
4672        // End old BaseStatusBar.startWorkChallengeIfNecessary.
4673    }
4674
4675    protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
4676            View clicked) {
4677        // Collapse notification and show work challenge
4678        animateCollapsePanels();
4679        startWorkChallengeIfNecessary(userId, null, null);
4680        // Add pending remote input view after starting work challenge, as starting work challenge
4681        // will clear all previous pending review view
4682        mPendingWorkRemoteInputView = clicked;
4683    }
4684
4685    private boolean isAnyProfilePublicMode() {
4686        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
4687            if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
4688                return true;
4689            }
4690        }
4691        return false;
4692    }
4693
4694    protected void onWorkChallengeChanged() {
4695        updatePublicMode();
4696        updateNotifications();
4697        if (mPendingWorkRemoteInputView != null && !isAnyProfilePublicMode()) {
4698            // Expand notification panel and the notification row, then click on remote input view
4699            final Runnable clickPendingViewRunnable = new Runnable() {
4700                @Override
4701                public void run() {
4702                    final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
4703                    if (pendingWorkRemoteInputView == null) {
4704                        return;
4705                    }
4706
4707                    // Climb up the hierarchy until we get to the container for this row.
4708                    ViewParent p = pendingWorkRemoteInputView.getParent();
4709                    while (!(p instanceof ExpandableNotificationRow)) {
4710                        if (p == null) {
4711                            return;
4712                        }
4713                        p = p.getParent();
4714                    }
4715
4716                    final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
4717                    ViewParent viewParent = row.getParent();
4718                    if (viewParent instanceof NotificationStackScrollLayout) {
4719                        final NotificationStackScrollLayout scrollLayout =
4720                                (NotificationStackScrollLayout) viewParent;
4721                        row.makeActionsVisibile();
4722                        row.post(new Runnable() {
4723                            @Override
4724                            public void run() {
4725                                final Runnable finishScrollingCallback = new Runnable() {
4726                                    @Override
4727                                    public void run() {
4728                                        mPendingWorkRemoteInputView.callOnClick();
4729                                        mPendingWorkRemoteInputView = null;
4730                                        scrollLayout.setFinishScrollingCallback(null);
4731                                    }
4732                                };
4733                                if (scrollLayout.scrollTo(row)) {
4734                                    // It scrolls! So call it when it's finished.
4735                                    scrollLayout.setFinishScrollingCallback(
4736                                            finishScrollingCallback);
4737                                } else {
4738                                    // It does not scroll, so call it now!
4739                                    finishScrollingCallback.run();
4740                                }
4741                            }
4742                        });
4743                    }
4744                }
4745            };
4746            mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
4747                    new ViewTreeObserver.OnGlobalLayoutListener() {
4748                        @Override
4749                        public void onGlobalLayout() {
4750                            if (mNotificationPanel.mStatusBar.getStatusBarWindow()
4751                                    .getHeight() != mNotificationPanel.mStatusBar
4752                                            .getStatusBarHeight()) {
4753                                mNotificationPanel.getViewTreeObserver()
4754                                        .removeOnGlobalLayoutListener(this);
4755                                mNotificationPanel.post(clickPendingViewRunnable);
4756                            }
4757                        }
4758                    });
4759            instantExpandNotificationsPanel();
4760        }
4761    }
4762
4763    @Override
4764    public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
4765        mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
4766        if (mState == StatusBarState.KEYGUARD && nowExpanded) {
4767            goToLockedShade(clickedEntry.row);
4768        }
4769    }
4770
4771    /**
4772     * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
4773     */
4774    public void goToKeyguard() {
4775        if (mState == StatusBarState.SHADE_LOCKED) {
4776            mStackScroller.onGoToKeyguard();
4777            setBarState(StatusBarState.KEYGUARD);
4778            updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/);
4779        }
4780    }
4781
4782    public long getKeyguardFadingAwayDelay() {
4783        return mKeyguardFadingAwayDelay;
4784    }
4785
4786    public long getKeyguardFadingAwayDuration() {
4787        return mKeyguardFadingAwayDuration;
4788    }
4789
4790    public void setBouncerShowing(boolean bouncerShowing) {
4791        mBouncerShowing = bouncerShowing;
4792        mStatusBarView.setBouncerShowing(bouncerShowing);
4793        recomputeDisableFlags(true /* animate */);
4794    }
4795
4796    public void onStartedGoingToSleep() {
4797        mStartedGoingToSleep = true;
4798    }
4799
4800    public void onFinishedGoingToSleep() {
4801        mNotificationPanel.onAffordanceLaunchEnded();
4802        releaseGestureWakeLock();
4803        mLaunchCameraOnScreenTurningOn = false;
4804        mStartedGoingToSleep = false;
4805        mDeviceInteractive = false;
4806        mWakeUpComingFromTouch = false;
4807        mWakeUpTouchLocation = null;
4808        mStackScroller.setAnimationsEnabled(false);
4809        mVisualStabilityManager.setScreenOn(false);
4810        updateVisibleToUser();
4811        if (mLaunchCameraOnFinishedGoingToSleep) {
4812            mLaunchCameraOnFinishedGoingToSleep = false;
4813
4814            // This gets executed before we will show Keyguard, so post it in order that the state
4815            // is correct.
4816            mHandler.post(new Runnable() {
4817                @Override
4818                public void run() {
4819                    onCameraLaunchGestureDetected(mLastCameraLaunchSource);
4820                }
4821            });
4822        }
4823    }
4824
4825    public void onStartedWakingUp() {
4826        mDeviceInteractive = true;
4827        mStackScroller.setAnimationsEnabled(true);
4828        mVisualStabilityManager.setScreenOn(true);
4829        mNotificationPanel.setTouchDisabled(false);
4830        updateVisibleToUser();
4831    }
4832
4833    public void onScreenTurningOn() {
4834        mScreenTurningOn = true;
4835        mFalsingManager.onScreenTurningOn();
4836        mNotificationPanel.onScreenTurningOn();
4837        if (mLaunchCameraOnScreenTurningOn) {
4838            mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
4839            mLaunchCameraOnScreenTurningOn = false;
4840        }
4841    }
4842
4843    private void vibrateForCameraGesture() {
4844        // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
4845        mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
4846    }
4847
4848    public void onScreenTurnedOn() {
4849        mScreenTurningOn = false;
4850        mDozeScrimController.onScreenTurnedOn();
4851    }
4852
4853    @Override
4854    public void showScreenPinningRequest(int taskId) {
4855        if (mKeyguardMonitor.isShowing()) {
4856            // Don't allow apps to trigger this from keyguard.
4857            return;
4858        }
4859        // Show screen pinning request, since this comes from an app, show 'no thanks', button.
4860        showScreenPinningRequest(taskId, true);
4861    }
4862
4863    public void showScreenPinningRequest(int taskId, boolean allowCancel) {
4864        mScreenPinningRequest.showPrompt(taskId, allowCancel);
4865    }
4866
4867    public boolean hasActiveNotifications() {
4868        return !mNotificationData.getActiveNotifications().isEmpty();
4869    }
4870
4871    public void wakeUpIfDozing(long time, View where) {
4872        if (mDozing) {
4873            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
4874            pm.wakeUp(time, "com.android.systemui:NODOZE");
4875            mWakeUpComingFromTouch = true;
4876            where.getLocationInWindow(mTmpInt2);
4877            mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
4878                    mTmpInt2[1] + where.getHeight() / 2);
4879            mNotificationPanel.setTouchDisabled(false);
4880            mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
4881            mFalsingManager.onScreenOnFromTouch();
4882        }
4883    }
4884
4885    @Override
4886    public void appTransitionCancelled() {
4887        EventBus.getDefault().send(new AppTransitionFinishedEvent());
4888    }
4889
4890    @Override
4891    public void appTransitionFinished() {
4892        EventBus.getDefault().send(new AppTransitionFinishedEvent());
4893    }
4894
4895    @Override
4896    public void onCameraLaunchGestureDetected(int source) {
4897        mLastCameraLaunchSource = source;
4898        if (mStartedGoingToSleep) {
4899            mLaunchCameraOnFinishedGoingToSleep = true;
4900            return;
4901        }
4902        if (!mNotificationPanel.canCameraGestureBeLaunched(
4903                mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
4904            return;
4905        }
4906        if (!mDeviceInteractive) {
4907            PowerManager pm = mContext.getSystemService(PowerManager.class);
4908            pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE");
4909            mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
4910        }
4911        vibrateForCameraGesture();
4912        if (!mStatusBarKeyguardViewManager.isShowing()) {
4913            startActivity(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
4914                    true /* dismissShade */);
4915        } else {
4916            if (!mDeviceInteractive) {
4917                // Avoid flickering of the scrim when we instant launch the camera and the bouncer
4918                // comes on.
4919                mScrimController.dontAnimateBouncerChangesUntilNextFrame();
4920                mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
4921            }
4922            if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
4923                mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
4924            } else {
4925                // We need to defer the camera launch until the screen comes on, since otherwise
4926                // we will dismiss us too early since we are waiting on an activity to be drawn and
4927                // incorrectly get notified because of the screen on event (which resumes and pauses
4928                // some activities)
4929                mLaunchCameraOnScreenTurningOn = true;
4930            }
4931        }
4932    }
4933
4934    @Override
4935    public void showTvPictureInPictureMenu() {
4936        // no-op.
4937    }
4938
4939    public void notifyFpAuthModeChanged() {
4940        updateDozing();
4941    }
4942
4943    private void updateDozing() {
4944        Trace.beginSection("StatusBar#updateDozing");
4945        // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
4946        mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD
4947                || mFingerprintUnlockController.getMode()
4948                        == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
4949        updateDozingState();
4950        Trace.endSection();
4951    }
4952
4953    public boolean isKeyguardShowing() {
4954        return mStatusBarKeyguardViewManager.isShowing();
4955    }
4956
4957    private final class DozeServiceHost implements DozeHost {
4958        private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
4959
4960        @Override
4961        public String toString() {
4962            return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
4963        }
4964
4965        public void firePowerSaveChanged(boolean active) {
4966            for (Callback callback : mCallbacks) {
4967                callback.onPowerSaveChanged(active);
4968            }
4969        }
4970
4971        public void fireNotificationHeadsUp() {
4972            for (Callback callback : mCallbacks) {
4973                callback.onNotificationHeadsUp();
4974            }
4975        }
4976
4977        @Override
4978        public void addCallback(@NonNull Callback callback) {
4979            mCallbacks.add(callback);
4980        }
4981
4982        @Override
4983        public void removeCallback(@NonNull Callback callback) {
4984            mCallbacks.remove(callback);
4985        }
4986
4987        @Override
4988        public void startDozing() {
4989            if (!mDozingRequested) {
4990                mDozingRequested = true;
4991                DozeLog.traceDozing(mContext, mDozing);
4992                updateDozing();
4993            }
4994        }
4995
4996        @Override
4997        public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
4998            mDozeScrimController.pulse(new PulseCallback() {
4999
5000                @Override
5001                public void onPulseStarted() {
5002                    callback.onPulseStarted();
5003                    if (!mHeadsUpManager.getAllEntries().isEmpty()) {
5004                        // Only pulse the stack scroller if there's actually something to show.
5005                        // Otherwise just show the always-on screen.
5006                        mStackScroller.setPulsing(true);
5007                        mVisualStabilityManager.setPulsing(true);
5008                    }
5009                }
5010
5011                @Override
5012                public void onPulseFinished() {
5013                    callback.onPulseFinished();
5014                    mStackScroller.setPulsing(false);
5015                    mVisualStabilityManager.setPulsing(false);
5016                }
5017            }, reason);
5018        }
5019
5020        @Override
5021        public void stopDozing() {
5022            if (mDozingRequested) {
5023                mDozingRequested = false;
5024                DozeLog.traceDozing(mContext, mDozing);
5025                updateDozing();
5026            }
5027        }
5028
5029        @Override
5030        public void dozeTimeTick() {
5031            mKeyguardStatusView.refreshTime();
5032        }
5033
5034        @Override
5035        public boolean isPowerSaveActive() {
5036            return mBatteryController.isPowerSave();
5037        }
5038
5039        @Override
5040        public boolean isPulsingBlocked() {
5041            return mFingerprintUnlockController.getMode()
5042                    == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
5043        }
5044
5045        @Override
5046        public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
5047            StatusBar.this.startPendingIntentDismissingKeyguard(intent);
5048        }
5049
5050    }
5051
5052    public SnoozeListener getSnoozeListener() {
5053        return this;
5054    }
5055
5056    @Override
5057    public void snoozeNotification(StatusBarNotification sbn, SnoozeOption snoozeOption) {
5058        setNotificationSnoozed(sbn, snoozeOption);
5059    }
5060
5061    // Begin Extra BaseStatusBar methods.
5062
5063    protected CommandQueue mCommandQueue;
5064    protected IStatusBarService mBarService;
5065
5066    // all notifications
5067    protected NotificationData mNotificationData;
5068    protected NotificationStackScrollLayout mStackScroller;
5069
5070    protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
5071
5072    protected RemoteInputController mRemoteInputController;
5073
5074    // for heads up notifications
5075    protected HeadsUpManager mHeadsUpManager;
5076
5077    // handling reordering
5078    protected VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager();
5079
5080    protected int mCurrentUserId = 0;
5081    final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
5082
5083    protected int mLayoutDirection = -1; // invalid
5084    protected AccessibilityManager mAccessibilityManager;
5085
5086    protected boolean mDeviceInteractive;
5087
5088    protected boolean mVisible;
5089    protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
5090    protected ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>();
5091
5092    /**
5093     * Notifications with keys in this set are not actually around anymore. We kept them around
5094     * when they were canceled in response to a remote input interaction. This allows us to show
5095     * what you replied and allows you to continue typing into it.
5096     */
5097    protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
5098
5099    // mScreenOnFromKeyguard && mVisible.
5100    private boolean mVisibleToUser;
5101
5102    private Locale mLocale;
5103
5104    protected boolean mUseHeadsUp = false;
5105    protected boolean mHeadsUpTicker = false;
5106    protected boolean mDisableNotificationAlerts = false;
5107
5108    protected DevicePolicyManager mDevicePolicyManager;
5109    protected IDreamManager mDreamManager;
5110    protected PowerManager mPowerManager;
5111    protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
5112
5113    // public mode, private notifications, etc
5114    private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
5115    private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
5116    private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
5117
5118    private UserManager mUserManager;
5119
5120    protected KeyguardManager mKeyguardManager;
5121    private LockPatternUtils mLockPatternUtils;
5122    private DeviceProvisionedController mDeviceProvisionedController;
5123
5124    // UI-specific methods
5125
5126    protected WindowManager mWindowManager;
5127    protected IWindowManager mWindowManagerService;
5128
5129    protected Display mDisplay;
5130
5131    protected RecentsComponent mRecents;
5132
5133    protected int mZenMode;
5134
5135    // which notification is currently being longpress-examined by the user
5136    private NotificationGuts mNotificationGutsExposed;
5137    private MenuItem mGutsMenuItem;
5138
5139    private KeyboardShortcuts mKeyboardShortcuts;
5140
5141    protected NotificationShelf mNotificationShelf;
5142    protected DismissView mDismissView;
5143    protected EmptyShadeView mEmptyShadeView;
5144
5145    private NotificationClicker mNotificationClicker = new NotificationClicker();
5146
5147    protected AssistManager mAssistManager;
5148
5149    protected boolean mVrMode;
5150
5151    private Set<String> mNonBlockablePkgs;
5152
5153    @Override  // NotificationData.Environment
5154    public boolean isDeviceProvisioned() {
5155        return mDeviceProvisionedController.isDeviceProvisioned();
5156    }
5157
5158    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
5159        @Override
5160        public void onVrStateChanged(boolean enabled) {
5161            mVrMode = enabled;
5162        }
5163    };
5164
5165    public boolean isDeviceInVrMode() {
5166        return mVrMode;
5167    }
5168
5169    private final DeviceProvisionedListener mDeviceProvisionedListener =
5170            new DeviceProvisionedListener() {
5171        @Override
5172        public void onDeviceProvisionedChanged() {
5173            updateNotifications();
5174        }
5175    };
5176
5177    protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
5178        @Override
5179        public void onChange(boolean selfChange) {
5180            final int mode = Settings.Global.getInt(mContext.getContentResolver(),
5181                    Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
5182            setZenMode(mode);
5183
5184            updateLockscreenNotificationSetting();
5185        }
5186    };
5187
5188    private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
5189        @Override
5190        public void onChange(boolean selfChange) {
5191            // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
5192            // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
5193            mUsersAllowingPrivateNotifications.clear();
5194            mUsersAllowingNotifications.clear();
5195            // ... and refresh all the notifications
5196            updateLockscreenNotificationSetting();
5197            updateNotifications();
5198        }
5199    };
5200
5201    private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
5202
5203        @Override
5204        public boolean onClickHandler(
5205                final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
5206            wakeUpIfDozing(SystemClock.uptimeMillis(), view);
5207
5208
5209            if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
5210                return true;
5211            }
5212
5213            if (DEBUG) {
5214                Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
5215            }
5216            logActionClick(view);
5217            // The intent we are sending is for the application, which
5218            // won't have permission to immediately start an activity after
5219            // the user switches to home.  We know it is safe to do at this
5220            // point, so make sure new activity switches are now allowed.
5221            try {
5222                ActivityManager.getService().resumeAppSwitches();
5223            } catch (RemoteException e) {
5224            }
5225            final boolean isActivity = pendingIntent.isActivity();
5226            if (isActivity) {
5227                final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
5228                final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
5229                        mContext, pendingIntent.getIntent(), mCurrentUserId);
5230                dismissKeyguardThenExecute(new OnDismissAction() {
5231                    @Override
5232                    public boolean onDismiss() {
5233                        try {
5234                            ActivityManager.getService().resumeAppSwitches();
5235                        } catch (RemoteException e) {
5236                        }
5237
5238                        boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
5239
5240                        // close the shade if it was open
5241                        if (handled) {
5242                            animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
5243                                    true /* force */);
5244                            visibilityChanged(false);
5245                            mAssistManager.hideAssist();
5246                        }
5247
5248                        // Wait for activity start.
5249                        return handled;
5250                    }
5251                }, afterKeyguardGone);
5252                return true;
5253            } else {
5254                return superOnClickHandler(view, pendingIntent, fillInIntent);
5255            }
5256        }
5257
5258        private void logActionClick(View view) {
5259            ViewParent parent = view.getParent();
5260            String key = getNotificationKeyForParent(parent);
5261            if (key == null) {
5262                Log.w(TAG, "Couldn't determine notification for click.");
5263                return;
5264            }
5265            int index = -1;
5266            // If this is a default template, determine the index of the button.
5267            if (view.getId() == com.android.internal.R.id.action0 &&
5268                    parent != null && parent instanceof ViewGroup) {
5269                ViewGroup actionGroup = (ViewGroup) parent;
5270                index = actionGroup.indexOfChild(view);
5271            }
5272            try {
5273                mBarService.onNotificationActionClick(key, index);
5274            } catch (RemoteException e) {
5275                // Ignore
5276            }
5277        }
5278
5279        private String getNotificationKeyForParent(ViewParent parent) {
5280            while (parent != null) {
5281                if (parent instanceof ExpandableNotificationRow) {
5282                    return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
5283                }
5284                parent = parent.getParent();
5285            }
5286            return null;
5287        }
5288
5289        private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
5290                Intent fillInIntent) {
5291            return super.onClickHandler(view, pendingIntent, fillInIntent,
5292                    StackId.FULLSCREEN_WORKSPACE_STACK_ID);
5293        }
5294
5295        private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
5296            Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
5297            RemoteInput[] inputs = null;
5298            if (tag instanceof RemoteInput[]) {
5299                inputs = (RemoteInput[]) tag;
5300            }
5301
5302            if (inputs == null) {
5303                return false;
5304            }
5305
5306            RemoteInput input = null;
5307
5308            for (RemoteInput i : inputs) {
5309                if (i.getAllowFreeFormInput()) {
5310                    input = i;
5311                }
5312            }
5313
5314            if (input == null) {
5315                return false;
5316            }
5317
5318            ViewParent p = view.getParent();
5319            RemoteInputView riv = null;
5320            while (p != null) {
5321                if (p instanceof View) {
5322                    View pv = (View) p;
5323                    if (pv.isRootNamespace()) {
5324                        riv = findRemoteInputView(pv);
5325                        break;
5326                    }
5327                }
5328                p = p.getParent();
5329            }
5330            ExpandableNotificationRow row = null;
5331            while (p != null) {
5332                if (p instanceof ExpandableNotificationRow) {
5333                    row = (ExpandableNotificationRow) p;
5334                    break;
5335                }
5336                p = p.getParent();
5337            }
5338
5339            if (row == null) {
5340                return false;
5341            }
5342
5343            row.setUserExpanded(true);
5344
5345            if (!mAllowLockscreenRemoteInput) {
5346                final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
5347                if (isLockscreenPublicMode(userId)) {
5348                    onLockedRemoteInput(row, view);
5349                    return true;
5350                }
5351                if (mUserManager.getUserInfo(userId).isManagedProfile()
5352                        && mKeyguardManager.isDeviceLocked(userId)) {
5353                    onLockedWorkRemoteInput(userId, row, view);
5354                    return true;
5355                }
5356            }
5357
5358            if (riv == null) {
5359                riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
5360                if (riv == null) {
5361                    return false;
5362                }
5363                if (!row.getPrivateLayout().getExpandedChild().isShown()) {
5364                    onMakeExpandedVisibleForRemoteInput(row, view);
5365                    return true;
5366                }
5367            }
5368
5369            int width = view.getWidth();
5370            if (view instanceof TextView) {
5371                // Center the reveal on the text which might be off-center from the TextView
5372                TextView tv = (TextView) view;
5373                if (tv.getLayout() != null) {
5374                    int innerWidth = (int) tv.getLayout().getLineWidth(0);
5375                    innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
5376                    width = Math.min(width, innerWidth);
5377                }
5378            }
5379            int cx = view.getLeft() + width / 2;
5380            int cy = view.getTop() + view.getHeight() / 2;
5381            int w = riv.getWidth();
5382            int h = riv.getHeight();
5383            int r = Math.max(
5384                    Math.max(cx + cy, cx + (h - cy)),
5385                    Math.max((w - cx) + cy, (w - cx) + (h - cy)));
5386
5387            riv.setRevealParameters(cx, cy, r);
5388            riv.setPendingIntent(pendingIntent);
5389            riv.setRemoteInput(inputs, input);
5390            riv.focusAnimated();
5391
5392            return true;
5393        }
5394
5395        private RemoteInputView findRemoteInputView(View v) {
5396            if (v == null) {
5397                return null;
5398            }
5399            return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
5400        }
5401    };
5402
5403    private final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
5404        @Override
5405        public void onReceive(Context context, Intent intent) {
5406            String action = intent.getAction();
5407            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
5408                mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5409                updateCurrentProfilesCache();
5410                if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
5411
5412                updateLockscreenNotificationSetting();
5413
5414                userSwitched(mCurrentUserId);
5415            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
5416                updateCurrentProfilesCache();
5417            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
5418                List<ActivityManager.RecentTaskInfo> recentTask = null;
5419                try {
5420                    recentTask = ActivityManager.getService().getRecentTasks(1,
5421                            ActivityManager.RECENT_WITH_EXCLUDED
5422                            | ActivityManager.RECENT_INCLUDE_PROFILES,
5423                            mCurrentUserId).getList();
5424                } catch (RemoteException e) {
5425                    // Abandon hope activity manager not running.
5426                }
5427                if (recentTask != null && recentTask.size() > 0) {
5428                    UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
5429                    if (user != null && user.isManagedProfile()) {
5430                        Toast toast = Toast.makeText(mContext,
5431                                R.string.managed_profile_foreground_toast,
5432                                Toast.LENGTH_SHORT);
5433                        TextView text = (TextView) toast.getView().findViewById(
5434                                android.R.id.message);
5435                        text.setCompoundDrawablesRelativeWithIntrinsicBounds(
5436                                R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
5437                        int paddingPx = mContext.getResources().getDimensionPixelSize(
5438                                R.dimen.managed_profile_toast_padding);
5439                        text.setCompoundDrawablePadding(paddingPx);
5440                        toast.show();
5441                    }
5442                }
5443            } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
5444                NotificationManager noMan = (NotificationManager)
5445                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
5446                noMan.cancel(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS);
5447
5448                Settings.Secure.putInt(mContext.getContentResolver(),
5449                        Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
5450                if (BANNER_ACTION_SETUP.equals(action)) {
5451                    animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
5452                            true /* force */);
5453                    mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
5454                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
5455
5456                    );
5457                }
5458            } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
5459                final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
5460                final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
5461                if (intentSender != null) {
5462                    try {
5463                        mContext.startIntentSender(intentSender, null, 0, 0, 0);
5464                    } catch (IntentSender.SendIntentException e) {
5465                        /* ignore */
5466                    }
5467                }
5468                if (notificationKey != null) {
5469                    try {
5470                        mBarService.onNotificationClick(notificationKey);
5471                    } catch (RemoteException e) {
5472                        /* ignore */
5473                    }
5474                }
5475            }
5476        }
5477    };
5478
5479    private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
5480        @Override
5481        public void onReceive(Context context, Intent intent) {
5482            final String action = intent.getAction();
5483            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
5484
5485            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
5486                    isCurrentProfile(getSendingUserId())) {
5487                mUsersAllowingPrivateNotifications.clear();
5488                updateLockscreenNotificationSetting();
5489                updateNotifications();
5490            } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
5491                if (userId != mCurrentUserId && isCurrentProfile(userId)) {
5492                    onWorkChallengeChanged();
5493                }
5494            }
5495        }
5496    };
5497
5498    private final NotificationListenerService mNotificationListener =
5499            new NotificationListenerService() {
5500        @Override
5501        public void onListenerConnected() {
5502            if (DEBUG) Log.d(TAG, "onListenerConnected");
5503            final StatusBarNotification[] notifications = getActiveNotifications();
5504            if (notifications == null) {
5505                Log.w(TAG, "onListenerConnected unable to get active notifications.");
5506                return;
5507            }
5508            final RankingMap currentRanking = getCurrentRanking();
5509            mHandler.post(new Runnable() {
5510                @Override
5511                public void run() {
5512                    for (StatusBarNotification sbn : notifications) {
5513                        try {
5514                            addNotification(sbn, currentRanking, null /* oldEntry */);
5515                        } catch (InflationException e) {
5516                            handleInflationException(sbn, e);
5517                        }
5518                    }
5519                }
5520            });
5521        }
5522
5523        @Override
5524        public void onNotificationPosted(final StatusBarNotification sbn,
5525                final RankingMap rankingMap) {
5526            if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
5527            if (sbn != null) {
5528                mHandler.post(new Runnable() {
5529                    @Override
5530                    public void run() {
5531                        processForRemoteInput(sbn.getNotification());
5532                        String key = sbn.getKey();
5533                        mKeysKeptForRemoteInput.remove(key);
5534                        boolean isUpdate = mNotificationData.get(key) != null;
5535                        // In case we don't allow child notifications, we ignore children of
5536                        // notifications that have a summary, since we're not going to show them
5537                        // anyway. This is true also when the summary is canceled,
5538                        // because children are automatically canceled by NoMan in that case.
5539                        if (!ENABLE_CHILD_NOTIFICATIONS
5540                            && mGroupManager.isChildInGroupWithSummary(sbn)) {
5541                            if (DEBUG) {
5542                                Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
5543                            }
5544
5545                            // Remove existing notification to avoid stale data.
5546                            if (isUpdate) {
5547                                removeNotification(key, rankingMap);
5548                            } else {
5549                                mNotificationData.updateRanking(rankingMap);
5550                            }
5551                            return;
5552                        }
5553                        try {
5554                            if (isUpdate) {
5555                                updateNotification(sbn, rankingMap);
5556                            } else {
5557                                addNotification(sbn, rankingMap, null /* oldEntry */);
5558                            }
5559                        } catch (InflationException e) {
5560                            handleInflationException(sbn, e);
5561                        }
5562                    }
5563                });
5564            }
5565        }
5566
5567        @Override
5568        public void onNotificationRemoved(StatusBarNotification sbn,
5569                final RankingMap rankingMap) {
5570            if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
5571            if (sbn != null) {
5572                final String key = sbn.getKey();
5573                mHandler.post(new Runnable() {
5574                    @Override
5575                    public void run() {
5576                        removeNotification(key, rankingMap);
5577                    }
5578                });
5579            }
5580        }
5581
5582        @Override
5583        public void onNotificationRankingUpdate(final RankingMap rankingMap) {
5584            if (DEBUG) Log.d(TAG, "onRankingUpdate");
5585            if (rankingMap != null) {
5586            mHandler.post(new Runnable() {
5587                @Override
5588                public void run() {
5589                    updateNotificationRanking(rankingMap);
5590                }
5591            });
5592        }                            }
5593
5594    };
5595
5596    private void updateCurrentProfilesCache() {
5597        synchronized (mCurrentProfiles) {
5598            mCurrentProfiles.clear();
5599            if (mUserManager != null) {
5600                for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
5601                    mCurrentProfiles.put(user.id, user);
5602                }
5603            }
5604        }
5605    }
5606
5607    protected void notifyUserAboutHiddenNotifications() {
5608        if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
5609                Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
5610            Log.d(TAG, "user hasn't seen notification about hidden notifications");
5611            if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
5612                Log.d(TAG, "insecure lockscreen, skipping notification");
5613                Settings.Secure.putInt(mContext.getContentResolver(),
5614                        Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
5615                return;
5616            }
5617            Log.d(TAG, "disabling lockecreen notifications and alerting the user");
5618            // disable lockscreen notifications until user acts on the banner.
5619            Settings.Secure.putInt(mContext.getContentResolver(),
5620                    Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
5621            Settings.Secure.putInt(mContext.getContentResolver(),
5622                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
5623
5624            final String packageName = mContext.getPackageName();
5625            PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
5626                    new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
5627                    PendingIntent.FLAG_CANCEL_CURRENT);
5628            PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
5629                    new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
5630                    PendingIntent.FLAG_CANCEL_CURRENT);
5631
5632            final int colorRes = com.android.internal.R.color.system_notification_accent_color;
5633            Notification.Builder note =
5634                    new Notification.Builder(mContext, NotificationChannels.GENERAL)
5635                            .setSmallIcon(R.drawable.ic_android)
5636                            .setContentTitle(mContext.getString(
5637                                    R.string.hidden_notifications_title))
5638                            .setContentText(mContext.getString(R.string.hidden_notifications_text))
5639                            .setOngoing(true)
5640                            .setColor(mContext.getColor(colorRes))
5641                            .setContentIntent(setupIntent)
5642                            .addAction(R.drawable.ic_close,
5643                                    mContext.getString(R.string.hidden_notifications_cancel),
5644                                    cancelIntent)
5645                            .addAction(R.drawable.ic_settings,
5646                                    mContext.getString(R.string.hidden_notifications_setup),
5647                                    setupIntent);
5648            overrideNotificationAppName(mContext, note);
5649
5650            NotificationManager noMan =
5651                    (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
5652            noMan.notify(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS, note.build());
5653        }
5654    }
5655
5656    @Override  // NotificationData.Environment
5657    public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
5658        final int thisUserId = mCurrentUserId;
5659        final int notificationUserId = n.getUserId();
5660        if (DEBUG && MULTIUSER_DEBUG) {
5661            Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
5662                    n, thisUserId, notificationUserId));
5663        }
5664        return isCurrentProfile(notificationUserId);
5665    }
5666
5667    protected void setNotificationShown(StatusBarNotification n) {
5668        setNotificationsShown(new String[]{n.getKey()});
5669    }
5670
5671    protected void setNotificationsShown(String[] keys) {
5672        try {
5673            mNotificationListener.setNotificationsShown(keys);
5674        } catch (RuntimeException e) {
5675            Log.d(TAG, "failed setNotificationsShown: ", e);
5676        }
5677    }
5678
5679    protected boolean isCurrentProfile(int userId) {
5680        synchronized (mCurrentProfiles) {
5681            return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
5682        }
5683    }
5684
5685    @Override
5686    public NotificationGroupManager getGroupManager() {
5687        return mGroupManager;
5688    }
5689
5690    public boolean isMediaNotification(NotificationData.Entry entry) {
5691        // TODO: confirm that there's a valid media key
5692        return entry.getExpandedContentView() != null &&
5693               entry.getExpandedContentView()
5694                       .findViewById(com.android.internal.R.id.media_actions) != null;
5695    }
5696
5697    // The (i) button in the guts that links to the system notification settings for that app
5698    private void startAppNotificationSettingsActivity(String packageName, final int appUid,
5699            final String channelId) {
5700        final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
5701        intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
5702        intent.putExtra(Settings.EXTRA_APP_UID, appUid);
5703        intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channelId);
5704        startNotificationGutsIntent(intent, appUid);
5705    }
5706
5707    private void startNotificationGutsIntent(final Intent intent, final int appUid) {
5708        dismissKeyguardThenExecute(new OnDismissAction() {
5709            @Override
5710            public boolean onDismiss() {
5711                AsyncTask.execute(new Runnable() {
5712                    @Override
5713                    public void run() {
5714                        TaskStackBuilder.create(mContext)
5715                                .addNextIntentWithParentStack(intent)
5716                                .startActivities(getActivityOptions(),
5717                                        new UserHandle(UserHandle.getUserId(appUid)));
5718                    }
5719                });
5720                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
5721                return true;
5722            }
5723        }, false /* afterKeyguardGone */);
5724    }
5725
5726    protected void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
5727        if (snoozeOption.criterion != null) {
5728            mNotificationListener.snoozeNotification(sbn.getKey(), snoozeOption.criterion.getId());
5729        } else {
5730            mNotificationListener.snoozeNotification(sbn.getKey(),
5731                    snoozeOption.snoozeForMinutes * 60 * 1000);
5732        }
5733    }
5734
5735    private void bindGuts(final ExpandableNotificationRow row, MenuItem item) {
5736        row.inflateGuts();
5737        row.setGutsView(item);
5738        final StatusBarNotification sbn = row.getStatusBarNotification();
5739        row.setTag(sbn.getPackageName());
5740        final NotificationGuts guts = row.getGuts();
5741        guts.setClosedListener((NotificationGuts g) -> {
5742            if (!g.willBeRemoved() && !row.isRemoved()) {
5743                mStackScroller.onHeightChanged(row, !isPanelFullyCollapsed() /* needsAnimation */);
5744            }
5745            mNotificationGutsExposed = null;
5746            mGutsMenuItem = null;
5747        });
5748
5749        if (item.gutsContent instanceof SnoozeGutsContent) {
5750            ((SnoozeGutsContent) item.gutsContent).setSnoozeListener(getSnoozeListener());
5751            ((SnoozeGutsContent) item.gutsContent).setStatusBarNotification(sbn);
5752            ((NotificationSnooze) item.gutsContent).setSnoozeOptions(row.getEntry().snoozeCriteria);
5753        }
5754
5755        if (item.gutsContent instanceof NotificationInfo) {
5756            final NotificationChannel channel = row.getEntry().channel;
5757            PackageManager pmUser = getPackageManagerForUser(mContext,
5758                    sbn.getUser().getIdentifier());
5759            final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
5760                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
5761            final String pkg = sbn.getPackageName();
5762            NotificationInfo info = (NotificationInfo) item.gutsContent;
5763            final NotificationInfo.OnSettingsClickListener onSettingsClick = (View v,
5764                    int appUid) -> {
5765                MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
5766                guts.resetFalsingCheck();
5767                startAppNotificationSettingsActivity(pkg, appUid, channel.getId());
5768            };
5769            final View.OnClickListener onDoneClick = (View v) -> {
5770                // If the user has security enabled, show challenge if the setting is changed.
5771                if (info.hasImportanceChanged()
5772                        && isLockscreenPublicMode(sbn.getUser().getIdentifier())
5773                        && (mState == StatusBarState.KEYGUARD
5774                                || mState == StatusBarState.SHADE_LOCKED)) {
5775                    OnDismissAction dismissAction = new OnDismissAction() {
5776                        @Override
5777                        public boolean onDismiss() {
5778                            saveAndCloseNotificationMenu(info, row, guts, v);
5779                            return true;
5780                        }
5781                    };
5782                    onLockedNotificationImportanceChange(dismissAction);
5783                } else {
5784                    saveAndCloseNotificationMenu(info, row, guts, v);
5785                }
5786            };
5787            info.bindNotification(pmUser, iNotificationManager, sbn, channel, onSettingsClick,
5788                    onDoneClick,
5789                    mNonBlockablePkgs);
5790        }
5791    }
5792
5793    private void saveAndCloseNotificationMenu(NotificationInfo info,
5794            ExpandableNotificationRow row, NotificationGuts guts, View done) {
5795        guts.resetFalsingCheck();
5796        int[] rowLocation = new int[2];
5797        int[] doneLocation = new int[2];
5798        row.getLocationOnScreen(rowLocation);
5799        done.getLocationOnScreen(doneLocation);
5800
5801        final int centerX = done.getWidth() / 2;
5802        final int centerY = done.getHeight() / 2;
5803        final int x = doneLocation[0] - rowLocation[0] + centerX;
5804        final int y = doneLocation[1] - rowLocation[1] + centerY;
5805        dismissPopups(x, y);
5806    }
5807
5808    protected SwipeHelper.LongPressListener getNotificationLongClicker() {
5809        return new SwipeHelper.LongPressListener() {
5810            @Override
5811            public boolean onLongPress(View v, final int x, final int y,
5812                    MenuItem item) {
5813                if (!(v instanceof ExpandableNotificationRow)) {
5814                    return false;
5815                }
5816                if (v.getWindowToken() == null) {
5817                    Log.e(TAG, "Trying to show notification guts, but not attached to window");
5818                    return false;
5819                }
5820
5821                final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
5822                bindGuts(row, item);
5823                NotificationGuts guts = row.getGuts();
5824
5825                // Assume we are a status_bar_notification_row
5826                if (guts == null) {
5827                    // This view has no guts. Examples are the more card or the dismiss all view
5828                    return false;
5829                }
5830
5831                // Already showing?
5832                if (guts.getVisibility() == View.VISIBLE) {
5833                    dismissPopups(x, y);
5834                    return false;
5835                }
5836
5837                MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
5838
5839                // ensure that it's laid but not visible until actually laid out
5840                guts.setVisibility(View.INVISIBLE);
5841                // Post to ensure the the guts are properly laid out.
5842                guts.post(new Runnable() {
5843                    @Override
5844                    public void run() {
5845                        if (row.getWindowToken() == null) {
5846                            Log.e(TAG, "Trying to show notification guts, but not attached to "
5847                                    + "window");
5848                            return;
5849                        }
5850                        dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */,
5851                                false /* animate */);
5852                        guts.setVisibility(View.VISIBLE);
5853                        final double horz = Math.max(guts.getWidth() - x, x);
5854                        final double vert = Math.max(guts.getHeight() - y, y);
5855                        final float r = (float) Math.hypot(horz, vert);
5856                        final Animator a
5857                                = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
5858                        a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
5859                        a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
5860                        a.addListener(new AnimatorListenerAdapter() {
5861                            @Override
5862                            public void onAnimationEnd(Animator animation) {
5863                                super.onAnimationEnd(animation);
5864                                // Move the notification view back over the gear
5865                                row.resetTranslation();
5866                            }
5867                        });
5868                        a.start();
5869                        guts.setExposed(true /* exposed */,
5870                                mState == StatusBarState.KEYGUARD /* needsFalsingProtection */);
5871                        row.closeRemoteInput();
5872                        mStackScroller.onHeightChanged(row, true /* needsAnimation */);
5873                        mNotificationGutsExposed = guts;
5874                        mGutsMenuItem = item;
5875                    }
5876                });
5877                return true;
5878            }
5879        };
5880    }
5881
5882    /**
5883     * Returns the exposed NotificationGuts or null if none are exposed.
5884     */
5885    public NotificationGuts getExposedGuts() {
5886        return mNotificationGutsExposed;
5887    }
5888
5889    public void dismissPopups() {
5890        dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */, false /* animate */);
5891    }
5892
5893    private void dismissPopups(int x, int y) {
5894        dismissPopups(x, y, true /* resetGear */, false /* animate */);
5895    }
5896
5897    public void dismissPopups(int x, int y, boolean resetGear, boolean animate) {
5898        if (mNotificationGutsExposed != null) {
5899            mNotificationGutsExposed.closeControls(x, y, true /* save */);
5900        }
5901        if (resetGear) {
5902            mStackScroller.resetExposedGearView(animate, true /* force */);
5903        }
5904    }
5905
5906    @Override
5907    public void toggleSplitScreen() {
5908        toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
5909    }
5910
5911    @Override
5912    public void preloadRecentApps() {
5913        int msg = MSG_PRELOAD_RECENT_APPS;
5914        mHandler.removeMessages(msg);
5915        mHandler.sendEmptyMessage(msg);
5916    }
5917
5918    @Override
5919    public void cancelPreloadRecentApps() {
5920        int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
5921        mHandler.removeMessages(msg);
5922        mHandler.sendEmptyMessage(msg);
5923    }
5924
5925    @Override
5926    public void dismissKeyboardShortcutsMenu() {
5927        int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
5928        mHandler.removeMessages(msg);
5929        mHandler.sendEmptyMessage(msg);
5930    }
5931
5932    @Override
5933    public void toggleKeyboardShortcutsMenu(int deviceId) {
5934        int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
5935        mHandler.removeMessages(msg);
5936        mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
5937    }
5938
5939    protected void sendCloseSystemWindows(String reason) {
5940        try {
5941            ActivityManager.getService().closeSystemDialogs(reason);
5942        } catch (RemoteException e) {
5943        }
5944    }
5945
5946    protected void toggleKeyboardShortcuts(int deviceId) {
5947        KeyboardShortcuts.toggle(mContext, deviceId);
5948    }
5949
5950    protected void dismissKeyboardShortcuts() {
5951        KeyboardShortcuts.dismiss();
5952    }
5953
5954    /**
5955     * Save the current "public" (locked and secure) state of the lockscreen.
5956     */
5957    public void setLockscreenPublicMode(boolean publicMode, int userId) {
5958        mLockscreenPublicMode.put(userId, publicMode);
5959    }
5960
5961    public boolean isLockscreenPublicMode(int userId) {
5962        return mLockscreenPublicMode.get(userId, false);
5963    }
5964
5965    /**
5966     * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
5967     * "public" (secure & locked) mode?
5968     */
5969    public boolean userAllowsNotificationsInPublic(int userHandle) {
5970        if (userHandle == UserHandle.USER_ALL) {
5971            return true;
5972        }
5973
5974        if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
5975            final boolean allowed = 0 != Settings.Secure.getIntForUser(
5976                    mContext.getContentResolver(),
5977                    Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
5978            mUsersAllowingNotifications.append(userHandle, allowed);
5979            return allowed;
5980        }
5981
5982        return mUsersAllowingNotifications.get(userHandle);
5983    }
5984
5985    /**
5986     * Has the given user chosen to allow their private (full) notifications to be shown even
5987     * when the lockscreen is in "public" (secure & locked) mode?
5988     */
5989    public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
5990        if (userHandle == UserHandle.USER_ALL) {
5991            return true;
5992        }
5993
5994        if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
5995            final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
5996                    mContext.getContentResolver(),
5997                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
5998            final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
5999            final boolean allowed = allowedByUser && allowedByDpm;
6000            mUsersAllowingPrivateNotifications.append(userHandle, allowed);
6001            return allowed;
6002        }
6003
6004        return mUsersAllowingPrivateNotifications.get(userHandle);
6005    }
6006
6007    private boolean adminAllowsUnredactedNotifications(int userHandle) {
6008        if (userHandle == UserHandle.USER_ALL) {
6009            return true;
6010        }
6011        final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
6012                    userHandle);
6013        return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
6014    }
6015
6016    /**
6017     * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
6018     * If so, notifications should be hidden.
6019     */
6020    @Override  // NotificationData.Environment
6021    public boolean shouldHideNotifications(int userId) {
6022        return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
6023                || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId));
6024    }
6025
6026    /**
6027     * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
6028     * package-specific override.
6029     */
6030    @Override // NotificationDate.Environment
6031    public boolean shouldHideNotifications(String key) {
6032        return isLockscreenPublicMode(mCurrentUserId)
6033                && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
6034    }
6035
6036    /**
6037     * Returns true if we're on a secure lockscreen.
6038     */
6039    @Override  // NotificationData.Environment
6040    public boolean isSecurelyLocked(int userId) {
6041        return isLockscreenPublicMode(userId);
6042    }
6043
6044    public void onNotificationClear(StatusBarNotification notification) {
6045        try {
6046            mBarService.onNotificationClear(
6047                    notification.getPackageName(),
6048                    notification.getTag(),
6049                    notification.getId(),
6050                    notification.getUserId());
6051        } catch (android.os.RemoteException ex) {
6052            // oh well
6053        }
6054    }
6055
6056    /**
6057     * Called when the notification panel layouts
6058     */
6059    public void onPanelLaidOut() {
6060        if (mState == StatusBarState.KEYGUARD) {
6061            // Since the number of notifications is determined based on the height of the view, we
6062            // need to update them.
6063            int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
6064            int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
6065            if (maxBefore != maxNotifications) {
6066                updateRowStates();
6067            }
6068        }
6069    }
6070
6071    protected void inflateViews(Entry entry, ViewGroup parent) throws
6072            InflationException {
6073        PackageManager pmUser = getPackageManagerForUser(mContext,
6074                entry.notification.getUser().getIdentifier());
6075
6076        final StatusBarNotification sbn = entry.notification;
6077        ExpandableNotificationRow row;
6078        if (entry.row != null) {
6079            row = entry.row;
6080            entry.reset();
6081        } else {
6082            // create the row view
6083            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
6084                    Context.LAYOUT_INFLATER_SERVICE);
6085            row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
6086                    parent, false);
6087            row.setExpansionLogger(this, entry.notification.getKey());
6088            row.setGroupManager(mGroupManager);
6089            row.setHeadsUpManager(mHeadsUpManager);
6090            row.setRemoteInputController(mRemoteInputController);
6091            row.setOnExpandClickListener(this);
6092            row.setRemoteViewClickHandler(mOnClickHandler);
6093            row.setInflateExceptionHandler(mInflationExceptionHandler);
6094
6095            // Get the app name.
6096            // Note that Notification.Builder#bindHeaderAppName has similar logic
6097            // but since this field is used in the guts, it must be accurate.
6098            // Therefore we will only show the application label, or, failing that, the
6099            // package name. No substitutions.
6100            final String pkg = sbn.getPackageName();
6101            String appname = pkg;
6102            try {
6103                final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
6104                        PackageManager.MATCH_UNINSTALLED_PACKAGES
6105                                | PackageManager.MATCH_DISABLED_COMPONENTS);
6106                if (info != null) {
6107                    appname = String.valueOf(pmUser.getApplicationLabel(info));
6108                }
6109            } catch (NameNotFoundException e) {
6110                // Do nothing
6111            }
6112            row.setAppName(appname);
6113            row.setOnDismissRunnable(() ->
6114                    performRemoveNotification(row.getStatusBarNotification()));
6115            row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
6116            if (ENABLE_REMOTE_INPUT) {
6117                row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
6118            }
6119        }
6120
6121        boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
6122        row.setIsLowPriority(isLowPriority);
6123        // bind the click event to the content area
6124        mNotificationClicker.register(row, sbn);
6125
6126        // Extract target SDK version.
6127        try {
6128            ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
6129            entry.targetSdk = info.targetSdkVersion;
6130        } catch (NameNotFoundException ex) {
6131            Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
6132        }
6133        row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
6134                && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
6135        entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
6136        entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
6137
6138        entry.row = row;
6139        entry.row.setOnActivatedListener(this);
6140
6141        boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn,
6142                mNotificationData.getImportance(sbn.getKey()));
6143        boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight && mPanelExpanded;
6144        row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
6145        row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
6146        row.updateNotification(entry);
6147    }
6148
6149    /**
6150     * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
6151     * via first-class API.
6152     *
6153     * TODO: Remove once enough apps specify remote inputs on their own.
6154     */
6155    private void processForRemoteInput(Notification n) {
6156        if (!ENABLE_REMOTE_INPUT) return;
6157
6158        if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
6159                (n.actions == null || n.actions.length == 0)) {
6160            Notification.Action viableAction = null;
6161            Notification.WearableExtender we = new Notification.WearableExtender(n);
6162
6163            List<Notification.Action> actions = we.getActions();
6164            final int numActions = actions.size();
6165
6166            for (int i = 0; i < numActions; i++) {
6167                Notification.Action action = actions.get(i);
6168                if (action == null) {
6169                    continue;
6170                }
6171                RemoteInput[] remoteInputs = action.getRemoteInputs();
6172                if (remoteInputs == null) {
6173                    continue;
6174                }
6175                for (RemoteInput ri : remoteInputs) {
6176                    if (ri.getAllowFreeFormInput()) {
6177                        viableAction = action;
6178                        break;
6179                    }
6180                }
6181                if (viableAction != null) {
6182                    break;
6183                }
6184            }
6185
6186            if (viableAction != null) {
6187                Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
6188                rebuilder.setActions(viableAction);
6189                rebuilder.build(); // will rewrite n
6190            }
6191        }
6192    }
6193
6194    public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
6195        if (!isDeviceProvisioned()) return;
6196
6197        final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
6198        final boolean afterKeyguardGone = intent.isActivity()
6199                && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
6200                mCurrentUserId);
6201        dismissKeyguardThenExecute(new OnDismissAction() {
6202            @Override
6203            public boolean onDismiss() {
6204                new Thread() {
6205                    @Override
6206                    public void run() {
6207                        try {
6208                            // The intent we are sending is for the application, which
6209                            // won't have permission to immediately start an activity after
6210                            // the user switches to home.  We know it is safe to do at this
6211                            // point, so make sure new activity switches are now allowed.
6212                            ActivityManager.getService().resumeAppSwitches();
6213                        } catch (RemoteException e) {
6214                        }
6215                        try {
6216                            intent.send(null, 0, null, null, null, null, getActivityOptions());
6217                        } catch (PendingIntent.CanceledException e) {
6218                            // the stack trace isn't very helpful here.
6219                            // Just log the exception message.
6220                            Log.w(TAG, "Sending intent failed: " + e);
6221
6222                            // TODO: Dismiss Keyguard.
6223                        }
6224                        if (intent.isActivity()) {
6225                            mAssistManager.hideAssist();
6226                        }
6227                    }
6228                }.start();
6229
6230                // close the shade if it was open
6231                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
6232                        true /* force */, true /* delayed */);
6233                visibilityChanged(false);
6234
6235                return true;
6236            }
6237        }, afterKeyguardGone);
6238    }
6239
6240
6241    private final class NotificationClicker implements View.OnClickListener {
6242
6243        @Override
6244        public void onClick(final View v) {
6245            if (!(v instanceof ExpandableNotificationRow)) {
6246                Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
6247                return;
6248            }
6249
6250            wakeUpIfDozing(SystemClock.uptimeMillis(), v);
6251
6252            final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
6253            final StatusBarNotification sbn = row.getStatusBarNotification();
6254            if (sbn == null) {
6255                Log.e(TAG, "NotificationClicker called on an unclickable notification,");
6256                return;
6257            }
6258
6259            // Check if the notification is displaying the gear, if so slide notification back
6260            if (row.getSettingsRow() != null && row.getSettingsRow().isVisible()) {
6261                row.animateTranslateNotification(0);
6262                return;
6263            }
6264
6265            Notification notification = sbn.getNotification();
6266            final PendingIntent intent = notification.contentIntent != null
6267                    ? notification.contentIntent
6268                    : notification.fullScreenIntent;
6269            final String notificationKey = sbn.getKey();
6270
6271            // Mark notification for one frame.
6272            row.setJustClicked(true);
6273            DejankUtils.postAfterTraversal(new Runnable() {
6274                @Override
6275                public void run() {
6276                    row.setJustClicked(false);
6277                }
6278            });
6279
6280            final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
6281            final boolean afterKeyguardGone = intent.isActivity()
6282                    && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
6283                            mCurrentUserId);
6284            dismissKeyguardThenExecute(new OnDismissAction() {
6285                @Override
6286                public boolean onDismiss() {
6287                    if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
6288                        // Release the HUN notification to the shade.
6289
6290                        if (isPanelFullyCollapsed()) {
6291                            HeadsUpManager.setIsClickedNotification(row, true);
6292                        }
6293                        //
6294                        // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
6295                        // become canceled shortly by NoMan, but we can't assume that.
6296                        mHeadsUpManager.releaseImmediately(notificationKey);
6297                    }
6298                    StatusBarNotification parentToCancel = null;
6299                    if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
6300                        StatusBarNotification summarySbn = mGroupManager.getLogicalGroupSummary(sbn)
6301                                        .getStatusBarNotification();
6302                        if (shouldAutoCancel(summarySbn)) {
6303                            parentToCancel = summarySbn;
6304                        }
6305                    }
6306                    final StatusBarNotification parentToCancelFinal = parentToCancel;
6307                    new Thread() {
6308                        @Override
6309                        public void run() {
6310                            try {
6311                                // The intent we are sending is for the application, which
6312                                // won't have permission to immediately start an activity after
6313                                // the user switches to home.  We know it is safe to do at this
6314                                // point, so make sure new activity switches are now allowed.
6315                                ActivityManager.getService().resumeAppSwitches();
6316                            } catch (RemoteException e) {
6317                            }
6318                            if (intent != null) {
6319                                // If we are launching a work activity and require to launch
6320                                // separate work challenge, we defer the activity action and cancel
6321                                // notification until work challenge is unlocked.
6322                                if (intent.isActivity()) {
6323                                    final int userId = intent.getCreatorUserHandle()
6324                                            .getIdentifier();
6325                                    if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
6326                                            && mKeyguardManager.isDeviceLocked(userId)) {
6327                                        boolean canBypass = false;
6328                                        try {
6329                                            canBypass = ActivityManager.getService()
6330                                                    .canBypassWorkChallenge(intent);
6331                                        } catch (RemoteException e) {
6332                                        }
6333                                        // For direct-boot aware activities, they can be shown when
6334                                        // the device is still locked without triggering the work
6335                                        // challenge.
6336                                        if ((!canBypass) && startWorkChallengeIfNecessary(userId,
6337                                                    intent.getIntentSender(), notificationKey)) {
6338                                            // Show work challenge, do not run PendingIntent and
6339                                            // remove notification
6340                                            return;
6341                                        }
6342                                    }
6343                                }
6344                                try {
6345                                    intent.send(null, 0, null, null, null, null,
6346                                            getActivityOptions());
6347                                } catch (PendingIntent.CanceledException e) {
6348                                    // the stack trace isn't very helpful here.
6349                                    // Just log the exception message.
6350                                    Log.w(TAG, "Sending contentIntent failed: " + e);
6351
6352                                    // TODO: Dismiss Keyguard.
6353                                }
6354                                if (intent.isActivity()) {
6355                                    mAssistManager.hideAssist();
6356                                }
6357                            }
6358
6359                            try {
6360                                mBarService.onNotificationClick(notificationKey);
6361                            } catch (RemoteException ex) {
6362                                // system process is dead if we're here.
6363                            }
6364                            if (parentToCancelFinal != null) {
6365                                // We have to post it to the UI thread for synchronization
6366                                mHandler.post(new Runnable() {
6367                                    @Override
6368                                    public void run() {
6369                                        Runnable removeRunnable = new Runnable() {
6370                                            @Override
6371                                            public void run() {
6372                                                performRemoveNotification(parentToCancelFinal);
6373                                            }
6374                                        };
6375                                        if (isCollapsing()) {
6376                                            // To avoid lags we're only performing the remove
6377                                            // after the shade was collapsed
6378                                            addPostCollapseAction(removeRunnable);
6379                                        } else {
6380                                            removeRunnable.run();
6381                                        }
6382                                    }
6383                                });
6384                            }
6385                        }
6386                    }.start();
6387
6388                    // close the shade if it was open
6389                    animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
6390                            true /* force */, true /* delayed */);
6391                    visibilityChanged(false);
6392
6393                    return true;
6394                }
6395            }, afterKeyguardGone);
6396        }
6397
6398        private boolean shouldAutoCancel(StatusBarNotification sbn) {
6399            int flags = sbn.getNotification().flags;
6400            if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
6401                return false;
6402            }
6403            if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
6404                return false;
6405            }
6406            return true;
6407        }
6408
6409        public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
6410            Notification notification = sbn.getNotification();
6411            if (notification.contentIntent != null || notification.fullScreenIntent != null) {
6412                row.setOnClickListener(this);
6413            } else {
6414                row.setOnClickListener(null);
6415            }
6416        }
6417    }
6418
6419    protected Bundle getActivityOptions() {
6420        // Anything launched from the notification shade should always go into the
6421        // fullscreen stack.
6422        ActivityOptions options = ActivityOptions.makeBasic();
6423        options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
6424        return options.toBundle();
6425    }
6426
6427    protected void visibilityChanged(boolean visible) {
6428        if (mVisible != visible) {
6429            mVisible = visible;
6430            if (!visible) {
6431                dismissPopups();
6432            }
6433        }
6434        updateVisibleToUser();
6435    }
6436
6437    protected void updateVisibleToUser() {
6438        boolean oldVisibleToUser = mVisibleToUser;
6439        mVisibleToUser = mVisible && mDeviceInteractive;
6440
6441        if (oldVisibleToUser != mVisibleToUser) {
6442            handleVisibleToUserChanged(mVisibleToUser);
6443        }
6444    }
6445
6446    /**
6447     * Clear Buzz/Beep/Blink.
6448     */
6449    public void clearNotificationEffects() {
6450        try {
6451            mBarService.clearNotificationEffects();
6452        } catch (RemoteException e) {
6453            // Won't fail unless the world has ended.
6454        }
6455    }
6456
6457    /**
6458     * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
6459     * about the failure.
6460     *
6461     * WARNING: this will call back into us.  Don't hold any locks.
6462     */
6463    void handleNotificationError(StatusBarNotification n, String message) {
6464        removeNotification(n.getKey(), null);
6465        try {
6466            mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
6467                    n.getInitialPid(), message, n.getUserId());
6468        } catch (RemoteException ex) {
6469            // The end is nigh.
6470        }
6471    }
6472
6473    protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
6474        NotificationData.Entry entry = mNotificationData.remove(key, ranking);
6475        if (entry == null) {
6476            Log.w(TAG, "removeNotification for unknown key: " + key);
6477            return null;
6478        }
6479        updateNotifications();
6480        Dependency.get(LeakDetector.class).trackGarbage(entry);
6481        return entry.notification;
6482    }
6483
6484    protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)
6485            throws InflationException {
6486        if (DEBUG) {
6487            Log.d(TAG, "createNotificationViews(notification=" + sbn);
6488        }
6489        NotificationData.Entry entry = new NotificationData.Entry(sbn);
6490        Dependency.get(LeakDetector.class).trackInstance(entry);
6491        entry.createIcons(mContext, sbn);
6492
6493        // Construct the expanded view.
6494        inflateViews(entry, mStackScroller);
6495        return entry;
6496    }
6497
6498    protected void addNotificationViews(Entry entry, RankingMap ranking) {
6499        if (entry == null) {
6500            return;
6501        }
6502        // Add the expanded view and icon.
6503        mNotificationData.add(entry, ranking);
6504        updateNotifications();
6505    }
6506
6507    /**
6508     * Updates expanded, dimmed and locked states of notification rows.
6509     */
6510    protected void updateRowStates() {
6511        final int N = mStackScroller.getChildCount();
6512
6513        int visibleNotifications = 0;
6514        boolean onKeyguard = mState == StatusBarState.KEYGUARD;
6515        int maxNotifications = -1;
6516        if (onKeyguard) {
6517            maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
6518        }
6519        mStackScroller.setMaxDisplayedNotifications(maxNotifications);
6520        Stack<ExpandableNotificationRow> stack = new Stack<>();
6521        for (int i = N - 1; i >= 0; i--) {
6522            View child = mStackScroller.getChildAt(i);
6523            if (!(child instanceof ExpandableNotificationRow)) {
6524                continue;
6525            }
6526            stack.push((ExpandableNotificationRow) child);
6527        }
6528        while(!stack.isEmpty()) {
6529            ExpandableNotificationRow row = stack.pop();
6530            NotificationData.Entry entry = row.getEntry();
6531            boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
6532            if (onKeyguard) {
6533                row.setOnKeyguard(true);
6534            } else {
6535                row.setOnKeyguard(false);
6536                row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
6537            }
6538            entry.row.setShowAmbient(isDozing());
6539            int userId = entry.notification.getUserId();
6540            boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
6541                    entry.notification) && !entry.row.isRemoved();
6542            boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
6543            if (suppressedSummary
6544                    || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
6545                    || (onKeyguard && !showOnKeyguard)) {
6546                entry.row.setVisibility(View.GONE);
6547            } else {
6548                boolean wasGone = entry.row.getVisibility() == View.GONE;
6549                if (wasGone) {
6550                    entry.row.setVisibility(View.VISIBLE);
6551                }
6552                if (!childNotification && !entry.row.isRemoved()) {
6553                    if (wasGone) {
6554                        // notify the scroller of a child addition
6555                        mStackScroller.generateAddAnimation(entry.row,
6556                                !showOnKeyguard /* fromMoreCard */);
6557                    }
6558                    visibleNotifications++;
6559                }
6560            }
6561            if (row.isSummaryWithChildren()) {
6562                List<ExpandableNotificationRow> notificationChildren =
6563                        row.getNotificationChildren();
6564                int size = notificationChildren.size();
6565                for (int i = size - 1; i >= 0; i--) {
6566                    stack.push(notificationChildren.get(i));
6567                }
6568            }
6569        }
6570        mNotificationPanel.setNoVisibleNotifications(visibleNotifications == 0);
6571
6572        mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
6573        mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
6574        mStackScroller.changeViewPosition(mNotificationShelf, mStackScroller.getChildCount() - 3);
6575    }
6576
6577    public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
6578        return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
6579    }
6580
6581    // extended in StatusBar
6582    protected void setShowLockscreenNotifications(boolean show) {
6583        mShowLockscreenNotifications = show;
6584    }
6585
6586    protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
6587        mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
6588    }
6589
6590    private void updateLockscreenNotificationSetting() {
6591        final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
6592                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
6593                1,
6594                mCurrentUserId) != 0;
6595        final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
6596                null /* admin */, mCurrentUserId);
6597        final boolean allowedByDpm = (dpmFlags
6598                & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
6599
6600        setShowLockscreenNotifications(show && allowedByDpm);
6601
6602        if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
6603            final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
6604                    Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
6605                    0,
6606                    mCurrentUserId) != 0;
6607            final boolean remoteInputDpm =
6608                    (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
6609
6610            setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
6611        } else {
6612            setLockScreenAllowRemoteInput(false);
6613        }
6614    }
6615
6616    public void updateNotification(StatusBarNotification notification, RankingMap ranking)
6617            throws InflationException {
6618        if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
6619
6620        final String key = notification.getKey();
6621        Entry entry = mNotificationData.get(key);
6622        if (entry == null) {
6623            return;
6624        } else {
6625            mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
6626            mRemoteInputEntriesToRemoveOnCollapse.remove(entry);
6627        }
6628
6629        Notification n = notification.getNotification();
6630        mNotificationData.updateRanking(ranking);
6631
6632        final StatusBarNotification oldNotification = entry.notification;
6633        entry.notification = notification;
6634        mGroupManager.onEntryUpdated(entry, oldNotification);
6635
6636        entry.updateIcons(mContext, n);
6637        inflateViews(entry, mStackScroller);
6638
6639        boolean shouldPeek = shouldPeek(entry, notification);
6640        boolean alertAgain = alertAgain(entry, n);
6641
6642        updateHeadsUp(key, entry, shouldPeek, alertAgain);
6643        updateNotifications();
6644
6645        if (!notification.isClearable()) {
6646            // The user may have performed a dismiss action on the notification, since it's
6647            // not clearable we should snap it back.
6648            mStackScroller.snapViewIfNeeded(entry.row);
6649        }
6650
6651        if (DEBUG) {
6652            // Is this for you?
6653            boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
6654            Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
6655        }
6656        setAreThereNotifications();
6657    }
6658
6659    protected void updatePublicContentView(Entry entry,
6660            StatusBarNotification sbn) {
6661        final RemoteViews publicContentView = entry.cachedPublicContentView;
6662        View inflatedView = entry.getPublicContentView();
6663        if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
6664            final boolean disabledByPolicy =
6665                    !adminAllowsUnredactedNotifications(entry.notification.getUserId());
6666            String notificationHiddenText = mContext.getString(disabledByPolicy
6667                    ? com.android.internal.R.string.notification_hidden_by_policy_text
6668                    : com.android.internal.R.string.notification_hidden_text);
6669            TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
6670            if (titleView != null
6671                    && !titleView.getText().toString().equals(notificationHiddenText)) {
6672                titleView.setText(notificationHiddenText);
6673            }
6674        }
6675    }
6676
6677    protected void notifyHeadsUpScreenOff() {
6678        maybeEscalateHeadsUp();
6679    }
6680
6681    private boolean alertAgain(Entry oldEntry, Notification newNotification) {
6682        return oldEntry == null || !oldEntry.hasInterrupted()
6683                || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
6684    }
6685
6686    protected boolean shouldPeek(Entry entry) {
6687        return shouldPeek(entry, entry.notification);
6688    }
6689
6690    protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
6691        if (!mUseHeadsUp || isDeviceInVrMode()) {
6692            return false;
6693        }
6694
6695        if (mNotificationData.shouldFilterOut(sbn)) {
6696            if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
6697            return false;
6698        }
6699
6700        boolean inUse = mPowerManager.isScreenOn();
6701        try {
6702            inUse = inUse && !mDreamManager.isDreaming();
6703        } catch (RemoteException e) {
6704            Log.d(TAG, "failed to query dream manager", e);
6705        }
6706
6707        if (!inUse && !isDozing()) {
6708            if (DEBUG) {
6709                Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
6710            }
6711            return false;
6712        }
6713
6714        if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
6715            if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
6716            return false;
6717        }
6718
6719        if (entry.hasJustLaunchedFullScreenIntent()) {
6720            if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
6721            return false;
6722        }
6723
6724        if (isSnoozedPackage(sbn)) {
6725            if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
6726            return false;
6727        }
6728
6729        // Allow peeking for DEFAULT notifications only if we're on Ambient Display.
6730        int importanceLevel = isDozing() ? NotificationManager.IMPORTANCE_DEFAULT
6731                : NotificationManager.IMPORTANCE_HIGH;
6732        if (mNotificationData.getImportance(sbn.getKey()) < importanceLevel) {
6733            if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
6734            return false;
6735        }
6736
6737        if (sbn.getNotification().fullScreenIntent != null) {
6738            if (mAccessibilityManager.isTouchExplorationEnabled()) {
6739                if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
6740                return false;
6741            } else {
6742                // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
6743                return !mStatusBarKeyguardViewManager.isShowing()
6744                        || mStatusBarKeyguardViewManager.isOccluded();
6745            }
6746        }
6747
6748        return true;
6749    }
6750
6751    /**
6752     * @return Whether the security bouncer from Keyguard is showing.
6753     */
6754    public boolean isBouncerShowing() {
6755        return mBouncerShowing;
6756    }
6757
6758    /**
6759     * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
6760     *         return PackageManager for mContext
6761     */
6762    public static PackageManager getPackageManagerForUser(Context context, int userId) {
6763        Context contextForUser = context;
6764        // UserHandle defines special userId as negative values, e.g. USER_ALL
6765        if (userId >= 0) {
6766            try {
6767                // Create a context for the correct user so if a package isn't installed
6768                // for user 0 we can still load information about the package.
6769                contextForUser =
6770                        context.createPackageContextAsUser(context.getPackageName(),
6771                        Context.CONTEXT_RESTRICTED,
6772                        new UserHandle(userId));
6773            } catch (NameNotFoundException e) {
6774                // Shouldn't fail to find the package name for system ui.
6775            }
6776        }
6777        return contextForUser.getPackageManager();
6778    }
6779
6780    @Override
6781    public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
6782        try {
6783            mBarService.onNotificationExpansionChanged(key, userAction, expanded);
6784        } catch (RemoteException e) {
6785            // Ignore.
6786        }
6787    }
6788
6789    public boolean isKeyguardSecure() {
6790        if (mStatusBarKeyguardViewManager == null) {
6791            // startKeyguard() hasn't been called yet, so we don't know.
6792            // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
6793            // value onVisibilityChanged().
6794            Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
6795                    new Throwable());
6796            return false;
6797        }
6798        return mStatusBarKeyguardViewManager.isSecure();
6799    }
6800
6801    @Override
6802    public void showAssistDisclosure() {
6803        if (mAssistManager != null) {
6804            mAssistManager.showDisclosure();
6805        }
6806    }
6807
6808    @Override
6809    public void startAssist(Bundle args) {
6810        if (mAssistManager != null) {
6811            mAssistManager.startAssist(args);
6812        }
6813    }
6814    // End Extra BaseStatusBarMethods.
6815}
6816