Merge "Updated OverlayPanelViewController to allow for showing overlay panel from the bottom navigation bar." into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c65d2c3e06
@@ -72,11 +72,21 @@
|
|||||||
|
|
||||||
<!-- Car System UI's OverlayViewsMediator-->
|
<!-- Car System UI's OverlayViewsMediator-->
|
||||||
<string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
|
<string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
|
||||||
<item>com.android.systemui.car.notification.NotificationPanelViewMediator</item>
|
<item>@string/config_notificationPanelViewMediator</item>
|
||||||
<item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item>
|
<item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item>
|
||||||
<item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
|
<item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Car SystemUI's notification mediator. Replace with other notification mediators to have
|
||||||
|
the notification panel show from another system bar. The system bar should be enabled to
|
||||||
|
use the mediator with that system bar.
|
||||||
|
Example: config_enableBottomNavigationBar=true
|
||||||
|
config_notificationPanelViewMediator=
|
||||||
|
com.android.systemui.car.notification.BottomNotificationPanelViewMediator -->
|
||||||
|
<string name="config_notificationPanelViewMediator" translatable="false">
|
||||||
|
com.android.systemui.car.notification.TopNotificationPanelViewMediator</string>
|
||||||
|
|
||||||
<!-- List of package names that are allowed sources of app installation. -->
|
<!-- List of package names that are allowed sources of app installation. -->
|
||||||
<string-array name="config_allowedAppInstallSources" translatable="false">
|
<string-array name="config_allowedAppInstallSources" translatable="false">
|
||||||
<item>com.android.vending</item>
|
<item>com.android.vending</item>
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.car.notification;
|
||||||
|
|
||||||
|
import com.android.systemui.car.CarDeviceProvisionedController;
|
||||||
|
import com.android.systemui.car.navigationbar.CarNavigationBarController;
|
||||||
|
import com.android.systemui.car.window.OverlayPanelViewController;
|
||||||
|
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of NotificationPanelViewMediator that sets the notification panel to be opened
|
||||||
|
* from the top navigation bar.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class BottomNotificationPanelViewMediator extends NotificationPanelViewMediator {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public BottomNotificationPanelViewMediator(
|
||||||
|
CarNavigationBarController carNavigationBarController,
|
||||||
|
NotificationPanelViewController notificationPanelViewController,
|
||||||
|
|
||||||
|
PowerManagerHelper powerManagerHelper,
|
||||||
|
|
||||||
|
CarDeviceProvisionedController carDeviceProvisionedController,
|
||||||
|
ConfigurationController configurationController
|
||||||
|
) {
|
||||||
|
super(carNavigationBarController,
|
||||||
|
notificationPanelViewController,
|
||||||
|
powerManagerHelper,
|
||||||
|
carDeviceProvisionedController,
|
||||||
|
configurationController);
|
||||||
|
notificationPanelViewController.setOverlayDirection(
|
||||||
|
OverlayPanelViewController.OVERLAY_FROM_BOTTOM_BAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerListeners() {
|
||||||
|
super.registerListeners();
|
||||||
|
getCarNavigationBarController().registerBottomBarTouchListener(
|
||||||
|
getNotificationPanelViewController().getDragOpenTouchListener());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,9 +83,9 @@ public class NotificationPanelViewController extends OverlayPanelViewController
|
|||||||
private NotificationViewController mNotificationViewController;
|
private NotificationViewController mNotificationViewController;
|
||||||
|
|
||||||
private boolean mIsTracking;
|
private boolean mIsTracking;
|
||||||
private boolean mNotificationListAtBottom;
|
private boolean mNotificationListAtEnd;
|
||||||
private float mFirstTouchDownOnGlassPane;
|
private float mFirstTouchDownOnGlassPane;
|
||||||
private boolean mNotificationListAtBottomAtTimeOfTouch;
|
private boolean mNotificationListAtEndAtTimeOfTouch;
|
||||||
private boolean mIsSwipingVerticallyToClose;
|
private boolean mIsSwipingVerticallyToClose;
|
||||||
private boolean mIsNotificationCardSwiping;
|
private boolean mIsNotificationCardSwiping;
|
||||||
|
|
||||||
@@ -233,11 +233,11 @@ public class NotificationPanelViewController extends OverlayPanelViewController
|
|||||||
// This allows us to initialize gesture listeners and detect when to close the notifications
|
// This allows us to initialize gesture listeners and detect when to close the notifications
|
||||||
glassPane.setOnTouchListener((v, event) -> {
|
glassPane.setOnTouchListener((v, event) -> {
|
||||||
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||||
mNotificationListAtBottomAtTimeOfTouch = false;
|
mNotificationListAtEndAtTimeOfTouch = false;
|
||||||
}
|
}
|
||||||
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||||
mFirstTouchDownOnGlassPane = event.getRawX();
|
mFirstTouchDownOnGlassPane = event.getRawX();
|
||||||
mNotificationListAtBottomAtTimeOfTouch = mNotificationListAtBottom;
|
mNotificationListAtEndAtTimeOfTouch = mNotificationListAtEnd;
|
||||||
// Reset the tracker when there is a touch down on the glass pane.
|
// Reset the tracker when there is a touch down on the glass pane.
|
||||||
mIsTracking = false;
|
mIsTracking = false;
|
||||||
// Pass the down event to gesture detector so that it knows where the touch event
|
// Pass the down event to gesture detector so that it knows where the touch event
|
||||||
@@ -251,34 +251,34 @@ public class NotificationPanelViewController extends OverlayPanelViewController
|
|||||||
@Override
|
@Override
|
||||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||||
super.onScrolled(recyclerView, dx, dy);
|
super.onScrolled(recyclerView, dx, dy);
|
||||||
// Check if we can scroll vertically downwards.
|
// Check if we can scroll vertically in the animation direction.
|
||||||
if (!mNotificationList.canScrollVertically(/* direction= */ 1)) {
|
if (!mNotificationList.canScrollVertically(mAnimateDirection)) {
|
||||||
mNotificationListAtBottom = true;
|
mNotificationListAtEnd = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mNotificationListAtBottom = false;
|
mNotificationListAtEnd = false;
|
||||||
mIsSwipingVerticallyToClose = false;
|
mIsSwipingVerticallyToClose = false;
|
||||||
mNotificationListAtBottomAtTimeOfTouch = false;
|
mNotificationListAtEndAtTimeOfTouch = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mNotificationList.setOnTouchListener((v, event) -> {
|
mNotificationList.setOnTouchListener((v, event) -> {
|
||||||
mIsNotificationCardSwiping = Math.abs(mFirstTouchDownOnGlassPane - event.getRawX())
|
mIsNotificationCardSwiping = Math.abs(mFirstTouchDownOnGlassPane - event.getRawX())
|
||||||
> SWIPE_MAX_OFF_PATH;
|
> SWIPE_MAX_OFF_PATH;
|
||||||
if (mNotificationListAtBottomAtTimeOfTouch && mNotificationListAtBottom) {
|
if (mNotificationListAtEndAtTimeOfTouch && mNotificationListAtEnd) {
|
||||||
// We need to save the state here as if notification card is swiping we will
|
// We need to save the state here as if notification card is swiping we will
|
||||||
// change the mNotificationListAtBottomAtTimeOfTouch. This is to protect
|
// change the mNotificationListAtEndAtTimeOfTouch. This is to protect
|
||||||
// closing the notification shade while the notification card is being swiped.
|
// closing the notification shade while the notification card is being swiped.
|
||||||
mIsSwipingVerticallyToClose = true;
|
mIsSwipingVerticallyToClose = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the card is swiping we should not allow the notification shade to close.
|
// If the card is swiping we should not allow the notification shade to close.
|
||||||
// Hence setting mNotificationListAtBottomAtTimeOfTouch to false will stop that
|
// Hence setting mNotificationListAtEndAtTimeOfTouch to false will stop that
|
||||||
// for us. We are also checking for mIsTracking because while swiping the
|
// for us. We are also checking for mIsTracking because while swiping the
|
||||||
// notification shade to close if the user goes a bit horizontal while swiping
|
// notification shade to close if the user goes a bit horizontal while swiping
|
||||||
// upwards then also this should close.
|
// upwards then also this should close.
|
||||||
if (mIsNotificationCardSwiping && !mIsTracking) {
|
if (mIsNotificationCardSwiping && !mIsTracking) {
|
||||||
mNotificationListAtBottomAtTimeOfTouch = false;
|
mNotificationListAtEndAtTimeOfTouch = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean handled = closeGestureDetector.onTouchEvent(event);
|
boolean handled = closeGestureDetector.onTouchEvent(event);
|
||||||
@@ -290,7 +290,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController
|
|||||||
}
|
}
|
||||||
if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP
|
if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP
|
||||||
&& mIsSwipingVerticallyToClose) {
|
&& mIsSwipingVerticallyToClose) {
|
||||||
if (getSettleClosePercentage() < getPercentageFromBottom() && isTracking) {
|
if (getSettleClosePercentage() < getPercentageFromEndingEdge() && isTracking) {
|
||||||
animatePanel(DEFAULT_FLING_VELOCITY, false);
|
animatePanel(DEFAULT_FLING_VELOCITY, false);
|
||||||
} else if (clippedHeight != getLayout().getHeight() && isTracking) {
|
} else if (clippedHeight != getLayout().getHeight() && isTracking) {
|
||||||
// this can be caused when user is at the end of the list and trying to
|
// this can be caused when user is at the end of the list and trying to
|
||||||
@@ -299,11 +299,11 @@ public class NotificationPanelViewController extends OverlayPanelViewController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updating the mNotificationListAtBottomAtTimeOfTouch state has to be done after
|
// Updating the mNotificationListAtEndAtTimeOfTouch state has to be done after
|
||||||
// the event has been passed to the closeGestureDetector above, such that the
|
// the event has been passed to the closeGestureDetector above, such that the
|
||||||
// closeGestureDetector sees the up event before the state has changed.
|
// closeGestureDetector sees the up event before the state has changed.
|
||||||
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||||
mNotificationListAtBottomAtTimeOfTouch = false;
|
mNotificationListAtEndAtTimeOfTouch = false;
|
||||||
}
|
}
|
||||||
return handled || isTracking;
|
return handled || isTracking;
|
||||||
});
|
});
|
||||||
@@ -377,25 +377,31 @@ public class NotificationPanelViewController extends OverlayPanelViewController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onScroll(int height) {
|
protected void onScroll(int y) {
|
||||||
if (mHandleBar != null) {
|
if (mHandleBar != null) {
|
||||||
ViewGroup.MarginLayoutParams lp =
|
ViewGroup.MarginLayoutParams lp =
|
||||||
(ViewGroup.MarginLayoutParams) mHandleBar.getLayoutParams();
|
(ViewGroup.MarginLayoutParams) mHandleBar.getLayoutParams();
|
||||||
mHandleBar.setTranslationY(height - mHandleBar.getHeight() - lp.bottomMargin);
|
// Adjust handlebar to new pointer position, and a little more depending on the
|
||||||
|
// animate direction so the bar can be seen fully.
|
||||||
|
if (mAnimateDirection > 0) {
|
||||||
|
mHandleBar.setTranslationY(y - mHandleBar.getHeight() - lp.bottomMargin);
|
||||||
|
} else {
|
||||||
|
mHandleBar.setTranslationY(y + mHandleBar.getHeight() + lp.topMargin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNotificationView.getHeight() > 0) {
|
if (mNotificationView.getHeight() > 0) {
|
||||||
Drawable background = mNotificationView.getBackground().mutate();
|
Drawable background = mNotificationView.getBackground().mutate();
|
||||||
background.setAlpha((int) (getBackgroundAlpha(height) * 255));
|
background.setAlpha((int) (getBackgroundAlpha(y) * 255));
|
||||||
mNotificationView.setBackground(background);
|
mNotificationView.setBackground(background);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldAllowClosingScroll() {
|
protected boolean shouldAllowClosingScroll() {
|
||||||
// Unless the notification list is at the bottom, the panel shouldn't be allowed to
|
// Unless the notification list is at the end, the panel shouldn't be allowed to
|
||||||
// collapse on scroll.
|
// collapse on scroll.
|
||||||
return mNotificationListAtBottomAtTimeOfTouch;
|
return mNotificationListAtEndAtTimeOfTouch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -403,9 +409,11 @@ public class NotificationPanelViewController extends OverlayPanelViewController
|
|||||||
* shade is visible to the user. When the notification shade is completely open then
|
* shade is visible to the user. When the notification shade is completely open then
|
||||||
* alpha value will be 1.
|
* alpha value will be 1.
|
||||||
*/
|
*/
|
||||||
private float getBackgroundAlpha(int height) {
|
private float getBackgroundAlpha(int y) {
|
||||||
return mInitialBackgroundAlpha
|
float fractionCovered =
|
||||||
+ ((float) height / mNotificationView.getHeight() * mBackgroundAlphaDiff);
|
((float) (mAnimateDirection > 0 ? y : mNotificationView.getHeight() - y))
|
||||||
|
/ mNotificationView.getHeight();
|
||||||
|
return mInitialBackgroundAlpha + fractionCovered * mBackgroundAlphaDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the unseen count listener. */
|
/** Sets the unseen count listener. */
|
||||||
@@ -431,13 +439,18 @@ public class NotificationPanelViewController extends OverlayPanelViewController
|
|||||||
@Override
|
@Override
|
||||||
public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
|
public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
|
||||||
float distanceY) {
|
float distanceY) {
|
||||||
calculatePercentageFromBottom(event2.getRawY());
|
calculatePercentageFromEndingEdge(event2.getRawY());
|
||||||
// To prevent the jump in the clip bounds while closing the notification shade using
|
// To prevent the jump in the clip bounds while closing the notification panel using
|
||||||
// the handle bar we should calculate the height using the diff of event1 and event2.
|
// the handle bar we should calculate the height using the diff of event1 and event2.
|
||||||
// This will help the notification shade to clip smoothly as the event2 value changes
|
// This will help the notification shade to clip smoothly as the event2 value changes
|
||||||
// as event1 value will be fixed.
|
// as event1 value will be fixed.
|
||||||
int clipHeight = getLayout().getHeight() - (int) (event1.getRawY() - event2.getRawY());
|
float diff = mAnimateDirection * (event1.getRawY() - event2.getRawY());
|
||||||
setViewClipBounds(clipHeight);
|
float y = mAnimateDirection > 0
|
||||||
|
? getLayout().getHeight() - diff
|
||||||
|
: diff;
|
||||||
|
// Ensure the position is within the overlay panel.
|
||||||
|
y = Math.max(0, Math.min(y, getLayout().getHeight()));
|
||||||
|
setViewClipBounds((int) y);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,17 +19,15 @@ package com.android.systemui.car.notification;
|
|||||||
import android.car.hardware.power.CarPowerManager;
|
import android.car.hardware.power.CarPowerManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
|
||||||
|
import androidx.annotation.CallSuper;
|
||||||
|
|
||||||
import com.android.systemui.car.CarDeviceProvisionedController;
|
import com.android.systemui.car.CarDeviceProvisionedController;
|
||||||
import com.android.systemui.car.navigationbar.CarNavigationBarController;
|
import com.android.systemui.car.navigationbar.CarNavigationBarController;
|
||||||
import com.android.systemui.car.window.OverlayViewMediator;
|
import com.android.systemui.car.window.OverlayViewMediator;
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
/** The view mediator which attaches the view controller to other elements of the system ui. */
|
/** The view mediator which attaches the view controller to other elements of the system ui. */
|
||||||
@Singleton
|
public abstract class NotificationPanelViewMediator implements OverlayViewMediator,
|
||||||
public class NotificationPanelViewMediator implements OverlayViewMediator,
|
|
||||||
ConfigurationController.ConfigurationListener {
|
ConfigurationController.ConfigurationListener {
|
||||||
|
|
||||||
private final CarNavigationBarController mCarNavigationBarController;
|
private final CarNavigationBarController mCarNavigationBarController;
|
||||||
@@ -38,7 +36,6 @@ public class NotificationPanelViewMediator implements OverlayViewMediator,
|
|||||||
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
|
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
|
||||||
private final ConfigurationController mConfigurationController;
|
private final ConfigurationController mConfigurationController;
|
||||||
|
|
||||||
@Inject
|
|
||||||
public NotificationPanelViewMediator(
|
public NotificationPanelViewMediator(
|
||||||
CarNavigationBarController carNavigationBarController,
|
CarNavigationBarController carNavigationBarController,
|
||||||
NotificationPanelViewController notificationPanelViewController,
|
NotificationPanelViewController notificationPanelViewController,
|
||||||
@@ -56,9 +53,10 @@ public class NotificationPanelViewMediator implements OverlayViewMediator,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@CallSuper
|
||||||
public void registerListeners() {
|
public void registerListeners() {
|
||||||
mCarNavigationBarController.registerTopBarTouchListener(
|
mCarNavigationBarController.registerTopBarTouchListener(
|
||||||
mNotificationPanelViewController.getDragOpenTouchListener());
|
mNotificationPanelViewController.getDragCloseTouchListener());
|
||||||
mCarNavigationBarController.registerBottomBarTouchListener(
|
mCarNavigationBarController.registerBottomBarTouchListener(
|
||||||
mNotificationPanelViewController.getDragCloseTouchListener());
|
mNotificationPanelViewController.getDragCloseTouchListener());
|
||||||
mCarNavigationBarController.registerLeftBarTouchListener(
|
mCarNavigationBarController.registerLeftBarTouchListener(
|
||||||
@@ -128,4 +126,12 @@ public class NotificationPanelViewMediator implements OverlayViewMediator,
|
|||||||
mNotificationPanelViewController.reinflate();
|
mNotificationPanelViewController.reinflate();
|
||||||
registerListeners();
|
registerListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final CarNavigationBarController getCarNavigationBarController() {
|
||||||
|
return mCarNavigationBarController;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final NotificationPanelViewController getNotificationPanelViewController() {
|
||||||
|
return mNotificationPanelViewController;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.car.notification;
|
||||||
|
|
||||||
|
import com.android.systemui.car.CarDeviceProvisionedController;
|
||||||
|
import com.android.systemui.car.navigationbar.CarNavigationBarController;
|
||||||
|
import com.android.systemui.car.window.OverlayPanelViewController;
|
||||||
|
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of NotificationPanelViewMediator that sets the notification panel to be opened
|
||||||
|
* from the top navigation bar.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class TopNotificationPanelViewMediator extends NotificationPanelViewMediator {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public TopNotificationPanelViewMediator(
|
||||||
|
CarNavigationBarController carNavigationBarController,
|
||||||
|
NotificationPanelViewController notificationPanelViewController,
|
||||||
|
|
||||||
|
PowerManagerHelper powerManagerHelper,
|
||||||
|
|
||||||
|
CarDeviceProvisionedController carDeviceProvisionedController,
|
||||||
|
ConfigurationController configurationController
|
||||||
|
) {
|
||||||
|
super(carNavigationBarController,
|
||||||
|
notificationPanelViewController,
|
||||||
|
powerManagerHelper,
|
||||||
|
carDeviceProvisionedController,
|
||||||
|
configurationController);
|
||||||
|
notificationPanelViewController.setOverlayDirection(
|
||||||
|
OverlayPanelViewController.OVERLAY_FROM_TOP_BAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerListeners() {
|
||||||
|
super.registerListeners();
|
||||||
|
getCarNavigationBarController().registerBottomBarTouchListener(
|
||||||
|
getNotificationPanelViewController().getDragOpenTouchListener());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ package com.android.systemui.car.window;
|
|||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
|
import android.annotation.IntDef;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
@@ -35,13 +36,36 @@ import com.android.systemui.car.CarDeviceProvisionedController;
|
|||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.statusbar.FlingAnimationUtils;
|
import com.android.systemui.statusbar.FlingAnimationUtils;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link OverlayPanelViewController} provides additional dragging animation capabilities to
|
* The {@link OverlayPanelViewController} provides additional dragging animation capabilities to
|
||||||
* {@link OverlayViewController}.
|
* {@link OverlayViewController}.
|
||||||
*/
|
*/
|
||||||
public abstract class OverlayPanelViewController extends OverlayViewController {
|
public abstract class OverlayPanelViewController extends OverlayViewController {
|
||||||
|
|
||||||
private static final boolean DEBUG = true;
|
/** @hide */
|
||||||
|
@IntDef(flag = true, prefix = { "OVERLAY_" }, value = {
|
||||||
|
OVERLAY_FROM_TOP_BAR,
|
||||||
|
OVERLAY_FROM_BOTTOM_BAR
|
||||||
|
})
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface OverlayDirection {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the overlay panel should be opened from the top bar and expanded by dragging
|
||||||
|
* towards the bottom bar.
|
||||||
|
*/
|
||||||
|
public static final int OVERLAY_FROM_TOP_BAR = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the overlay panel should be opened from the bottom bar and expanded by
|
||||||
|
* dragging towards the top bar.
|
||||||
|
*/
|
||||||
|
public static final int OVERLAY_FROM_BOTTOM_BAR = 1;
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
private static final String TAG = "OverlayPanelViewController";
|
private static final String TAG = "OverlayPanelViewController";
|
||||||
|
|
||||||
// used to calculate how fast to open or close the window
|
// used to calculate how fast to open or close the window
|
||||||
@@ -54,14 +78,18 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
protected static final int SWIPE_DOWN_MIN_DISTANCE = 25;
|
protected static final int SWIPE_DOWN_MIN_DISTANCE = 25;
|
||||||
protected static final int SWIPE_MAX_OFF_PATH = 75;
|
protected static final int SWIPE_MAX_OFF_PATH = 75;
|
||||||
protected static final int SWIPE_THRESHOLD_VELOCITY = 200;
|
protected static final int SWIPE_THRESHOLD_VELOCITY = 200;
|
||||||
|
private static final int POSITIVE_DIRECTION = 1;
|
||||||
|
private static final int NEGATIVE_DIRECTION = -1;
|
||||||
|
|
||||||
private final FlingAnimationUtils mFlingAnimationUtils;
|
private final FlingAnimationUtils mFlingAnimationUtils;
|
||||||
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
|
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
|
||||||
private final View.OnTouchListener mDragOpenTouchListener;
|
private final View.OnTouchListener mDragOpenTouchListener;
|
||||||
private final View.OnTouchListener mDragCloseTouchListener;
|
private final View.OnTouchListener mDragCloseTouchListener;
|
||||||
|
|
||||||
|
protected int mAnimateDirection = POSITIVE_DIRECTION;
|
||||||
|
|
||||||
private final int mSettleClosePercentage;
|
private final int mSettleClosePercentage;
|
||||||
private int mPercentageFromBottom;
|
private int mPercentageFromEndingEdge;
|
||||||
|
|
||||||
private boolean mPanelVisible;
|
private boolean mPanelVisible;
|
||||||
private boolean mPanelExpanded;
|
private boolean mPanelExpanded;
|
||||||
@@ -91,8 +119,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
mSettleClosePercentage = resources.getInteger(
|
mSettleClosePercentage = resources.getInteger(
|
||||||
R.integer.notification_settle_close_percentage);
|
R.integer.notification_settle_close_percentage);
|
||||||
|
|
||||||
// Attached to the top navigation bar (i.e. status bar) to detect pull down of the
|
// Attached to a navigation bar to open the overlay panel
|
||||||
// notification shade.
|
|
||||||
GestureDetector openGestureDetector = new GestureDetector(context,
|
GestureDetector openGestureDetector = new GestureDetector(context,
|
||||||
new OpenGestureListener() {
|
new OpenGestureListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -101,8 +128,8 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Attached to the NavBars to close the notification shade
|
// Attached to the other navigation bars to close the overlay panel
|
||||||
GestureDetector navBarCloseNotificationGestureDetector = new GestureDetector(context,
|
GestureDetector closeGestureDetector = new GestureDetector(context,
|
||||||
new SystemBarCloseGestureListener() {
|
new SystemBarCloseGestureListener() {
|
||||||
@Override
|
@Override
|
||||||
protected void close() {
|
protected void close() {
|
||||||
@@ -132,7 +159,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
if (!isInflated()) {
|
if (!isInflated()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
boolean consumed = navBarCloseNotificationGestureDetector.onTouchEvent(event);
|
boolean consumed = closeGestureDetector.onTouchEvent(event);
|
||||||
if (consumed) {
|
if (consumed) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -141,6 +168,17 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sets the overlay panel animation direction along the x or y axis. */
|
||||||
|
public void setOverlayDirection(@OverlayDirection int direction) {
|
||||||
|
if (direction == OVERLAY_FROM_TOP_BAR) {
|
||||||
|
mAnimateDirection = POSITIVE_DIRECTION;
|
||||||
|
} else if (direction == OVERLAY_FROM_BOTTOM_BAR) {
|
||||||
|
mAnimateDirection = NEGATIVE_DIRECTION;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Direction not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Toggles the visibility of the panel. */
|
/** Toggles the visibility of the panel. */
|
||||||
public void toggle() {
|
public void toggle() {
|
||||||
if (!isInflated()) {
|
if (!isInflated()) {
|
||||||
@@ -207,7 +245,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
protected void maybeCompleteAnimation(MotionEvent event) {
|
protected void maybeCompleteAnimation(MotionEvent event) {
|
||||||
if (event.getActionMasked() == MotionEvent.ACTION_UP
|
if (event.getActionMasked() == MotionEvent.ACTION_UP
|
||||||
&& isPanelVisible()) {
|
&& isPanelVisible()) {
|
||||||
if (mSettleClosePercentage < mPercentageFromBottom) {
|
if (mSettleClosePercentage < mPercentageFromEndingEdge) {
|
||||||
animatePanel(DEFAULT_FLING_VELOCITY, false);
|
animatePanel(DEFAULT_FLING_VELOCITY, false);
|
||||||
} else {
|
} else {
|
||||||
animatePanel(DEFAULT_FLING_VELOCITY, true);
|
animatePanel(DEFAULT_FLING_VELOCITY, true);
|
||||||
@@ -221,16 +259,15 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
* panel this method also makes the view invisible after animation ends.
|
* panel this method also makes the view invisible after animation ends.
|
||||||
*/
|
*/
|
||||||
protected void animatePanel(float velocity, boolean isClosing) {
|
protected void animatePanel(float velocity, boolean isClosing) {
|
||||||
float to = 0;
|
float to = getEndPosition(isClosing);
|
||||||
if (!isClosing) {
|
|
||||||
to = getLayout().getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect rect = getLayout().getClipBounds();
|
Rect rect = getLayout().getClipBounds();
|
||||||
if (rect != null && rect.bottom != to) {
|
if (rect != null) {
|
||||||
float from = rect.bottom;
|
float from = getCurrentStartPosition(rect);
|
||||||
animate(from, to, velocity, isClosing);
|
if (from != to) {
|
||||||
return;
|
animate(from, to, velocity, isClosing);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We will only be here if the shade is being opened programmatically or via button when
|
// We will only be here if the shade is being opened programmatically or via button when
|
||||||
@@ -242,12 +279,32 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
public void onGlobalLayout() {
|
public void onGlobalLayout() {
|
||||||
ViewTreeObserver obs = getLayout().getViewTreeObserver();
|
ViewTreeObserver obs = getLayout().getViewTreeObserver();
|
||||||
obs.removeOnGlobalLayoutListener(this);
|
obs.removeOnGlobalLayoutListener(this);
|
||||||
float to = getLayout().getHeight();
|
animate(
|
||||||
animate(/* from= */ 0, to, velocity, isClosing);
|
getDefaultStartPosition(),
|
||||||
|
getEndPosition(/* isClosing= */ false),
|
||||||
|
velocity,
|
||||||
|
isClosing
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the start position if the user has not started swiping. */
|
||||||
|
private int getDefaultStartPosition() {
|
||||||
|
return mAnimateDirection > 0 ? 0 : getLayout().getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the start position if we are in the middle of swiping. */
|
||||||
|
private int getCurrentStartPosition(Rect clipBounds) {
|
||||||
|
return mAnimateDirection > 0 ? clipBounds.bottom : clipBounds.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getEndPosition(boolean isClosing) {
|
||||||
|
return (mAnimateDirection > 0 && !isClosing) || (mAnimateDirection == -1 && isClosing)
|
||||||
|
? getLayout().getHeight()
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
private void animate(float from, float to, float velocity, boolean isClosing) {
|
private void animate(float from, float to, float velocity, boolean isClosing) {
|
||||||
if (mIsAnimating) {
|
if (mIsAnimating) {
|
||||||
return;
|
return;
|
||||||
@@ -356,25 +413,44 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
* Misc
|
* Misc
|
||||||
* ***************************************************************************************** */
|
* ***************************************************************************************** */
|
||||||
|
|
||||||
protected void calculatePercentageFromBottom(float height) {
|
/**
|
||||||
|
* Given the position of the pointer dragging the panel, return the percentage of its closeness
|
||||||
|
* to the ending edge.
|
||||||
|
*/
|
||||||
|
protected void calculatePercentageFromEndingEdge(float y) {
|
||||||
if (getLayout().getHeight() > 0) {
|
if (getLayout().getHeight() > 0) {
|
||||||
mPercentageFromBottom = (int) Math.abs(
|
float height = getVisiblePanelHeight(y);
|
||||||
height / getLayout().getHeight() * 100);
|
mPercentageFromEndingEdge = (int) Math.abs(height / getLayout().getHeight() * 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setViewClipBounds(int height) {
|
private float getVisiblePanelHeight(float y) {
|
||||||
if (height > getLayout().getHeight()) {
|
return mAnimateDirection > 0 ? y : getLayout().getHeight() - y;
|
||||||
height = getLayout().getHeight();
|
}
|
||||||
}
|
|
||||||
|
/** Sets the boundaries of the overlay panel that can be seen based on pointer position. */
|
||||||
|
protected void setViewClipBounds(int y) {
|
||||||
|
// Bound the pointer position to be within the overlay panel.
|
||||||
|
y = Math.max(0, Math.min(y, getLayout().getHeight()));
|
||||||
Rect clipBounds = new Rect();
|
Rect clipBounds = new Rect();
|
||||||
clipBounds.set(0, 0, getLayout().getWidth(), height);
|
int top, bottom;
|
||||||
|
if (mAnimateDirection > 0) {
|
||||||
|
top = 0;
|
||||||
|
bottom = y;
|
||||||
|
} else {
|
||||||
|
top = y;
|
||||||
|
bottom = getLayout().getHeight();
|
||||||
|
}
|
||||||
|
clipBounds.set(0, top, getLayout().getWidth(), bottom);
|
||||||
getLayout().setClipBounds(clipBounds);
|
getLayout().setClipBounds(clipBounds);
|
||||||
onScroll(height);
|
onScroll(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called while scrolling. */
|
/**
|
||||||
protected abstract void onScroll(int height);
|
* Called while scrolling, this passes the position of the clip boundary that is currently
|
||||||
|
* changing.
|
||||||
|
*/
|
||||||
|
protected abstract void onScroll(int y);
|
||||||
|
|
||||||
/* ***************************************************************************************** *
|
/* ***************************************************************************************** *
|
||||||
* Getters
|
* Getters
|
||||||
@@ -406,8 +482,8 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the percentage of the panel that is open from the bottom. */
|
/** Returns the percentage of the panel that is open from the bottom. */
|
||||||
protected final int getPercentageFromBottom() {
|
protected final int getPercentageFromEndingEdge() {
|
||||||
return mPercentageFromBottom;
|
return mPercentageFromEndingEdge;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the percentage at which we've determined whether to open or close the panel. */
|
/** Returns the percentage at which we've determined whether to open or close the panel. */
|
||||||
@@ -443,7 +519,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
|
|
||||||
// Initially the scroll starts with height being zero. This checks protects from divide
|
// Initially the scroll starts with height being zero. This checks protects from divide
|
||||||
// by zero error.
|
// by zero error.
|
||||||
calculatePercentageFromBottom(event2.getRawY());
|
calculatePercentageFromEndingEdge(event2.getRawY());
|
||||||
|
|
||||||
mIsTracking = true;
|
mIsTracking = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -453,7 +529,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onFling(MotionEvent event1, MotionEvent event2,
|
public boolean onFling(MotionEvent event1, MotionEvent event2,
|
||||||
float velocityX, float velocityY) {
|
float velocityX, float velocityY) {
|
||||||
if (velocityY > SWIPE_THRESHOLD_VELOCITY) {
|
if (mAnimateDirection * velocityY > SWIPE_THRESHOLD_VELOCITY) {
|
||||||
mOpeningVelocity = velocityY;
|
mOpeningVelocity = velocityY;
|
||||||
open();
|
open();
|
||||||
return true;
|
return true;
|
||||||
@@ -483,19 +559,14 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
|
public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
|
||||||
float distanceY) {
|
float distanceY) {
|
||||||
// should not clip while scroll to the bottom of the list.
|
|
||||||
if (!shouldAllowClosingScroll()) {
|
if (!shouldAllowClosingScroll()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
float actualNotificationHeight =
|
float y = getYPositionOfPanelEndingEdge(event1, event2);
|
||||||
getLayout().getHeight() - (event1.getRawY() - event2.getRawY());
|
|
||||||
if (actualNotificationHeight > getLayout().getHeight()) {
|
|
||||||
actualNotificationHeight = getLayout().getHeight();
|
|
||||||
}
|
|
||||||
if (getLayout().getHeight() > 0) {
|
if (getLayout().getHeight() > 0) {
|
||||||
mPercentageFromBottom = (int) Math.abs(
|
mPercentageFromEndingEdge = (int) Math.abs(
|
||||||
actualNotificationHeight / getLayout().getHeight() * 100);
|
y / getLayout().getHeight() * 100);
|
||||||
boolean isUp = distanceY > 0;
|
boolean isInClosingDirection = mAnimateDirection * distanceY > 0;
|
||||||
|
|
||||||
// This check is to figure out if onScroll was called while swiping the card at
|
// This check is to figure out if onScroll was called while swiping the card at
|
||||||
// bottom of the list. At that time we should not allow notification shade to
|
// bottom of the list. At that time we should not allow notification shade to
|
||||||
@@ -503,23 +574,37 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
// possible if a user is closing the notification shade and while swiping starts
|
// possible if a user is closing the notification shade and while swiping starts
|
||||||
// to open again but does not fling. At that time we should allow the
|
// to open again but does not fling. At that time we should allow the
|
||||||
// notification shade to close fully or else it would stuck in between.
|
// notification shade to close fully or else it would stuck in between.
|
||||||
if (Math.abs(getLayout().getHeight() - actualNotificationHeight)
|
if (Math.abs(getLayout().getHeight() - y)
|
||||||
> SWIPE_DOWN_MIN_DISTANCE && isUp) {
|
> SWIPE_DOWN_MIN_DISTANCE && isInClosingDirection) {
|
||||||
setViewClipBounds((int) actualNotificationHeight);
|
setViewClipBounds((int) y);
|
||||||
mIsTracking = true;
|
mIsTracking = true;
|
||||||
} else if (!isUp) {
|
} else if (!isInClosingDirection) {
|
||||||
setViewClipBounds((int) actualNotificationHeight);
|
setViewClipBounds((int) y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if we return true the items in RV won't be scrollable.
|
// if we return true the items in RV won't be scrollable.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To prevent the jump in the clip bounds while closing the panel we should calculate the y
|
||||||
|
* position using the diff of event1 and event2. This will help the panel clip smoothly as
|
||||||
|
* the event2 value changes while event1 value will be fixed.
|
||||||
|
* @param event1 MotionEvent that contains the position of where the event2 started.
|
||||||
|
* @param event2 MotionEvent that contains the position of where the user has scrolled to
|
||||||
|
* on the screen.
|
||||||
|
*/
|
||||||
|
private float getYPositionOfPanelEndingEdge(MotionEvent event1, MotionEvent event2) {
|
||||||
|
float diff = mAnimateDirection * (event1.getRawY() - event2.getRawY());
|
||||||
|
float y = mAnimateDirection > 0 ? getLayout().getHeight() - diff : diff;
|
||||||
|
y = Math.max(0, Math.min(y, getLayout().getHeight()));
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onFling(MotionEvent event1, MotionEvent event2,
|
public boolean onFling(MotionEvent event1, MotionEvent event2,
|
||||||
float velocityX, float velocityY) {
|
float velocityX, float velocityY) {
|
||||||
// should not fling if the touch does not start when view is at the bottom of the list.
|
// should not fling if the touch does not start when view is at the end of the list.
|
||||||
if (!shouldAllowClosingScroll()) {
|
if (!shouldAllowClosingScroll()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -528,8 +613,8 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
// swipe was not vertical or was not fast enough
|
// swipe was not vertical or was not fast enough
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean isUp = velocityY < 0;
|
boolean isInClosingDirection = mAnimateDirection * velocityY < 0;
|
||||||
if (isUp) {
|
if (isInClosingDirection) {
|
||||||
close();
|
close();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@@ -555,7 +640,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
|
public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
|
||||||
float distanceY) {
|
float distanceY) {
|
||||||
calculatePercentageFromBottom(event2.getRawY());
|
calculatePercentageFromEndingEdge(event2.getRawY());
|
||||||
setViewClipBounds((int) event2.getRawY());
|
setViewClipBounds((int) event2.getRawY());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
package com.android.systemui.car.window;
|
package com.android.systemui.car.window;
|
||||||
|
|
||||||
import com.android.systemui.car.keyguard.CarKeyguardViewMediator;
|
import com.android.systemui.car.keyguard.CarKeyguardViewMediator;
|
||||||
import com.android.systemui.car.notification.NotificationPanelViewMediator;
|
import com.android.systemui.car.notification.BottomNotificationPanelViewMediator;
|
||||||
|
import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
|
||||||
import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator;
|
import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator;
|
||||||
|
|
||||||
import dagger.Binds;
|
import dagger.Binds;
|
||||||
@@ -31,12 +32,19 @@ import dagger.multibindings.IntoMap;
|
|||||||
@Module
|
@Module
|
||||||
public abstract class OverlayWindowModule {
|
public abstract class OverlayWindowModule {
|
||||||
|
|
||||||
/** Injects NotificationPanelViewMediator. */
|
/** Injects TopNotificationPanelViewMediator. */
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@ClassKey(NotificationPanelViewMediator.class)
|
@ClassKey(TopNotificationPanelViewMediator.class)
|
||||||
public abstract OverlayViewMediator bindNotificationPanelViewMediator(
|
public abstract OverlayViewMediator bindTopNotificationPanelViewMediator(
|
||||||
NotificationPanelViewMediator notificationPanelViewMediator);
|
TopNotificationPanelViewMediator topNotificationPanelViewMediator);
|
||||||
|
|
||||||
|
/** Injects BottomNotificationPanelViewMediator. */
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ClassKey(BottomNotificationPanelViewMediator.class)
|
||||||
|
public abstract OverlayViewMediator bindBottomNotificationPanelViewMediator(
|
||||||
|
BottomNotificationPanelViewMediator bottomNotificationPanelViewMediator);
|
||||||
|
|
||||||
/** Inject into CarKeyguardViewMediator. */
|
/** Inject into CarKeyguardViewMediator. */
|
||||||
@Binds
|
@Binds
|
||||||
|
|||||||
@@ -18,13 +18,16 @@ package com.android.systemui.car.window;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Rect;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -42,6 +45,7 @@ import com.android.systemui.tests.R;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
@@ -172,6 +176,51 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase {
|
|||||||
assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isTrue();
|
assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void animateCollapsePanel_withOverlayFromTopBar_collapsesTowardsTopBar() {
|
||||||
|
mOverlayPanelViewController.inflate(mBaseLayout);
|
||||||
|
// Mock a panel that has layout size 50 and where the panel is opened.
|
||||||
|
int size = 50;
|
||||||
|
mockPanelWithSize(size);
|
||||||
|
mOverlayPanelViewController.getLayout().setClipBounds(
|
||||||
|
new Rect(0, 0, size, size));
|
||||||
|
mOverlayPanelViewController.setShouldAnimateCollapsePanel(true);
|
||||||
|
mOverlayPanelViewController.setPanelExpanded(true);
|
||||||
|
mOverlayPanelViewController.setPanelVisible(true);
|
||||||
|
mOverlayPanelViewController.setOverlayDirection(
|
||||||
|
OverlayPanelViewController.OVERLAY_FROM_TOP_BAR);
|
||||||
|
|
||||||
|
mOverlayPanelViewController.animateCollapsePanel();
|
||||||
|
|
||||||
|
ArgumentCaptor<Float> endValueCaptor = ArgumentCaptor.forClass(Float.class);
|
||||||
|
verify(mFlingAnimationUtils).apply(
|
||||||
|
any(Animator.class), anyFloat(), endValueCaptor.capture(), anyFloat());
|
||||||
|
assertThat(endValueCaptor.getValue().intValue()).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void animateCollapsePanel_withOverlayFromBottomBar_collapsesTowardsBottomBar() {
|
||||||
|
mOverlayPanelViewController.inflate(mBaseLayout);
|
||||||
|
// Mock a panel that has layout size 50 and where the panel is opened.
|
||||||
|
int size = 50;
|
||||||
|
mockPanelWithSize(size);
|
||||||
|
mOverlayPanelViewController.getLayout().setClipBounds(
|
||||||
|
new Rect(0, 0, size, size));
|
||||||
|
mOverlayPanelViewController.setShouldAnimateCollapsePanel(true);
|
||||||
|
mOverlayPanelViewController.setPanelExpanded(true);
|
||||||
|
mOverlayPanelViewController.setPanelVisible(true);
|
||||||
|
mOverlayPanelViewController.setOverlayDirection(
|
||||||
|
OverlayPanelViewController.OVERLAY_FROM_BOTTOM_BAR);
|
||||||
|
|
||||||
|
mOverlayPanelViewController.animateCollapsePanel();
|
||||||
|
|
||||||
|
ArgumentCaptor<Float> endValueCaptor = ArgumentCaptor.forClass(Float.class);
|
||||||
|
verify(mFlingAnimationUtils).apply(
|
||||||
|
any(Animator.class), anyFloat(), endValueCaptor.capture(), anyFloat());
|
||||||
|
assertThat(endValueCaptor.getValue().intValue()).isEqualTo(
|
||||||
|
mOverlayPanelViewController.getLayout().getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void animateCollapsePanel_removesWindowFocus() {
|
public void animateCollapsePanel_removesWindowFocus() {
|
||||||
mOverlayPanelViewController.inflate(mBaseLayout);
|
mOverlayPanelViewController.inflate(mBaseLayout);
|
||||||
@@ -218,6 +267,49 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase {
|
|||||||
assertThat(mOverlayPanelViewController.mOnAnimateExpandPanelCalled).isTrue();
|
assertThat(mOverlayPanelViewController.mOnAnimateExpandPanelCalled).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void animateExpandPanel_withOverlayFromTopBar_expandsToBottom() {
|
||||||
|
mOverlayPanelViewController.inflate(mBaseLayout);
|
||||||
|
// Mock a panel that has layout size 50 and where the panel is not opened.
|
||||||
|
int size = 50;
|
||||||
|
mockPanelWithSize(size);
|
||||||
|
mOverlayPanelViewController.getLayout().setClipBounds(
|
||||||
|
new Rect(0, 0, size, 0));
|
||||||
|
mOverlayPanelViewController.setShouldAnimateExpandPanel(true);
|
||||||
|
when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
|
||||||
|
mOverlayPanelViewController.setOverlayDirection(
|
||||||
|
OverlayPanelViewController.OVERLAY_FROM_TOP_BAR);
|
||||||
|
|
||||||
|
mOverlayPanelViewController.animateExpandPanel();
|
||||||
|
|
||||||
|
ArgumentCaptor<Float> endValueCaptor = ArgumentCaptor.forClass(Float.class);
|
||||||
|
verify(mFlingAnimationUtils).apply(
|
||||||
|
any(Animator.class), anyFloat(), endValueCaptor.capture(), anyFloat());
|
||||||
|
assertThat(endValueCaptor.getValue().intValue()).isEqualTo(
|
||||||
|
mOverlayPanelViewController.getLayout().getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void animateExpandPanel_withOverlayFromBottomBar_expandsToTop() {
|
||||||
|
mOverlayPanelViewController.inflate(mBaseLayout);
|
||||||
|
// Mock a panel that has layout size 50 and where the panel is not opened.
|
||||||
|
int size = 50;
|
||||||
|
mockPanelWithSize(size);
|
||||||
|
mOverlayPanelViewController.getLayout().setClipBounds(
|
||||||
|
new Rect(0, size, size, size));
|
||||||
|
mOverlayPanelViewController.setShouldAnimateExpandPanel(true);
|
||||||
|
when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
|
||||||
|
mOverlayPanelViewController.setOverlayDirection(
|
||||||
|
OverlayPanelViewController.OVERLAY_FROM_BOTTOM_BAR);
|
||||||
|
|
||||||
|
mOverlayPanelViewController.animateExpandPanel();
|
||||||
|
|
||||||
|
ArgumentCaptor<Float> endValueCaptor = ArgumentCaptor.forClass(Float.class);
|
||||||
|
verify(mFlingAnimationUtils).apply(
|
||||||
|
any(Animator.class), anyFloat(), endValueCaptor.capture(), anyFloat());
|
||||||
|
assertThat(endValueCaptor.getValue().intValue()).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void animateExpandPanel_setsPanelVisible() {
|
public void animateExpandPanel_setsPanelVisible() {
|
||||||
mOverlayPanelViewController.inflate(mBaseLayout);
|
mOverlayPanelViewController.inflate(mBaseLayout);
|
||||||
@@ -330,6 +422,10 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase {
|
|||||||
verify(mOverlayViewGlobalStateController).inflateView(mOverlayPanelViewController);
|
verify(mOverlayViewGlobalStateController).inflateView(mOverlayPanelViewController);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mockPanelWithSize(int size) {
|
||||||
|
mOverlayPanelViewController.getLayout().setLeftTopRightBottom(0, 0, size, size);
|
||||||
|
}
|
||||||
|
|
||||||
private static class TestOverlayPanelViewController extends OverlayPanelViewController {
|
private static class TestOverlayPanelViewController extends OverlayPanelViewController {
|
||||||
|
|
||||||
private boolean mShouldAnimateCollapsePanel;
|
private boolean mShouldAnimateCollapsePanel;
|
||||||
|
|||||||
Reference in New Issue
Block a user