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

Unverified Commit 8190fb43 authored by Rashed Abdel-Tawab's avatar Rashed Abdel-Tawab Committed by Michael Bestas
Browse files

SystemUI: Add double tap to sleep gesture



Co-authored-by: default avatarAdnan Begovic <adnan@cyngn.com>
Co-authored-by: default avatarAltaf-Mahdi <altaf.mahdi@gmail.com>
Co-authored-by: default avatarArian <arian.kulmer@web.de>
Co-authored-by: default avatarBruno Martins <bgcngm@gmail.com>
Co-authored-by: default avatarDhina17 <dhinalogu@gmail.com>
Co-authored-by: default avatardianlujitao <dianlujitao@lineageos.org>
Co-authored-by: default avatarMichael W <baddaemon87@gmail.com>
Co-authored-by: default avatarpppig236 <priv@pppig236.com>
Co-authored-by: default avatarRoman Birg <roman@cyngn.com>
Co-authored-by: default avatarZhao Wei Liew <zhaoweiliew@gmail.com>
Change-Id: I7489204e348906dcf6e34fa04f2121974c22ddb9
parent 9ddf3e88
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -524,7 +524,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
                mStatusBarStateController,
                mNotificationShadeWindowController,
                mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
                mLatencyTracker, mAccessibilityManager, 0, mUpdateMonitor,
                mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
                mMetricsLogger,
                mShadeLog,
                mConfigurationController,
@@ -580,7 +580,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
                mMSDLPlayer,
                mBrightnessMirrorShowingRepository,
                new BlurConfig(0f, 0f),
                () -> mKosmos.getFakeShadeDisplaysRepository());
                () -> mKosmos.getFakeShadeDisplaysRepository(),
                mContext);
        mNotificationPanelViewController.initDependencies(
                mCentralSurfaces,
                null,
+2 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
    @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
    @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
    @Mock lateinit var configurationForwarder: ConfigurationForwarder
    @Mock private lateinit var qqsGestureListener: QQSGestureListener
    @Captor
    private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>

@@ -221,6 +222,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
                { configurationForwarder },
                brightnessMirrorShowingInteractor,
                UnconfinedTestDispatcher(),
                qqsGestureListener,
            )

        controller.setupExpandedStatusBar()
+48 −1
Original line number Diff line number Diff line
@@ -51,8 +51,11 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -61,11 +64,14 @@ import android.graphics.RenderEffect;
import android.graphics.Shader;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.os.Trace;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.MathUtils;
import android.view.Display;
import android.view.GestureDetector;
import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -214,6 +220,8 @@ import kotlinx.coroutines.flow.Flow;
import kotlinx.coroutines.flow.MutableStateFlow;
import kotlinx.coroutines.flow.StateFlow;

import lineageos.providers.LineageSettings;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -282,6 +290,7 @@ public final class NotificationPanelViewController implements
    private final ShadeHeadsUpChangedListener mOnHeadsUpChangedListener =
            new ShadeHeadsUpChangedListener();
    private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
    private final ContentObserver mDoubleTapToSleepObserver;
    private final StatusBarStateListener mStatusBarStateListener = new StatusBarStateListener();
    private final NotificationPanelView mView;
    private final VibratorHelper mVibratorHelper;
@@ -290,6 +299,7 @@ public final class NotificationPanelViewController implements
    private final ConfigurationController mConfigurationController;
    private final Provider<FlingAnimationUtils.Builder> mFlingAnimationUtilsBuilder;
    private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
    private final PowerManager mPowerManager;
    private final AccessibilityManager mAccessibilityManager;
    private final NotificationWakeUpCoordinator mWakeUpCoordinator;
    private final PulseExpansionHandler mPulseExpansionHandler;
@@ -463,6 +473,8 @@ public final class NotificationPanelViewController implements
    private final NotificationShadeDepthController mDepthController;
    private final NavigationBarController mNavigationBarController;
    private final int mDisplayId;
    private boolean mDoubleTapToSleepEnabled;
    private GestureDetector mDoubleTapGesture;

    private final KeyguardIndicationController mKeyguardIndicationController;
    private int mHeadsUpInset;
@@ -481,6 +493,7 @@ public final class NotificationPanelViewController implements
    private boolean mIsGestureNavigation;
    private int mOldLayoutDirection;

    private final ContentResolver mContentResolver;
    private float mMinFraction;

    private final KeyguardMediaController mKeyguardMediaController;
