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

Unverified Commit 58162665 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 553bb21e
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -699,7 +699,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
                mStatusBarStateController,
                mNotificationShadeWindowController,
                mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
                mLatencyTracker, mAccessibilityManager, 0, mUpdateMonitor,
                mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
                mMetricsLogger,
                mShadeLog,
                mConfigurationController,
@@ -769,7 +769,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
                mKeyguardClockPositionAlgorithm,
                mNaturalScrollingSettingObserver,
                mMSDLPlayer,
                mBrightnessMirrorShowingInteractor);
                mBrightnessMirrorShowingInteractor,
                mContext);
        mNotificationPanelViewController.initDependencies(
                mCentralSurfaces,
                null,
+2 −0
Original line number Diff line number Diff line
@@ -131,6 +131,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>

@@ -205,6 +206,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
                mock(),
                { configurationForwarder },
                brightnessMirrorShowingInteractor,
                qqsGestureListener,
            )

        controller.setupExpandedStatusBar()
+41 −2
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Color;
@@ -66,12 +67,14 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.os.Trace;
import android.os.UserManager;
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.LayoutInflater;
import android.view.MotionEvent;
@@ -247,6 +250,8 @@ import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.flow.Flow;
import kotlinx.coroutines.flow.StateFlow;

import lineageos.providers.LineageSettings;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -314,6 +319,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;
@@ -324,6 +330,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
    private final LayoutInflater mLayoutInflater;
    private final FeatureFlags mFeatureFlags;
    private final PowerManager mPowerManager;
    private final AccessibilityManager mAccessibilityManager;
    private final NotificationWakeUpCoordinator mWakeUpCoordinator;
    private final PulseExpansionHandler mPulseExpansionHandler;
@@ -364,7 +371,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    private final QuickSettingsControllerImpl mQsController;
    private final NaturalScrollingSettingObserver mNaturalScrollingSettingObserver;
    private final TouchHandler mTouchHandler = new TouchHandler();

    private long mDownTime;
    private long mStatusBarLongPressDowntime;
    private boolean mTouchSlopExceededBeforeDown;
@@ -509,6 +515,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;
@@ -689,6 +697,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
            CommandQueue commandQueue,
            VibratorHelper vibratorHelper,
            LatencyTracker latencyTracker,
            PowerManager powerManager,
            AccessibilityManager accessibilityManager,
            @DisplayId int displayId,
            KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -763,7 +772,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
            KeyguardClockPositionAlgorithm keyguardClockPositionAlgorithm,
            NaturalScrollingSettingObserver naturalScrollingSettingObserver,
            MSDLPlayer msdlPlayer,
            BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor) {
            BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor,
            Context context) {
        SceneContainerFlag.assertInLegacyMode();
        keyguardStateController.addCallback(new KeyguardStateController.Callback() {
            @Override
@@ -873,6 +883,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
        mFeatureFlags = featureFlags;
        mAnimateBack = predictiveBackAnimateShade();
        mFalsingCollector = falsingCollector;
        mPowerManager = powerManager;
        mWakeUpCoordinator = coordinator;
        mMainDispatcher = mainDispatcher;
        mAccessibilityManager = accessibilityManager;
@@ -906,6 +917,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;
@@ -4679,6 +4709,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
                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
@@ -4690,6 +4724,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());
@@ -5074,6 +5109,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) {
+12 −2
Original line number Diff line number Diff line
@@ -158,6 +158,9 @@ public class NotificationShadeWindowViewController implements Dumpable {
            };
    private final SystemClock mClock;

    private GestureDetector mQQSGestureHandler;
    private final QQSGestureListener mQQSGestureListener;

    @ExperimentalCoroutinesApi
    @Inject
    public NotificationShadeWindowViewController(
@@ -195,7 +198,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
            AlternateBouncerInteractor alternateBouncerInteractor,
            BouncerViewBinder bouncerViewBinder,
            @ShadeDisplayAware Provider<ConfigurationForwarder> configurationForwarder,
            BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor) {
            BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor,
            QQSGestureListener qqsGestureListener) {
        mLockscreenShadeTransitionController = transitionController;
        mFalsingCollector = falsingCollector;
        mStatusBarStateController = statusBarStateController;
@@ -223,6 +227,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
        mPrimaryBouncerInteractor = primaryBouncerInteractor;
        mAlternateBouncerInteractor = alternateBouncerInteractor;
        mQuickSettingsController = quickSettingsController;
        mQQSGestureListener = qqsGestureListener;

        // This view is not part of the newly inflated expanded status bar.
        mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -337,6 +342,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.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
            boolean mUseDragDownHelperForTouch = false;
@@ -399,7 +406,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