diff options
Diffstat (limited to 'packages/CarSystemUI/src')
23 files changed, 1079 insertions, 347 deletions
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java new file mode 100644 index 000000000000..8e0a3eb53e6f --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui; + +import com.android.systemui.navigationbar.car.CarNavigationBar; + +import dagger.Binds; +import dagger.Module; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; + +/** Binder for car specific {@link SystemUI} modules. */ +@Module +public abstract class CarSystemUIBinder { + /** */ + @Binds + @IntoMap + @ClassKey(CarNavigationBar.class) + public abstract SystemUI bindCarNavigationBar(CarNavigationBar sysui); +} diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java index c7654e81e0b1..be4b8897d00b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java @@ -20,11 +20,10 @@ import android.content.Context; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.ViewMediatorCallback; -import com.android.systemui.statusbar.car.CarFacetButtonController; +import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.navigationbar.car.CarFacetButtonController; import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.volume.CarVolumeDialogComponent; -import com.android.systemui.volume.VolumeDialogComponent; import javax.inject.Singleton; @@ -43,7 +42,6 @@ public class CarSystemUIFactory extends SystemUIFactory { .contextHolder(new ContextHolder(context)) .build(); return DaggerCarSystemUIRootComponent.builder() - .dependencyProvider(new com.android.systemui.DependencyProvider()) .contextHolder(new ContextHolder(context)) .build(); } @@ -57,10 +55,6 @@ public class CarSystemUIFactory extends SystemUIFactory { return new CarStatusBarKeyguardViewManager(context, viewMediatorCallback, lockPatternUtils); } - public VolumeDialogComponent createVolumeDialogComponent(SystemUI systemUi, Context context) { - return new CarVolumeDialogComponent(systemUi, context); - } - @Singleton @Component(modules = ContextHolder.class) public interface CarDependencyComponent { diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index 9a063aa7b791..93e553f59dcf 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -23,18 +23,22 @@ import android.content.Context; import com.android.systemui.car.CarNotificationEntryManager; import com.android.systemui.car.CarNotificationInterruptionStateProvider; +import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; import com.android.systemui.power.EnhancedEstimates; import com.android.systemui.power.EnhancedEstimatesImpl; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; +import com.android.systemui.statusbar.car.CarStatusBar; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.volume.CarVolumeDialogComponent; +import com.android.systemui.volume.VolumeDialogComponent; import javax.inject.Named; import javax.inject.Singleton; @@ -42,6 +46,8 @@ import javax.inject.Singleton; import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; @Module abstract class CarSystemUIModule { @@ -94,4 +100,16 @@ abstract class CarSystemUIModule { @Binds abstract SystemUIRootComponent bindSystemUIRootComponent( CarSystemUIRootComponent systemUIRootComponent); + + @Binds + public abstract StatusBar bindStatusBar(CarStatusBar statusBar); + + @Binds + @IntoMap + @ClassKey(StatusBar.class) + public abstract SystemUI providesStatusBar(CarStatusBar statusBar); + + @Binds + abstract VolumeDialogComponent bindVolumeDialogComponent( + CarVolumeDialogComponent carVolumeDialogComponent); } diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java index 264b7d52c02f..c2847c88785b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java @@ -16,6 +16,12 @@ package com.android.systemui; +import com.android.systemui.dagger.DependencyBinder; +import com.android.systemui.dagger.DependencyProvider; +import com.android.systemui.dagger.SystemServicesModule; +import com.android.systemui.dagger.SystemUIModule; +import com.android.systemui.dagger.SystemUIRootComponent; + import javax.inject.Singleton; import dagger.Component; @@ -26,8 +32,10 @@ import dagger.Component; DependencyProvider.class, DependencyBinder.class, SystemUIFactory.ContextHolder.class, + SystemServicesModule.class, SystemUIModule.class, - CarSystemUIModule.class + CarSystemUIModule.class, + CarSystemUIBinder.class }) interface CarSystemUIRootComponent extends SystemUIRootComponent { diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java index a107dd793551..53a88a9a54e9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java @@ -15,11 +15,12 @@ */ package com.android.systemui.car; -import android.content.Context; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.logging.NotifLog; import javax.inject.Inject; import javax.inject.Singleton; @@ -34,8 +35,8 @@ import javax.inject.Singleton; public class CarNotificationEntryManager extends NotificationEntryManager { @Inject - public CarNotificationEntryManager(Context context) { - super(context); + public CarNotificationEntryManager(NotificationData notificationData, NotifLog notifLog) { + super(notificationData, notifLog); } @Override diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java index afd722ba0091..447e579ece42 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java @@ -22,6 +22,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.policy.BatteryController; import javax.inject.Inject; import javax.inject.Singleton; @@ -34,8 +35,9 @@ public class CarNotificationInterruptionStateProvider extends @Inject public CarNotificationInterruptionStateProvider(Context context, NotificationFilter filter, - StatusBarStateController stateController) { - super(context, filter, stateController); + StatusBarStateController stateController, + BatteryController batteryController) { + super(context, filter, stateController, batteryController); } @Override diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/AssitantButton.java index b36a7da35acf..c50de22fb2d8 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/AssitantButton.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.car; +package com.android.systemui.navigationbar.car; import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE; @@ -33,6 +33,7 @@ import com.android.internal.app.IVoiceInteractionSessionShowCallback; public class AssitantButton extends CarFacetButton { private static final String TAG = "CarFacetButton"; + private final AssistUtils mAssistUtils; private IVoiceInteractionSessionShowCallback mShowCallback = new IVoiceInteractionSessionShowCallback.Stub() { @Override @@ -45,8 +46,6 @@ public class AssitantButton extends CarFacetButton { Log.d(TAG, "IVoiceInteractionSessionShowCallback onShown()"); } }; - - private final AssistUtils mAssistUtils; public AssitantButton(Context context, AttributeSet attrs) { super(context, attrs); @@ -63,7 +62,7 @@ public class AssitantButton extends CarFacetButton { } @Override - protected void setupIntents(TypedArray typedArray){ + protected void setupIntents(TypedArray typedArray) { // left blank because for the assistant button Intent will not be passed from the layout. } } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java index 0421c3bebcfc..c46e6e7433a3 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.car; +package com.android.systemui.navigationbar.car; import android.app.ActivityOptions; import android.content.Context; diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java index 5f99e1750bb6..30f63f052b9f 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.car; +package com.android.systemui.navigationbar.car; import android.app.ActivityManager; import android.content.ComponentName; @@ -76,6 +76,7 @@ public class CarFacetButtonController { } } + /** Removes all buttons from the button maps. */ public void removeAll() { mButtonsByCategory.clear(); mButtonsByPackage.clear(); @@ -129,7 +130,7 @@ public class CarFacetButtonController { if (mSelectedFacetButtons != null) { Iterator<CarFacetButton> iterator = mSelectedFacetButtons.iterator(); - while(iterator.hasNext()) { + while (iterator.hasNext()) { CarFacetButton carFacetButton = iterator.next(); if (carFacetButton.getDisplayId() == validStackInfo.displayId) { carFacetButton.setSelected(false); diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java new file mode 100644 index 000000000000..6fba1d516c73 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.navigationbar.car; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.inputmethodservice.InputMethodService; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.view.Display; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.RegisterStatusBarResult; +import com.android.systemui.R; +import com.android.systemui.SystemUI; +import com.android.systemui.dagger.qualifiers.MainHandler; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.statusbar.car.hvac.HvacController; +import com.android.systemui.statusbar.car.hvac.TemperatureView; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.KeyguardStateController; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +import javax.inject.Inject; + +import dagger.Lazy; + +/** Navigation bars customized for the automotive use case. */ +public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks { + + private final NavigationBarViewFactory mNavigationBarViewFactory; + private final WindowManager mWindowManager; + private final DeviceProvisionedController mDeviceProvisionedController; + private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListener; + private final Handler mMainHandler; + private final Lazy<KeyguardStateController> mKeyguardStateController; + private final Lazy<CarFacetButtonController> mFacetButtonController; + private final Lazy<NavigationBarController> mNavigationBarController; + private final Lazy<HvacController> mHvacController; + + private IStatusBarService mBarService; + private CommandQueue mCommandQueue; + private ActivityManagerWrapper mActivityManagerWrapper; + + // If the nav bar should be hidden when the soft keyboard is visible. + private boolean mHideNavBarForKeyboard; + private boolean mBottomNavBarVisible; + + // Nav bar views. + private ViewGroup mNavigationBarWindow; + private ViewGroup mLeftNavigationBarWindow; + private ViewGroup mRightNavigationBarWindow; + private CarNavigationBarView mNavigationBarView; + private CarNavigationBarView mLeftNavigationBarView; + private CarNavigationBarView mRightNavigationBarView; + + // To be attached to the navigation bars such that they can close the notification panel if + // it's open. + private boolean mDeviceIsSetUpForUser = true; + + // Configuration values for if nav bars should be shown. + private boolean mShowBottom; + private boolean mShowLeft; + private boolean mShowRight; + + + @Inject + public CarNavigationBar(Context context, + NavigationBarViewFactory navigationBarViewFactory, + WindowManager windowManager, + DeviceProvisionedController deviceProvisionedController, + Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListener, + @MainHandler Handler mainHandler, + Lazy<KeyguardStateController> keyguardStateController, + Lazy<CarFacetButtonController> facetButtonController, + Lazy<NavigationBarController> navigationBarController, + Lazy<HvacController> hvacController) { + super(context); + mNavigationBarViewFactory = navigationBarViewFactory; + mWindowManager = windowManager; + mDeviceProvisionedController = deviceProvisionedController; + mFacetButtonTaskStackListener = facetButtonTaskStackListener; + mMainHandler = mainHandler; + mKeyguardStateController = keyguardStateController; + mFacetButtonController = facetButtonController; + mNavigationBarController = navigationBarController; + mHvacController = hvacController; + } + + @Override + public void start() { + // Set initial state. + mHideNavBarForKeyboard = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard); + mBottomNavBarVisible = false; + + // Read configuration. + mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar); + mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar); + mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar); + + // Get bar service. + mBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + + // Connect into the status bar manager service + mCommandQueue = getComponent(CommandQueue.class); + mCommandQueue.addCallback(this); + + RegisterStatusBarResult result = null; + try { + result = mBarService.registerStatusBar(mCommandQueue); + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + + mDeviceIsSetUpForUser = mDeviceProvisionedController.isCurrentUserSetup(); + mDeviceProvisionedController.addCallback( + new DeviceProvisionedController.DeviceProvisionedListener() { + @Override + public void onUserSetupChanged() { + mMainHandler.post(() -> restartNavBarsIfNecessary()); + } + + @Override + public void onUserSwitched() { + mMainHandler.post(() -> restartNavBarsIfNecessary()); + } + }); + + createNavigationBar(result); + + mActivityManagerWrapper = ActivityManagerWrapper.getInstance(); + mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListener.get()); + + mHvacController.get().connectToCarService(); + } + + private void restartNavBarsIfNecessary() { + boolean currentUserSetup = mDeviceProvisionedController.isCurrentUserSetup(); + if (mDeviceIsSetUpForUser != currentUserSetup) { + mDeviceIsSetUpForUser = currentUserSetup; + restartNavBars(); + } + } + + /** + * Remove all content from navbars and rebuild them. Used to allow for different nav bars + * before and after the device is provisioned. . Also for change of density and font size. + */ + private void restartNavBars() { + // remove and reattach all hvac components such that we don't keep a reference to unused + // ui elements + mHvacController.get().removeAllComponents(); + mFacetButtonController.get().removeAll(); + + if (mNavigationBarWindow != null) { + mNavigationBarWindow.removeAllViews(); + mNavigationBarView = null; + } + + if (mLeftNavigationBarWindow != null) { + mLeftNavigationBarWindow.removeAllViews(); + mLeftNavigationBarView = null; + } + + if (mRightNavigationBarWindow != null) { + mRightNavigationBarWindow.removeAllViews(); + mRightNavigationBarView = null; + } + + buildNavBarContent(); + // If the UI was rebuilt (day/night change) while the keyguard was up we need to + // correctly respect that state. + if (mKeyguardStateController.get().isShowing()) { + updateNavBarForKeyguardContent(); + } + + // CarFacetButtonController was reset therefore we need to re-add the status bar elements + // to the controller. + // TODO(hseog): Add facet buttons in status bar to controller. + } + + private void createNavigationBar(RegisterStatusBarResult result) { + buildNavBarWindows(); + buildNavBarContent(); + attachNavBarWindows(); + + // Try setting up the initial state of the nav bar if applicable. + if (result != null) { + setImeWindowStatus(Display.DEFAULT_DISPLAY, result.mImeToken, + result.mImeWindowVis, result.mImeBackDisposition, + result.mShowImeSwitcher); + } + + // There has been a car customized nav bar on the default display, so just create nav bars + // on external displays. + mNavigationBarController.get().createNavigationBars(/* includeDefaultDisplay= */ false, + result); + } + + private void buildNavBarWindows() { + if (mShowBottom) { + mNavigationBarWindow = mNavigationBarViewFactory.getBottomWindow(); + } + + if (mShowLeft) { + mLeftNavigationBarWindow = mNavigationBarViewFactory.getLeftWindow(); + } + + if (mShowRight) { + mRightNavigationBarWindow = mNavigationBarViewFactory.getRightWindow(); + } + } + + private void buildNavBarContent() { + if (mShowBottom) { + mNavigationBarView = mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser); + mNavigationBarWindow.addView(mNavigationBarView); + addTemperatureViewToController(mNavigationBarView); + } + + if (mShowLeft) { + mLeftNavigationBarView = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser); + mLeftNavigationBarWindow.addView(mLeftNavigationBarView); + addTemperatureViewToController(mLeftNavigationBarView); + } + + if (mShowRight) { + mRightNavigationBarView = mNavigationBarViewFactory.getRightBar(mDeviceIsSetUpForUser); + mRightNavigationBarWindow.addView(mRightNavigationBarView); + // Add ability to toggle notification center. + addTemperatureViewToController(mRightNavigationBarView); + // Add ability to close notification center on touch. + } + } + + private void addTemperatureViewToController(View v) { + if (v instanceof TemperatureView) { + mHvacController.get().addHvacTextView((TemperatureView) v); + } else if (v instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) v; + for (int i = 0; i < viewGroup.getChildCount(); i++) { + addTemperatureViewToController(viewGroup.getChildAt(i)); + } + } + } + + private void attachNavBarWindows() { + if (mShowBottom && !mBottomNavBarVisible) { + mBottomNavBarVisible = true; + + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + lp.setTitle("CarNavigationBar"); + lp.windowAnimations = 0; + mWindowManager.addView(mNavigationBarWindow, lp); + } + + if (mShowLeft) { + int width = mContext.getResources().getDimensionPixelSize( + R.dimen.car_left_navigation_bar_width); + WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams( + width, ViewGroup.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + leftlp.setTitle("LeftCarNavigationBar"); + leftlp.windowAnimations = 0; + leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; + leftlp.gravity = Gravity.LEFT; + mWindowManager.addView(mLeftNavigationBarWindow, leftlp); + } + if (mShowRight) { + int width = mContext.getResources().getDimensionPixelSize( + R.dimen.car_right_navigation_bar_width); + WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams( + width, ViewGroup.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + rightlp.setTitle("RightCarNavigationBar"); + rightlp.windowAnimations = 0; + rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; + rightlp.gravity = Gravity.RIGHT; + mWindowManager.addView(mRightNavigationBarWindow, rightlp); + } + } + + /** + * We register for soft keyboard visibility events such that we can hide the navigation bar + * giving more screen space to the IME. Note: this is optional and controlled by + * {@code com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard}. + */ + @Override + public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, + boolean showImeSwitcher) { + if (!mHideNavBarForKeyboard) { + return; + } + + if (mContext.getDisplay().getDisplayId() != displayId) { + return; + } + + boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0; + showBottomNavBarWindow(isKeyboardVisible); + } + + private void showBottomNavBarWindow(boolean isKeyboardVisible) { + if (!mShowBottom) { + return; + } + + // If keyboard is visible and bottom nav bar not visible, this is the correct state, so do + // nothing. Same with if keyboard is not visible and bottom nav bar is visible. + if (isKeyboardVisible ^ mBottomNavBarVisible) { + return; + } + + mNavigationBarViewFactory.getBottomWindow().setVisibility( + isKeyboardVisible ? View.GONE : View.VISIBLE); + mBottomNavBarVisible = !isKeyboardVisible; + } + + private void updateNavBarForKeyguardContent() { + if (mNavigationBarView != null) { + mNavigationBarView.showKeyguardButtons(); + } + if (mLeftNavigationBarView != null) { + mLeftNavigationBarView.showKeyguardButtons(); + } + if (mRightNavigationBarView != null) { + mRightNavigationBarView.showKeyguardButtons(); + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.print(" mTaskStackListener="); + pw.println(mFacetButtonTaskStackListener.get()); + pw.print(" mNavigationBarView="); + pw.println(mNavigationBarView); + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java index 05a41e68e972..afb69547cb47 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.car; +package com.android.systemui.navigationbar.car; import android.content.Context; import android.util.AttributeSet; @@ -24,6 +24,7 @@ import android.widget.LinearLayout; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.statusbar.car.CarStatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; /** @@ -32,7 +33,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconController; * The navigation bar in the automotive use case is more like a list of shortcuts, rendered * in a linear layout. */ -class CarNavigationBarView extends LinearLayout { +public class CarNavigationBarView extends LinearLayout { private View mNavButtons; private CarNavigationButton mNotificationsButton; private CarStatusBar mCarStatusBar; @@ -81,7 +82,7 @@ class CarNavigationBarView extends LinearLayout { return super.onInterceptTouchEvent(ev); } - void setStatusBar(CarStatusBar carStatusBar) { + public void setStatusBar(CarStatusBar carStatusBar) { mCarStatusBar = carStatusBar; } @@ -90,7 +91,7 @@ class CarNavigationBarView extends LinearLayout { * * @param statusBarWindowTouchListener The listener to call from touch and intercept touch */ - void setStatusBarWindowTouchListener(OnTouchListener statusBarWindowTouchListener) { + public void setStatusBarWindowTouchListener(OnTouchListener statusBarWindowTouchListener) { mStatusBarWindowTouchListener = statusBarWindowTouchListener; } @@ -134,7 +135,7 @@ class CarNavigationBarView extends LinearLayout { * * @param hasUnseen true if the unseen notification count is great than 0. */ - void toggleNotificationUnseenIndicator(Boolean hasUnseen) { + public void toggleNotificationUnseenIndicator(Boolean hasUnseen) { if (mNotificationsButton == null) return; mNotificationsButton.setUnseen(hasUnseen); diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java index c0dcbbcf30d4..707d80fc0d3b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.car; +package com.android.systemui.navigationbar.car; import android.app.ActivityOptions; import android.content.Context; diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/FacetButtonTaskStackListener.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/FacetButtonTaskStackListener.java new file mode 100644 index 000000000000..4925220d9cad --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/FacetButtonTaskStackListener.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.navigationbar.car; + +import android.app.ActivityTaskManager; +import android.util.Log; + +import com.android.systemui.shared.system.TaskStackChangeListener; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import dagger.Lazy; + +/** + * An implementation of TaskStackChangeListener, that listens for changes in the system + * task stack and notifies the navigation bar. + */ +@Singleton +class FacetButtonTaskStackListener extends TaskStackChangeListener { + private static final String TAG = FacetButtonTaskStackListener.class.getSimpleName(); + + private final Lazy<CarFacetButtonController> mFacetButtonControllerLazy; + + @Inject + FacetButtonTaskStackListener( + Lazy<CarFacetButtonController> carFacetButtonControllerLazy) { + mFacetButtonControllerLazy = carFacetButtonControllerLazy; + } + + @Override + public void onTaskStackChanged() { + try { + mFacetButtonControllerLazy.get().taskChanged( + ActivityTaskManager.getService().getAllStackInfos()); + } catch (Exception e) { + Log.e(TAG, "Getting StackInfo from activity manager failed", e); + } + } + + @Override + public void onTaskDisplayChanged(int taskId, int newDisplayId) { + try { + mFacetButtonControllerLazy.get().taskChanged( + ActivityTaskManager.getService().getAllStackInfos()); + } catch (Exception e) { + Log.e(TAG, "Getting StackInfo from activity manager failed", e); + } + + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/NavigationBarViewFactory.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/NavigationBarViewFactory.java new file mode 100644 index 000000000000..519b33a2f53e --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/NavigationBarViewFactory.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.navigationbar.car; + +import android.content.Context; +import android.util.ArrayMap; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.LayoutRes; + +import com.android.systemui.R; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** A factory that creates and caches views for navigation bars. */ +@Singleton +public class NavigationBarViewFactory { + + private static final String TAG = NavigationBarViewFactory.class.getSimpleName(); + private static final ArrayMap<Type, Integer> sLayoutMap = setupLayoutMapping(); + + private static ArrayMap<Type, Integer> setupLayoutMapping() { + ArrayMap<Type, Integer> map = new ArrayMap<>(); + map.put(Type.TOP, R.layout.car_top_navigation_bar); + map.put(Type.TOP_UNPROVISIONED, R.layout.car_top_navigation_bar_unprovisioned); + map.put(Type.BOTTOM, R.layout.car_navigation_bar); + map.put(Type.BOTTOM_UNPROVISIONED, R.layout.car_navigation_bar_unprovisioned); + map.put(Type.LEFT, R.layout.car_left_navigation_bar); + map.put(Type.LEFT_UNPROVISIONED, R.layout.car_left_navigation_bar_unprovisioned); + map.put(Type.RIGHT, R.layout.car_right_navigation_bar); + map.put(Type.RIGHT_UNPROVISIONED, R.layout.car_right_navigation_bar_unprovisioned); + return map; + } + + private final Context mContext; + private final ArrayMap<Type, CarNavigationBarView> mCachedViewMap = new ArrayMap<>( + Type.values().length); + private final ArrayMap<Type, ViewGroup> mCachedContainerMap = new ArrayMap<>(); + + /** Type of navigation bar to be created. */ + private enum Type { + TOP, + TOP_UNPROVISIONED, + BOTTOM, + BOTTOM_UNPROVISIONED, + LEFT, + LEFT_UNPROVISIONED, + RIGHT, + RIGHT_UNPROVISIONED + } + + @Inject + public NavigationBarViewFactory(Context context) { + mContext = context; + } + + /** Gets the bottom window. */ + public ViewGroup getBottomWindow() { + return getWindowCached(Type.BOTTOM); + } + + /** Gets the left window. */ + public ViewGroup getLeftWindow() { + return getWindowCached(Type.LEFT); + } + + /** Gets the right window. */ + public ViewGroup getRightWindow() { + return getWindowCached(Type.RIGHT); + } + + /** Gets the top bar. */ + public CarNavigationBarView getTopBar(boolean isSetUp) { + return getBar(isSetUp, Type.TOP, Type.TOP_UNPROVISIONED); + } + + /** Gets the bottom bar. */ + public CarNavigationBarView getBottomBar(boolean isSetUp) { + return getBar(isSetUp, Type.BOTTOM, Type.BOTTOM_UNPROVISIONED); + } + + /** Gets the left bar. */ + public CarNavigationBarView getLeftBar(boolean isSetUp) { + return getBar(isSetUp, Type.LEFT, Type.LEFT_UNPROVISIONED); + } + + /** Gets the right bar. */ + public CarNavigationBarView getRightBar(boolean isSetUp) { + return getBar(isSetUp, Type.RIGHT, Type.RIGHT_UNPROVISIONED); + } + + private ViewGroup getWindowCached(Type type) { + if (mCachedContainerMap.containsKey(type)) { + return mCachedContainerMap.get(type); + } + + ViewGroup window = (ViewGroup) View.inflate(mContext, + R.layout.navigation_bar_window, /* root= */ null); + mCachedContainerMap.put(type, window); + return mCachedContainerMap.get(type); + } + + private CarNavigationBarView getBar(boolean isSetUp, Type provisioned, Type unprovisioned) { + CarNavigationBarView view; + if (isSetUp) { + view = getBarCached(provisioned, sLayoutMap.get(provisioned)); + } else { + view = getBarCached(unprovisioned, sLayoutMap.get(unprovisioned)); + } + + if (view == null) { + String name = isSetUp ? provisioned.name() : unprovisioned.name(); + Log.e(TAG, "CarStatusBar failed inflate for " + name); + throw new RuntimeException( + "Unable to build " + name + " nav bar due to missing layout"); + } + return view; + } + + private CarNavigationBarView getBarCached(Type type, @LayoutRes int barLayout) { + if (mCachedViewMap.containsKey(type)) { + return mCachedViewMap.get(type); + } + + CarNavigationBarView view = (CarNavigationBarView) View.inflate(mContext, barLayout, + /* root= */ null); + mCachedViewMap.put(type, view); + return mCachedViewMap.get(type); + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java index 58f80a4ed968..d79849ccafc6 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java @@ -257,6 +257,11 @@ public class CarBatteryController extends BroadcastReceiver implements BatteryCo return false; } + @Override + public boolean isAodPowerSave() { + return false; + } + private void notifyBatteryLevelChanged() { for (int i = 0, size = mChangeCallbacks.size(); i < size; i++) { mChangeCallbacks.get(i) diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index b0ab5b49f340..52aaf4f41eec 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -16,12 +16,13 @@ package com.android.systemui.statusbar.car; +import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.car.Car; import android.car.drivingstate.CarDrivingStateEvent; import android.car.drivingstate.CarUxRestrictionsManager; @@ -29,21 +30,16 @@ import android.car.hardware.power.CarPowerManager.CarPowerStateListener; import android.car.trust.CarTrustAgentEnrollmentManager; import android.content.Context; import android.content.res.Configuration; -import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.inputmethodservice.InputMethodService; -import android.os.IBinder; +import android.os.PowerManager; +import android.util.DisplayMetrics; import android.util.Log; -import android.view.Display; import android.view.GestureDetector; -import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; -import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; @@ -57,38 +53,97 @@ import com.android.car.notification.NotificationClickHandlerFactory; import com.android.car.notification.NotificationDataManager; import com.android.car.notification.NotificationViewController; import com.android.car.notification.PreprocessingManager; +import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.RegisterStatusBarResult; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.BatteryMeterView; import com.android.systemui.CarSystemUIFactory; import com.android.systemui.Dependency; +import com.android.systemui.ForegroundServiceController; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; +import com.android.systemui.UiOffloadThread; +import com.android.systemui.appops.AppOpsController; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.bubbles.BubbleController; import com.android.systemui.classifier.FalsingLog; +import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.doze.DozeLog; import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.navigationbar.car.CarFacetButtonController; +import com.android.systemui.navigationbar.car.CarNavigationBarView; +import com.android.systemui.navigationbar.car.NavigationBarViewFactory; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.car.CarQSFragment; -import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.TaskStackChangeListener; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationViewHierarchyManager; +import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.car.hvac.HvacController; import com.android.systemui.statusbar.car.hvac.TemperatureView; +import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.NewNotifPipeline; +import com.android.systemui.statusbar.notification.NotificationAlertingManager; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.logging.NotifLog; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; +import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.phone.DozeScrimController; +import com.android.systemui.statusbar.phone.DozeServiceHost; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.LockscreenWallpaper; +import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; +import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.phone.StatusBarWindowController; +import com.android.systemui.statusbar.phone.StatusBarWindowViewController; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.InjectionInflationController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Map; +import javax.inject.Inject; +import javax.inject.Named; + +import dagger.Lazy; + /** - * A status bar (and navigation bar) tailored for the automotive use case. + * A status bar tailored for the automotive use case. */ public class CarStatusBar extends StatusBar implements CarBatteryController.BatteryViewHandler { private static final String TAG = "CarStatusBar"; @@ -98,21 +153,22 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private static final float FLING_ANIMATION_MAX_TIME = 0.5f; // acceleration rate for the fling animation private static final float FLING_SPEED_UP_FACTOR = 0.6f; + private final ScrimController mScrimController; private float mOpeningVelocity = DEFAULT_FLING_VELOCITY; private float mClosingVelocity = DEFAULT_FLING_VELOCITY; - private TaskStackListenerImpl mTaskStackListener; - private FullscreenUserSwitcher mFullscreenUserSwitcher; private CarBatteryController mCarBatteryController; private BatteryMeterView mBatteryMeterView; private Drawable mNotificationPanelBackground; + private ViewGroup mTopNavigationBarContainer; private ViewGroup mNavigationBarWindow; private ViewGroup mLeftNavigationBarWindow; private ViewGroup mRightNavigationBarWindow; + private CarNavigationBarView mTopNavigationBarView; private CarNavigationBarView mNavigationBarView; private CarNavigationBarView mLeftNavigationBarView; private CarNavigationBarView mRightNavigationBarView; @@ -121,10 +177,10 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private boolean mShowLeft; private boolean mShowRight; private boolean mShowBottom; + private final NavigationBarViewFactory mNavigationBarViewFactory; private CarFacetButtonController mCarFacetButtonController; - private ActivityManagerWrapper mActivityManagerWrapper; private DeviceProvisionedController mDeviceProvisionedController; - private boolean mDeviceIsProvisioned = true; + private boolean mDeviceIsSetUpForUser = true; private HvacController mHvacController; private DrivingStateHelper mDrivingStateHelper; private PowerManagerHelper mPowerManagerHelper; @@ -145,10 +201,12 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private boolean mNotificationListAtBottom; // Was the notification list at the bottom when the user first touched the screen private boolean mNotificationListAtBottomAtTimeOfTouch; + // To be attached to the top navigation bar (i.e. status bar) to pull down the notification + // panel. + private View.OnTouchListener mTopNavBarNotificationTouchListener; // To be attached to the navigation bars such that they can close the notification panel if // it's open. private View.OnTouchListener mNavBarNotificationTouchListener; - // Percentage from top of the screen after which the notification shade will open. This value // will be used while opening the notification shade. private int mSettleOpenPercentage; @@ -159,21 +217,16 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private int mPercentageFromBottom; // If notification shade is animation to close or to open. private boolean mIsNotificationAnimating; - // Tracks when the notification shade is being scrolled. This refers to the glass pane being // scrolled not the recycler view. private boolean mIsTracking; private float mFirstTouchDownOnGlassPane; - // If the notification card inside the recycler view is being swiped. private boolean mIsNotificationCardSwiping; // If notification shade is being swiped vertically to close. private boolean mIsSwipingVerticallyToClose; // Whether heads-up notifications should be shown when shade is open. private boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen; - // If the nav bar should be hidden when the soft keyboard is visible. - private boolean mHideNavBarForKeyboard; - private boolean mBottomNavBarVisible; private final CarPowerStateListener mCarPowerStateListener = (int state) -> { @@ -189,27 +242,159 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } }; + @Inject + public CarStatusBar( + Context context, + FeatureFlags featureFlags, + LightBarController lightBarController, + AutoHideController autoHideController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + StatusBarIconController statusBarIconController, + DozeLog dozeLog, + InjectionInflationController injectionInflationController, + PulseExpansionHandler pulseExpansionHandler, + NotificationWakeUpCoordinator notificationWakeUpCoordinator, + KeyguardBypassController keyguardBypassController, + KeyguardStateController keyguardStateController, + HeadsUpManagerPhone headsUpManagerPhone, + DynamicPrivacyController dynamicPrivacyController, + BypassHeadsUpNotifier bypassHeadsUpNotifier, + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress, + Lazy<NewNotifPipeline> newNotifPipeline, + FalsingManager falsingManager, + BroadcastDispatcher broadcastDispatcher, + RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, + NotificationGutsManager notificationGutsManager, + NotificationLogger notificationLogger, + NotificationEntryManager notificationEntryManager, + NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationViewHierarchyManager notificationViewHierarchyManager, + ForegroundServiceController foregroundServiceController, + AppOpsController appOpsController, + KeyguardViewMediator keyguardViewMediator, + ZenModeController zenModeController, + NotificationAlertingManager notificationAlertingManager, + DisplayMetrics displayMetrics, + MetricsLogger metricsLogger, + UiOffloadThread uiOffloadThread, + NotificationMediaManager notificationMediaManager, + NotificationLockscreenUserManager lockScreenUserManager, + NotificationRemoteInputManager remoteInputManager, + UserSwitcherController userSwitcherController, + NetworkController networkController, + BatteryController batteryController, + SysuiColorExtractor colorExtractor, + ScreenLifecycle screenLifecycle, + WakefulnessLifecycle wakefulnessLifecycle, + SysuiStatusBarStateController statusBarStateController, + VibratorHelper vibratorHelper, + BubbleController bubbleController, + NotificationGroupManager groupManager, + NotificationGroupAlertTransferHelper groupAlertTransferHelper, + VisualStabilityManager visualStabilityManager, + DeviceProvisionedController deviceProvisionedController, + NavigationBarController navigationBarController, + AssistManager assistManager, + NotificationListener notificationListener, + ConfigurationController configurationController, + StatusBarWindowController statusBarWindowController, + StatusBarWindowViewController.Builder statusBarWindowViewControllerBuild, + NotifLog notifLog, + DozeParameters dozeParameters, + ScrimController scrimController, + Lazy<LockscreenWallpaper> lockscreenWallpaperLazy, + Lazy<BiometricUnlockController> biometricUnlockControllerLazy, + DozeServiceHost dozeServiceHost, + PowerManager powerManager, + DozeScrimController dozeScrimController, + + /* Car Settings injected components. */ + NavigationBarViewFactory navigationBarViewFactory) { + super( + context, + featureFlags, + lightBarController, + autoHideController, + keyguardUpdateMonitor, + statusBarIconController, + dozeLog, + injectionInflationController, + pulseExpansionHandler, + notificationWakeUpCoordinator, + keyguardBypassController, + keyguardStateController, + headsUpManagerPhone, + dynamicPrivacyController, + bypassHeadsUpNotifier, + allowNotificationLongPress, + newNotifPipeline, + falsingManager, + broadcastDispatcher, + remoteInputQuickSettingsDisabler, + notificationGutsManager, + notificationLogger, + notificationEntryManager, + notificationInterruptionStateProvider, + notificationViewHierarchyManager, + foregroundServiceController, + appOpsController, + keyguardViewMediator, + zenModeController, + notificationAlertingManager, + displayMetrics, + metricsLogger, + uiOffloadThread, + notificationMediaManager, + lockScreenUserManager, + remoteInputManager, + userSwitcherController, + networkController, + batteryController, + colorExtractor, + screenLifecycle, + wakefulnessLifecycle, + statusBarStateController, + vibratorHelper, + bubbleController, + groupManager, + groupAlertTransferHelper, + visualStabilityManager, + deviceProvisionedController, + navigationBarController, + assistManager, + notificationListener, + configurationController, + statusBarWindowController, + statusBarWindowViewControllerBuild, + notifLog, + dozeParameters, + scrimController, + lockscreenWallpaperLazy, + biometricUnlockControllerLazy, + dozeServiceHost, + powerManager, + dozeScrimController); + mScrimController = scrimController; + mNavigationBarViewFactory = navigationBarViewFactory; + } + @Override public void start() { // get the provisioned state before calling the parent class since it's that flow that // builds the nav bar mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); - mDeviceIsProvisioned = mDeviceProvisionedController.isDeviceProvisioned(); - - // Keyboard related setup, before nav bars are created. - mHideNavBarForKeyboard = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard); - mBottomNavBarVisible = false; + mDeviceIsSetUpForUser = mDeviceProvisionedController.isCurrentUserSetup(); // Need to initialize screen lifecycle before calling super.start - before switcher is // created. mScreenLifecycle = Dependency.get(ScreenLifecycle.class); mScreenLifecycle.addObserver(mScreenObserver); + // Need to initialize HVAC controller before calling super.start - before system bars are + // created. + mHvacController = new HvacController(mContext); + super.start(); - mTaskStackListener = new TaskStackListenerImpl(); - mActivityManagerWrapper = ActivityManagerWrapper.getInstance(); - mActivityManagerWrapper.registerTaskStackListener(mTaskStackListener); mNotificationPanel.setScrollingEnabled(true); mSettleOpenPercentage = mContext.getResources().getInteger( @@ -224,25 +409,18 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mHvacController.connectToCarService(); - CarSystemUIFactory factory = SystemUIFactory.getInstance(); - if (!mDeviceIsProvisioned) { - mDeviceProvisionedController.addCallback( - new DeviceProvisionedController.DeviceProvisionedListener() { - @Override - public void onDeviceProvisionedChanged() { - mHandler.post(() -> { - // on initial boot we are getting a call even though the value - // is the same so we are confirming the reset is needed - boolean deviceProvisioned = - mDeviceProvisionedController.isDeviceProvisioned(); - if (mDeviceIsProvisioned != deviceProvisioned) { - mDeviceIsProvisioned = deviceProvisioned; - restartNavBars(); - } - }); - } - }); - } + mDeviceProvisionedController.addCallback( + new DeviceProvisionedController.DeviceProvisionedListener() { + @Override + public void onUserSetupChanged() { + mHandler.post(() -> restartNavBarsIfNecessary()); + } + + @Override + public void onUserSwitched() { + mHandler.post(() -> restartNavBarsIfNecessary()); + } + }); // Register a listener for driving state changes. mDrivingStateHelper = new DrivingStateHelper(mContext, this::onDrivingStateChanged); @@ -254,6 +432,14 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mSwitchToGuestTimer = new SwitchToGuestTimer(mContext); } + private void restartNavBarsIfNecessary() { + boolean currentUserSetup = mDeviceProvisionedController.isCurrentUserSetup(); + if (mDeviceIsSetUpForUser != currentUserSetup) { + mDeviceIsSetUpForUser = currentUserSetup; + restartNavBars(); + } + } + /** * Remove all content from navbars and rebuild them. Used to allow for different nav bars * before and after the device is provisioned. . Also for change of density and font size. @@ -262,29 +448,19 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt // remove and reattach all hvac components such that we don't keep a reference to unused // ui elements mHvacController.removeAllComponents(); - addTemperatureViewToController(mStatusBarWindow); mCarFacetButtonController.removeAll(); + if (mNavigationBarWindow != null) { - mNavigationBarWindow.removeAllViews(); mNavigationBarView = null; } - if (mLeftNavigationBarWindow != null) { - mLeftNavigationBarWindow.removeAllViews(); mLeftNavigationBarView = null; } - if (mRightNavigationBarWindow != null) { - mRightNavigationBarWindow.removeAllViews(); mRightNavigationBarView = null; } buildNavBarContent(); - // If the UI was rebuilt (day/night change) while the keyguard was up we need to - // correctly respect that state. - if (mIsKeyguard) { - updateNavBarForKeyguardContent(); - } // CarFacetButtonController was reset therefore we need to re-add the status bar elements // to the controller. mCarFacetButtonController.addAllFacetButtons(mStatusBarWindow); @@ -317,7 +493,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } } - @Override public boolean hideKeyguard() { boolean result = super.hideKeyguard(); @@ -357,7 +532,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt @Override protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) { super.makeStatusBarView(result); - mHvacController = new HvacController(mContext); CarSystemUIFactory factory = SystemUIFactory.getInstance(); mCarFacetButtonController = factory.getCarDependencyComponent() @@ -382,7 +556,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt * touch listeners needed for opening and closing the notification panel */ private void connectNotificationsUI() { - // Attached to the status bar to detect pull down of the notification shade. + // Attached to the top navigation bar (i.e. status bar) to detect pull down of the + // notification shade. GestureDetector openGestureDetector = new GestureDetector(mContext, new OpenNotificationGestureListener() { @Override @@ -415,6 +590,18 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt GestureDetector handleBarCloseNotificationGestureDetector = new GestureDetector(mContext, new HandleBarCloseNotificationGestureListener()); + mTopNavBarNotificationTouchListener = (v, event) -> { + if (!mDeviceIsSetUpForUser) { + return true; + } + boolean consumed = openGestureDetector.onTouchEvent(event); + if (consumed) { + return true; + } + maybeCompleteAnimation(event); + return true; + }; + mNavBarNotificationTouchListener = (v, event) -> { boolean consumed = navBarCloseNotificationGestureDetector.onTouchEvent(event); @@ -425,21 +612,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt return true; }; - // The following are the ui elements that the user would call the status bar. - // This will set the status bar so it they can make call backs. - CarNavigationBarView topBar = mStatusBarWindow.findViewById(R.id.car_top_bar); - topBar.setStatusBar(this); - topBar.setStatusBarWindowTouchListener((v1, event1) -> { - - boolean consumed = openGestureDetector.onTouchEvent(event1); - if (consumed) { - return true; - } - maybeCompleteAnimation(event1); - return true; - } - ); - mNotificationClickHandlerFactory = new NotificationClickHandlerFactory(mBarService); mNotificationClickHandlerFactory.registerClickListener((launchResult, alertEntry) -> { if (launchResult == ActivityManager.START_TASK_TO_FRONT @@ -616,7 +788,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt return; } mStatusBarWindowController.setStatusBarFocusable(false); - mStatusBarWindow.cancelExpandHelper(); + mStatusBarWindowViewController.cancelExpandHelper(); mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor); animateNotificationPanel(mClosingVelocity, true); @@ -731,197 +903,55 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt buildNavBarWindows(); buildNavBarContent(); - attachNavBarWindows(); - - // Try setting up the initial state of the nav bar if applicable. - if (result != null) { - setImeWindowStatus(Display.DEFAULT_DISPLAY, result.mImeToken, - result.mImeWindowVis, result.mImeBackDisposition, - result.mShowImeSwitcher); - } - - // There has been a car customized nav bar on the default display, so just create nav bars - // on external displays. - mNavigationBarController.createNavigationBars(false /* includeDefaultDisplay */, result); } private void buildNavBarContent() { + buildTopBar(); + if (mShowBottom) { - buildBottomBar((mDeviceIsProvisioned) ? R.layout.car_navigation_bar : - R.layout.car_navigation_bar_unprovisioned); + mNavigationBarView = mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser); + mNavigationBarView.setStatusBar(this); + mNavigationBarView.setStatusBarWindowTouchListener(mNavBarNotificationTouchListener); } if (mShowLeft) { - buildLeft((mDeviceIsProvisioned) ? R.layout.car_left_navigation_bar : - R.layout.car_left_navigation_bar_unprovisioned); + mLeftNavigationBarView = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser); + mLeftNavigationBarView.setStatusBar(this); + mLeftNavigationBarView.setStatusBarWindowTouchListener( + mNavBarNotificationTouchListener); } if (mShowRight) { - buildRight((mDeviceIsProvisioned) ? R.layout.car_right_navigation_bar : - R.layout.car_right_navigation_bar_unprovisioned); + mRightNavigationBarView = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser); + mRightNavigationBarView.setStatusBar(this); + mRightNavigationBarView.setStatusBarWindowTouchListener( + mNavBarNotificationTouchListener); } } private void buildNavBarWindows() { - if (mShowBottom) { - mNavigationBarWindow = (ViewGroup) View.inflate(mContext, - R.layout.navigation_bar_window, null); - } - if (mShowLeft) { - mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext, - R.layout.navigation_bar_window, null); - } - if (mShowRight) { - mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext, - R.layout.navigation_bar_window, null); - } - - } - - /** - * We register for soft keyboard visibility events such that we can hide the navigation bar - * giving more screen space to the IME. Note: this is optional and controlled by - * {@code com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard}. - */ - @Override - public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, - boolean showImeSwitcher) { - if (!mHideNavBarForKeyboard) { - return; - } + mTopNavigationBarContainer = mStatusBarWindow + .findViewById(R.id.car_top_navigation_bar_container); - if (mContext.getDisplay().getDisplayId() != displayId) { - return; - } - - boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0; - if (!isKeyboardVisible) { - attachBottomNavBarWindow(); - } else { - detachBottomNavBarWindow(); + if (mShowBottom) { + mNavigationBarWindow = mNavigationBarViewFactory.getBottomWindow(); } - } - - private void attachNavBarWindows() { - attachBottomNavBarWindow(); - if (mShowLeft) { - int width = mContext.getResources().getDimensionPixelSize( - R.dimen.car_left_navigation_bar_width); - WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams( - width, LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - leftlp.setTitle("LeftCarNavigationBar"); - leftlp.windowAnimations = 0; - leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; - leftlp.gravity = Gravity.LEFT; - mWindowManager.addView(mLeftNavigationBarWindow, leftlp); + mLeftNavigationBarWindow = mNavigationBarViewFactory.getLeftWindow(); } if (mShowRight) { - int width = mContext.getResources().getDimensionPixelSize( - R.dimen.car_right_navigation_bar_width); - WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams( - width, LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - rightlp.setTitle("RightCarNavigationBar"); - rightlp.windowAnimations = 0; - rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; - rightlp.gravity = Gravity.RIGHT; - mWindowManager.addView(mRightNavigationBarWindow, rightlp); + mRightNavigationBarWindow = mNavigationBarViewFactory.getRightWindow(); } } - /** - * Attaches the bottom nav bar window. Can be extended to modify the specific behavior of - * attaching the bottom nav bar. - */ - protected void attachBottomNavBarWindow() { - if (!mShowBottom) { - return; - } + private void buildTopBar() { + mTopNavigationBarContainer.removeAllViews(); + mTopNavigationBarView = mNavigationBarViewFactory.getTopBar(mDeviceIsSetUpForUser); + mTopNavigationBarContainer.addView(mTopNavigationBarView); - if (mBottomNavBarVisible) { - return; - } - mBottomNavBarVisible = true; - - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - lp.setTitle("CarNavigationBar"); - lp.windowAnimations = 0; - mWindowManager.addView(mNavigationBarWindow, lp); - } - - /** - * Detaches the bottom nav bar window. Can be extended to modify the specific behavior of - * detaching the bottom nav bar. - */ - protected void detachBottomNavBarWindow() { - if (!mShowBottom) { - return; - } - - if (!mBottomNavBarVisible) { - return; - } - mBottomNavBarVisible = false; - mWindowManager.removeView(mNavigationBarWindow); - } - - private void buildBottomBar(int layout) { - // SystemUI requires that the navigation bar view have a parent. Since the regular - // StatusBar inflates navigation_bar_window as this parent view, use the same view for the - // CarNavigationBarView. - View.inflate(mContext, layout, mNavigationBarWindow); - mNavigationBarView = (CarNavigationBarView) mNavigationBarWindow.getChildAt(0); - if (mNavigationBarView == null) { - Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar"); - throw new RuntimeException("Unable to build botom nav bar due to missing layout"); - } - mNavigationBarView.setStatusBar(this); - addTemperatureViewToController(mNavigationBarView); - mNavigationBarView.setStatusBarWindowTouchListener(mNavBarNotificationTouchListener); - } - - private void buildLeft(int layout) { - View.inflate(mContext, layout, mLeftNavigationBarWindow); - mLeftNavigationBarView = (CarNavigationBarView) mLeftNavigationBarWindow.getChildAt(0); - if (mLeftNavigationBarView == null) { - Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar"); - throw new RuntimeException("Unable to build left nav bar due to missing layout"); - } - mLeftNavigationBarView.setStatusBar(this); - addTemperatureViewToController(mLeftNavigationBarView); - mLeftNavigationBarView.setStatusBarWindowTouchListener(mNavBarNotificationTouchListener); - } - - - private void buildRight(int layout) { - View.inflate(mContext, layout, mRightNavigationBarWindow); - mRightNavigationBarView = (CarNavigationBarView) mRightNavigationBarWindow.getChildAt(0); - if (mRightNavigationBarView == null) { - Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar"); - throw new RuntimeException("Unable to build right nav bar due to missing layout"); - } - mRightNavigationBarView.setStatusBar(this); - addTemperatureViewToController(mRightNavigationBarView); - mRightNavigationBarView.setStatusBarWindowTouchListener(mNavBarNotificationTouchListener); + mTopNavigationBarView.setStatusBar(this); + addTemperatureViewToController(mTopNavigationBarView); + mTopNavigationBarView.setStatusBarWindowTouchListener(mTopNavBarNotificationTouchListener); } @Override @@ -935,8 +965,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt + "," + mStackScroller.getScrollY()); } - pw.print(" mTaskStackListener="); - pw.println(mTaskStackListener); pw.print(" mCarFacetButtonController="); pw.println(mCarFacetButtonController); pw.print(" mFullscreenUserSwitcher="); @@ -945,8 +973,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt pw.println(mCarBatteryController); pw.print(" mBatteryMeterView="); pw.println(mBatteryMeterView); - pw.print(" mNavigationBarView="); - pw.println(mNavigationBarView); if (Dependency.get(KeyguardUpdateMonitor.class) != null) { Dependency.get(KeyguardUpdateMonitor.class).dump(fd, pw, args); @@ -986,32 +1012,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } } - /** - * An implementation of TaskStackChangeListener, that listens for changes in the system - * task stack and notifies the navigation bar. - */ - private class TaskStackListenerImpl extends TaskStackChangeListener { - @Override - public void onTaskStackChanged() { - try { - mCarFacetButtonController.taskChanged( - ActivityTaskManager.getService().getAllStackInfos()); - } catch (Exception e) { - Log.e(TAG, "Getting StackInfo from activity manager failed", e); - } - } - - @Override - public void onTaskDisplayChanged(int taskId, int newDisplayId) { - try { - mCarFacetButtonController.taskChanged( - ActivityTaskManager.getService().getAllStackInfos()); - } catch (Exception e) { - Log.e(TAG, "Getting StackInfo from activity manager failed", e); - } - } - } - private void onDrivingStateChanged(CarDrivingStateEvent notUsed) { // Check if we need to start the timer every time driving state changes. startSwitchToGuestTimerIfDrivingOnKeyguard(); diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java index 827a59eddf56..3b482599b2a0 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java @@ -18,18 +18,25 @@ package com.android.systemui.statusbar.car; import static android.content.DialogInterface.BUTTON_NEGATIVE; import static android.content.DialogInterface.BUTTON_POSITIVE; +import static android.os.UserManager.DISALLOW_ADD_USER; +import android.app.ActivityManager; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Dialog; import android.car.userlib.CarUserManagerHelper; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Rect; import android.os.AsyncTask; +import android.os.UserHandle; +import android.os.UserManager; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -48,24 +55,33 @@ import com.android.systemui.statusbar.phone.SystemUIDialog; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * Displays a GridLayout with icons for the users in the system to allow switching between users. * One of the uses of this is for the lock screen in auto. */ -public class UserGridRecyclerView extends RecyclerView implements - CarUserManagerHelper.OnUsersUpdateListener { +public class UserGridRecyclerView extends RecyclerView { private UserSelectionListener mUserSelectionListener; private UserAdapter mAdapter; private CarUserManagerHelper mCarUserManagerHelper; + private UserManager mUserManager; private Context mContext; + private final BroadcastReceiver mUserUpdateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUsersUpdate(); + } + }; + public UserGridRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; mCarUserManagerHelper = new CarUserManagerHelper(mContext); + mUserManager = UserManager.get(mContext); - addItemDecoration(new ItemSpacingDecoration(context.getResources().getDimensionPixelSize( + addItemDecoration(new ItemSpacingDecoration(mContext.getResources().getDimensionPixelSize( R.dimen.car_user_switcher_vertical_spacing_between_users))); } @@ -75,7 +91,7 @@ public class UserGridRecyclerView extends RecyclerView implements @Override public void onFinishInflate() { super.onFinishInflate(); - mCarUserManagerHelper.registerOnUsersUpdateListener(this); + registerForUserEvents(); } /** @@ -84,7 +100,7 @@ public class UserGridRecyclerView extends RecyclerView implements @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); - mCarUserManagerHelper.unregisterOnUsersUpdateListener(this); + unregisterForUserEvents(); } /** @@ -93,12 +109,18 @@ public class UserGridRecyclerView extends RecyclerView implements * @return the adapter */ public void buildAdapter() { - List<UserRecord> userRecords = createUserRecords(mCarUserManagerHelper - .getAllUsers()); + List<UserRecord> userRecords = createUserRecords(getUsersForUserGrid()); mAdapter = new UserAdapter(mContext, userRecords); super.setAdapter(mAdapter); } + private List<UserInfo> getUsersForUserGrid() { + return mUserManager.getUsers(/* excludeDying= */ true) + .stream() + .filter(UserInfo::supportsSwitchToByUser) + .collect(Collectors.toList()); + } + private List<UserRecord> createUserRecords(List<UserInfo> userInfoList) { List<UserRecord> userRecords = new ArrayList<>(); @@ -114,8 +136,7 @@ public class UserGridRecyclerView extends RecyclerView implements continue; } - boolean isForeground = - mCarUserManagerHelper.getCurrentForegroundUserId() == userInfo.id; + boolean isForeground = ActivityManager.getCurrentUser() == userInfo.id; UserRecord record = new UserRecord(userInfo, false /* isStartGuestSession */, false /* isAddUser */, isForeground); userRecords.add(record); @@ -125,7 +146,8 @@ public class UserGridRecyclerView extends RecyclerView implements userRecords.add(createStartGuestUserRecord()); // Add add user record if the foreground user can add users - if (mCarUserManagerHelper.canForegroundUserAddUsers()) { + UserHandle fgUserHandle = UserHandle.of(ActivityManager.getCurrentUser()); + if (!mUserManager.hasUserRestriction(DISALLOW_ADD_USER, fgUserHandle)) { userRecords.add(createAddUserRecord()); } @@ -133,7 +155,7 @@ public class UserGridRecyclerView extends RecyclerView implements } private UserRecord createForegroundUserRecord() { - return new UserRecord(mCarUserManagerHelper.getCurrentForegroundUserInfo(), + return new UserRecord(mUserManager.getUserInfo(ActivityManager.getCurrentUser()), false /* isStartGuestSession */, false /* isAddUser */, true /* isForeground */); } @@ -161,13 +183,30 @@ public class UserGridRecyclerView extends RecyclerView implements mUserSelectionListener = userSelectionListener; } - @Override - public void onUsersUpdate() { + private void onUsersUpdate() { mAdapter.clearUsers(); - mAdapter.updateUsers(createUserRecords(mCarUserManagerHelper.getAllUsers())); + mAdapter.updateUsers(createUserRecords(getUsersForUserGrid())); mAdapter.notifyDataSetChanged(); } + private void registerForUserEvents() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_ADDED); + filter.addAction(Intent.ACTION_USER_INFO_CHANGED); + filter.addAction(Intent.ACTION_USER_SWITCHED); + mContext.registerReceiverAsUser( + mUserUpdateReceiver, + UserHandle.ALL, // Necessary because CarSystemUi lives in User 0 + filter, + /* broadcastPermission= */ null, + /* scheduler= */ null); + } + + private void unregisterForUserEvents() { + mContext.unregisterReceiver(mUserUpdateReceiver); + } + /** * Adapter to populate the grid layout with the available user profiles */ @@ -248,7 +287,7 @@ public class UserGridRecyclerView extends RecyclerView implements } private void handleAddUserClicked() { - if (mCarUserManagerHelper.isUserLimitReached()) { + if (!mUserManager.canAddMoreUsers()) { mAddUserView.setEnabled(true); showMaxUserLimitReachedDialog(); } else { diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java index 30429eda7be7..e81be1b0b186 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java @@ -38,6 +38,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import javax.inject.Inject; + /** * Manages the connection to the Car service and delegates value changes to the registered * {@link TemperatureView}s @@ -119,6 +121,7 @@ public class HvacController { } }; + @Inject public HvacController(Context context) { mContext = context; } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/OngoingPrivacyChip.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/OngoingPrivacyChip.java index ead1de2bd352..88d641e8bb36 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/OngoingPrivacyChip.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/OngoingPrivacyChip.java @@ -47,6 +47,7 @@ import java.util.stream.Collectors; public class OngoingPrivacyChip extends LinearLayout implements View.OnClickListener { private Context mContext; + private Handler mHandler; private LinearLayout mIconsContainer; private List<PrivacyItem> mPrivacyItems; @@ -88,6 +89,7 @@ public class OngoingPrivacyChip extends LinearLayout implements View.OnClickList private void init(Context context) { mContext = context; + mHandler = new Handler(Looper.getMainLooper()); mPrivacyItems = new ArrayList<>(); sAppOpsController = Dependency.get(AppOpsController.class); mUserManager = mContext.getSystemService(UserManager.class); @@ -131,8 +133,7 @@ public class OngoingPrivacyChip extends LinearLayout implements View.OnClickList @Override public void onClick(View v) { updatePrivacyList(); - Handler mUiHandler = new Handler(Looper.getMainLooper()); - mUiHandler.post(() -> { + mHandler.post(() -> { mActivityStarter.postStartActivityDismissingKeyguard( new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0); }); @@ -152,21 +153,17 @@ public class OngoingPrivacyChip extends LinearLayout implements View.OnClickList } private void updatePrivacyList() { - mPrivacyItems = mCurrentUserIds.stream() + List<PrivacyItem> privacyItems = mCurrentUserIds.stream() .flatMap(item -> sAppOpsController.getActiveAppOpsForUser(item).stream()) .filter(Objects::nonNull) .map(item -> toPrivacyItem(item)) .filter(Objects::nonNull) .collect(Collectors.toList()); - mPrivacyDialogBuilder = new PrivacyDialogBuilder(mContext, mPrivacyItems); - - Handler refresh = new Handler(Looper.getMainLooper()); - refresh.post(new Runnable() { - @Override - public void run() { - updateView(); - } - }); + if (!privacyItems.equals(mPrivacyItems)) { + mPrivacyItems = privacyItems; + mPrivacyDialogBuilder = new PrivacyDialogBuilder(mContext, mPrivacyItems); + mHandler.post(this::updateView); + } } private PrivacyItem toPrivacyItem(AppOpItem appOpItem) { diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyApplication.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyApplication.java index 5ec7a77cb305..a5d3bf7cc9c1 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyApplication.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyApplication.java @@ -16,28 +16,31 @@ package com.android.systemui.statusbar.car.privacy; -import android.car.userlib.CarUserManagerHelper; +import android.app.ActivityManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.util.Log; +import java.util.Objects; + /** * Class to hold the data for the applications that are using the AppOps permissions. */ public class PrivacyApplication { private static final String TAG = "PrivacyApplication"; + private String mPackageName; private Drawable mIcon; private String mApplicationName; public PrivacyApplication(String packageName, Context context) { + mPackageName = packageName; try { - CarUserManagerHelper carUserManagerHelper = new CarUserManagerHelper(context); ApplicationInfo app = context.getPackageManager() .getApplicationInfoAsUser(packageName, 0, - carUserManagerHelper.getCurrentForegroundUserId()); + ActivityManager.getCurrentUser()); mIcon = context.getPackageManager().getApplicationIcon(app); mApplicationName = context.getPackageManager().getApplicationLabel(app).toString(); } catch (PackageManager.NameNotFoundException e) { @@ -59,4 +62,17 @@ public class PrivacyApplication { public String getApplicationName() { return mApplicationName; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PrivacyApplication that = (PrivacyApplication) o; + return mPackageName.equals(that.mPackageName); + } + + @Override + public int hashCode() { + return Objects.hash(mPackageName); + } } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyItem.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyItem.java index fca137392d74..d3e123ed8c25 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyItem.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyItem.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.car.privacy; +import java.util.Objects; + /** * Class for holding the data of each privacy item displayed in {@link OngoingPrivacyDialog} */ @@ -43,4 +45,18 @@ public class PrivacyItem { public PrivacyType getPrivacyType() { return mPrivacyType; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PrivacyItem that = (PrivacyItem) o; + return mPrivacyType == that.mPrivacyType + && mPrivacyApplication.equals(that.mPrivacyApplication); + } + + @Override + public int hashCode() { + return Objects.hash(mPrivacyType, mPrivacyApplication); + } } diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java index 71cc19b63ac1..4d6af95b3f9c 100644 --- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java @@ -19,15 +19,21 @@ package com.android.systemui.volume; import android.content.Context; import com.android.systemui.SystemUI; +import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.VolumeDialog; +import javax.inject.Inject; +import javax.inject.Singleton; + /** * Allows for adding car specific dialog when the volume dialog is created. */ +@Singleton public class CarVolumeDialogComponent extends VolumeDialogComponent { - public CarVolumeDialogComponent(SystemUI sysui, Context context) { - super(sysui, context); + @Inject + public CarVolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator) { + super(context, keyguardViewMediator); } protected VolumeDialog createDefault() { diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java index d0a63f058291..22c7c7a3d6af 100644 --- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java @@ -143,6 +143,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { private boolean mHovering; private int mCurrentlyDisplayingGroupId; private boolean mShowing; + private boolean mDismissing; private boolean mExpanded; private View mExpandIcon; private final ServiceConnection mServiceConnection = new ServiceConnection() { @@ -244,6 +245,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { mHovering = false; mShowing = false; + mDismissing = false; mExpanded = false; mWindow = mDialog.getWindow(); mWindow.requestFeature(Window.FEATURE_NO_TITLE); @@ -335,14 +337,11 @@ public class CarVolumeDialogImpl implements VolumeDialog { mHandler.removeMessages(H.DISMISS); mHandler.removeMessages(H.SHOW); - if (!mShowing) { + if (!mShowing || mDismissing) { return; } - mListView.animate().cancel(); - - mListView.setTranslationY(0); - mListView.setAlpha(1); + mDismissing = true; mListView.animate() .alpha(0) .translationY(-mListView.getHeight()) @@ -354,7 +353,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { } mDialog.dismiss(); mShowing = false; - mShowing = false; + mDismissing = false; // if mExpandIcon is null that means user never clicked on the expanded arrow // which implies that the dialog is still not expanded. In that case we do // not want to reset the state |