Merge "Replace RotationUtils#Rotation with Surface#Rotation for wired charging animation." into tm-qpr-dev
This commit is contained in:
@@ -20,7 +20,7 @@ import android.content.Context
|
|||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.PixelFormat
|
import android.graphics.PixelFormat
|
||||||
import android.os.SystemProperties
|
import android.os.SystemProperties
|
||||||
import android.util.DisplayMetrics
|
import android.view.Surface
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import com.android.internal.annotations.VisibleForTesting
|
import com.android.internal.annotations.VisibleForTesting
|
||||||
@@ -36,7 +36,6 @@ import com.android.systemui.statusbar.commandline.Command
|
|||||||
import com.android.systemui.statusbar.commandline.CommandRegistry
|
import com.android.systemui.statusbar.commandline.CommandRegistry
|
||||||
import com.android.systemui.statusbar.policy.BatteryController
|
import com.android.systemui.statusbar.policy.BatteryController
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||||
import com.android.systemui.util.leak.RotationUtils
|
|
||||||
import com.android.systemui.util.time.SystemClock
|
import com.android.systemui.util.time.SystemClock
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -172,30 +171,28 @@ class WiredChargingRippleController @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun layoutRipple() {
|
private fun layoutRipple() {
|
||||||
val displayMetrics = DisplayMetrics()
|
val bounds = windowManager.currentWindowMetrics.bounds
|
||||||
context.display.getRealMetrics(displayMetrics)
|
val width = bounds.width()
|
||||||
val width = displayMetrics.widthPixels
|
val height = bounds.height()
|
||||||
val height = displayMetrics.heightPixels
|
|
||||||
val maxDiameter = Integer.max(width, height) * 2f
|
val maxDiameter = Integer.max(width, height) * 2f
|
||||||
rippleView.setMaxSize(maxDiameter, maxDiameter)
|
rippleView.setMaxSize(maxDiameter, maxDiameter)
|
||||||
when (RotationUtils.getExactRotation(context)) {
|
when (context.display.rotation) {
|
||||||
RotationUtils.ROTATION_LANDSCAPE -> {
|
Surface.ROTATION_0 -> {
|
||||||
|
rippleView.setCenter(
|
||||||
|
width * normalizedPortPosX, height * normalizedPortPosY)
|
||||||
|
}
|
||||||
|
Surface.ROTATION_90 -> {
|
||||||
rippleView.setCenter(
|
rippleView.setCenter(
|
||||||
width * normalizedPortPosY, height * (1 - normalizedPortPosX))
|
width * normalizedPortPosY, height * (1 - normalizedPortPosX))
|
||||||
}
|
}
|
||||||
RotationUtils.ROTATION_UPSIDE_DOWN -> {
|
Surface.ROTATION_180 -> {
|
||||||
rippleView.setCenter(
|
rippleView.setCenter(
|
||||||
width * (1 - normalizedPortPosX), height * (1 - normalizedPortPosY))
|
width * (1 - normalizedPortPosX), height * (1 - normalizedPortPosY))
|
||||||
}
|
}
|
||||||
RotationUtils.ROTATION_SEASCAPE -> {
|
Surface.ROTATION_270 -> {
|
||||||
rippleView.setCenter(
|
rippleView.setCenter(
|
||||||
width * (1 - normalizedPortPosY), height * normalizedPortPosX)
|
width * (1 - normalizedPortPosY), height * normalizedPortPosX)
|
||||||
}
|
}
|
||||||
else -> {
|
|
||||||
// ROTATION_NONE
|
|
||||||
rippleView.setCenter(
|
|
||||||
width * normalizedPortPosX, height * normalizedPortPosY)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 The Android Open Source Project
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* except in compliance with the License. You may obtain a copy of the License at
|
* 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
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* KIND, either express or implied. See the License for the specific language governing
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* permissions and limitations under the License.
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.systemui.util.leak;
|
package com.android.systemui.util.leak;
|
||||||
@@ -26,7 +28,27 @@ import android.view.Surface;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
public class RotationUtils {
|
/**
|
||||||
|
* Utility class that provides device orientation.
|
||||||
|
*
|
||||||
|
* <p>Consider using {@link Surface.Rotation} or add a function that respects device aspect ratio
|
||||||
|
* and {@code android.internal.R.bool.config_reverseDefaultRotation}.
|
||||||
|
*
|
||||||
|
* <p>If you only care about the rotation, use {@link Surface.Rotation}, as it always gives the
|
||||||
|
* counter clock-wise rotation. (e.g. If you have a device that has a charging port at the bottom,
|
||||||
|
* rotating three times in counter clock direction will give you {@link Surface#ROTATION_270} while
|
||||||
|
* having the charging port on the left side of the device.)
|
||||||
|
*
|
||||||
|
* <p>If you need whether the device is in portrait or landscape (or their opposites), please add a
|
||||||
|
* function here that respects the device aspect ratio and
|
||||||
|
* {@code android.internal.R.bool.config_reverseDefaultRotation} together.
|
||||||
|
*
|
||||||
|
* <p>Note that {@code android.internal.R.bool.config_reverseDefaultRotation} does not change the
|
||||||
|
* winding order. In other words, the rotation order (counter clock-wise) will remain the same. It
|
||||||
|
* only flips the device orientation, such that portrait becomes upside down, landscape becomes
|
||||||
|
* seascape.
|
||||||
|
*/
|
||||||
|
public final class RotationUtils {
|
||||||
|
|
||||||
public static final int ROTATION_NONE = 0;
|
public static final int ROTATION_NONE = 0;
|
||||||
public static final int ROTATION_LANDSCAPE = 1;
|
public static final int ROTATION_LANDSCAPE = 1;
|
||||||
|
|||||||
@@ -16,18 +16,23 @@
|
|||||||
|
|
||||||
package com.android.systemui.charging
|
package com.android.systemui.charging
|
||||||
|
|
||||||
|
import android.graphics.Rect
|
||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.view.Surface
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.view.WindowMetrics
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.internal.logging.UiEventLogger
|
import com.android.internal.logging.UiEventLogger
|
||||||
|
import com.android.systemui.R
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.flags.FeatureFlags
|
import com.android.systemui.flags.FeatureFlags
|
||||||
import com.android.systemui.flags.Flags
|
import com.android.systemui.flags.Flags
|
||||||
import com.android.systemui.surfaceeffects.ripple.RippleView
|
|
||||||
import com.android.systemui.statusbar.commandline.CommandRegistry
|
import com.android.systemui.statusbar.commandline.CommandRegistry
|
||||||
import com.android.systemui.statusbar.policy.BatteryController
|
import com.android.systemui.statusbar.policy.BatteryController
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||||
|
import com.android.systemui.surfaceeffects.ripple.RippleView
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
import com.android.systemui.util.time.FakeSystemClock
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -35,12 +40,12 @@ import org.junit.runner.RunWith
|
|||||||
import org.mockito.ArgumentCaptor
|
import org.mockito.ArgumentCaptor
|
||||||
import org.mockito.ArgumentMatchers
|
import org.mockito.ArgumentMatchers
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.`when`
|
||||||
import org.mockito.Mockito.any
|
import org.mockito.Mockito.any
|
||||||
import org.mockito.Mockito.eq
|
import org.mockito.Mockito.eq
|
||||||
import org.mockito.Mockito.never
|
import org.mockito.Mockito.never
|
||||||
import org.mockito.Mockito.reset
|
import org.mockito.Mockito.reset
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
import org.mockito.Mockito.`when`
|
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@@ -54,6 +59,7 @@ class WiredChargingRippleControllerTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var rippleView: RippleView
|
@Mock private lateinit var rippleView: RippleView
|
||||||
@Mock private lateinit var windowManager: WindowManager
|
@Mock private lateinit var windowManager: WindowManager
|
||||||
@Mock private lateinit var uiEventLogger: UiEventLogger
|
@Mock private lateinit var uiEventLogger: UiEventLogger
|
||||||
|
@Mock private lateinit var windowMetrics: WindowMetrics
|
||||||
private val systemClock = FakeSystemClock()
|
private val systemClock = FakeSystemClock()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -66,6 +72,9 @@ class WiredChargingRippleControllerTest : SysuiTestCase() {
|
|||||||
rippleView.setupShader()
|
rippleView.setupShader()
|
||||||
controller.rippleView = rippleView // Replace the real ripple view with a mock instance
|
controller.rippleView = rippleView // Replace the real ripple view with a mock instance
|
||||||
controller.registerCallbacks()
|
controller.registerCallbacks()
|
||||||
|
|
||||||
|
`when`(windowMetrics.bounds).thenReturn(Rect(0, 0, 100, 100))
|
||||||
|
`when`(windowManager.currentWindowMetrics).thenReturn(windowMetrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -164,4 +173,63 @@ class WiredChargingRippleControllerTest : SysuiTestCase() {
|
|||||||
verify(rippleView, never()).addOnAttachStateChangeListener(attachListenerCaptor.capture())
|
verify(rippleView, never()).addOnAttachStateChangeListener(attachListenerCaptor.capture())
|
||||||
verify(windowManager, never()).addView(eq(rippleView), any<WindowManager.LayoutParams>())
|
verify(windowManager, never()).addView(eq(rippleView), any<WindowManager.LayoutParams>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRipple_layoutsCorrectly() {
|
||||||
|
// Sets the correct ripple size.
|
||||||
|
val width = 100
|
||||||
|
val height = 200
|
||||||
|
whenever(windowMetrics.bounds).thenReturn(Rect(0, 0, width, height))
|
||||||
|
|
||||||
|
// Trigger ripple.
|
||||||
|
val captor = ArgumentCaptor
|
||||||
|
.forClass(BatteryController.BatteryStateChangeCallback::class.java)
|
||||||
|
verify(batteryController).addCallback(captor.capture())
|
||||||
|
|
||||||
|
captor.value.onBatteryLevelChanged(
|
||||||
|
/* unusedBatteryLevel= */ 0,
|
||||||
|
/* plugged in= */ true,
|
||||||
|
/* charging= */ false)
|
||||||
|
|
||||||
|
val attachListenerCaptor =
|
||||||
|
ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
|
||||||
|
verify(rippleView).addOnAttachStateChangeListener(attachListenerCaptor.capture())
|
||||||
|
verify(windowManager).addView(eq(rippleView), any<WindowManager.LayoutParams>())
|
||||||
|
|
||||||
|
val runnableCaptor =
|
||||||
|
ArgumentCaptor.forClass(Runnable::class.java)
|
||||||
|
attachListenerCaptor.value.onViewAttachedToWindow(rippleView)
|
||||||
|
verify(rippleView).startRipple(runnableCaptor.capture())
|
||||||
|
|
||||||
|
// Verify size and center position.
|
||||||
|
val maxSize = 400f // Double the max value between width and height.
|
||||||
|
verify(rippleView).setMaxSize(maxWidth = maxSize, maxHeight = maxSize)
|
||||||
|
|
||||||
|
val normalizedPortPosX =
|
||||||
|
context.resources.getFloat(R.dimen.physical_charger_port_location_normalized_x)
|
||||||
|
val normalizedPortPosY =
|
||||||
|
context.resources.getFloat(R.dimen.physical_charger_port_location_normalized_y)
|
||||||
|
val expectedCenterX: Float
|
||||||
|
val expectedCenterY: Float
|
||||||
|
when (context.display.rotation) {
|
||||||
|
Surface.ROTATION_90 -> {
|
||||||
|
expectedCenterX = width * normalizedPortPosY
|
||||||
|
expectedCenterY = height * (1 - normalizedPortPosX)
|
||||||
|
}
|
||||||
|
Surface.ROTATION_180 -> {
|
||||||
|
expectedCenterX = width * (1 - normalizedPortPosX)
|
||||||
|
expectedCenterY = height * (1 - normalizedPortPosY)
|
||||||
|
}
|
||||||
|
Surface.ROTATION_270 -> {
|
||||||
|
expectedCenterX = width * (1 - normalizedPortPosY)
|
||||||
|
expectedCenterY = height * normalizedPortPosX
|
||||||
|
}
|
||||||
|
else -> { // Surface.ROTATION_0
|
||||||
|
expectedCenterX = width * normalizedPortPosX
|
||||||
|
expectedCenterY = height * normalizedPortPosY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(rippleView).setCenter(expectedCenterX, expectedCenterY)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user