Allow nav bar to consume touch events based on configuration
This is particularly useful for OEMs that want to ensure that OEMs can override the touch behavior of the system bars without impacting the notification panel touch behavior. Bug: 150613278 Test: manual, atest CarNavigationBarViewTest Change-Id: Icb5ae3388f4004b4f465e9a9e85e8d175bbe7d78
This commit is contained in:
@@ -32,6 +32,10 @@
|
||||
<!-- Disable normal notification rendering; we handle that ourselves -->
|
||||
<bool name="config_renderNotifications">false</bool>
|
||||
|
||||
<!-- Whether navigationBar touch events should be consumed before reaching the CarFacetButton \
|
||||
when the notification panel is open. -->
|
||||
<bool name="config_consumeNavigationBarTouchWhenNotificationPanelOpen">false</bool>
|
||||
|
||||
<!-- Whether heads-up notifications should be shown when shade is open. -->
|
||||
<bool name="config_enableHeadsUpNotificationWhenNotificationShadeOpen">true</bool>
|
||||
<!-- Whether heads-up notifications should be shown on the bottom. If false, heads-up
|
||||
|
||||
@@ -599,6 +599,11 @@ public class NotificationPanelViewController extends OverlayViewController {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns {@code true} if the notification panel is expanded. */
|
||||
public boolean isPanelExpanded() {
|
||||
return mPanelExpanded;
|
||||
}
|
||||
|
||||
/** Sets the unseen count listener. */
|
||||
public void setOnUnseenCountUpdateListener(OnUnseenCountUpdateListener listener) {
|
||||
mUnseenCountUpdateListener = listener;
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.car.hardware.power.CarPowerManager;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import com.android.systemui.car.CarDeviceProvisionedController;
|
||||
import com.android.systemui.car.CarServiceProvider;
|
||||
import com.android.systemui.navigationbar.car.CarNavigationBarController;
|
||||
import com.android.systemui.statusbar.car.PowerManagerHelper;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
@@ -36,7 +35,6 @@ public class NotificationPanelViewMediator implements OverlayViewMediator,
|
||||
|
||||
private final CarNavigationBarController mCarNavigationBarController;
|
||||
private final NotificationPanelViewController mNotificationPanelViewController;
|
||||
private final CarServiceProvider mCarServiceProvider;
|
||||
private final PowerManagerHelper mPowerManagerHelper;
|
||||
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
|
||||
private final ConfigurationController mConfigurationController;
|
||||
@@ -46,7 +44,6 @@ public class NotificationPanelViewMediator implements OverlayViewMediator,
|
||||
CarNavigationBarController carNavigationBarController,
|
||||
NotificationPanelViewController notificationPanelViewController,
|
||||
|
||||
CarServiceProvider carServiceProvider,
|
||||
PowerManagerHelper powerManagerHelper,
|
||||
|
||||
CarDeviceProvisionedController carDeviceProvisionedController,
|
||||
@@ -54,7 +51,6 @@ public class NotificationPanelViewMediator implements OverlayViewMediator,
|
||||
) {
|
||||
mCarNavigationBarController = carNavigationBarController;
|
||||
mNotificationPanelViewController = notificationPanelViewController;
|
||||
mCarServiceProvider = carServiceProvider;
|
||||
mPowerManagerHelper = powerManagerHelper;
|
||||
mCarDeviceProvisionedController = carDeviceProvisionedController;
|
||||
mConfigurationController = configurationController;
|
||||
@@ -72,7 +68,17 @@ public class NotificationPanelViewMediator implements OverlayViewMediator,
|
||||
mNotificationPanelViewController.getNavBarNotificationTouchListener());
|
||||
|
||||
mCarNavigationBarController.registerNotificationController(
|
||||
() -> mNotificationPanelViewController.toggle());
|
||||
new CarNavigationBarController.NotificationsShadeController() {
|
||||
@Override
|
||||
public void togglePanel() {
|
||||
mNotificationPanelViewController.toggle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNotificationPanelOpen() {
|
||||
return mNotificationPanelViewController.isPanelExpanded();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -314,6 +314,9 @@ public class CarNavigationBarController {
|
||||
public interface NotificationsShadeController {
|
||||
/** Toggles the visibility of the notifications shade. */
|
||||
void togglePanel();
|
||||
|
||||
/** Returns {@code true} if the panel is open. */
|
||||
boolean isNotificationPanelOpen();
|
||||
}
|
||||
|
||||
private void checkAllBars(boolean isSetUp) {
|
||||
|
||||
@@ -35,10 +35,11 @@ import com.android.systemui.statusbar.phone.StatusBarIconController;
|
||||
* in a linear layout.
|
||||
*/
|
||||
public class CarNavigationBarView extends LinearLayout {
|
||||
private final boolean mConsumeTouchWhenPanelOpen;
|
||||
|
||||
private View mNavButtons;
|
||||
private CarNavigationButton mNotificationsButton;
|
||||
private NotificationsShadeController mNotificationsShadeController;
|
||||
private Context mContext;
|
||||
private View mLockScreenButtons;
|
||||
// used to wire in open/close gestures for notifications
|
||||
private OnTouchListener mStatusBarWindowTouchListener;
|
||||
@@ -46,7 +47,8 @@ public class CarNavigationBarView extends LinearLayout {
|
||||
|
||||
public CarNavigationBarView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
mConsumeTouchWhenPanelOpen = getResources().getBoolean(
|
||||
R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,9 +79,16 @@ public class CarNavigationBarView extends LinearLayout {
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (mStatusBarWindowTouchListener != null) {
|
||||
boolean shouldConsumeEvent = mNotificationsShadeController == null ? false
|
||||
: mNotificationsShadeController.isNotificationPanelOpen();
|
||||
|
||||
// Forward touch events to the status bar window so it can drag
|
||||
// windows if required (Notification shade)
|
||||
mStatusBarWindowTouchListener.onTouch(this, ev);
|
||||
|
||||
if (mConsumeTouchWhenPanelOpen && shouldConsumeEvent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<com.android.systemui.navigationbar.car.CarNavigationBarView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/system_bar_background"
|
||||
android:orientation="vertical">
|
||||
<!--The 20dp padding is the difference between the background selected icon size and the ripple
|
||||
that was chosen, thus it's a hack to make it look pretty and not an official margin value-->
|
||||
<LinearLayout
|
||||
android:id="@id/nav_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:gravity="center">
|
||||
|
||||
<com.android.systemui.navigationbar.car.CarNavigationButton
|
||||
android:id="@+id/home"
|
||||
style="@style/NavigationBarButton"
|
||||
systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
|
||||
systemui:icon="@drawable/car_ic_overview"
|
||||
systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
|
||||
systemui:selectedIcon="@drawable/car_ic_overview_selected"
|
||||
systemui:highlightWhenSelected="true"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/lock_screen_nav_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="@dimen/car_keyline_1"
|
||||
android:paddingEnd="@dimen/car_keyline_1"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
</com.android.systemui.navigationbar.car.CarNavigationBarView>
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.navigationbar.car;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
@SmallTest
|
||||
public class CarNavigationBarViewTest extends SysuiTestCase {
|
||||
|
||||
private CarNavigationBarView mNavBarView;
|
||||
|
||||
@Mock
|
||||
private CarNavigationBarController.NotificationsShadeController mNotificationsShadeController;
|
||||
|
||||
@Mock
|
||||
private View.OnTouchListener mNavBarTouchListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
getContext().getOrCreateTestableResources().addOverride(
|
||||
R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatchTouch_shadeOpen_flagOff_doesNotConsumeTouch() {
|
||||
getContext().getOrCreateTestableResources().addOverride(
|
||||
R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen, false);
|
||||
when(mNotificationsShadeController.isNotificationPanelOpen()).thenReturn(true);
|
||||
mNavBarView = (CarNavigationBarView) LayoutInflater.from(getContext()).inflate(
|
||||
R.layout.car_navigation_bar_view_test, /* root= */ null);
|
||||
mNavBarView.setNotificationsPanelController(mNotificationsShadeController);
|
||||
mNavBarView.setStatusBarWindowTouchListener(mNavBarTouchListener);
|
||||
|
||||
boolean consume = mNavBarView.onInterceptTouchEvent(
|
||||
MotionEvent.obtain(/* downTime= */ 200, /* eventTime= */ 300,
|
||||
MotionEvent.ACTION_MOVE, mNavBarView.getX(),
|
||||
mNavBarView.getY(), /* metaState= */ 0));
|
||||
|
||||
assertThat(consume).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatchTouch_shadeOpen_flagOn_consumesTouch() {
|
||||
getContext().getOrCreateTestableResources().addOverride(
|
||||
R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen, true);
|
||||
when(mNotificationsShadeController.isNotificationPanelOpen()).thenReturn(true);
|
||||
mNavBarView = (CarNavigationBarView) LayoutInflater.from(getContext()).inflate(
|
||||
R.layout.car_navigation_bar_view_test, /* root= */ null);
|
||||
mNavBarView.setNotificationsPanelController(mNotificationsShadeController);
|
||||
mNavBarView.setStatusBarWindowTouchListener(mNavBarTouchListener);
|
||||
|
||||
boolean consume = mNavBarView.onInterceptTouchEvent(
|
||||
MotionEvent.obtain(/* downTime= */ 200, /* eventTime= */ 300,
|
||||
MotionEvent.ACTION_MOVE, mNavBarView.getX(),
|
||||
mNavBarView.getY(), /* metaState= */ 0));
|
||||
|
||||
assertThat(consume).isTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user