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

Commit 2e418b21 authored by Caitlin Cassidy's avatar Caitlin Cassidy Committed by Android (Google) Code Review
Browse files

Merge "[Media TTT] Hide the chip if the user taps the screen."

parents dac4c250 4e3e7af4
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import androidx.annotation.VisibleForTesting
import com.android.internal.widget.CachingIconView
import com.android.internal.widget.CachingIconView
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.gesture.TapGestureDetector
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.DelayableExecutor


/**
/**
@@ -42,6 +43,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
    internal val context: Context,
    internal val context: Context,
    private val windowManager: WindowManager,
    private val windowManager: WindowManager,
    @Main private val mainExecutor: DelayableExecutor,
    @Main private val mainExecutor: DelayableExecutor,
    private val tapGestureDetector: TapGestureDetector,
    @LayoutRes private val chipLayoutRes: Int
    @LayoutRes private val chipLayoutRes: Int
) {
) {
    /** The window layout parameters we'll use when attaching the view to a window. */
    /** The window layout parameters we'll use when attaching the view to a window. */
@@ -82,6 +84,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(


        // Add view if necessary
        // Add view if necessary
        if (oldChipView == null) {
        if (oldChipView == null) {
            tapGestureDetector.addOnGestureDetectedCallback(TAG, this::removeChip)
            windowManager.addView(chipView, windowLayoutParams)
            windowManager.addView(chipView, windowLayoutParams)
        }
        }


@@ -96,6 +99,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
        //  TransferTriggered state: Once the user has initiated the transfer, they should be able
        //  TransferTriggered state: Once the user has initiated the transfer, they should be able
        //  to move away from the receiver device but still see the status of the transfer.
        //  to move away from the receiver device but still see the status of the transfer.
        if (chipView == null) { return }
        if (chipView == null) { return }
        tapGestureDetector.removeOnGestureDetectedCallback(TAG)
        windowManager.removeView(chipView)
        windowManager.removeView(chipView)
        chipView = null
        chipView = null
    }
    }
@@ -128,5 +132,6 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
// Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
// Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
// UpdateMediaTapToTransferReceiverDisplayTest
// UpdateMediaTapToTransferReceiverDisplayTest
private const val WINDOW_TITLE = "Media Transfer Chip View"
private const val WINDOW_TITLE = "Media Transfer Chip View"
private val TAG = MediaTttChipControllerCommon::class.simpleName!!
@VisibleForTesting
@VisibleForTesting
const val TIMEOUT_MILLIS = 3000L
const val TIMEOUT_MILLIS = 3000L
+3 −1
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.gesture.TapGestureDetector
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.DelayableExecutor
import javax.inject.Inject
import javax.inject.Inject