@@ -568,6 +581,7 @@ public final class NotificationPanelViewController implements

    @Inject
    public NotificationPanelViewController(NotificationPanelView view,
            @Main Handler handler,
            NotificationWakeUpCoordinator coordinator,
            PulseExpansionHandler pulseExpansionHandler,
            DynamicPrivacyController dynamicPrivacyController,
@@ -582,6 +596,7 @@ public final class NotificationPanelViewController implements
            CommandQueue commandQueue,
            VibratorHelper vibratorHelper,
            LatencyTracker latencyTracker,
            PowerManager powerManager,
            AccessibilityManager accessibilityManager,
            @DisplayId int displayId,
            KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -609,6 +624,7 @@ public final class NotificationPanelViewController implements
            QuickSettingsControllerImpl quickSettingsController,
            FragmentService fragmentService,
            IStatusBarService statusBarService,
            ContentResolver contentResolver,
            ShadeHeaderController shadeHeaderController,
            ScreenOffAnimationController screenOffAnimationController,
            LockscreenGestureLogger lockscreenGestureLogger,
@@ -642,7 +658,8 @@ public final class NotificationPanelViewController implements
            MSDLPlayer msdlPlayer,
            BrightnessMirrorShowingRepository brightnessMirrorShowingRepository,
            BlurConfig blurConfig,
            Lazy<ShadeDisplaysRepository> shadeDisplaysRepository) {
            Lazy<ShadeDisplaysRepository> shadeDisplaysRepository,
            Context context) {
        mBlurConfig = blurConfig;
        SceneContainerFlag.assertInLegacyMode();
        keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@@ -727,6 +744,7 @@ public final class NotificationPanelViewController implements
        mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
        mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
        mDepthController = notificationShadeDepthController;
        mContentResolver = contentResolver;
        mFragmentService = fragmentService;
        mStatusBarService = statusBarService;
        mSplitShadeStateController = splitShadeStateController;
@@ -736,6 +754,7 @@ public final class NotificationPanelViewController implements
        mShadeHeaderController = shadeHeaderController;
        mAnimateBack = predictiveBackAnimateShade();
        mFalsingCollector = falsingCollector;
        mPowerManager = powerManager;
        mWakeUpCoordinator = coordinator;
        mMainDispatcher = mainDispatcher;
        mAccessibilityManager = accessibilityManager;
@@ -761,6 +780,25 @@ public final class NotificationPanelViewController implements
        quickSettingsController.setFlingQsWithoutClickListener(this::onFlingQsWithoutClick);
        quickSettingsController.setExpansionHeightSetToMaxListener(this::onExpansionHeightSetToMax);
        shadeExpansionStateManager.addStateListener(this::onPanelStateChanged);
        mDoubleTapGesture = new GestureDetector(context,
                new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                if (mPowerManager != null) {
                    mPowerManager.goToSleep(e.getEventTime());
                }
                return true;
            }
        });
        mDoubleTapToSleepObserver = new ContentObserver(handler) {
            @Override
            public void onChange(boolean selfChange) {
                mDoubleTapToSleepEnabled = LineageSettings.System.getInt(mContentResolver,
                        LineageSettings.System.DOUBLE_TAP_SLEEP_GESTURE,
                        mResources.getBoolean(org.lineageos.platform.internal.R.bool.
                                config_dt2sGestureEnabledByDefault) ? 1 : 0) != 0;
            }
        };
        mConversationNotificationManager = conversationNotificationManager;
        mScreenOffAnimationController = screenOffAnimationController;
        mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
@@ -3638,6 +3676,10 @@ public final class NotificationPanelViewController implements
                mStatusBarStateListener.onStateChanged(mStatusBarStateController.getState(), true);
            }
            mConfigurationController.addCallback(mConfigurationListener);
            mContentResolver.registerContentObserver(LineageSettings.System.getUriFor(
                    LineageSettings.System.DOUBLE_TAP_SLEEP_GESTURE), false,
                    mDoubleTapToSleepObserver);
            mDoubleTapToSleepObserver.onChange(true);
            // Theme might have changed between inflating this view and attaching it to the
            // window, so
            // force a call to onThemeChanged
