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

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

SystemUI: Add double tap to sleep gesture



Author: Roman Birg <roman@cyngn.com>
Date:   Sun Nov 23 06:54:06 2014 -0800

    SystemUI: double tap to sleep improvements

    * Make it more reliable
    * Add it to keyguard
    * Add a content observer to not always query Settings.System on every
    touch event

    Change-Id: I292c4d9d9f810843590b7a9ec6e15b99ac44009d
    Signed-off-by: default avatarRoman Birg <roman@cyngn.com>

Author: Adnan Begovic <adnan@cyngn.com>
Date:   Wed Nov 11 12:05:59 2015 -0800

    fw: Move DOUBLE_TAP_SLEEP_GESTURE to CMSettings.

    Change-Id: I8274b7c241cef6835a1114a702e68c95b6d2e036

Author: Zhao Wei Liew <zhaoweiliew@gmail.com>
Date:   Fri Oct 7 08:56:25 2016 +0800

    SystemUI: Use Tuner API for CM settings

    Get rid of all the excess code by implementing TunerService.Tunable
    and observing any changes made to the settings through it.

    Remove UserContentObserver as the Tuner API handles user switches.

    Also remove some unused imports that were introduced in earlier
    CM commits, but were never removed since.

    Change-Id: Iecafafabdaec82b3b3c72293bea865de48f0e90a

Author: Altaf-Mahdi <altaf.mahdi@gmail.com>
Date:   Wed Nov 11 16:07:49 2015 -0500

    Double tap to sleep anywhere on the lock screen [1/3]

    Change-Id: I7dd46f3fafeb2e629974c0f32083d4d9774fb1de
    [neo: Using Tuner API.]
    Signed-off-by: default avatarPranav Vashi <neobuddy89@gmail.com>

Author: dianlujitao <dianlujitao@lineageos.org>
Date:   Thu Feb 27 12:57:07 2020 +0800

    SystemUI: Don't sleep on double tap below status bar

    Change-Id: Ic64c29eae63e96f34dc37cda355401b7e2cd2d39

Author: Arian <arian.kulmer@web.de>
Date:   2020-12-27 14:35:33 +0100

    NotificationPanelViewController: Fix DT2S gesture handling

    Change-Id: I9f2d3c63d397c998bea5137f747a9ad95ae2c746

Author:     maxwen <max.weninger@gmail.com>
AuthorDate: Mon Nov 18 00:29:15 2019 +0100

    SystemUI: use DOUBLE_TAP_TO_WAKE setting also for wake from aod

    Co-authored-by: default avatarMichael W <baddaemon87@gmail.com>
    Change-Id: Ib51fdeaaa9a1b18b79f4f311c65565352d909a72

Author:     Dhina17 <dhinalogu@gmail.com>
AuthorDate: Tue Sep 12 11:08:28 2023 +0530

    SystemUI: Move DT2S from PulsingGestureListener

    PulsingGestureListener should handle the touch events in the
    dozing state (AOD/ambient).
    Our DT2S should work in non-dozing mode so move out from here.

    Test:
    Double tap to sleep on QQS status bar works fine as before.

    Change-Id: Ia79df2eb73e54d8b0dcb1d10b18539f4e88a0a18

Author:     Dhina17 <dhinalogu@gmail.com>
AuthorDate: Mon Sep 11 16:24:24 2023 +0530

    SystemUI: Pass touch events to pulsing gesture listener only if dozing

    PulsingGestureListener should handle touch events only in the
    dozing state (AOD/ambient).

    Otherwise lockscreen DT2S and AOD DT2W will be in conflict.

    Explanation:
    Enable AOD, DT2W and DT2S in the display settings.

    In the scenerio, touch events are passed to
    first NotificationPanelView then NotificationShadeWindowView.

    So first NotificationPanelView(Controller) detects the double tap
    and put the screen to sleep (hence dozing = true).
    Then as the NotificationShadeWindowView(Controller) detects the double tap at dozing,
    it wakes up from the AOD immediately [from PulsingGestureListener].

    so it won't let the screen to sleep on double tap the lockscreen
    when AOD and DT2W are available.

    PulsingGestureListener is supposed to receive touch events only in
    the dozing state, so it won't cause this conflict.

    Test:
    - Enable AOD, DT2W and DT2S in the display settings
    - Double tap in the lockscreen, it will go to AOD screen.

    Change-Id: I6ede700e690ad4c37fea64419cfe8a53d64a9e9a

Author: Bruno Martins <bgcngm@gmail.com>
Date:   Fri Oct 13 14:04:00 2023 +0100

    SystemUI: Respect status bar DT2S gesture defaults

    Feature can be disabled by default, but if additionally the preference
    is hidden in Settings, it doesn't allow TunerService to set the proper
    default.

    Change-Id: I12b37335fba12cf4d5564f1aa19c5e4cf19f8775

[Pig]: Forward port to R
[bgcngm]: Forward port to S

Co-authored-by: default avatarMichael W <baddaemon87@gmail.com>
Change-Id: I7489204e348906dcf6e34fa04f2121974c22ddb9
parent 21c364e9
Loading
Loading
Loading
Loading
+37 −1
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.StatusBarManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Color;
@@ -71,6 +72,7 @@ import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.MathUtils;
import android.view.GestureDetector;
import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
import android.view.LayoutInflater;
@@ -229,6 +231,8 @@ import com.android.systemui.util.Utils;
import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.animation.FlingAnimationUtils;

