Add all the needed touch listeners and gesture detectors to allow for car
Test: on car product build Change-Id: Icc44cae87033383535d6a0ab13203afb14cf83e0 (cherry picked from commit 3f55c3502e120bacea38162ccbff94e462b009ed)
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
android:layout_height="@dimen/status_bar_height">
|
||||
|
||||
<include layout="@layout/car_top_navigation_bar"
|
||||
android:id="@+id/qs_car_top_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 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.
|
||||
-->
|
||||
<com.android.car.notification.CarNotificationView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/notification_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<View
|
||||
android:id="@+id/glass_pane"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:translationZ="2dp"
|
||||
/>
|
||||
|
||||
<androidx.car.widget.PagedListView
|
||||
android:id="@+id/notifications"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:orientation="vertical"
|
||||
android:theme="@style/PagedListTheme"
|
||||
app:gutter="none"
|
||||
app:itemSpacing="@dimen/item_spacing"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:scrollBarEnabled="false"
|
||||
app:showPagedListViewDivider="false"/>
|
||||
|
||||
</com.android.car.notification.CarNotificationView>
|
||||
@@ -37,8 +37,8 @@
|
||||
<color name="status_bar_background_color">#33000000</color>
|
||||
<drawable name="system_bar_background">@color/status_bar_background_color</drawable>
|
||||
|
||||
<!-- The scrim color for the background of the notifications shade. -->
|
||||
<color name="scrim_behind_color">#172026</color>
|
||||
<!-- The background color of the notification shade -->
|
||||
<color name="notification_shade_background_color">#99000000</color>
|
||||
|
||||
<!-- The color of the dividing line between grouped notifications. -->
|
||||
<color name="notification_divider_color">@*android:color/notification_action_list</color>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<string-array name="config_systemUIServiceComponents" translatable="false">
|
||||
<item>com.android.systemui.Dependency$DependencyCreator</item>
|
||||
<item>com.android.systemui.util.NotificationChannels</item>
|
||||
<item>com.android.systemui.notifications.NotificationsUI</item>
|
||||
<item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
|
||||
<item>com.android.systemui.keyguard.KeyguardViewMediator</item>
|
||||
<item>com.android.systemui.recents.Recents</item>
|
||||
@@ -52,6 +53,5 @@
|
||||
<item>com.android.systemui.globalactions.GlobalActionsComponent</item>
|
||||
<item>com.android.systemui.ScreenDecorations</item>
|
||||
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
|
||||
<item>com.android.systemui.notifications.NotificationsUI</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@@ -24,4 +24,12 @@
|
||||
<!-- If the number is negative, the feature is disabled.
|
||||
If it's zero, we switch to guest immediately as we start driving. -->
|
||||
<integer name="driving_on_keyguard_timeout_ms">30000</integer>
|
||||
|
||||
<!--Percentage of the screen height, from the bottom, that a notification panel being
|
||||
partially closed at will result in it remaining open if released-->
|
||||
<integer name="notification_settle_open_percentage">20</integer>
|
||||
<!--Percentage of the screen height, from the bottom, that a notification panel being peeked
|
||||
at will result in remaining closed the panel if released-->
|
||||
<integer name="notification_settle_close_percentage">80</integer>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -21,4 +21,7 @@
|
||||
<!--This Theme contains attributes required for components from the car support lib -->
|
||||
<style name="PagedListTheme" parent="Theme.CarSupportWrapper.NoActionBar">
|
||||
</style>
|
||||
|
||||
<style name="Theme.Notification" parent="Theme.DeviceDefault.NoActionBar.Notification">
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.systemui.notifications;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityManager;
|
||||
import android.car.Car;
|
||||
import android.car.CarNotConnectedException;
|
||||
@@ -23,29 +27,48 @@ import android.car.drivingstate.CarUxRestrictionsManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.IBinder;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.car.notification.CarNotificationListener;
|
||||
import com.android.car.notification.CarNotificationView;
|
||||
import com.android.car.notification.CarUxRestrictionManagerWrapper;
|
||||
import com.android.car.notification.NotificationClickHandlerFactory;
|
||||
import com.android.car.notification.NotificationViewController;
|
||||
import com.android.car.notification.PreprocessingManager;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.statusbar.FlingAnimationUtils;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
|
||||
/**
|
||||
* Standalone SystemUI for displaying Notifications that have been designed to be used in the car
|
||||
*/
|
||||
public class NotificationsUI extends SystemUI {
|
||||
public class NotificationsUI extends SystemUI
|
||||
implements ConfigurationController.ConfigurationListener {
|
||||
|
||||
private static final String TAG = "NotificationsUI";
|
||||
// used to calculate how fast to open or close the window
|
||||
private static final float DEFAULT_FLING_VELOCITY = 0;
|
||||
// max time a fling animation takes
|
||||
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 CarNotificationListener mCarNotificationListener;
|
||||
private CarUxRestrictionsManager mCarUxRestrictionsManager;
|
||||
private NotificationClickHandlerFactory mClickHandlerFactory;
|
||||
@@ -53,8 +76,20 @@ public class NotificationsUI extends SystemUI {
|
||||
private ViewGroup mCarNotificationWindow;
|
||||
private NotificationViewController mNotificationViewController;
|
||||
private boolean mIsShowing;
|
||||
private boolean mIsTracking;
|
||||
private boolean mNotificationListAtBottom;
|
||||
private boolean mNotificationListAtBottomAtTimeOfTouch;
|
||||
private CarUxRestrictionManagerWrapper mCarUxRestrictionManagerWrapper =
|
||||
new CarUxRestrictionManagerWrapper();
|
||||
// Used in the Notification panel touch listener
|
||||
private GestureDetector mGestureDetector;
|
||||
// Used in scrollable content of the notifications
|
||||
private GestureDetector mScrollUpDetector;
|
||||
private View mContent;
|
||||
private View.OnTouchListener mOnTouchListener;
|
||||
private FlingAnimationUtils mFlingAnimationUtils;
|
||||
private static int sSettleOpenPercentage;
|
||||
private static int sSettleClosePercentage;
|
||||
|
||||
/**
|
||||
* Inits the window that hosts the notifications and establishes the connections
|
||||
@@ -62,32 +97,41 @@ public class NotificationsUI extends SystemUI {
|
||||
*/
|
||||
@Override
|
||||
public void start() {
|
||||
sSettleOpenPercentage = mContext.getResources().getInteger(
|
||||
R.integer.notification_settle_open_percentage);
|
||||
sSettleClosePercentage = mContext.getResources().getInteger(
|
||||
R.integer.notification_settle_close_percentage);
|
||||
WindowManager windowManager =
|
||||
(WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
|
||||
mFlingAnimationUtils = new FlingAnimationUtils(mContext,
|
||||
FLING_ANIMATION_MAX_TIME, FLING_SPEED_UP_FACTOR);
|
||||
mCarNotificationListener = new CarNotificationListener();
|
||||
// create a notification click handler that closes the notification ui if the an activity
|
||||
// is launched successfully
|
||||
mClickHandlerFactory = new NotificationClickHandlerFactory(
|
||||
IStatusBarService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.STATUS_BAR_SERVICE)),
|
||||
launchResult -> {
|
||||
if (launchResult == ActivityManager.START_TASK_TO_FRONT
|
||||
|| launchResult == ActivityManager.START_SUCCESS) {
|
||||
closeCarNotifications();
|
||||
closeCarNotifications(DEFAULT_FLING_VELOCITY);
|
||||
}
|
||||
});
|
||||
mCarNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper,
|
||||
mClickHandlerFactory);
|
||||
mCar = Car.createCar(mContext, mCarConnectionListener);
|
||||
mCar.connect();
|
||||
|
||||
|
||||
mCarNotificationWindow = (ViewGroup) View.inflate(mContext,
|
||||
NotificationGestureListener gestureListener = new NotificationGestureListener();
|
||||
mGestureDetector = new GestureDetector(mContext, gestureListener);
|
||||
mScrollUpDetector = new GestureDetector(mContext, new ScrollUpDetector());
|
||||
mOnTouchListener = new NotificationPanelTouchListener();
|
||||
mCarNotificationWindow = (ViewGroup) View.inflate(new ContextThemeWrapper(mContext,
|
||||
R.style.Theme_Notification),
|
||||
R.layout.navigation_bar_window, null);
|
||||
View.inflate(mContext,
|
||||
com.android.car.notification.R.layout.notification_center_activity,
|
||||
mCarNotificationWindow);
|
||||
mCarNotificationWindow.findViewById(
|
||||
com.android.car.notification.R.id.exit_button_container)
|
||||
.setOnClickListener(v -> toggleShowingCarNotifications());
|
||||
mCarNotificationWindow
|
||||
.setBackgroundColor(mContext.getColor(R.color.notification_shade_background_color));
|
||||
|
||||
inflateNotificationContent();
|
||||
|
||||
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
@@ -101,15 +145,222 @@ public class NotificationsUI extends SystemUI {
|
||||
// start in the hidden state
|
||||
mCarNotificationWindow.setVisibility(View.GONE);
|
||||
windowManager.addView(mCarNotificationWindow, layoutParams);
|
||||
|
||||
// Add this object to the SystemUI component registry such that the status bar
|
||||
// can get a reference to it.
|
||||
putComponent(NotificationsUI.class, this);
|
||||
Dependency.get(ConfigurationController.class).addCallback(this);
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private void inflateNotificationContent() {
|
||||
if (mNotificationViewController != null) {
|
||||
mNotificationViewController.disable();
|
||||
}
|
||||
mCarNotificationWindow.removeAllViews();
|
||||
|
||||
mContent = View.inflate(new ContextThemeWrapper(mContext,
|
||||
com.android.car.notification.R.style.Theme_Notification),
|
||||
R.layout.notification_center_activity,
|
||||
mCarNotificationWindow);
|
||||
// set the click handler such that we can dismiss the UI when a notification is clicked
|
||||
CarNotificationView noteView = mCarNotificationWindow.findViewById(R.id.notification_view);
|
||||
noteView.setClickHandlerFactory(mClickHandlerFactory);
|
||||
|
||||
mContent.setOnTouchListener(mOnTouchListener);
|
||||
// set initial translation after size is calculated
|
||||
mContent.getViewTreeObserver().addOnGlobalLayoutListener(
|
||||
new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
mContent.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
if (!mIsShowing && !mIsTracking) {
|
||||
mContent.setTranslationY(mContent.getHeight() * -1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
RecyclerView notificationList = mCarNotificationWindow
|
||||
.findViewById(com.android.car.notification.R.id.recycler_view);
|
||||
// register a scroll listener so we can figure out if we are at the bottom of the
|
||||
// list of notifications
|
||||
notificationList.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
super.onScrolled(recyclerView, dx, dy);
|
||||
if (!notificationList.canScrollVertically(1)) {
|
||||
mNotificationListAtBottom = true;
|
||||
return;
|
||||
}
|
||||
mNotificationListAtBottom = false;
|
||||
mNotificationListAtBottomAtTimeOfTouch = false;
|
||||
}
|
||||
});
|
||||
// add a touch listener such that when the user scrolls up and they are at the bottom
|
||||
// of the list we can start the closing of the view.
|
||||
notificationList.setOnTouchListener(new NotificationListTouchListener());
|
||||
|
||||
// There's a view installed at a higher z-order such that we can intercept the ACTION_DOWN
|
||||
// to set the initial click state.
|
||||
mCarNotificationWindow.findViewById(R.id.glass_pane).setOnTouchListener((v, event) -> {
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||
mNotificationListAtBottomAtTimeOfTouch = false;
|
||||
}
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||
mNotificationListAtBottomAtTimeOfTouch = mNotificationListAtBottom;
|
||||
// register the down event with the gesture detectors so then know where the down
|
||||
// started. This is needed because at this point we don't know which listener
|
||||
// is going to handle scroll and fling events.
|
||||
mGestureDetector.onTouchEvent(event);
|
||||
mScrollUpDetector.onTouchEvent(event);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
mNotificationViewController = new NotificationViewController(
|
||||
mCarNotificationWindow
|
||||
.findViewById(com.android.car.notification.R.id.notification_view),
|
||||
PreprocessingManager.getInstance(mContext),
|
||||
mCarNotificationListener,
|
||||
mCarUxRestrictionManagerWrapper
|
||||
);
|
||||
// Add to the SystemUI component registry
|
||||
putComponent(NotificationsUI.class, this);
|
||||
mCarUxRestrictionManagerWrapper);
|
||||
mNotificationViewController.enable();
|
||||
}
|
||||
|
||||
// allows for day night switch
|
||||
@Override
|
||||
public void onConfigChanged(Configuration newConfig) {
|
||||
inflateNotificationContent();
|
||||
}
|
||||
|
||||
public View.OnTouchListener getDragDownListener() {
|
||||
return mOnTouchListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* This listener is attached to the notification list UI to intercept gestures if the user
|
||||
* is scrolling up when the notification list is at the bottom
|
||||
*/
|
||||
private class ScrollUpDetector extends GestureDetector.SimpleOnGestureListener {
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
return distanceY > 0;
|
||||
}
|
||||
}
|
||||
|
||||
private class NotificationListTouchListener implements View.OnTouchListener {
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
// reset mNotificationListAtBottomAtTimeOfTouch here since the "glass pane" will not
|
||||
// get the up event
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||
mNotificationListAtBottomAtTimeOfTouch = false;
|
||||
}
|
||||
boolean wasScrolledUp = mScrollUpDetector.onTouchEvent(event);
|
||||
|
||||
if (mIsTracking
|
||||
|| (mNotificationListAtBottomAtTimeOfTouch && mNotificationListAtBottom
|
||||
&& wasScrolledUp)) {
|
||||
mOnTouchListener.onTouch(v, event);
|
||||
// touch event should not be propagated further
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Touch listener installed on the notification panel. It is also used by the Nav and StatusBar
|
||||
*/
|
||||
private class NotificationPanelTouchListener implements View.OnTouchListener {
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
boolean consumed = mGestureDetector.onTouchEvent(event);
|
||||
if (consumed) {
|
||||
return true;
|
||||
}
|
||||
if (!mIsTracking || event.getActionMasked() != MotionEvent.ACTION_UP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float percentFromBottom =
|
||||
Math.abs(mContent.getTranslationY() / mContent.getHeight()) * 100;
|
||||
if (mIsShowing) {
|
||||
if (percentFromBottom < sSettleOpenPercentage) {
|
||||
// panel started to close but did not cross minimum threshold thus we open
|
||||
// it back up
|
||||
openCarNotifications(DEFAULT_FLING_VELOCITY);
|
||||
return true;
|
||||
}
|
||||
// panel was lifted more than the threshold thus we close it the rest of the way
|
||||
closeCarNotifications(DEFAULT_FLING_VELOCITY);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (percentFromBottom > sSettleClosePercentage) {
|
||||
// panel was only peeked at thus close it back up
|
||||
closeCarNotifications(DEFAULT_FLING_VELOCITY);
|
||||
return true;
|
||||
}
|
||||
// panel has been open more than threshold thus open it the rest of the way
|
||||
openCarNotifications(DEFAULT_FLING_VELOCITY);
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener called by mGestureDetector. This will be initiated from the
|
||||
* NotificationPanelTouchListener
|
||||
*/
|
||||
private class NotificationGestureListener extends GestureDetector.SimpleOnGestureListener {
|
||||
private static final int SWIPE_UP_MIN_DISTANCE = 75;
|
||||
private static final int SWIPE_DOWN_MIN_DISTANCE = 25;
|
||||
private static final int SWIPE_MAX_OFF_PATH = 75;
|
||||
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
|
||||
float distanceY) {
|
||||
mIsTracking = true;
|
||||
mCarNotificationWindow.setVisibility(View.VISIBLE);
|
||||
|
||||
mContent.setTranslationY(Math.min(mContent.getTranslationY() - distanceY, 0));
|
||||
if (mContent.getTranslationY() == 0) {
|
||||
mIsTracking = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent event1, MotionEvent event2,
|
||||
float velocityX, float velocityY) {
|
||||
if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
|
||||
|| Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
|
||||
// swipe was not vertical or was not fast enough
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isUp = velocityY < 0;
|
||||
float distanceDelta = Math.abs(event1.getY() - event2.getY());
|
||||
|
||||
if (isUp && distanceDelta > SWIPE_UP_MIN_DISTANCE) {
|
||||
// fling up
|
||||
mIsTracking = false;
|
||||
closeCarNotifications(Math.abs(velocityY));
|
||||
return true;
|
||||
|
||||
} else if (!isUp && distanceDelta > SWIPE_DOWN_MIN_DISTANCE) {
|
||||
// fling down
|
||||
mIsTracking = false;
|
||||
openCarNotifications(velocityY);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,38 +390,56 @@ public class NotificationsUI extends SystemUI {
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggles the visiblity of the notifications
|
||||
* Toggles the visibility of the notifications
|
||||
*/
|
||||
public void toggleShowingCarNotifications() {
|
||||
if (mCarNotificationWindow.getVisibility() == View.VISIBLE) {
|
||||
closeCarNotifications();
|
||||
closeCarNotifications(DEFAULT_FLING_VELOCITY);
|
||||
return;
|
||||
}
|
||||
openCarNotifications();
|
||||
openCarNotifications(DEFAULT_FLING_VELOCITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the notifications
|
||||
*/
|
||||
public void closeCarNotifications() {
|
||||
mCarNotificationWindow.setVisibility(View.GONE);
|
||||
public void closeCarNotifications(float velocityY) {
|
||||
float closedTranslation = mContent.getHeight() * -1;
|
||||
ValueAnimator animator =
|
||||
ValueAnimator.ofFloat(mContent.getTranslationY(), closedTranslation);
|
||||
animator.addUpdateListener(
|
||||
animation -> mContent.setTranslationY((Float) animation.getAnimatedValue()));
|
||||
mFlingAnimationUtils.apply(
|
||||
animator, mContent.getTranslationY(), closedTranslation, velocityY);
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mCarNotificationWindow.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
mNotificationViewController.disable();
|
||||
mIsShowing = false;
|
||||
mIsTracking = false;
|
||||
RecyclerView notificationListView = mCarNotificationWindow.findViewById(
|
||||
com.android.car.notification.R.id.recycler_view);
|
||||
notificationListView.scrollToPosition(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the notifications to visible
|
||||
*/
|
||||
public void openCarNotifications() {
|
||||
public void openCarNotifications(float velocityY) {
|
||||
mCarNotificationWindow.setVisibility(View.VISIBLE);
|
||||
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(mContent.getTranslationY(), 0);
|
||||
animator.addUpdateListener(
|
||||
animation -> mContent.setTranslationY((Float) animation.getAnimatedValue()));
|
||||
mFlingAnimationUtils.apply(animator, mContent.getTranslationY(), 0, velocityY);
|
||||
animator.start();
|
||||
|
||||
mNotificationViewController.enable();
|
||||
mIsShowing = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if notifications are currently on the screen
|
||||
*/
|
||||
public boolean isShowing() {
|
||||
return mIsShowing;
|
||||
mIsTracking = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.car;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
@@ -37,6 +38,8 @@ class CarNavigationBarView extends LinearLayout {
|
||||
private CarStatusBar mCarStatusBar;
|
||||
private Context mContext;
|
||||
private View mLockScreenButtons;
|
||||
private OnTouchListener mStatusBarWindowTouchListener;
|
||||
|
||||
|
||||
public CarNavigationBarView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@@ -62,11 +65,22 @@ class CarNavigationBarView extends LinearLayout {
|
||||
mDarkIconManager.setShouldLog(true);
|
||||
Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (mStatusBarWindowTouchListener == null) {
|
||||
return false;
|
||||
}
|
||||
// forward touch events to the status bar window so it can add a drag down
|
||||
// windows if required (Notification shade)
|
||||
mStatusBarWindowTouchListener.onTouch(this, ev);
|
||||
return false;
|
||||
}
|
||||
|
||||
void setStatusBar(CarStatusBar carStatusBar) {
|
||||
mCarStatusBar = carStatusBar;
|
||||
mStatusBarWindowTouchListener = carStatusBar.getStatusBarWindowTouchListener();
|
||||
}
|
||||
|
||||
protected void onNotificationsClick(View v) {
|
||||
|
||||
@@ -211,6 +211,7 @@ public class CarStatusBar extends StatusBar implements
|
||||
@Override
|
||||
public void showKeyguard() {
|
||||
super.showKeyguard();
|
||||
getComponent(NotificationsUI.class).closeCarNotifications(0);
|
||||
if (mNavigationBarView != null) {
|
||||
mNavigationBarView.showKeyguardButtons();
|
||||
}
|
||||
@@ -264,6 +265,12 @@ public class CarStatusBar extends StatusBar implements
|
||||
mBatteryMeterView.setVisibility(View.GONE);
|
||||
});
|
||||
addTemperatureViewToController(mStatusBarWindow);
|
||||
// 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);
|
||||
CarNavigationBarView qsTopBar = mStatusBarWindow.findViewById(R.id.qs_car_top_bar);
|
||||
qsTopBar.setStatusBar(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -339,6 +346,7 @@ public class CarStatusBar extends StatusBar implements
|
||||
lp.setTitle("CarNavigationBar");
|
||||
lp.windowAnimations = 0;
|
||||
mWindowManager.addView(mNavigationBarWindow, lp);
|
||||
mNavigationBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
|
||||
}
|
||||
if (mShowLeft) {
|
||||
int width = mContext.getResources().getDimensionPixelSize(
|
||||
@@ -458,10 +466,8 @@ public class CarStatusBar extends StatusBar implements
|
||||
|
||||
@Override
|
||||
protected View.OnTouchListener getStatusBarWindowTouchListener() {
|
||||
// Usually, a touch on the background window will dismiss the notification shade. However,
|
||||
// for the car use-case, the shade should remain unless the user switches to a different
|
||||
// facet (e.g. phone).
|
||||
return null;
|
||||
// Gets the car specific notification touch listener
|
||||
return getComponent(NotificationsUI.class).getDragDownListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user