blob: bcb76d7169ecd5baf56dfb338cf8f88b5f7a9616 [file] [log] [blame]
Rakesh Iyer1186faa2015-12-07 16:48:46 -08001/*
Brad Stenning8d1a51c2018-11-20 17:34:16 -08002 * Copyright (C) 2018 The Android Open Source Project
Rakesh Iyer1186faa2015-12-07 16:48:46 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar.car;
18
Dave Mankoffbb9575f2019-10-02 12:23:49 -040019import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
20
Priyank Singhb0241582019-04-19 18:46:26 -070021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
23import android.animation.ValueAnimator;
Matthew Ng94380652019-04-08 13:43:07 -070024import android.annotation.Nullable;
Brad Stenning3b0d7642019-03-28 11:04:30 -070025import android.app.ActivityManager;
Brad Stenningd3ede642019-04-23 21:19:27 -070026import android.car.Car;
Brad Stenningd3ede642019-04-23 21:19:27 -070027import android.car.drivingstate.CarUxRestrictionsManager;
Jonathan Koo007ff072019-05-10 09:24:08 -070028import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
Brad Stenning2ccc2a42019-04-15 10:17:01 -070029import android.content.Context;
Priyank Singh956c4822019-07-10 12:28:24 -070030import android.content.res.Configuration;
Priyank Singhb0241582019-04-19 18:46:26 -070031import android.graphics.Rect;
Anthony Chene658cc22017-04-27 11:17:35 -070032import android.graphics.drawable.Drawable;
Dave Mankoff1193aa42019-10-28 17:51:26 -040033import android.os.PowerManager;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040034import android.util.DisplayMetrics;
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080035import android.util.Log;
Brad Stenning3b0d7642019-03-28 11:04:30 -070036import android.view.GestureDetector;
Brad Stenning3b0d7642019-03-28 11:04:30 -070037import android.view.MotionEvent;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080038import android.view.View;
Anthony Chen0801a5c2017-03-22 09:54:37 -070039import android.view.ViewGroup;
Priyank Singhb9ab0522019-05-03 15:36:25 -070040import android.view.ViewTreeObserver;
Anthony Chene658cc22017-04-27 11:17:35 -070041
Brad Stenning3b0d7642019-03-28 11:04:30 -070042import androidx.annotation.NonNull;
43import androidx.recyclerview.widget.RecyclerView;
44
Brad Stenning2ccc2a42019-04-15 10:17:01 -070045import com.android.car.notification.CarHeadsUpNotificationManager;
Brad Stenning3b0d7642019-03-28 11:04:30 -070046import com.android.car.notification.CarNotificationListener;
47import com.android.car.notification.CarNotificationView;
48import com.android.car.notification.CarUxRestrictionManagerWrapper;
Brad Stenning2ccc2a42019-04-15 10:17:01 -070049import com.android.car.notification.HeadsUpEntry;
Brad Stenning3b0d7642019-03-28 11:04:30 -070050import com.android.car.notification.NotificationClickHandlerFactory;
Brad Stenning2ccc2a42019-04-15 10:17:01 -070051import com.android.car.notification.NotificationDataManager;
Brad Stenning3b0d7642019-03-28 11:04:30 -070052import com.android.car.notification.NotificationViewController;
53import com.android.car.notification.PreprocessingManager;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040054import com.android.internal.logging.MetricsLogger;
Matthew Ng94380652019-04-08 13:43:07 -070055import com.android.internal.statusbar.RegisterStatusBarResult;
Winson Chung2db35572017-10-09 15:08:30 -070056import com.android.keyguard.KeyguardUpdateMonitor;
Heemin Seog032075c2019-11-06 16:29:12 -080057import com.android.keyguard.ViewMediatorCallback;
Anthony Chenda62fdcd52016-04-06 16:15:14 -070058import com.android.systemui.BatteryMeterView;
Jason Monk9c7844c2017-01-18 15:21:53 -050059import com.android.systemui.Dependency;
Winson Chung2db35572017-10-09 15:08:30 -070060import com.android.systemui.Prefs;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080061import com.android.systemui.R;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040062import com.android.systemui.UiOffloadThread;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040063import com.android.systemui.assist.AssistManager;
64import com.android.systemui.broadcast.BroadcastDispatcher;
65import com.android.systemui.bubbles.BubbleController;
Heemin Seogeeca9a92019-11-08 16:16:49 -080066import com.android.systemui.car.CarServiceProvider;
Winson Chung2db35572017-10-09 15:08:30 -070067import com.android.systemui.classifier.FalsingLog;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040068import com.android.systemui.colorextraction.SysuiColorExtractor;
Jason Monkaa573e92017-01-27 17:00:29 -050069import com.android.systemui.fragments.FragmentHostManager;
Heemin Seog032075c2019-11-06 16:29:12 -080070import com.android.systemui.keyguard.DismissCallbackRegistry;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040071import com.android.systemui.keyguard.KeyguardViewMediator;
jovanak622def22019-06-11 11:51:54 -070072import com.android.systemui.keyguard.ScreenLifecycle;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040073import com.android.systemui.keyguard.WakefulnessLifecycle;
Heemin Seogfcccab72019-10-22 08:30:23 -070074import com.android.systemui.navigationbar.car.CarNavigationBarController;
Dave Mankoffc195ea82019-06-28 16:33:25 -040075import com.android.systemui.plugins.FalsingManager;
Brad Stenning8d1a51c2018-11-20 17:34:16 -080076import com.android.systemui.plugins.qs.QS;
77import com.android.systemui.qs.car.CarQSFragment;
Dave Mankoff6c64d1f2019-11-07 17:27:50 -050078import com.android.systemui.recents.Recents;
Dave Mankoff4dd47fa2019-11-07 10:44:48 -050079import com.android.systemui.recents.ScreenPinningRequest;
Dave Mankoff2e484922019-10-31 12:25:08 -040080import com.android.systemui.shared.plugins.PluginManager;
Dave Mankoff613c7c62019-11-04 11:46:36 -050081import com.android.systemui.stackdivider.Divider;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040082import com.android.systemui.statusbar.CommandQueue;
Ned Burnsf098dbf2019-09-13 19:17:53 -040083import com.android.systemui.statusbar.FeatureFlags;
Priyank Singhb0241582019-04-19 18:46:26 -070084import com.android.systemui.statusbar.FlingAnimationUtils;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040085import com.android.systemui.statusbar.NavigationBarController;
86import com.android.systemui.statusbar.NotificationListener;
87import com.android.systemui.statusbar.NotificationLockscreenUserManager;
88import com.android.systemui.statusbar.NotificationMediaManager;
89import com.android.systemui.statusbar.NotificationRemoteInputManager;
90import com.android.systemui.statusbar.NotificationViewHierarchyManager;
91import com.android.systemui.statusbar.PulseExpansionHandler;
Rakesh Iyer2790a372016-01-22 15:33:39 -080092import com.android.systemui.statusbar.StatusBarState;
Heemin Seogafb3dbc2019-11-04 16:05:19 -080093import com.android.systemui.statusbar.SuperStatusBarViewFactory;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040094import com.android.systemui.statusbar.SysuiStatusBarStateController;
95import com.android.systemui.statusbar.VibratorHelper;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040096import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
97import com.android.systemui.statusbar.notification.DynamicPrivacyController;
Dave Mankoffbb9575f2019-10-02 12:23:49 -040098import com.android.systemui.statusbar.notification.NotificationAlertingManager;
99import com.android.systemui.statusbar.notification.NotificationEntryManager;
100import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
101import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
102import com.android.systemui.statusbar.notification.VisualStabilityManager;
Ned Burns77050aa2019-10-17 21:55:24 -0400103import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400104import com.android.systemui.statusbar.notification.logging.NotificationLogger;
105import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
106import com.android.systemui.statusbar.phone.AutoHideController;
Dave Mankoffbbc2f8f2019-10-21 12:21:29 -0400107import com.android.systemui.statusbar.phone.BiometricUnlockController;
Jason Monkaa573e92017-01-27 17:00:29 -0500108import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
Dave Mankoff2aff6c32019-10-14 17:40:37 -0400109import com.android.systemui.statusbar.phone.DozeParameters;
Dave Mankoff1193aa42019-10-28 17:51:26 -0400110import com.android.systemui.statusbar.phone.DozeScrimController;
111import com.android.systemui.statusbar.phone.DozeServiceHost;
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400112import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
113import com.android.systemui.statusbar.phone.KeyguardBypassController;
114import com.android.systemui.statusbar.phone.LightBarController;
Beverlyea2010c2019-11-04 09:55:29 -0500115import com.android.systemui.statusbar.phone.LightsOutNotifController;
Heemin Seog82b96cd2019-11-12 16:40:00 -0800116import com.android.systemui.statusbar.phone.LockscreenLockIconController;
Dave Mankoffa8749962019-10-18 10:44:07 -0400117import com.android.systemui.statusbar.phone.LockscreenWallpaper;
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400118import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
119import com.android.systemui.statusbar.phone.NotificationGroupManager;
Dave Mankoffa8749962019-10-18 10:44:07 -0400120import com.android.systemui.statusbar.phone.ScrimController;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500121import com.android.systemui.statusbar.phone.StatusBar;
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400122import com.android.systemui.statusbar.phone.StatusBarIconController;
Heemin Seog032075c2019-11-06 16:29:12 -0800123import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Dave Mankoff4c73e652019-11-14 17:39:08 -0500124import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400125import com.android.systemui.statusbar.phone.StatusBarWindowController;
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400126import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700127import com.android.systemui.statusbar.policy.BatteryController;
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400128import com.android.systemui.statusbar.policy.ConfigurationController;
Brad Stenning224b5b32018-03-28 21:26:57 -0700129import com.android.systemui.statusbar.policy.DeviceProvisionedController;
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400130import com.android.systemui.statusbar.policy.KeyguardStateController;
131import com.android.systemui.statusbar.policy.NetworkController;
132import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
Aran Ink979c9762019-10-24 16:09:45 -0400133import com.android.systemui.statusbar.policy.RemoteInputUriController;
Jason Monk9c7844c2017-01-18 15:21:53 -0500134import com.android.systemui.statusbar.policy.UserSwitcherController;
Dave Mankoffa30b88b2019-11-05 20:21:38 -0500135import com.android.systemui.volume.VolumeComponent;
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800136
Qiming Shib9dfb922017-04-13 16:23:18 +0800137import java.io.FileDescriptor;
138import java.io.PrintWriter;
139import java.util.Map;
Dave Mankoff613c7c62019-11-04 11:46:36 -0500140import java.util.Optional;
davidln54739152018-07-02 13:25:44 -0700141
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400142import javax.inject.Named;
143
Ned Burnsf098dbf2019-09-13 19:17:53 -0400144import dagger.Lazy;
145
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800146/**
Heemin Seog1a39dea2019-10-16 15:58:21 -0700147 * A status bar tailored for the automotive use case.
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800148 */
Heemin Seog26c830d2019-08-15 13:18:41 -0700149public class CarStatusBar extends StatusBar implements CarBatteryController.BatteryViewHandler {
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800150 private static final String TAG = "CarStatusBar";
Priyank Singhb0241582019-04-19 18:46:26 -0700151 // used to calculate how fast to open or close the window
152 private static final float DEFAULT_FLING_VELOCITY = 0;
153 // max time a fling animation takes
154 private static final float FLING_ANIMATION_MAX_TIME = 0.5f;
155 // acceleration rate for the fling animation
156 private static final float FLING_SPEED_UP_FACTOR = 0.6f;
Heemin Seog82b96cd2019-11-12 16:40:00 -0800157
Dave Mankoffa8749962019-10-18 10:44:07 -0400158 private final ScrimController mScrimController;
Heemin Seog82b96cd2019-11-12 16:40:00 -0800159 private final StatusBarWindowViewController mStatusBarWindowViewController;
160 private final LockscreenLockIconController mLockscreenLockIconController;
Priyank Singhb0241582019-04-19 18:46:26 -0700161
162 private float mOpeningVelocity = DEFAULT_FLING_VELOCITY;
163 private float mClosingVelocity = DEFAULT_FLING_VELOCITY;
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800164
JianYang Liucf7b3362019-10-24 17:19:44 -0700165 private float mBackgroundAlphaDiff;
166 private float mInitialBackgroundAlpha;
167
Heemin Seogeeca9a92019-11-08 16:16:49 -0800168 private final Lazy<FullscreenUserSwitcher> mFullscreenUserSwitcherLazy;
Rakesh Iyer2790a372016-01-22 15:33:39 -0800169 private FullscreenUserSwitcher mFullscreenUserSwitcher;
Victor Chan1c6d0582016-01-09 16:26:37 -0800170
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700171 private CarBatteryController mCarBatteryController;
172 private BatteryMeterView mBatteryMeterView;
Anthony Chene658cc22017-04-27 11:17:35 -0700173 private Drawable mNotificationPanelBackground;
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700174
Qiming Shib9dfb922017-04-13 16:23:18 +0800175 private final Object mQueueLock = new Object();
Heemin Seogfcccab72019-10-22 08:30:23 -0700176 private final CarNavigationBarController mCarNavigationBarController;
Heemin Seogeeca9a92019-11-08 16:16:49 -0800177 private final Lazy<DrivingStateHelper> mDrivingStateHelperLazy;
178 private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy;
179 private final CarServiceProvider mCarServiceProvider;
Heemin Seogd59786b2019-11-08 09:20:26 -0800180
Brad Stenning224b5b32018-03-28 21:26:57 -0700181 private DeviceProvisionedController mDeviceProvisionedController;
Jonathan Koo007ff072019-05-10 09:24:08 -0700182 private PowerManagerHelper mPowerManagerHelper;
183 private FlingAnimationUtils mFlingAnimationUtils;
Jonathan Koo007ff072019-05-10 09:24:08 -0700184 private NotificationDataManager mNotificationDataManager;
185 private NotificationClickHandlerFactory mNotificationClickHandlerFactory;
jovanak622def22019-06-11 11:51:54 -0700186 private ScreenLifecycle mScreenLifecycle;
Brad Stenning078235b2017-12-18 08:25:10 -0800187
Brad Stenning3b0d7642019-03-28 11:04:30 -0700188 // The container for the notifications.
189 private CarNotificationView mNotificationView;
190 private RecyclerView mNotificationList;
Priyank Singh647f9e62019-05-16 15:19:53 -0700191 // The handler bar view at the bottom of notification shade.
192 private View mHandleBar;
Adora Zhangdaea9112019-04-11 17:47:40 -0700193 // The controller for the notification view.
194 private NotificationViewController mNotificationViewController;
Brad Stenning3b0d7642019-03-28 11:04:30 -0700195 // The state of if the notification list is currently showing the bottom.
196 private boolean mNotificationListAtBottom;
197 // Was the notification list at the bottom when the user first touched the screen
198 private boolean mNotificationListAtBottomAtTimeOfTouch;
Heemin Seog956cd512019-10-03 16:15:50 -0700199 // To be attached to the top navigation bar (i.e. status bar) to pull down the notification
200 // panel.
201 private View.OnTouchListener mTopNavBarNotificationTouchListener;
Brad Stenning3b0d7642019-03-28 11:04:30 -0700202 // To be attached to the navigation bars such that they can close the notification panel if
203 // it's open.
204 private View.OnTouchListener mNavBarNotificationTouchListener;
Priyank Singhb0241582019-04-19 18:46:26 -0700205 // Percentage from top of the screen after which the notification shade will open. This value
206 // will be used while opening the notification shade.
207 private int mSettleOpenPercentage;
208 // Percentage from top of the screen below which the notification shade will close. This
209 // value will be used while closing the notification shade.
210 private int mSettleClosePercentage;
211 // Percentage of notification shade open from top of the screen.
212 private int mPercentageFromBottom;
213 // If notification shade is animation to close or to open.
214 private boolean mIsNotificationAnimating;
Priyank Singhb0241582019-04-19 18:46:26 -0700215 // Tracks when the notification shade is being scrolled. This refers to the glass pane being
216 // scrolled not the recycler view.
217 private boolean mIsTracking;
218 private float mFirstTouchDownOnGlassPane;
Priyank Singhb0241582019-04-19 18:46:26 -0700219 // If the notification card inside the recycler view is being swiped.
220 private boolean mIsNotificationCardSwiping;
221 // If notification shade is being swiped vertically to close.
222 private boolean mIsSwipingVerticallyToClose;
Priyank Singh8bd920f2019-06-04 15:21:46 -0700223 // Whether heads-up notifications should be shown when shade is open.
224 private boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400225
Keun young Parkfaae6482019-10-11 20:00:22 -0700226 private CarUxRestrictionManagerWrapper mCarUxRestrictionManagerWrapper;
227
Jonathan Koo007ff072019-05-10 09:24:08 -0700228 private final CarPowerStateListener mCarPowerStateListener =
229 (int state) -> {
230 // When the car powers on, clear all notifications and mute/unread states.
231 Log.d(TAG, "New car power state: " + state);
232 if (state == CarPowerStateListener.ON) {
233 if (mNotificationClickHandlerFactory != null) {
234 mNotificationClickHandlerFactory.clearAllNotifications();
235 }
236 if (mNotificationDataManager != null) {
237 mNotificationDataManager.clearAll();
238 }
239 }
240 };
241
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400242 public CarStatusBar(
Dave Mankoffa5d8a392019-10-10 12:21:09 -0400243 Context context,
Ned Burnsf098dbf2019-09-13 19:17:53 -0400244 FeatureFlags featureFlags,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400245 LightBarController lightBarController,
246 AutoHideController autoHideController,
247 KeyguardUpdateMonitor keyguardUpdateMonitor,
248 StatusBarIconController statusBarIconController,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400249 PulseExpansionHandler pulseExpansionHandler,
250 NotificationWakeUpCoordinator notificationWakeUpCoordinator,
251 KeyguardBypassController keyguardBypassController,
252 KeyguardStateController keyguardStateController,
253 HeadsUpManagerPhone headsUpManagerPhone,
254 DynamicPrivacyController dynamicPrivacyController,
255 BypassHeadsUpNotifier bypassHeadsUpNotifier,
256 @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
Ned Burnsf098dbf2019-09-13 19:17:53 -0400257 Lazy<NewNotifPipeline> newNotifPipeline,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400258 FalsingManager falsingManager,
259 BroadcastDispatcher broadcastDispatcher,
260 RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
261 NotificationGutsManager notificationGutsManager,
262 NotificationLogger notificationLogger,
263 NotificationEntryManager notificationEntryManager,
264 NotificationInterruptionStateProvider notificationInterruptionStateProvider,
265 NotificationViewHierarchyManager notificationViewHierarchyManager,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400266 KeyguardViewMediator keyguardViewMediator,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400267 NotificationAlertingManager notificationAlertingManager,
268 DisplayMetrics displayMetrics,
269 MetricsLogger metricsLogger,
270 UiOffloadThread uiOffloadThread,
271 NotificationMediaManager notificationMediaManager,
272 NotificationLockscreenUserManager lockScreenUserManager,
273 NotificationRemoteInputManager remoteInputManager,
274 UserSwitcherController userSwitcherController,
275 NetworkController networkController,
276 BatteryController batteryController,
277 SysuiColorExtractor colorExtractor,
278 ScreenLifecycle screenLifecycle,
279 WakefulnessLifecycle wakefulnessLifecycle,
280 SysuiStatusBarStateController statusBarStateController,
281 VibratorHelper vibratorHelper,
282 BubbleController bubbleController,
283 NotificationGroupManager groupManager,
284 NotificationGroupAlertTransferHelper groupAlertTransferHelper,
285 VisualStabilityManager visualStabilityManager,
286 DeviceProvisionedController deviceProvisionedController,
287 NavigationBarController navigationBarController,
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500288 Lazy<AssistManager> assistManagerLazy,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400289 NotificationListener notificationListener,
290 ConfigurationController configurationController,
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400291 StatusBarWindowController statusBarWindowController,
Heemin Seog82b96cd2019-11-12 16:40:00 -0800292 StatusBarWindowViewController statusBarWindowViewController,
293 LockscreenLockIconController lockscreenLockIconController,
Dave Mankoffa8749962019-10-18 10:44:07 -0400294 DozeParameters dozeParameters,
295 ScrimController scrimController,
Heemin Seog1a39dea2019-10-16 15:58:21 -0700296 Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
Dave Mankoffbbc2f8f2019-10-21 12:21:29 -0400297 Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
Dave Mankoff1193aa42019-10-28 17:51:26 -0400298 DozeServiceHost dozeServiceHost,
299 PowerManager powerManager,
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500300 ScreenPinningRequest screenPinningRequest,
Dave Mankoff1193aa42019-10-28 17:51:26 -0400301 DozeScrimController dozeScrimController,
Dave Mankoffa30b88b2019-11-05 20:21:38 -0500302 VolumeComponent volumeComponent,
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400303 CommandQueue commandQueue,
Dave Mankoff6c64d1f2019-11-07 17:27:50 -0500304 Optional<Recents> recents,
Dave Mankoff2e484922019-10-31 12:25:08 -0400305 PluginManager pluginManager,
Aran Ink979c9762019-10-24 16:09:45 -0400306 RemoteInputUriController remoteInputUriController,
Dave Mankoff613c7c62019-11-04 11:46:36 -0500307 Optional<Divider> dividerOptional,
Heemin Seogafb3dbc2019-11-04 16:05:19 -0800308 SuperStatusBarViewFactory superStatusBarViewFactory,
Beverlyea2010c2019-11-04 09:55:29 -0500309 LightsOutNotifController lightsOutNotifController,
Dave Mankoff4c73e652019-11-14 17:39:08 -0500310 StatusBarNotificationActivityStarter.Builder
311 statusBarNotificationActivityStarterBuilder,
Heemin Seog032075c2019-11-06 16:29:12 -0800312 StatusBarKeyguardViewManager statusBarKeyguardViewManager,
313 ViewMediatorCallback viewMediatorCallback,
314 DismissCallbackRegistry dismissCallbackRegistry,
Heemin Seog1a39dea2019-10-16 15:58:21 -0700315 /* Car Settings injected components. */
Heemin Seogeeca9a92019-11-08 16:16:49 -0800316 CarServiceProvider carServiceProvider,
317 Lazy<DrivingStateHelper> drivingStateHelperLazy,
318 Lazy<PowerManagerHelper> powerManagerHelperLazy,
319 Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
Heemin Seogfcccab72019-10-22 08:30:23 -0700320 CarNavigationBarController carNavigationBarController) {
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400321 super(
Dave Mankoffa5d8a392019-10-10 12:21:09 -0400322 context,
Ned Burnsf098dbf2019-09-13 19:17:53 -0400323 featureFlags,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400324 lightBarController,
325 autoHideController,
326 keyguardUpdateMonitor,
327 statusBarIconController,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400328 pulseExpansionHandler,
329 notificationWakeUpCoordinator,
330 keyguardBypassController,
331 keyguardStateController,
332 headsUpManagerPhone,
333 dynamicPrivacyController,
334 bypassHeadsUpNotifier,
335 allowNotificationLongPress,
Ned Burnsf098dbf2019-09-13 19:17:53 -0400336 newNotifPipeline,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400337 falsingManager,
338 broadcastDispatcher,
339 remoteInputQuickSettingsDisabler,
340 notificationGutsManager,
341 notificationLogger,
342 notificationEntryManager,
343 notificationInterruptionStateProvider,
344 notificationViewHierarchyManager,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400345 keyguardViewMediator,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400346 notificationAlertingManager,
347 displayMetrics,
348 metricsLogger,
349 uiOffloadThread,
350 notificationMediaManager,
351 lockScreenUserManager,
352 remoteInputManager,
353 userSwitcherController,
354 networkController,
355 batteryController,
356 colorExtractor,
357 screenLifecycle,
358 wakefulnessLifecycle,
359 statusBarStateController,
360 vibratorHelper,
361 bubbleController,
362 groupManager,
363 groupAlertTransferHelper,
364 visualStabilityManager,
365 deviceProvisionedController,
366 navigationBarController,
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500367 assistManagerLazy,
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400368 notificationListener,
369 configurationController,
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400370 statusBarWindowController,
Heemin Seog82b96cd2019-11-12 16:40:00 -0800371 statusBarWindowViewController,
372 lockscreenLockIconController,
Dave Mankoffa8749962019-10-18 10:44:07 -0400373 dozeParameters,
374 scrimController,
Lucas Dupin64171fe2019-10-30 14:28:29 -0700375 null /* keyguardLiftController */,
Dave Mankoffbbc2f8f2019-10-21 12:21:29 -0400376 lockscreenWallpaperLazy,
Dave Mankoff1193aa42019-10-28 17:51:26 -0400377 biometricUnlockControllerLazy,
378 dozeServiceHost,
379 powerManager,
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500380 screenPinningRequest,
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400381 dozeScrimController,
Dave Mankoffa30b88b2019-11-05 20:21:38 -0500382 volumeComponent,
Dave Mankoff2e484922019-10-31 12:25:08 -0400383 commandQueue,
Dave Mankoff6c64d1f2019-11-07 17:27:50 -0500384 recents,
Aran Ink979c9762019-10-24 16:09:45 -0400385 pluginManager,
Heemin Seogafb3dbc2019-11-04 16:05:19 -0800386 remoteInputUriController,
Dave Mankoff613c7c62019-11-04 11:46:36 -0500387 dividerOptional,
Beverlyea2010c2019-11-04 09:55:29 -0500388 lightsOutNotifController,
Dave Mankoff4c73e652019-11-14 17:39:08 -0500389 statusBarNotificationActivityStarterBuilder,
Heemin Seog032075c2019-11-06 16:29:12 -0800390 superStatusBarViewFactory,
391 statusBarKeyguardViewManager,
392 viewMediatorCallback,
393 dismissCallbackRegistry);
Dave Mankoffa8749962019-10-18 10:44:07 -0400394 mScrimController = scrimController;
Heemin Seog82b96cd2019-11-12 16:40:00 -0800395 mStatusBarWindowViewController = statusBarWindowViewController;
396 mLockscreenLockIconController = lockscreenLockIconController;
Heemin Seogd59786b2019-11-08 09:20:26 -0800397 mDeviceProvisionedController = deviceProvisionedController;
Heemin Seogeeca9a92019-11-08 16:16:49 -0800398 mCarServiceProvider = carServiceProvider;
399 mDrivingStateHelperLazy = drivingStateHelperLazy;
400 mPowerManagerHelperLazy = powerManagerHelperLazy;
401 mFullscreenUserSwitcherLazy = fullscreenUserSwitcherLazy;
Heemin Seogfcccab72019-10-22 08:30:23 -0700402 mCarNavigationBarController = carNavigationBarController;
Dave Mankoffbb9575f2019-10-02 12:23:49 -0400403 }
404
Victor Chan1c6d0582016-01-09 16:26:37 -0800405 @Override
406 public void start() {
jovanak4c4971d2019-08-19 16:32:50 -0700407 // Need to initialize screen lifecycle before calling super.start - before switcher is
408 // created.
409 mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
410 mScreenLifecycle.addObserver(mScreenObserver);
411
Heemin Seog82b96cd2019-11-12 16:40:00 -0800412 // Notification bar related setup.
JianYang Liucf7b3362019-10-24 17:19:44 -0700413 mInitialBackgroundAlpha = (float) mContext.getResources().getInteger(
Heemin Seog82b96cd2019-11-12 16:40:00 -0800414 R.integer.config_initialNotificationBackgroundAlpha) / 100;
JianYang Liucf7b3362019-10-24 17:19:44 -0700415 if (mInitialBackgroundAlpha < 0 || mInitialBackgroundAlpha > 100) {
416 throw new RuntimeException(
Heemin Seog82b96cd2019-11-12 16:40:00 -0800417 "Unable to setup notification bar due to incorrect initial background alpha"
418 + " percentage");
JianYang Liucf7b3362019-10-24 17:19:44 -0700419 }
420 float finalBackgroundAlpha = Math.max(
Heemin Seog82b96cd2019-11-12 16:40:00 -0800421 mInitialBackgroundAlpha,
422 (float) mContext.getResources().getInteger(
423 R.integer.config_finalNotificationBackgroundAlpha) / 100);
JianYang Liucf7b3362019-10-24 17:19:44 -0700424 if (finalBackgroundAlpha < 0 || finalBackgroundAlpha > 100) {
425 throw new RuntimeException(
Heemin Seog82b96cd2019-11-12 16:40:00 -0800426 "Unable to setup notification bar due to incorrect final background alpha"
427 + " percentage");
JianYang Liucf7b3362019-10-24 17:19:44 -0700428 }
429 mBackgroundAlphaDiff = finalBackgroundAlpha - mInitialBackgroundAlpha;
430
Victor Chan1c6d0582016-01-09 16:26:37 -0800431 super.start();
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700432
Jason Monke59dc402018-08-16 12:05:01 -0400433 mNotificationPanel.setScrollingEnabled(true);
Priyank Singhb0241582019-04-19 18:46:26 -0700434 mSettleOpenPercentage = mContext.getResources().getInteger(
435 R.integer.notification_settle_open_percentage);
436 mSettleClosePercentage = mContext.getResources().getInteger(
437 R.integer.notification_settle_close_percentage);
Jonathan Koo007ff072019-05-10 09:24:08 -0700438 mFlingAnimationUtils = new FlingAnimationUtils(mContext,
Priyank Singhb0241582019-04-19 18:46:26 -0700439 FLING_ANIMATION_MAX_TIME, FLING_SPEED_UP_FACTOR);
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800440
Rakesh Iyer545e47d2017-01-23 18:10:21 -0800441 createBatteryController();
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700442 mCarBatteryController.startListening();
Brad Stenning38b46f82018-03-27 13:57:29 -0700443
Heemin Seogeeca9a92019-11-08 16:16:49 -0800444 mPowerManagerHelper = mPowerManagerHelperLazy.get();
445 mPowerManagerHelper.setCarPowerStateListener(mCarPowerStateListener);
Jonathan Koo007ff072019-05-10 09:24:08 -0700446 mPowerManagerHelper.connectToCarService();
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700447 }
448
Brad Stenning7e411812018-04-13 22:52:39 -0700449 /**
450 * Allows for showing or hiding just the navigation bars. This is indented to be used when
451 * the full screen user selector is shown.
452 */
davidln54739152018-07-02 13:25:44 -0700453 void setNavBarVisibility(@View.Visibility int visibility) {
Heemin Seog8d6ec6a72019-10-25 14:34:11 -0700454 mCarNavigationBarController.setBottomWindowVisibility(visibility);
455 mCarNavigationBarController.setLeftWindowVisibility(visibility);
456 mCarNavigationBarController.setRightWindowVisibility(visibility);
Brad Stenning7e411812018-04-13 22:52:39 -0700457 }
458
Brad Stenning7e411812018-04-13 22:52:39 -0700459 @Override
460 public boolean hideKeyguard() {
461 boolean result = super.hideKeyguard();
Heemin Seogd59786b2019-11-08 09:20:26 -0800462 mCarNavigationBarController.hideAllKeyguardButtons(
463 mDeviceProvisionedController.isCurrentUserSetup());
Brad Stenning7e411812018-04-13 22:52:39 -0700464 return result;
465 }
466
Brad Stenning7e411812018-04-13 22:52:39 -0700467 @Override
468 public void showKeyguard() {
469 super.showKeyguard();
Heemin Seogd59786b2019-11-08 09:20:26 -0800470 mCarNavigationBarController.showAllKeyguardButtons(
471 mDeviceProvisionedController.isCurrentUserSetup());
Brad Stenning7e411812018-04-13 22:52:39 -0700472 }
Brad Stenning224b5b32018-03-28 21:26:57 -0700473
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700474 @Override
Matthew Ng94380652019-04-08 13:43:07 -0700475 protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
476 super.makeStatusBarView(result);
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700477
Anthony Chene658cc22017-04-27 11:17:35 -0700478 mNotificationPanelBackground = getDefaultWallpaper();
479 mScrimController.setScrimBehindDrawable(mNotificationPanelBackground);
480
Jason Monkaa573e92017-01-27 17:00:29 -0500481 FragmentHostManager manager = FragmentHostManager.get(mStatusBarWindow);
482 manager.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
Anthony Chene658cc22017-04-27 11:17:35 -0700483 mBatteryMeterView = fragment.getView().findViewById(R.id.battery);
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700484
Jason Monkaa573e92017-01-27 17:00:29 -0500485 // By default, the BatteryMeterView should not be visible. It will be toggled
486 // when a device has connected by bluetooth.
487 mBatteryMeterView.setVisibility(View.GONE);
Jason Monkaa573e92017-01-27 17:00:29 -0500488 });
Brad Stenning3b0d7642019-03-28 11:04:30 -0700489
490 connectNotificationsUI();
491 }
492
493 /**
494 * Attach the notification listeners and controllers to the UI as well as build all the
495 * touch listeners needed for opening and closing the notification panel
496 */
497 private void connectNotificationsUI() {
Heemin Seog956cd512019-10-03 16:15:50 -0700498 // Attached to the top navigation bar (i.e. status bar) to detect pull down of the
499 // notification shade.
Brad Stenning3b0d7642019-03-28 11:04:30 -0700500 GestureDetector openGestureDetector = new GestureDetector(mContext,
501 new OpenNotificationGestureListener() {
502 @Override
503 protected void openNotification() {
504 animateExpandNotificationsPanel();
505 }
506 });
507 // Attached to the notification ui to detect close request of the notification shade.
508 GestureDetector closeGestureDetector = new GestureDetector(mContext,
509 new CloseNotificationGestureListener() {
510 @Override
511 protected void close() {
Brad Stenning44d39072019-04-20 11:53:17 -0700512 if (mPanelExpanded) {
513 animateCollapsePanels();
514 }
Brad Stenning3b0d7642019-03-28 11:04:30 -0700515 }
516 });
517 // Attached to the NavBars to close the notification shade
518 GestureDetector navBarCloseNotificationGestureDetector = new GestureDetector(mContext,
519 new NavBarCloseNotificationGestureListener() {
520 @Override
521 protected void close() {
Brad Stenning44d39072019-04-20 11:53:17 -0700522 if (mPanelExpanded) {
523 animateCollapsePanels();
524 }
Brad Stenning3b0d7642019-03-28 11:04:30 -0700525 }
526 });
Priyank Singha47b6f72019-05-28 13:02:47 -0700527
528 // Attached to the Handle bar to close the notification shade
529 GestureDetector handleBarCloseNotificationGestureDetector = new GestureDetector(mContext,
530 new HandleBarCloseNotificationGestureListener());
531
Heemin Seog956cd512019-10-03 16:15:50 -0700532 mTopNavBarNotificationTouchListener = (v, event) -> {
Heemin Seogd59786b2019-11-08 09:20:26 -0800533 if (!mDeviceProvisionedController.isCurrentUserSetup()) {
Heemin Seog956cd512019-10-03 16:15:50 -0700534 return true;
535 }
536 boolean consumed = openGestureDetector.onTouchEvent(event);
537 if (consumed) {
538 return true;
539 }
540 maybeCompleteAnimation(event);
541 return true;
542 };
543
Brad Stenning3b0d7642019-03-28 11:04:30 -0700544 mNavBarNotificationTouchListener =
Priyank Singhb0241582019-04-19 18:46:26 -0700545 (v, event) -> {
546 boolean consumed = navBarCloseNotificationGestureDetector.onTouchEvent(event);
547 if (consumed) {
548 return true;
549 }
Priyank Singha47b6f72019-05-28 13:02:47 -0700550 maybeCompleteAnimation(event);
Priyank Singhb0241582019-04-19 18:46:26 -0700551 return true;
552 };
Brad Stenning3b0d7642019-03-28 11:04:30 -0700553
kwaky15fee3e2019-06-17 11:20:47 -0700554 mNotificationClickHandlerFactory = new NotificationClickHandlerFactory(mBarService);
555 mNotificationClickHandlerFactory.registerClickListener((launchResult, alertEntry) -> {
556 if (launchResult == ActivityManager.START_TASK_TO_FRONT
557 || launchResult == ActivityManager.START_SUCCESS) {
558 animateCollapsePanels();
559 }
560 });
Brad Stenning3b0d7642019-03-28 11:04:30 -0700561 CarNotificationListener carNotificationListener = new CarNotificationListener();
Keun young Parkfaae6482019-10-11 20:00:22 -0700562 mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper();
Jonathan Kooc9f71aa2019-05-06 08:20:14 -0700563
Jonathan Koo007ff072019-05-10 09:24:08 -0700564 mNotificationDataManager = new NotificationDataManager();
Heemin Seogba4cd512019-11-22 08:35:57 -0800565 mNotificationDataManager.setOnUnseenCountUpdateListener(this::onUnseenCountUpdate);
Jonathan Kooc9f71aa2019-05-06 08:20:14 -0700566
Priyank Singh8bd920f2019-06-04 15:21:46 -0700567 mEnableHeadsUpNotificationWhenNotificationShadeOpen = mContext.getResources().getBoolean(
568 R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen);
Brad Stenning2ccc2a42019-04-15 10:17:01 -0700569 CarHeadsUpNotificationManager carHeadsUpNotificationManager =
Jonathan Koo007ff072019-05-10 09:24:08 -0700570 new CarSystemUIHeadsUpNotificationManager(mContext,
571 mNotificationClickHandlerFactory, mNotificationDataManager);
572 mNotificationClickHandlerFactory.setNotificationDataManager(mNotificationDataManager);
Brad Stenning2ccc2a42019-04-15 10:17:01 -0700573
Keun young Parkfaae6482019-10-11 20:00:22 -0700574 carNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper,
Jonathan Koo007ff072019-05-10 09:24:08 -0700575 carHeadsUpNotificationManager, mNotificationDataManager);
Brad Stenning3b0d7642019-03-28 11:04:30 -0700576
577 mNotificationView = mStatusBarWindow.findViewById(R.id.notification_view);
578 View glassPane = mStatusBarWindow.findViewById(R.id.glass_pane);
Priyank Singh647f9e62019-05-16 15:19:53 -0700579 mHandleBar = mStatusBarWindow.findViewById(R.id.handle_bar);
Jonathan Koo007ff072019-05-10 09:24:08 -0700580 mNotificationView.setClickHandlerFactory(mNotificationClickHandlerFactory);
581 mNotificationView.setNotificationDataManager(mNotificationDataManager);
Brad Stenning3b0d7642019-03-28 11:04:30 -0700582
583 // The glass pane is used to view touch events before passed to the notification list.
584 // This allows us to initialize gesture listeners and detect when to close the notifications
585 glassPane.setOnTouchListener((v, event) -> {
586 if (event.getActionMasked() == MotionEvent.ACTION_UP) {
587 mNotificationListAtBottomAtTimeOfTouch = false;
588 }
589 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
Priyank Singhb0241582019-04-19 18:46:26 -0700590 mFirstTouchDownOnGlassPane = event.getRawX();
Brad Stenning3b0d7642019-03-28 11:04:30 -0700591 mNotificationListAtBottomAtTimeOfTouch = mNotificationListAtBottom;
Priyank Singhb0241582019-04-19 18:46:26 -0700592 // Reset the tracker when there is a touch down on the glass pane.
593 mIsTracking = false;
Brad Stenning3b0d7642019-03-28 11:04:30 -0700594 // Pass the down event to gesture detector so that it knows where the touch event
595 // started.
596 closeGestureDetector.onTouchEvent(event);
597 }
598 return false;
599 });
Priyank Singha47b6f72019-05-28 13:02:47 -0700600
601 mHandleBar.setOnTouchListener((v, event) -> {
602 handleBarCloseNotificationGestureDetector.onTouchEvent(event);
603 maybeCompleteAnimation(event);
604 return true;
605 });
606
Brad Stenning3b0d7642019-03-28 11:04:30 -0700607 mNotificationList = mNotificationView.findViewById(R.id.notifications);
608 mNotificationList.addOnScrollListener(new RecyclerView.OnScrollListener() {
609 @Override
610 public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
611 super.onScrolled(recyclerView, dx, dy);
612 if (!mNotificationList.canScrollVertically(1)) {
613 mNotificationListAtBottom = true;
614 return;
615 }
616 mNotificationListAtBottom = false;
Priyank Singhb0241582019-04-19 18:46:26 -0700617 mIsSwipingVerticallyToClose = false;
Brad Stenning3b0d7642019-03-28 11:04:30 -0700618 mNotificationListAtBottomAtTimeOfTouch = false;
619 }
620 });
621 mNotificationList.setOnTouchListener(new View.OnTouchListener() {
622 @Override
623 public boolean onTouch(View v, MotionEvent event) {
Priyank Singhb0241582019-04-19 18:46:26 -0700624 mIsNotificationCardSwiping = Math.abs(mFirstTouchDownOnGlassPane - event.getRawX())
625 > SWIPE_MAX_OFF_PATH;
626 if (mNotificationListAtBottomAtTimeOfTouch && mNotificationListAtBottom) {
627 // We need to save the state here as if notification card is swiping we will
628 // change the mNotificationListAtBottomAtTimeOfTouch. This is to protect
629 // closing the notification shade while the notification card is being swiped.
630 mIsSwipingVerticallyToClose = true;
631 }
632
633 // If the card is swiping we should not allow the notification shade to close.
634 // Hence setting mNotificationListAtBottomAtTimeOfTouch to false will stop that
635 // for us. We are also checking for mIsTracking because while swiping the
636 // notification shade to close if the user goes a bit horizontal while swiping
637 // upwards then also this should close.
638 if (mIsNotificationCardSwiping && !mIsTracking) {
639 mNotificationListAtBottomAtTimeOfTouch = false;
640 }
641
Priyank Singhbae09ae2019-04-25 18:17:02 -0700642 boolean handled = closeGestureDetector.onTouchEvent(event);
Priyank Singhb0241582019-04-19 18:46:26 -0700643 boolean isTracking = mIsTracking;
Priyank Singh647f9e62019-05-16 15:19:53 -0700644 Rect rect = mNotificationView.getClipBounds();
Priyank Singhf3912862019-04-22 10:41:58 -0700645 float clippedHeight = 0;
646 if (rect != null) {
647 clippedHeight = rect.bottom;
648 }
Priyank Singhb0241582019-04-19 18:46:26 -0700649 if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP
650 && mIsSwipingVerticallyToClose) {
651 if (mSettleClosePercentage < mPercentageFromBottom && isTracking) {
652 animateNotificationPanel(DEFAULT_FLING_VELOCITY, false);
653 } else if (clippedHeight != mNotificationView.getHeight() && isTracking) {
654 // this can be caused when user is at the end of the list and trying to
655 // fling to top of the list by scrolling down.
656 animateNotificationPanel(DEFAULT_FLING_VELOCITY, true);
657 }
658 }
659
Brad Stenning3b0d7642019-03-28 11:04:30 -0700660 // Updating the mNotificationListAtBottomAtTimeOfTouch state has to be done after
661 // the event has been passed to the closeGestureDetector above, such that the
662 // closeGestureDetector sees the up event before the state has changed.
663 if (event.getActionMasked() == MotionEvent.ACTION_UP) {
664 mNotificationListAtBottomAtTimeOfTouch = false;
665 }
Priyank Singhb0241582019-04-19 18:46:26 -0700666 return handled || isTracking;
Brad Stenning3b0d7642019-03-28 11:04:30 -0700667 }
668 });
JianYang Liu1d429ee2019-11-15 13:20:35 -0800669 mCarServiceProvider.addListener(car -> {
670 CarUxRestrictionsManager carUxRestrictionsManager =
671 (CarUxRestrictionsManager)
672 car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
673 mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager(
674 carUxRestrictionsManager);
Brad Stenning3b0d7642019-03-28 11:04:30 -0700675
JianYang Liu1d429ee2019-11-15 13:20:35 -0800676 mNotificationViewController = new NotificationViewController(
677 mNotificationView,
678 PreprocessingManager.getInstance(mContext),
679 carNotificationListener,
680 mCarUxRestrictionManagerWrapper,
681 mNotificationDataManager);
682 mNotificationViewController.enable();
683 });
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700684 }
685
Brad Stenning44d39072019-04-20 11:53:17 -0700686 /**
Heemin Seogba4cd512019-11-22 08:35:57 -0800687 * This method is called whenever there is an update to the number of unseen notifications.
688 * This method can be extended by OEMs to customize the desired logic.
689 */
690 protected void onUnseenCountUpdate() {
691 if (mNotificationDataManager != null) {
692 boolean hasUnseen = mNotificationDataManager.getUnseenNotificationCount() > 0;
693 mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(
694 mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen);
695 }
696 }
697
698 /**
Brad Stenning44d39072019-04-20 11:53:17 -0700699 * @return true if the notification panel is currently visible
700 */
701 boolean isNotificationPanelOpen() {
702 return mPanelExpanded;
703 }
704
Brad Stenning8d1a51c2018-11-20 17:34:16 -0800705 @Override
Brad Stenning3b0d7642019-03-28 11:04:30 -0700706 public void animateExpandNotificationsPanel() {
707 if (!mCommandQueue.panelsEnabled() || !mUserSetup) {
708 return;
709 }
710 // scroll to top
711 mNotificationList.scrollToPosition(0);
712 mStatusBarWindowController.setPanelVisible(true);
713 mNotificationView.setVisibility(View.VISIBLE);
Priyank Singhb0241582019-04-19 18:46:26 -0700714 animateNotificationPanel(mOpeningVelocity, false);
715
Brad Stenning3b0d7642019-03-28 11:04:30 -0700716 setPanelExpanded(true);
717 }
718
719 @Override
720 public void animateCollapsePanels(int flags, boolean force, boolean delayed,
721 float speedUpFactor) {
722 super.animateCollapsePanels(flags, force, delayed, speedUpFactor);
723 if (!mPanelExpanded || mNotificationView.getVisibility() == View.INVISIBLE) {
724 return;
725 }
726 mStatusBarWindowController.setStatusBarFocusable(false);
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400727 mStatusBarWindowViewController.cancelExpandHelper();
Brad Stenning3b0d7642019-03-28 11:04:30 -0700728 mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
Priyank Singhb0241582019-04-19 18:46:26 -0700729
730 animateNotificationPanel(mClosingVelocity, true);
731
732 if (!mIsTracking) {
733 mStatusBarWindowController.setPanelVisible(false);
734 mNotificationView.setVisibility(View.INVISIBLE);
735 }
736
Brad Stenning3b0d7642019-03-28 11:04:30 -0700737 setPanelExpanded(false);
738 }
739
Priyank Singha47b6f72019-05-28 13:02:47 -0700740 private void maybeCompleteAnimation(MotionEvent event) {
741 if (event.getActionMasked() == MotionEvent.ACTION_UP
742 && mNotificationView.getVisibility() == View.VISIBLE) {
743 if (mSettleClosePercentage < mPercentageFromBottom) {
744 animateNotificationPanel(DEFAULT_FLING_VELOCITY, false);
745 } else {
746 animateNotificationPanel(DEFAULT_FLING_VELOCITY, true);
747 }
748 }
749 }
750
Priyank Singhb0241582019-04-19 18:46:26 -0700751 /**
752 * Animates the notification shade from one position to other. This is used to either open or
Priyank Singh245bd122019-04-21 15:42:44 -0700753 * close the notification shade completely with a velocity. If the animation is to close the
Priyank Singhb0241582019-04-19 18:46:26 -0700754 * notification shade this method also makes the view invisible after animation ends.
755 */
756 private void animateNotificationPanel(float velocity, boolean isClosing) {
Priyank Singhb0241582019-04-19 18:46:26 -0700757 float to = 0;
758 if (!isClosing) {
759 to = mNotificationView.getHeight();
760 }
Priyank Singhb9ab0522019-05-03 15:36:25 -0700761
Priyank Singh647f9e62019-05-16 15:19:53 -0700762 Rect rect = mNotificationView.getClipBounds();
Priyank Singha0aa2972019-06-26 18:21:44 -0700763 if (rect != null && rect.bottom != to) {
Priyank Singhb9ab0522019-05-03 15:36:25 -0700764 float from = rect.bottom;
765 animate(from, to, velocity, isClosing);
766 return;
767 }
768
Priyank Singha0aa2972019-06-26 18:21:44 -0700769 // We will only be here if the shade is being opened programmatically or via button when
770 // height of the layout was not calculated.
Priyank Singhb9ab0522019-05-03 15:36:25 -0700771 ViewTreeObserver notificationTreeObserver = mNotificationView.getViewTreeObserver();
772 notificationTreeObserver.addOnGlobalLayoutListener(
773 new ViewTreeObserver.OnGlobalLayoutListener() {
774 @Override
775 public void onGlobalLayout() {
776 ViewTreeObserver obs = mNotificationView.getViewTreeObserver();
777 obs.removeOnGlobalLayoutListener(this);
778 float to = mNotificationView.getHeight();
779 animate(/* from= */ 0, to, velocity, isClosing);
780 }
781 });
782 }
783
784 private void animate(float from, float to, float velocity, boolean isClosing) {
Priyank Singhb0241582019-04-19 18:46:26 -0700785 if (mIsNotificationAnimating) {
786 return;
787 }
788 mIsNotificationAnimating = true;
789 mIsTracking = true;
790 ValueAnimator animator = ValueAnimator.ofFloat(from, to);
791 animator.addUpdateListener(
792 animation -> {
793 float animatedValue = (Float) animation.getAnimatedValue();
794 setNotificationViewClipBounds((int) animatedValue);
795 });
796 animator.addListener(new AnimatorListenerAdapter() {
797 @Override
798 public void onAnimationEnd(Animator animation) {
799 super.onAnimationEnd(animation);
800 mIsNotificationAnimating = false;
801 mIsTracking = false;
802 mOpeningVelocity = DEFAULT_FLING_VELOCITY;
803 mClosingVelocity = DEFAULT_FLING_VELOCITY;
804 if (isClosing) {
805 mStatusBarWindowController.setPanelVisible(false);
806 mNotificationView.setVisibility(View.INVISIBLE);
Priyank Singh647f9e62019-05-16 15:19:53 -0700807 mNotificationView.setClipBounds(null);
Danny Epsteind0af9d02019-06-19 13:48:51 -0700808 mNotificationViewController.onVisibilityChanged(false);
Priyank Singhb0241582019-04-19 18:46:26 -0700809 // let the status bar know that the panel is closed
810 setPanelExpanded(false);
811 } else {
Danny Epsteind0af9d02019-06-19 13:48:51 -0700812 mNotificationViewController.onVisibilityChanged(true);
Priyank Singhb0241582019-04-19 18:46:26 -0700813 // let the status bar know that the panel is open
Jonathan Kooc9f71aa2019-05-06 08:20:14 -0700814 mNotificationView.setVisibleNotificationsAsSeen();
Priyank Singhb0241582019-04-19 18:46:26 -0700815 setPanelExpanded(true);
816 }
817 }
818 });
Jonathan Koo007ff072019-05-10 09:24:08 -0700819 mFlingAnimationUtils.apply(animator, from, to, Math.abs(velocity));
Priyank Singhb0241582019-04-19 18:46:26 -0700820 animator.start();
821 }
Brad Stenning3b0d7642019-03-28 11:04:30 -0700822
823 @Override
Brad Stenning8d1a51c2018-11-20 17:34:16 -0800824 protected QS createDefaultQSFragment() {
825 return new CarQSFragment();
826 }
827
Rakesh Iyer545e47d2017-01-23 18:10:21 -0800828 private BatteryController createBatteryController() {
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700829 mCarBatteryController = new CarBatteryController(mContext);
830 mCarBatteryController.addBatteryViewHandler(this);
831 return mCarBatteryController;
Victor Chan1c6d0582016-01-09 16:26:37 -0800832 }
833
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800834 @Override
Matthew Ng94380652019-04-08 13:43:07 -0700835 protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
Heemin Seogd59786b2019-11-08 09:20:26 -0800836 registerNavBarListeners();
Brad Stenning224b5b32018-03-28 21:26:57 -0700837 }
838
Heemin Seogd59786b2019-11-08 09:20:26 -0800839 private void registerNavBarListeners() {
840 // In CarStatusBar, navigation bars are built by NavigationBar.java
841 // Instead, we register necessary callbacks to the navigation bar controller.
842 mCarNavigationBarController.registerTopBarTouchListener(
843 mTopNavBarNotificationTouchListener);
Heemin Seog956cd512019-10-03 16:15:50 -0700844
Heemin Seogfcccab72019-10-22 08:30:23 -0700845 mCarNavigationBarController.registerBottomBarTouchListener(
846 mNavBarNotificationTouchListener);
Brad Stenning224b5b32018-03-28 21:26:57 -0700847
Heemin Seogfcccab72019-10-22 08:30:23 -0700848 mCarNavigationBarController.registerLeftBarTouchListener(
849 mNavBarNotificationTouchListener);
Brad Stenning224b5b32018-03-28 21:26:57 -0700850
Heemin Seogfcccab72019-10-22 08:30:23 -0700851 mCarNavigationBarController.registerRightBarTouchListener(
852 mNavBarNotificationTouchListener);
853
854 mCarNavigationBarController.registerNotificationController(() -> togglePanel());
Brad Stenning224b5b32018-03-28 21:26:57 -0700855 }
856
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800857 @Override
Qiming Shib9dfb922017-04-13 16:23:18 +0800858 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Priyank Singhb0241582019-04-19 18:46:26 -0700859 //When executing dump() function simultaneously, we need to serialize them
Qiming Shib9dfb922017-04-13 16:23:18 +0800860 //to get mStackScroller's position correctly.
861 synchronized (mQueueLock) {
862 pw.println(" mStackScroller: " + viewInfo(mStackScroller));
863 pw.println(" mStackScroller: " + viewInfo(mStackScroller)
864 + " scroll " + mStackScroller.getScrollX()
865 + "," + mStackScroller.getScrollY());
866 }
867
davidln54739152018-07-02 13:25:44 -0700868 pw.print(" mFullscreenUserSwitcher=");
869 pw.println(mFullscreenUserSwitcher);
Qiming Shib9dfb922017-04-13 16:23:18 +0800870 pw.print(" mCarBatteryController=");
871 pw.println(mCarBatteryController);
872 pw.print(" mBatteryMeterView=");
873 pw.println(mBatteryMeterView);
Qiming Shib9dfb922017-04-13 16:23:18 +0800874
Dave Mankoffe2294692019-08-14 11:53:13 -0400875 if (Dependency.get(KeyguardUpdateMonitor.class) != null) {
876 Dependency.get(KeyguardUpdateMonitor.class).dump(fd, pw, args);
Qiming Shib9dfb922017-04-13 16:23:18 +0800877 }
878
Dave Mankoffc195ea82019-06-28 16:33:25 -0400879 Dependency.get(FalsingManager.class).dump(pw);
Qiming Shib9dfb922017-04-13 16:23:18 +0800880 FalsingLog.dump(pw);
881
882 pw.println("SharedPreferences:");
883 for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
davidln54739152018-07-02 13:25:44 -0700884 pw.print(" ");
885 pw.print(entry.getKey());
886 pw.print("=");
887 pw.println(entry.getValue());
Qiming Shib9dfb922017-04-13 16:23:18 +0800888 }
889 }
890
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800891 @Override
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700892 public void showBatteryView() {
893 if (Log.isLoggable(TAG, Log.DEBUG)) {
894 Log.d(TAG, "showBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
895 }
896
897 if (mBatteryMeterView != null) {
898 mBatteryMeterView.setVisibility(View.VISIBLE);
899 }
900 }
901
902 @Override
903 public void hideBatteryView() {
904 if (Log.isLoggable(TAG, Log.DEBUG)) {
905 Log.d(TAG, "hideBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
906 }
907
908 if (mBatteryMeterView != null) {
909 mBatteryMeterView.setVisibility(View.GONE);
910 }
911 }
912
Rakesh Iyer2790a372016-01-22 15:33:39 -0800913 @Override
914 protected void createUserSwitcher() {
Jason Monk9c7844c2017-01-18 15:21:53 -0500915 UserSwitcherController userSwitcherController =
916 Dependency.get(UserSwitcherController.class);
917 if (userSwitcherController.useFullscreenUserSwitcher()) {
Heemin Seogeeca9a92019-11-08 16:16:49 -0800918 mFullscreenUserSwitcher = mFullscreenUserSwitcherLazy.get();
919 mFullscreenUserSwitcher.setStatusBar(this);
920 mFullscreenUserSwitcher.setContainer(
921 mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
Rakesh Iyer2790a372016-01-22 15:33:39 -0800922 } else {
923 super.createUserSwitcher();
924 }
925 }
926
927 @Override
jovanak168dbdb2019-02-18 01:00:43 -0800928 public void setLockscreenUser(int newUserId) {
929 super.setLockscreenUser(newUserId);
930 // Try to dismiss the keyguard after every user switch.
931 dismissKeyguardWhenUserSwitcherNotDisplayed();
932 }
933
934 @Override
Jason Monk1fd3fc32018-08-14 17:20:09 -0400935 public void onStateChanged(int newState) {
936 super.onStateChanged(newState);
jovanakedba98c2018-09-14 15:46:24 -0700937
jovanak168dbdb2019-02-18 01:00:43 -0800938 if (newState != StatusBarState.FULLSCREEN_USER_SWITCHER) {
939 hideUserSwitcher();
jovanak604ad512018-08-14 18:41:27 -0700940 } else {
jovanak168dbdb2019-02-18 01:00:43 -0800941 dismissKeyguardWhenUserSwitcherNotDisplayed();
942 }
943 }
944
945 /** Makes the full screen user switcher visible, if applicable. */
946 public void showUserSwitcher() {
947 if (mFullscreenUserSwitcher != null && mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
948 mFullscreenUserSwitcher.show(); // Makes the switcher visible.
949 }
950 }
951
952 private void hideUserSwitcher() {
953 if (mFullscreenUserSwitcher != null) {
jovanak604ad512018-08-14 18:41:27 -0700954 mFullscreenUserSwitcher.hide();
Aarthi Balachander0a427ef2018-07-13 15:00:58 -0700955 }
956 }
957
jovanak622def22019-06-11 11:51:54 -0700958 final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
959 @Override
960 public void onScreenTurnedOn() {
961 dismissKeyguardWhenUserSwitcherNotDisplayed();
962 }
963 };
964
jovanak168dbdb2019-02-18 01:00:43 -0800965 // We automatically dismiss keyguard unless user switcher is being shown on the keyguard.
966 private void dismissKeyguardWhenUserSwitcherNotDisplayed() {
967 if (mFullscreenUserSwitcher == null) {
968 return; // Not using the full screen user switcher.
969 }
970
971 if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER
972 && !mFullscreenUserSwitcher.isVisible()) {
973 // Current execution path continues to set state after this, thus we deffer the
974 // dismissal to the next execution cycle.
975 postDismissKeyguard(); // Dismiss the keyguard if switcher is not visible.
Rakesh Iyer2790a372016-01-22 15:33:39 -0800976 }
977 }
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800978
jovanak604ad512018-08-14 18:41:27 -0700979 public void postDismissKeyguard() {
980 mHandler.post(this::dismissKeyguard);
981 }
982
983 /**
984 * Dismisses the keyguard and shows bouncer if authentication is necessary.
985 */
986 public void dismissKeyguard() {
jovanak622def22019-06-11 11:51:54 -0700987 // Don't dismiss keyguard when the screen is off.
988 if (mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF) {
989 return;
990 }
jovanak604ad512018-08-14 18:41:27 -0700991 executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */,
Brad Stenning8d1a51c2018-11-20 17:34:16 -0800992 true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
jovanak604ad512018-08-14 18:41:27 -0700993 }
994
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800995 /**
996 * Ensures that relevant child views are appropriately recreated when the device's density
997 * changes.
998 */
999 @Override
Jason Monk9cac5ff2017-06-02 11:35:50 -04001000 public void onDensityOrFontScaleChanged() {
Anthony Chen3cb3ad92016-12-01 10:58:47 -08001001 super.onDensityOrFontScaleChanged();
Heemin Seogd59786b2019-11-08 09:20:26 -08001002 registerNavBarListeners();
Anthony Chene658cc22017-04-27 11:17:35 -07001003 // Need to update the background on density changed in case the change was due to night
1004 // mode.
1005 mNotificationPanelBackground = getDefaultWallpaper();
1006 mScrimController.setScrimBehindDrawable(mNotificationPanelBackground);
1007 }
1008
1009 /**
1010 * Returns the {@link Drawable} that represents the wallpaper that the user has currently set.
1011 */
1012 private Drawable getDefaultWallpaper() {
1013 return mContext.getDrawable(com.android.internal.R.drawable.default_wallpaper);
Anthony Chen3cb3ad92016-12-01 10:58:47 -08001014 }
Brad Stenning19f236a2018-12-11 14:12:30 -08001015
Priyank Singhb0241582019-04-19 18:46:26 -07001016 private void setNotificationViewClipBounds(int height) {
Priyank Singhea4af132019-05-01 17:57:06 -07001017 if (height > mNotificationView.getHeight()) {
1018 height = mNotificationView.getHeight();
1019 }
Priyank Singhb0241582019-04-19 18:46:26 -07001020 Rect clipBounds = new Rect();
1021 clipBounds.set(0, 0, mNotificationView.getWidth(), height);
Priyank Singh245bd122019-04-21 15:42:44 -07001022 // Sets the clip region on the notification list view.
Priyank Singh647f9e62019-05-16 15:19:53 -07001023 mNotificationView.setClipBounds(clipBounds);
1024 if (mHandleBar != null) {
1025 ViewGroup.MarginLayoutParams lp =
1026 (ViewGroup.MarginLayoutParams) mHandleBar.getLayoutParams();
1027 mHandleBar.setTranslationY(height - mHandleBar.getHeight() - lp.bottomMargin);
1028 }
Priyank Singh245bd122019-04-21 15:42:44 -07001029 if (mNotificationView.getHeight() > 0) {
Brad Stenning0b7e45e2019-07-16 16:46:28 -07001030 Drawable background = mNotificationView.getBackground().mutate();
JianYang Liucf7b3362019-10-24 17:19:44 -07001031 background.setAlpha((int) (getBackgroundAlpha(height) * 255));
Brad Stenning0b7e45e2019-07-16 16:46:28 -07001032 mNotificationView.setBackground(background);
Priyank Singh245bd122019-04-21 15:42:44 -07001033 }
Priyank Singhb0241582019-04-19 18:46:26 -07001034 }
Brad Stenning3b0d7642019-03-28 11:04:30 -07001035
JianYang Liucf7b3362019-10-24 17:19:44 -07001036 /**
1037 * Calculates the alpha value for the background based on how much of the notification
1038 * shade is visible to the user. When the notification shade is completely open then
1039 * alpha value will be 1.
1040 */
1041 private float getBackgroundAlpha(int height) {
1042 return mInitialBackgroundAlpha +
1043 ((float) height / mNotificationView.getHeight() * mBackgroundAlphaDiff);
1044 }
1045
Priyank Singh956c4822019-07-10 12:28:24 -07001046 @Override
1047 public void onConfigChanged(Configuration newConfig) {
1048 super.onConfigChanged(newConfig);
1049
1050 int uiModeNightMask = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
1051
1052 boolean dayNightModeChanged = uiModeNightMask == Configuration.UI_MODE_NIGHT_YES
1053 || uiModeNightMask == Configuration.UI_MODE_NIGHT_NO;
1054
1055 if (dayNightModeChanged) {
1056 mNotificationView.setBackgroundColor(
1057 mContext.getColor(R.color.notification_shade_background_color));
1058 }
1059 }
1060
Priyank Singhb0241582019-04-19 18:46:26 -07001061 private void calculatePercentageFromBottom(float height) {
1062 if (mNotificationView.getHeight() > 0) {
1063 mPercentageFromBottom = (int) Math.abs(
1064 height / mNotificationView.getHeight() * 100);
1065 }
1066 }
1067
Brad Stenning3b0d7642019-03-28 11:04:30 -07001068 private static final int SWIPE_DOWN_MIN_DISTANCE = 25;
1069 private static final int SWIPE_MAX_OFF_PATH = 75;
1070 private static final int SWIPE_THRESHOLD_VELOCITY = 200;
Priyank Singhb0241582019-04-19 18:46:26 -07001071
Priyank Singha47b6f72019-05-28 13:02:47 -07001072 /**
1073 * Only responsible for open hooks. Since once the panel opens it covers all elements
1074 * there is no need to merge with close.
1075 */
Brad Stenning3b0d7642019-03-28 11:04:30 -07001076 private abstract class OpenNotificationGestureListener extends
1077 GestureDetector.SimpleOnGestureListener {
1078
1079 @Override
Priyank Singhb0241582019-04-19 18:46:26 -07001080 public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
1081 float distanceY) {
1082
1083 if (mNotificationView.getVisibility() == View.INVISIBLE) {
1084 // when the on-scroll is called for the first time to open.
1085 mNotificationList.scrollToPosition(0);
1086 }
1087 mStatusBarWindowController.setPanelVisible(true);
1088 mNotificationView.setVisibility(View.VISIBLE);
1089
1090 // clips the view for the notification shade when the user scrolls to open.
1091 setNotificationViewClipBounds((int) event2.getRawY());
1092
1093 // Initially the scroll starts with height being zero. This checks protects from divide
1094 // by zero error.
1095 calculatePercentageFromBottom(event2.getRawY());
1096
1097 mIsTracking = true;
1098 return true;
1099 }
1100
1101
1102 @Override
Brad Stenning3b0d7642019-03-28 11:04:30 -07001103 public boolean onFling(MotionEvent event1, MotionEvent event2,
1104 float velocityX, float velocityY) {
Priyank Singhb0241582019-04-19 18:46:26 -07001105 if (velocityY > SWIPE_THRESHOLD_VELOCITY) {
1106 mOpeningVelocity = velocityY;
Brad Stenning3b0d7642019-03-28 11:04:30 -07001107 openNotification();
1108 return true;
1109 }
Priyank Singhb0241582019-04-19 18:46:26 -07001110 animateNotificationPanel(DEFAULT_FLING_VELOCITY, true);
Brad Stenning3b0d7642019-03-28 11:04:30 -07001111
1112 return false;
1113 }
Priyank Singhb0241582019-04-19 18:46:26 -07001114
Brad Stenning3b0d7642019-03-28 11:04:30 -07001115 protected abstract void openNotification();
Brad Stenning19f236a2018-12-11 14:12:30 -08001116 }
1117
Priyank Singha47b6f72019-05-28 13:02:47 -07001118 /**
1119 * To be installed on the open panel notification panel
1120 */
Brad Stenning3b0d7642019-03-28 11:04:30 -07001121 private abstract class CloseNotificationGestureListener extends
1122 GestureDetector.SimpleOnGestureListener {
1123
1124 @Override
Priyank Singhbae09ae2019-04-25 18:17:02 -07001125 public boolean onSingleTapUp(MotionEvent motionEvent) {
Priyank Singhb9ab0522019-05-03 15:36:25 -07001126 if (mPanelExpanded) {
1127 animateNotificationPanel(DEFAULT_FLING_VELOCITY, true);
1128 }
1129 return true;
Priyank Singhbae09ae2019-04-25 18:17:02 -07001130 }
1131
1132 @Override
Priyank Singhb0241582019-04-19 18:46:26 -07001133 public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
1134 float distanceY) {
Priyank Singhbae09ae2019-04-25 18:17:02 -07001135 // should not clip while scroll to the bottom of the list.
Priyank Singhb0241582019-04-19 18:46:26 -07001136 if (!mNotificationListAtBottomAtTimeOfTouch) {
1137 return false;
1138 }
1139 float actualNotificationHeight =
1140 mNotificationView.getHeight() - (event1.getRawY() - event2.getRawY());
1141 if (actualNotificationHeight > mNotificationView.getHeight()) {
1142 actualNotificationHeight = mNotificationView.getHeight();
1143 }
1144 if (mNotificationView.getHeight() > 0) {
1145 mPercentageFromBottom = (int) Math.abs(
1146 actualNotificationHeight / mNotificationView.getHeight() * 100);
1147 boolean isUp = distanceY > 0;
1148
1149 // This check is to figure out if onScroll was called while swiping the card at
1150 // bottom of the list. At that time we should not allow notification shade to
1151 // close. We are also checking for the upwards swipe gesture here because it is
1152 // possible if a user is closing the notification shade and while swiping starts
1153 // to open again but does not fling. At that time we should allow the
1154 // notification shade to close fully or else it would stuck in between.
1155 if (Math.abs(mNotificationView.getHeight() - actualNotificationHeight)
1156 > SWIPE_DOWN_MIN_DISTANCE && isUp) {
1157 setNotificationViewClipBounds((int) actualNotificationHeight);
1158 mIsTracking = true;
1159 } else if (!isUp) {
1160 setNotificationViewClipBounds((int) actualNotificationHeight);
1161 }
1162 }
1163 // if we return true the the items in RV won't be scrollable.
1164 return false;
1165 }
1166
1167
1168 @Override
Brad Stenning3b0d7642019-03-28 11:04:30 -07001169 public boolean onFling(MotionEvent event1, MotionEvent event2,
1170 float velocityX, float velocityY) {
Priyank Singha01f2432019-05-17 16:33:57 -07001171 // should not fling if the touch does not start when view is at the bottom of the list.
1172 if (!mNotificationListAtBottomAtTimeOfTouch) {
Priyank Singhbae09ae2019-04-25 18:17:02 -07001173 return false;
1174 }
Brad Stenning3b0d7642019-03-28 11:04:30 -07001175 if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
1176 || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
1177 // swipe was not vertical or was not fast enough
1178 return false;
1179 }
1180 boolean isUp = velocityY < 0;
Priyank Singhb0241582019-04-19 18:46:26 -07001181 if (isUp) {
Brad Stenning3b0d7642019-03-28 11:04:30 -07001182 close();
1183 return true;
Priyank Singhb0241582019-04-19 18:46:26 -07001184 } else {
1185 // we should close the shade
1186 animateNotificationPanel(velocityY, false);
Brad Stenning3b0d7642019-03-28 11:04:30 -07001187 }
1188 return false;
1189 }
Priyank Singhb0241582019-04-19 18:46:26 -07001190
Brad Stenning3b0d7642019-03-28 11:04:30 -07001191 protected abstract void close();
1192 }
1193
Priyank Singha47b6f72019-05-28 13:02:47 -07001194 /**
1195 * To be installed on the nav bars.
1196 */
Brad Stenning3b0d7642019-03-28 11:04:30 -07001197 private abstract class NavBarCloseNotificationGestureListener extends
1198 CloseNotificationGestureListener {
1199 @Override
1200 public boolean onSingleTapUp(MotionEvent e) {
Priyank Singhb0241582019-04-19 18:46:26 -07001201 mClosingVelocity = DEFAULT_FLING_VELOCITY;
Priyank Singhb9ab0522019-05-03 15:36:25 -07001202 if (mPanelExpanded) {
1203 close();
1204 }
Brad Stenning3b0d7642019-03-28 11:04:30 -07001205 return super.onSingleTapUp(e);
1206 }
1207
1208 @Override
Priyank Singhb0241582019-04-19 18:46:26 -07001209 public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
1210 float distanceY) {
1211 calculatePercentageFromBottom(event2.getRawY());
1212 setNotificationViewClipBounds((int) event2.getRawY());
1213 return true;
1214 }
Adora Zhang0237b9c2019-03-08 12:27:09 -08001215 }
Brad Stenning2ccc2a42019-04-15 10:17:01 -07001216
1217 /**
Priyank Singha47b6f72019-05-28 13:02:47 -07001218 * To be installed on the handle bar.
1219 */
1220 private class HandleBarCloseNotificationGestureListener extends
1221 GestureDetector.SimpleOnGestureListener {
1222
1223 @Override
1224 public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
1225 float distanceY) {
1226 calculatePercentageFromBottom(event2.getRawY());
1227 // To prevent the jump in the clip bounds while closing the notification shade using
1228 // the handle bar we should calculate the height using the diff of event1 and event2.
1229 // This will help the notification shade to clip smoothly as the event2 value changes
1230 // as event1 value will be fixed.
1231 int clipHeight =
1232 mNotificationView.getHeight() - (int) (event1.getRawY() - event2.getRawY());
1233 setNotificationViewClipBounds(clipHeight);
1234 return true;
1235 }
1236 }
1237
1238 /**
1239 * SystemUi version of the notification manager that overrides methods such that the
Brad Stenning2ccc2a42019-04-15 10:17:01 -07001240 * notifications end up in the status bar layouts instead of a standalone window.
1241 */
1242 private class CarSystemUIHeadsUpNotificationManager extends CarHeadsUpNotificationManager {
1243
1244 CarSystemUIHeadsUpNotificationManager(Context context,
1245 NotificationClickHandlerFactory clickHandlerFactory,
1246 NotificationDataManager notificationDataManager) {
1247 super(context, clickHandlerFactory, notificationDataManager);
1248 }
1249
1250 @Override
1251 protected View createHeadsUpPanel() {
1252 // In SystemUi the view is already in the window so just return a reference.
1253 return mStatusBarWindow.findViewById(R.id.notification_headsup);
1254 }
1255
1256 @Override
1257 protected void addHeadsUpPanelToDisplay() {
1258 // Set the panel initial state to invisible
1259 mHeadsUpPanel.setVisibility(View.INVISIBLE);
1260 }
1261
1262 @Override
Priyank Singh8bd920f2019-06-04 15:21:46 -07001263 protected void setInternalInsetsInfo(ViewTreeObserver.InternalInsetsInfo info,
1264 HeadsUpEntry currentNotification, boolean panelExpanded) {
1265 super.setInternalInsetsInfo(info, currentNotification, mPanelExpanded);
1266 }
1267
1268 @Override
Brad Stenning2ccc2a42019-04-15 10:17:01 -07001269 protected void setHeadsUpVisible() {
Priyank Singh7e9344f2019-05-07 14:30:13 -07001270 // if the Notifications panel is showing don't show the Heads up
Priyank Singh8bd920f2019-06-04 15:21:46 -07001271 if (!mEnableHeadsUpNotificationWhenNotificationShadeOpen && mPanelExpanded) {
Priyank Singh7e9344f2019-05-07 14:30:13 -07001272 return;
1273 }
Priyank Singh8bd920f2019-06-04 15:21:46 -07001274
Brad Stenning2ccc2a42019-04-15 10:17:01 -07001275 super.setHeadsUpVisible();
1276 if (mHeadsUpPanel.getVisibility() == View.VISIBLE) {
1277 mStatusBarWindowController.setHeadsUpShowing(true);
1278 mStatusBarWindowController.setForceStatusBarVisible(true);
1279 }
1280 }
1281
1282 @Override
1283 protected void removeNotificationFromPanel(HeadsUpEntry currentHeadsUpNotification) {
1284 super.removeNotificationFromPanel(currentHeadsUpNotification);
1285 // If the panel ended up empty and hidden we can remove it from SystemUi
1286 if (mHeadsUpPanel.getVisibility() != View.VISIBLE) {
1287 mStatusBarWindowController.setHeadsUpShowing(false);
1288 mStatusBarWindowController.setForceStatusBarVisible(false);
1289 }
1290 }
1291 }
Rakesh Iyer1186faa2015-12-07 16:48:46 -08001292}