import lineageos.providers.LineageSettings;

import kotlin.Unit;

import java.io.PrintWriter;
@@ -309,6 +313,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
            new ShadeHeadsUpChangedListener();
    private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
    private final SettingsChangeObserver mSettingsChangeObserver;
    private final ContentObserver mDoubleTapToSleepObserver;
    private final StatusBarStateListener mStatusBarStateListener = new StatusBarStateListener();
    private final NotificationPanelView mView;
    private final VibratorHelper mVibratorHelper;
@@ -503,6 +508,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    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;
@@ -774,7 +781,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
            ActivityStarter activityStarter,
            KeyguardViewConfigurator keyguardViewConfigurator,
            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
            KeyguardRootView keyguardRootView) {
            KeyguardRootView keyguardRootView,
            Context context) {
        keyguardStateController.addCallback(new KeyguardStateController.Callback() {
            @Override
            public void onKeyguardFadingAwayChanged() {
@@ -913,6 +921,25 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
        });
        mBottomAreaShadeAlphaAnimator.setDuration(160);
        mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
        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;
        mAuthController = authController;
        mLockIconViewController = lockIconViewController;
@@ -4655,6 +4682,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
            mStatusBarStateController.addCallback(mStatusBarStateListener);
            mStatusBarStateListener.onStateChanged(mStatusBarStateController.getState());
            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
@@ -4666,6 +4697,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump

        @Override
        public void onViewDetachedFromWindow(View v) {
            mContentResolver.unregisterContentObserver(mDoubleTapToSleepObserver);
            mContentResolver.unregisterContentObserver(mSettingsChangeObserver);
            mFragmentService.getFragmentHostManager(mView)
                    .removeTagListener(QS.TAG, mQsController.getQsFragmentListener());
@@ -5019,6 +5051,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
                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) {
+14 −2
Original line number Diff line number Diff line
@@ -138,6 +138,9 @@ public class NotificationShadeWindowViewController {
            };
    private final SystemClock mClock;

    private GestureDetector mQQSGestureHandler;
    private final QQSGestureListener mQQSGestureListener;

    @Inject
    public NotificationShadeWindowViewController(
            LockscreenShadeTransitionController transitionController,
@@ -173,7 +176,8 @@ public class NotificationShadeWindowViewController {
            SystemClock clock,
            BouncerMessageInteractor bouncerMessageInteractor,
            BouncerLogger bouncerLogger,
            KeyEventInteractor keyEventInteractor) {
            KeyEventInteractor keyEventInteractor,
            QQSGestureListener qqsGestureListener) {
        mLockscreenShadeTransitionController = transitionController;
        mFalsingCollector = falsingCollector;
        mStatusBarStateController = statusBarStateController;
@@ -200,6 +204,7 @@ public class NotificationShadeWindowViewController {
        mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);
        mFeatureFlags = featureFlags;
        mKeyEventInteractor = keyEventInteractor;
        mQQSGestureListener = qqsGestureListener;

        // This view is not part of the newly inflated expanded status bar.
        mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -248,6 +253,8 @@ public class NotificationShadeWindowViewController {
        mStackScrollLayout = mView.findViewById(R.id.notification_stack_scroller);
        mPulsingWakeupGestureHandler = new GestureDetector(mView.getContext(),
                mPulsingGestureListener);
        mQQSGestureHandler = new GestureDetector(mView.getContext(),
                mQQSGestureListener);
        if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
            mDreamingWakeupGestureHandler = new GestureDetector(mView.getContext(),
                    mLockscreenHostedDreamGestureListener);
@@ -311,7 +318,12 @@ public class NotificationShadeWindowViewController {
                }

                mFalsingCollector.onTouchEvent(ev);
                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 (mStatusBarStateController.isDozing()) {
                    mPulsingWakeupGestureHandler.onTouchEvent(ev);
                }
                if (mDreamingWakeupGestureHandler != null
                        && mDreamingWakeupGestureHandler.onTouchEvent(ev)) {
                    return logDownDispatch(ev, "dream wakeup gesture handled", true);
+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
    }

}
+2 −1
Original line number Diff line number Diff line
@@ -652,7 +652,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
                mActivityStarter,
                mKeyguardViewConfigurator,
                mKeyguardFaceAuthInteractor,
                mKeyguardRootView);
                mKeyguardRootView,
                mContext);
        mNotificationPanelViewController.initDependencies(
                mCentralSurfaces,
                null,
+2 −0
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
    lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
    @Mock lateinit var keyEventInteractor: KeyEventInteractor
    private val notificationExpansionRepository = NotificationExpansionRepository()
    @Mock private lateinit var qqsGestureListener: QQSGestureListener

    private lateinit var fakeClock: FakeSystemClock
    private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
@@ -195,6 +196,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
                    ),
                    BouncerLogger(logcatLogBuffer("BouncerLog")),
                    keyEventInteractor,
                    qqsGestureListener,
            )
        underTest.setupExpandedStatusBar()

Loading