Do not use private APIs in unfold module
Removes usages of the private/hidden APIs in unfold module so it could be easily reused in 1p/3p apps. Bug: 258828766 Test: manual fold/unfold with a full screen app and in split screen Change-Id: I96b3ca38e11521cc4880de74ce143cea3aa015be
This commit is contained in:
@@ -16,22 +16,24 @@
|
||||
|
||||
package com.android.systemui.unfold.updates
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.os.Looper
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.view.IRotationWatcher
|
||||
import android.view.IWindowManager
|
||||
import android.view.Display
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.utils.os.FakeHandler
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.spy
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
import org.mockito.MockitoAnnotations
|
||||
@@ -42,19 +44,23 @@ class RotationChangeProviderTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var rotationChangeProvider: RotationChangeProvider
|
||||
|
||||
@Mock lateinit var windowManagerInterface: IWindowManager
|
||||
@Mock lateinit var displayManager: DisplayManager
|
||||
@Mock lateinit var listener: RotationListener
|
||||
@Captor lateinit var rotationWatcher: ArgumentCaptor<IRotationWatcher>
|
||||
private val fakeExecutor = FakeExecutor(FakeSystemClock())
|
||||
@Mock lateinit var display: Display
|
||||
@Captor lateinit var displayListener: ArgumentCaptor<DisplayManager.DisplayListener>
|
||||
private val fakeHandler = FakeHandler(Looper.getMainLooper())
|
||||
|
||||
private lateinit var spyContext: Context
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
rotationChangeProvider =
|
||||
RotationChangeProvider(windowManagerInterface, context, fakeExecutor)
|
||||
spyContext = spy(context)
|
||||
whenever(spyContext.display).thenReturn(display)
|
||||
rotationChangeProvider = RotationChangeProvider(displayManager, spyContext, fakeHandler)
|
||||
rotationChangeProvider.addCallback(listener)
|
||||
fakeExecutor.runAllReady()
|
||||
verify(windowManagerInterface).watchRotation(rotationWatcher.capture(), anyInt())
|
||||
fakeHandler.dispatchQueuedMessages()
|
||||
verify(displayManager).registerDisplayListener(displayListener.capture(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -70,15 +76,16 @@ class RotationChangeProviderTest : SysuiTestCase() {
|
||||
verify(listener).onRotationChanged(42)
|
||||
|
||||
rotationChangeProvider.removeCallback(listener)
|
||||
fakeExecutor.runAllReady()
|
||||
fakeHandler.dispatchQueuedMessages()
|
||||
sendRotationUpdate(43)
|
||||
|
||||
verify(windowManagerInterface).removeRotationWatcher(any())
|
||||
verify(displayManager).unregisterDisplayListener(any())
|
||||
verifyNoMoreInteractions(listener)
|
||||
}
|
||||
|
||||
private fun sendRotationUpdate(newRotation: Int) {
|
||||
rotationWatcher.value.onRotationChanged(newRotation)
|
||||
fakeExecutor.runAllReady()
|
||||
whenever(display.rotation).thenReturn(newRotation)
|
||||
displayListener.allValues.forEach { it.onDisplayChanged(display.displayId) }
|
||||
fakeHandler.dispatchQueuedMessages()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ android_library {
|
||||
],
|
||||
kotlincflags: ["-Xjvm-default=enable"],
|
||||
java_version: "1.8",
|
||||
sdk_version: "current",
|
||||
min_sdk_version: "current",
|
||||
plugins: ["dagger2-compiler"],
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ package com.android.systemui.unfold
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.hardware.SensorManager
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.os.Handler
|
||||
import android.view.IWindowManager
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig
|
||||
import com.android.systemui.unfold.dagger.UnfoldMain
|
||||
import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg
|
||||
@@ -61,7 +61,7 @@ interface UnfoldSharedComponent {
|
||||
@BindsInstance @UnfoldMain executor: Executor,
|
||||
@BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
|
||||
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
|
||||
@BindsInstance windowManager: IWindowManager,
|
||||
@BindsInstance displayManager: DisplayManager,
|
||||
@BindsInstance contentResolver: ContentResolver = context.contentResolver
|
||||
): UnfoldSharedComponent
|
||||
}
|
||||
@@ -84,8 +84,9 @@ interface RemoteUnfoldSharedComponent {
|
||||
@BindsInstance context: Context,
|
||||
@BindsInstance config: UnfoldTransitionConfig,
|
||||
@BindsInstance @UnfoldMain executor: Executor,
|
||||
@BindsInstance @UnfoldMain handler: Handler,
|
||||
@BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
|
||||
@BindsInstance windowManager: IWindowManager,
|
||||
@BindsInstance displayManager: DisplayManager,
|
||||
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
|
||||
): RemoteUnfoldSharedComponent
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ package com.android.systemui.unfold
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.SensorManager
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.os.Handler
|
||||
import android.view.IWindowManager
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig
|
||||
import com.android.systemui.unfold.updates.FoldProvider
|
||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
|
||||
@@ -47,7 +47,7 @@ fun createUnfoldSharedComponent(
|
||||
mainExecutor: Executor,
|
||||
singleThreadBgExecutor: Executor,
|
||||
tracingTagPrefix: String,
|
||||
windowManager: IWindowManager,
|
||||
displayManager: DisplayManager,
|
||||
): UnfoldSharedComponent =
|
||||
DaggerUnfoldSharedComponent.factory()
|
||||
.create(
|
||||
@@ -61,7 +61,7 @@ fun createUnfoldSharedComponent(
|
||||
mainExecutor,
|
||||
singleThreadBgExecutor,
|
||||
tracingTagPrefix,
|
||||
windowManager,
|
||||
displayManager,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -73,16 +73,18 @@ fun createRemoteUnfoldSharedComponent(
|
||||
context: Context,
|
||||
config: UnfoldTransitionConfig,
|
||||
mainExecutor: Executor,
|
||||
mainHandler: Handler,
|
||||
singleThreadBgExecutor: Executor,
|
||||
tracingTagPrefix: String,
|
||||
windowManager: IWindowManager,
|
||||
displayManager: DisplayManager,
|
||||
): RemoteUnfoldSharedComponent =
|
||||
DaggerRemoteUnfoldSharedComponent.factory()
|
||||
.create(
|
||||
context,
|
||||
config,
|
||||
mainExecutor,
|
||||
mainHandler,
|
||||
singleThreadBgExecutor,
|
||||
windowManager,
|
||||
displayManager,
|
||||
tracingTagPrefix,
|
||||
)
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.android.systemui.unfold.progress
|
||||
|
||||
import android.os.Trace
|
||||
import android.os.Trace.TRACE_TAG_APP
|
||||
import android.util.Log
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation
|
||||
import androidx.dynamicanimation.animation.FloatPropertyCompat
|
||||
@@ -110,7 +109,7 @@ class PhysicsBasedUnfoldTransitionProgressProvider @Inject constructor(
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onFoldUpdate = ${update.name()}")
|
||||
Trace.traceCounter(Trace.TRACE_TAG_APP, "fold_update", update)
|
||||
Trace.setCounter("fold_update", update.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ constructor(
|
||||
"lastHingeAngle: $lastHingeAngle, " +
|
||||
"lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition"
|
||||
)
|
||||
Trace.traceCounter(Trace.TRACE_TAG_APP, "hinge_angle", angle.toInt())
|
||||
Trace.setCounter( "hinge_angle", angle.toLong())
|
||||
}
|
||||
|
||||
val currentDirection =
|
||||
|
||||
@@ -17,36 +17,32 @@
|
||||
package com.android.systemui.unfold.updates
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.os.Handler
|
||||
import android.os.RemoteException
|
||||
import android.view.IRotationWatcher
|
||||
import android.view.IWindowManager
|
||||
import android.view.Surface.Rotation
|
||||
import com.android.systemui.unfold.dagger.UnfoldMain
|
||||
import com.android.systemui.unfold.util.CallbackController
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Allows to subscribe to rotation changes.
|
||||
*
|
||||
* This is needed as rotation updates from [IWindowManager] are received in a binder thread, while
|
||||
* most of the times we want them in the main one. Updates are provided for the display associated
|
||||
* Allows to subscribe to rotation changes. Updates are provided for the display associated
|
||||
* to [context].
|
||||
*/
|
||||
class RotationChangeProvider
|
||||
@Inject
|
||||
constructor(
|
||||
private val windowManagerInterface: IWindowManager,
|
||||
private val displayManager: DisplayManager,
|
||||
private val context: Context,
|
||||
@UnfoldMain private val mainExecutor: Executor,
|
||||
@UnfoldMain private val mainHandler: Handler,
|
||||
) : CallbackController<RotationChangeProvider.RotationListener> {
|
||||
|
||||
private val listeners = mutableListOf<RotationListener>()
|
||||
|
||||
private val rotationWatcher = RotationWatcher()
|
||||
private val displayListener = RotationDisplayListener()
|
||||
private var lastRotation: Int? = null
|
||||
|
||||
override fun addCallback(listener: RotationListener) {
|
||||
mainExecutor.execute {
|
||||
mainHandler.post {
|
||||
if (listeners.isEmpty()) {
|
||||
subscribeToRotation()
|
||||
}
|
||||
@@ -55,17 +51,18 @@ constructor(
|
||||
}
|
||||
|
||||
override fun removeCallback(listener: RotationListener) {
|
||||
mainExecutor.execute {
|
||||
mainHandler.post {
|
||||
listeners -= listener
|
||||
if (listeners.isEmpty()) {
|
||||
unsubscribeToRotation()
|
||||
lastRotation = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeToRotation() {
|
||||
try {
|
||||
windowManagerInterface.watchRotation(rotationWatcher, context.displayId)
|
||||
displayManager.registerDisplayListener(displayListener, mainHandler)
|
||||
} catch (e: RemoteException) {
|
||||
throw e.rethrowFromSystemServer()
|
||||
}
|
||||
@@ -73,7 +70,7 @@ constructor(
|
||||
|
||||
private fun unsubscribeToRotation() {
|
||||
try {
|
||||
windowManagerInterface.removeRotationWatcher(rotationWatcher)
|
||||
displayManager.unregisterDisplayListener(displayListener)
|
||||
} catch (e: RemoteException) {
|
||||
throw e.rethrowFromSystemServer()
|
||||
}
|
||||
@@ -82,12 +79,25 @@ constructor(
|
||||
/** Gets notified of rotation changes. */
|
||||
fun interface RotationListener {
|
||||
/** Called once rotation changes. */
|
||||
fun onRotationChanged(@Rotation newRotation: Int)
|
||||
fun onRotationChanged(newRotation: Int)
|
||||
}
|
||||
|
||||
private inner class RotationWatcher : IRotationWatcher.Stub() {
|
||||
override fun onRotationChanged(rotation: Int) {
|
||||
mainExecutor.execute { listeners.forEach { it.onRotationChanged(rotation) } }
|
||||
private inner class RotationDisplayListener : DisplayManager.DisplayListener {
|
||||
|
||||
override fun onDisplayChanged(displayId: Int) {
|
||||
val display = context.display ?: return
|
||||
|
||||
if (displayId == display.displayId) {
|
||||
val currentRotation = display.rotation
|
||||
if (lastRotation == null || lastRotation != currentRotation) {
|
||||
listeners.forEach { it.onRotationChanged(currentRotation) }
|
||||
lastRotation = currentRotation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDisplayAdded(displayId: Int) {}
|
||||
|
||||
override fun onDisplayRemoved(displayId: Int) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +79,9 @@ constructor(
|
||||
companion object {
|
||||
fun ContentResolver.areAnimationsEnabled(): Boolean {
|
||||
val animationScale =
|
||||
Settings.Global.getStringForUser(
|
||||
Settings.Global.getString(
|
||||
this,
|
||||
Settings.Global.ANIMATOR_DURATION_SCALE,
|
||||
this.userId
|
||||
)
|
||||
?.toFloatOrNull()
|
||||
?: 1f
|
||||
|
||||
Reference in New Issue
Block a user