@@ -43,9 +44,10 @@ class MediaTttChipControllerReceiver @Inject constructor(
    context: Context,
    context: Context,
    windowManager: WindowManager,
    windowManager: WindowManager,
    mainExecutor: DelayableExecutor,
    mainExecutor: DelayableExecutor,
    tapGestureDetector: TapGestureDetector,
    @Main private val mainHandler: Handler,
    @Main private val mainHandler: Handler,
) : MediaTttChipControllerCommon<ChipStateReceiver>(
) : MediaTttChipControllerCommon<ChipStateReceiver>(
    context, windowManager, mainExecutor, R.layout.media_ttt_chip_receiver
    context, windowManager, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip_receiver
) {
) {
    private val commandQueueCallbacks = object : CommandQueue.Callbacks {
    private val commandQueueCallbacks = object : CommandQueue.Callbacks {
        override fun updateMediaTapToTransferReceiverDisplay(
        override fun updateMediaTapToTransferReceiverDisplay(
+4 −2
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.gesture.TapGestureDetector
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.DelayableExecutor
import javax.inject.Inject
import javax.inject.Inject


@@ -42,9 +43,10 @@ class MediaTttChipControllerSender @Inject constructor(
    commandQueue: CommandQueue,
    commandQueue: CommandQueue,
    context: Context,
    context: Context,
    windowManager: WindowManager,
    windowManager: WindowManager,
    @Main private val mainExecutor: DelayableExecutor,
    @Main mainExecutor: DelayableExecutor,
    tapGestureDetector: TapGestureDetector,
) : MediaTttChipControllerCommon<ChipStateSender>(
) : MediaTttChipControllerCommon<ChipStateSender>(
    context, windowManager, mainExecutor,  R.layout.media_ttt_chip
    context, windowManager, mainExecutor,  tapGestureDetector, R.layout.media_ttt_chip
) {
) {
    private val commandQueueCallbacks = object : CommandQueue.Callbacks {
    private val commandQueueCallbacks = object : CommandQueue.Callbacks {
        override fun updateMediaTapToTransferSenderDisplay(
        override fun updateMediaTapToTransferSenderDisplay(
+102 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 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.statusbar.gesture

import android.annotation.CallSuper
import android.os.Looper
import android.view.Choreographer
import android.view.Display
import android.view.InputEvent
import com.android.systemui.shared.system.InputChannelCompat
import com.android.systemui.shared.system.InputMonitorCompat

/**
 * An abstract class to help detect gestures that occur anywhere on the display (not specific to a
 * certain view).
 *
 * This class handles starting/stopping the gesture detection system as well as
 * registering/unregistering callbacks for when gestures occur. Note that the class will only listen
 * for gestures when there's at least one callback registered.
 *
 * Subclasses should implement [onInputEvent] to detect their specific gesture. Once a specific
 * gesture is detected, they should call [onGestureDetected] (which will notify the callbacks).
 */
abstract class GenericGestureDetector(
    private val tag: String
) {
    /**
     * Active callbacks, each associated with a tag. Gestures will only be monitored if
     * [callbacks.size] > 0.
     */
    private val callbacks: MutableMap<String, () -> Unit> = mutableMapOf()

    private var inputMonitor: InputMonitorCompat? = null
    private var inputReceiver: InputChannelCompat.InputEventReceiver? = null

    /** Adds a callback that will be triggered when the tap gesture is detected. */
    fun addOnGestureDetectedCallback(tag: String, callback: () -> Unit) {
        val callbacksWasEmpty = callbacks.isEmpty()
        callbacks[tag] = callback
        if (callbacksWasEmpty) {
            startGestureListening()
        }
    }

    /** Removes the callback. */
    fun removeOnGestureDetectedCallback(tag: String) {
        callbacks.remove(tag)
        if (callbacks.isEmpty()) {
            stopGestureListening()
        }
    }

    /** Triggered each time a touch event occurs (and at least one callback is registered). */
    abstract fun onInputEvent(ev: InputEvent)

    /** Should be called by subclasses when their specific gesture is detected. */
    internal fun onGestureDetected() {
        callbacks.values.forEach { it.invoke() }
    }

    /** Start listening to touch events. */
    @CallSuper
    internal open fun startGestureListening() {
        stopGestureListening()

        inputMonitor = InputMonitorCompat(tag, Display.DEFAULT_DISPLAY).also {
            inputReceiver = it.getInputReceiver(
                Looper.getMainLooper(),
                Choreographer.getInstance(),
                this::onInputEvent
            )
        }
    }

    /** Stop listening to touch events. */
    @CallSuper
    internal open fun stopGestureListening() {
        inputMonitor?.let {
            inputMonitor = null
            it.dispose()
        }
        inputReceiver?.let {
            inputReceiver = null
            it.dispose()
        }
    }
}
+12 −58
Original line number Original line Diff line number Diff line
@@ -17,15 +17,13 @@
package com.android.systemui.statusbar.gesture
package com.android.systemui.statusbar.gesture


import android.content.Context
import android.content.Context
import android.os.Looper
import android.view.Choreographer
import android.view.Display
import android.view.InputEvent
import android.view.InputEvent
import android.view.MotionEvent
import android.view.MotionEvent
import android.view.MotionEvent.*
import android.view.MotionEvent.ACTION_CANCEL
import android.view.MotionEvent.ACTION_DOWN
import android.view.MotionEvent.ACTION_MOVE
import android.view.MotionEvent.ACTION_UP
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shared.system.InputChannelCompat
import com.android.systemui.shared.system.InputMonitorCompat
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
import javax.inject.Inject


@@ -38,43 +36,17 @@ open class SwipeStatusBarAwayGestureHandler @Inject constructor(
    context: Context,
    context: Context,
    private val statusBarWindowController: StatusBarWindowController,
    private val statusBarWindowController: StatusBarWindowController,
    private val logger: SwipeStatusBarAwayGestureLogger
    private val logger: SwipeStatusBarAwayGestureLogger
) {
) : GenericGestureDetector(SwipeStatusBarAwayGestureHandler::class.simpleName!!) {

    /**
     * Active callbacks, each associated with a tag. Gestures will only be monitored if
     * [callbacks.size] > 0.
     */
    private val callbacks: MutableMap<String, () -> Unit> = mutableMapOf()


    private var startY: Float = 0f
    private var startY: Float = 0f
    private var startTime: Long = 0L
    private var startTime: Long = 0L
    private var monitoringCurrentTouch: Boolean = false
    private var monitoringCurrentTouch: Boolean = false


    private var inputMonitor: InputMonitorCompat? = null
    private var inputReceiver: InputChannelCompat.InputEventReceiver? = null

    private var swipeDistanceThreshold: Int = context.resources.getDimensionPixelSize(
    private var swipeDistanceThreshold: Int = context.resources.getDimensionPixelSize(
        com.android.internal.R.dimen.system_gestures_start_threshold
        com.android.internal.R.dimen.system_gestures_start_threshold
    )
    )


    /** Adds a callback that will be triggered when the swipe away gesture is detected. */
    override fun onInputEvent(ev: InputEvent) {
    fun addOnGestureDetectedCallback(tag: String, callback: () -> Unit) {
        val callbacksWasEmpty = callbacks.isEmpty()
        callbacks[tag] = callback
        if (callbacksWasEmpty) {
            startGestureListening()
        }
    }

    /** Removes the callback. */
    fun removeOnGestureDetectedCallback(tag: String) {
        callbacks.remove(tag)
        if (callbacks.isEmpty()) {
             stopGestureListening()
        }
    }

    private fun onInputEvent(ev: InputEvent) {
        if (ev !is MotionEvent) {
        if (ev !is MotionEvent) {
            return
            return
        }
        }
@@ -108,7 +80,7 @@ open class SwipeStatusBarAwayGestureHandler @Inject constructor(
                ) {
                ) {
                    monitoringCurrentTouch = false
                    monitoringCurrentTouch = false
                    logger.logGestureDetected(ev.y.toInt())
                    logger.logGestureDetected(ev.y.toInt())
                    callbacks.values.forEach { it.invoke() }
                    onGestureDetected()
                }
                }
            }
            }
            ACTION_CANCEL, ACTION_UP -> {
            ACTION_CANCEL, ACTION_UP -> {
@@ -120,33 +92,15 @@ open class SwipeStatusBarAwayGestureHandler @Inject constructor(
        }
        }
    }
    }


    /** Start listening for the swipe gesture. */
    override fun startGestureListening() {
    private fun startGestureListening() {
        super.startGestureListening()
        stopGestureListening()

        logger.logInputListeningStarted()
        logger.logInputListeningStarted()
        inputMonitor = InputMonitorCompat(TAG, Display.DEFAULT_DISPLAY).also {
            inputReceiver = it.getInputReceiver(
                Looper.getMainLooper(),
                Choreographer.getInstance(),
                this::onInputEvent
            )
        }
    }
    }


    /** Stop listening for the swipe gesture. */
    override fun stopGestureListening() {
    private fun stopGestureListening() {
        super.stopGestureListening()
        inputMonitor?.let {
        logger.logInputListeningStopped()
        logger.logInputListeningStopped()
            inputMonitor = null
            it.dispose()
        }
        inputReceiver?.let {
            inputReceiver = null
            it.dispose()
        }
    }
    }
}
}


private const val SWIPE_TIMEOUT_MS: Long = 500
private const val SWIPE_TIMEOUT_MS: Long = 500
private val TAG = SwipeStatusBarAwayGestureHandler::class.simpleName
Loading