@@ -3648,6 +3690,7 @@ public final class NotificationPanelViewController implements

        @Override
        public void onViewDetachedFromWindow(View v) {
            mContentResolver.unregisterContentObserver(mDoubleTapToSleepObserver);
            mFragmentService.getFragmentHostManager(mView)
                    .removeTagListener(QS.TAG, mQsController.getQsFragmentListener());
            mStatusBarStateController.removeCallback(mStatusBarStateListener);
@@ -3972,6 +4015,10 @@ public final class NotificationPanelViewController implements
                return false;
            }

            if (mDoubleTapToSleepEnabled && !mPulsing && !mDozing) {
                mDoubleTapGesture.onTouchEvent(event);
            }

            // Make sure the next touch won't the blocked after the current ends.
            if (event.getAction() == MotionEvent.ACTION_UP
                    || event.getAction() == MotionEvent.ACTION_CANCEL) {
+12 −2
Original line number Diff line number Diff line
@@ -165,6 +165,9 @@ public class NotificationShadeWindowViewController implements Dumpable {
            };
    private final SystemClock mClock;

    private GestureDetector mQQSGestureHandler;
    private final QQSGestureListener mQQSGestureListener;

    @Inject
    public NotificationShadeWindowViewController(
            BlurUtils blurUtils,
@@ -206,7 +209,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
            BouncerViewBinder bouncerViewBinder,
            @ShadeDisplayAware Provider<ConfigurationForwarder> configurationForwarder,
            BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor,
            @Main CoroutineDispatcher mainDispatcher) {
            @Main CoroutineDispatcher mainDispatcher,
            QQSGestureListener qqsGestureListener) {
        mLockscreenShadeTransitionController = transitionController;
        mFalsingCollector = falsingCollector;
        mStatusBarStateController = statusBarStateController;
@@ -234,6 +238,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
        mAlternateBouncerInteractor = alternateBouncerInteractor;
        mQuickSettingsController = quickSettingsController;
        mMainDispatcher = mainDispatcher;
        mQQSGestureListener = qqsGestureListener;

        // This view is not part of the newly inflated expanded status bar.
        mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -365,6 +370,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
        mStackScrollLayout = mView.findViewById(R.id.notification_stack_scroller);
        mPulsingWakeupGestureHandler = new GestureDetector(mView.getContext(),
                mPulsingGestureListener);
        mQQSGestureHandler = new GestureDetector(mView.getContext(),
                mQQSGestureListener);
        mView.setLayoutInsetsController(mNotificationInsetsController);
        mView.setWindowRootViewKeyEventHandler(mWindowRootViewKeyEventHandler);
        mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
@@ -426,7 +433,10 @@ public class NotificationShadeWindowViewController implements Dumpable {
                }

                mFalsingCollector.onTouchEvent(ev);
                if (!SceneContainerFlag.isEnabled()) {
                mQQSGestureHandler.onTouchEvent(ev);
                // Pass touch events to the pulsing gesture listener only if it's dozing,
                // otherwise lockscreen DT2S and AOD DT2W will conflict.
                if (!SceneContainerFlag.isEnabled() && mStatusBarStateController.isDozing()) {
                    mPulsingWakeupGestureHandler.onTouchEvent(ev);
                }

+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The LineageOS 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.shade

import android.content.Context
import android.database.ContentObserver
import android.os.PowerManager
import android.view.GestureDetector
import android.view.MotionEvent
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import lineageos.providers.LineageSettings
import javax.inject.Inject

@SysUISingleton
class QQSGestureListener @Inject constructor(
        private val context: Context,
        private val falsingManager: FalsingManager,
        private val powerManager: PowerManager,
        private val statusBarStateController: StatusBarStateController,
) : GestureDetector.SimpleOnGestureListener() {

    private var doubleTapToSleepEnabled = false
    private val quickQsOffsetHeight: Int

    init {
        val contentObserver = object : ContentObserver(null) {
            override fun onChange(selfChange: Boolean) {
                doubleTapToSleepEnabled = LineageSettings.System.getInt(
                        context.contentResolver, LineageSettings.System.DOUBLE_TAP_SLEEP_GESTURE,
                        if (context.resources.getBoolean(org.lineageos.platform.internal.
                                R.bool.config_dt2sGestureEnabledByDefault)) 1 else 0) != 0
            }
        }
        context.contentResolver.registerContentObserver(
                LineageSettings.System.getUriFor(LineageSettings.System.DOUBLE_TAP_SLEEP_GESTURE),
                false, contentObserver)
        contentObserver.onChange(true)

        quickQsOffsetHeight = context.resources.getDimensionPixelSize(
                com.android.internal.R.dimen.quick_qs_offset_height)
    }

    override fun onDoubleTapEvent(e: MotionEvent): Boolean {
        // Go to sleep on double tap the QQS status bar
        if (e.actionMasked == MotionEvent.ACTION_UP &&
                !statusBarStateController.isDozing &&
                doubleTapToSleepEnabled &&
                e.getY() < quickQsOffsetHeight &&
                !falsingManager.isFalseDoubleTap
        ) {
            powerManager.goToSleep(e.getEventTime())
            return true
        }
        return false
    }

}
Loading