Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d922fb6 authored by JianYang Liu's avatar JianYang Liu Committed by Jian-Yang Liu
Browse files

Updated OverlayPanelViewController to allow for showing overlay panel

from the bottom navigation bar.

Added Top and Bottom NotificationPanelViewMediators that can be used to
change the direction that the notification panel should go in.

Bug: 145827692
Test: Manual
Change-Id: I813415711f826a70cdbf4bd16e9b4f425e81e0de
parent 9b896504
Loading
Loading
Loading
Loading
+11 −1
Original line number Original line Diff line number Diff line
@@ -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>
+59 −0
Original line number Original line Diff line number Diff line
/*
 * 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());
    }
}
+41 −28
Original line number Original line Diff line number Diff line
@@ -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;
        }
        }
    }
    }
+13 −7
Original line number Original line Diff line number Diff line
@@ -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;
    }
}
}
+59 −0
Original line number Original line Diff line number Diff line
/*
 * 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());
    }
}
Loading