Merge "[Unfold transition] Do not play haptics when hitting a timeout on folding" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
76c74ee9f2
@@ -3,26 +3,43 @@ package com.android.systemui.unfold
|
||||
import android.os.SystemProperties
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
||||
import com.android.systemui.unfold.updates.FoldProvider
|
||||
import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Class that plays a haptics effect during unfolding a foldable device
|
||||
*/
|
||||
/** Class that plays a haptics effect during unfolding a foldable device */
|
||||
@SysUIUnfoldScope
|
||||
class UnfoldHapticsPlayer
|
||||
@Inject
|
||||
constructor(
|
||||
unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
|
||||
foldProvider: FoldProvider,
|
||||
@Main private val mainExecutor: Executor,
|
||||
private val vibrator: Vibrator?
|
||||
) : TransitionProgressListener {
|
||||
|
||||
private var isFirstAnimationAfterUnfold = false
|
||||
|
||||
init {
|
||||
if (vibrator != null) {
|
||||
// We don't need to remove the callback because we should listen to it
|
||||
// the whole time when SystemUI process is alive
|
||||
unfoldTransitionProgressProvider.addCallback(this)
|
||||
}
|
||||
|
||||
foldProvider.registerCallback(
|
||||
object : FoldCallback {
|
||||
override fun onFoldUpdated(isFolded: Boolean) {
|
||||
if (isFolded) {
|
||||
isFirstAnimationAfterUnfold = true
|
||||
}
|
||||
}
|
||||
},
|
||||
mainExecutor
|
||||
)
|
||||
}
|
||||
|
||||
private var lastTransitionProgress = TRANSITION_PROGRESS_FULL_OPEN
|
||||
@@ -36,6 +53,13 @@ constructor(
|
||||
}
|
||||
|
||||
override fun onTransitionFinishing() {
|
||||
// Run haptics only when unfolding the device (first animation after unfolding)
|
||||
if (!isFirstAnimationAfterUnfold) {
|
||||
return
|
||||
}
|
||||
|
||||
isFirstAnimationAfterUnfold = false
|
||||
|
||||
// Run haptics only if the animation is long enough to notice
|
||||
if (lastTransitionProgress < TRANSITION_NOTICEABLE_THRESHOLD) {
|
||||
playHaptics()
|
||||
|
||||
@@ -26,6 +26,10 @@ class TestUnfoldTransitionProvider : UnfoldTransitionProgressProvider, Transitio
|
||||
listeners.forEach { it.onTransitionFinished() }
|
||||
}
|
||||
|
||||
override fun onTransitionFinishing() {
|
||||
listeners.forEach { it.onTransitionFinishing() }
|
||||
}
|
||||
|
||||
override fun onTransitionProgress(progress: Float) {
|
||||
listeners.forEach { it.onTransitionProgress(progress) }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.unfold
|
||||
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.unfold.updates.FoldProvider
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import java.util.concurrent.Executor
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
class UnfoldHapticsPlayerTest : SysuiTestCase() {
|
||||
|
||||
private val progressProvider = TestUnfoldTransitionProvider()
|
||||
private val vibrator: Vibrator = mock()
|
||||
private val testFoldProvider = TestFoldProvider()
|
||||
|
||||
private lateinit var player: UnfoldHapticsPlayer
|
||||
|
||||
@Before
|
||||
fun before() {
|
||||
player = UnfoldHapticsPlayer(progressProvider, testFoldProvider, Runnable::run, vibrator)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnfoldingTransitionFinishingEarly_playsHaptics() {
|
||||
testFoldProvider.onFoldUpdate(isFolded = true)
|
||||
testFoldProvider.onFoldUpdate(isFolded = false)
|
||||
progressProvider.onTransitionStarted()
|
||||
progressProvider.onTransitionProgress(0.5f)
|
||||
progressProvider.onTransitionFinishing()
|
||||
|
||||
verify(vibrator).vibrate(any<VibrationEffect>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnfoldingTransitionFinishingLate_doesNotPlayHaptics() {
|
||||
testFoldProvider.onFoldUpdate(isFolded = true)
|
||||
testFoldProvider.onFoldUpdate(isFolded = false)
|
||||
progressProvider.onTransitionStarted()
|
||||
progressProvider.onTransitionProgress(0.99f)
|
||||
progressProvider.onTransitionFinishing()
|
||||
|
||||
verify(vibrator, never()).vibrate(any<VibrationEffect>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFoldingAfterUnfolding_doesNotPlayHaptics() {
|
||||
// Unfold
|
||||
testFoldProvider.onFoldUpdate(isFolded = true)
|
||||
testFoldProvider.onFoldUpdate(isFolded = false)
|
||||
progressProvider.onTransitionStarted()
|
||||
progressProvider.onTransitionProgress(0.5f)
|
||||
progressProvider.onTransitionFinishing()
|
||||
progressProvider.onTransitionFinished()
|
||||
clearInvocations(vibrator)
|
||||
|
||||
// Fold
|
||||
progressProvider.onTransitionStarted()
|
||||
progressProvider.onTransitionProgress(0.5f)
|
||||
progressProvider.onTransitionFinished()
|
||||
testFoldProvider.onFoldUpdate(isFolded = true)
|
||||
|
||||
verify(vibrator, never()).vibrate(any<VibrationEffect>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnfoldingAfterFoldingAndUnfolding_playsHaptics() {
|
||||
// Unfold
|
||||
testFoldProvider.onFoldUpdate(isFolded = true)
|
||||
testFoldProvider.onFoldUpdate(isFolded = false)
|
||||
progressProvider.onTransitionStarted()
|
||||
progressProvider.onTransitionProgress(0.5f)
|
||||
progressProvider.onTransitionFinishing()
|
||||
progressProvider.onTransitionFinished()
|
||||
|
||||
// Fold
|
||||
progressProvider.onTransitionStarted()
|
||||
progressProvider.onTransitionProgress(0.5f)
|
||||
progressProvider.onTransitionFinished()
|
||||
testFoldProvider.onFoldUpdate(isFolded = true)
|
||||
clearInvocations(vibrator)
|
||||
|
||||
// Unfold again
|
||||
testFoldProvider.onFoldUpdate(isFolded = true)
|
||||
testFoldProvider.onFoldUpdate(isFolded = false)
|
||||
progressProvider.onTransitionStarted()
|
||||
progressProvider.onTransitionProgress(0.5f)
|
||||
progressProvider.onTransitionFinishing()
|
||||
progressProvider.onTransitionFinished()
|
||||
|
||||
verify(vibrator).vibrate(any<VibrationEffect>())
|
||||
}
|
||||
|
||||
private class TestFoldProvider : FoldProvider {
|
||||
private val listeners = arrayListOf<FoldProvider.FoldCallback>()
|
||||
|
||||
override fun registerCallback(callback: FoldProvider.FoldCallback, executor: Executor) {
|
||||
listeners += callback
|
||||
}
|
||||
|
||||
override fun unregisterCallback(callback: FoldProvider.FoldCallback) {
|
||||
listeners -= callback
|
||||
}
|
||||
|
||||
fun onFoldUpdate(isFolded: Boolean) {
|
||||
listeners.forEach { it.onFoldUpdated(isFolded) }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user