From 505a55c35622ab6949f76dc2b8dd7ab08e08812b Mon Sep 17 00:00:00 2001 From: Andrew Grieve Date: Thu, 13 Feb 2025 19:26:18 -0800 Subject: [PATCH 001/111] Avoid NPE in Html.toHtml() when is missing a face attribute See b/395473939 Change-Id: I02b4b3487211fbc032d874560b749d0f454c6b91 --- core/java/android/text/Html.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index ae12132d49a1f..a42eece57eec9 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -614,7 +614,7 @@ public class Html { if (style[j] instanceof TypefaceSpan) { String s = ((TypefaceSpan) style[j]).getFamily(); - if (s.equals("monospace")) { + if ("monospace".equals(s)) { out.append(""); } } -- GitLab From 75177e8983c9f48f042cf75516dacdb21524618f Mon Sep 17 00:00:00 2001 From: Anton Ivanov Date: Thu, 13 Feb 2025 22:37:35 -0800 Subject: [PATCH 002/111] Harden construction sites of android::StrongPointer. Bug: 393217449 Test: presubmit Flag: EXEMPT_refactor Change-Id: I913683213590dc0702935c111c85fbea678671f2 --- libs/hostgraphics/Fence.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/hostgraphics/Fence.cpp b/libs/hostgraphics/Fence.cpp index 4383bf02a00e5..938a9384768db 100644 --- a/libs/hostgraphics/Fence.cpp +++ b/libs/hostgraphics/Fence.cpp @@ -18,6 +18,6 @@ namespace android { -const sp Fence::NO_FENCE = sp(new Fence); +const sp Fence::NO_FENCE = sp::make(); } // namespace android -- GitLab From a1e84d0888dd976082e46129832ebdb2a234e83a Mon Sep 17 00:00:00 2001 From: Hawkwood Glazier Date: Thu, 13 Feb 2025 17:21:17 +0000 Subject: [PATCH 003/111] Limit interpolated axis values to set of valid values Rouding the axis values to the nearest valid step value should keep the var cache from missing repeatedly due to functionally identical axis values. Formerly this was not a problem because the progress float was rounded to the nearest animation frame. However that is no longer occuring as it caused issues w/ non-linear interpolation. Since different axes have different min and max values, we manually adjust the step size to roughly target the same number of valid values within that range. This gives us a good target, but also allows us to make specific adjustments to keep hit-rate high depending on which axes are more important visually. Bug: 394840414 Test: Ran animation on device Flag: NONE TextAnimator Memory Fix Change-Id: I1800b71601ef10e1c2b9fd083134f312c8dd6711 --- .../systemui/animation/FontInterpolator.kt | 93 ++++++------------ .../systemui/animation/FontVariationUtils.kt | 32 +++--- .../com/android/systemui/animation/GSFAxes.kt | 98 +++++++++++++++++++ .../shared/clocks/FlexClockController.kt | 30 ++---- .../shared/clocks/FlexClockFaceController.kt | 2 +- .../systemui/shared/clocks/FontUtils.kt | 43 ++++++++ .../clocks/view/SimpleDigitalClockTextView.kt | 31 +++--- .../animation/FontVariationUtilsTest.kt | 5 +- .../animation/FontInterpolatorTest.kt | 6 ++ 9 files changed, 223 insertions(+), 117 deletions(-) create mode 100644 packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt create mode 100644 packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FontUtils.kt diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt index f8bcb81dc0735..bc75b1dad40cd 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt @@ -22,19 +22,8 @@ import android.util.Log import android.util.LruCache import android.util.MathUtils import androidx.annotation.VisibleForTesting -import java.lang.Float.max -import java.lang.Float.min import kotlin.math.roundToInt -private const val TAG_WGHT = "wght" -private const val TAG_ITAL = "ital" - -private const val FONT_WEIGHT_DEFAULT_VALUE = 400f -private const val FONT_ITALIC_MAX = 1f -private const val FONT_ITALIC_MIN = 0f -private const val FONT_ITALIC_ANIMATION_STEP = 0.1f -private const val FONT_ITALIC_DEFAULT_VALUE = 0f - /** Caches for font interpolation */ interface FontCache { val animationFrameCount: Int @@ -91,11 +80,8 @@ class FontCacheImpl(override val animationFrameCount: Int = DEFAULT_FONT_CACHE_M class FontInterpolator(val fontCache: FontCache = FontCacheImpl()) { /** Linear interpolate the font variation settings. */ fun lerp(start: Font, end: Font, progress: Float, linearProgress: Float): Font { - if (progress == 0f) { - return start - } else if (progress == 1f) { - return end - } + if (progress <= 0f) return start + if (progress >= 1f) return end val startAxes = start.axes ?: EMPTY_AXES val endAxes = end.axes ?: EMPTY_AXES @@ -110,7 +96,7 @@ class FontInterpolator(val fontCache: FontCache = FontCacheImpl()) { InterpKey(start, end, (linearProgress * fontCache.animationFrameCount).roundToInt()) fontCache.get(iKey)?.let { if (DEBUG) { - Log.d(LOG_TAG, "[$progress] Interp. cache hit for $iKey") + Log.d(LOG_TAG, "[$progress, $linearProgress] Interp. cache hit for $iKey") } return it } @@ -121,37 +107,16 @@ class FontInterpolator(val fontCache: FontCache = FontCacheImpl()) { // and also pre-fill the missing axes value with default value from 'fvar' table. val newAxes = lerp(startAxes, endAxes) { tag, startValue, endValue -> - when (tag) { - TAG_WGHT -> - MathUtils.lerp( - startValue ?: FONT_WEIGHT_DEFAULT_VALUE, - endValue ?: FONT_WEIGHT_DEFAULT_VALUE, - progress, - ) - TAG_ITAL -> - adjustItalic( - MathUtils.lerp( - startValue ?: FONT_ITALIC_DEFAULT_VALUE, - endValue ?: FONT_ITALIC_DEFAULT_VALUE, - progress, - ) - ) - else -> { - require(startValue != null && endValue != null) { - "Unable to interpolate due to unknown default axes value : $tag" - } - MathUtils.lerp(startValue, endValue, progress) - } - } + MathUtils.lerp(startValue, endValue, progress) } // Check if we already make font for this axes. This is typically happens if the animation - // happens backward. + // happens backward and is being linearly interpolated. val vKey = VarFontKey(start, newAxes) fontCache.get(vKey)?.let { fontCache.put(iKey, it) if (DEBUG) { - Log.d(LOG_TAG, "[$progress] Axis cache hit for $vKey") + Log.d(LOG_TAG, "[$progress, $linearProgress] Axis cache hit for $vKey") } return it } @@ -164,14 +129,14 @@ class FontInterpolator(val fontCache: FontCache = FontCacheImpl()) { fontCache.put(vKey, newFont) // Cache misses are likely to create memory leaks, so this is logged at error level. - Log.e(LOG_TAG, "[$progress] Cache MISS for $iKey / $vKey") + Log.e(LOG_TAG, "[$progress, $linearProgress] Cache MISS for $iKey / $vKey") return newFont } private fun lerp( start: Array, end: Array, - filter: (tag: String, left: Float?, right: Float?) -> Float, + filter: (tag: String, left: Float, right: Float) -> Float, ): List { // Safe to modify result of Font#getAxes since it returns cloned object. start.sortBy { axis -> axis.tag } @@ -191,39 +156,37 @@ class FontInterpolator(val fontCache: FontCache = FontCacheImpl()) { else -> tagA.compareTo(tagB) } - val axis = + val tag = + when { + comp == 0 -> tagA!! + comp < 0 -> tagA!! + else -> tagB!! + } + + val axisDefinition = GSFAxes.getAxis(tag) + require(comp == 0 || axisDefinition != null) { + "Unable to interpolate due to unknown default axes value: $tag" + } + + val axisValue = when { - comp == 0 -> { - val v = filter(tagA!!, start[i++].styleValue, end[j++].styleValue) - FontVariationAxis(tagA, v) - } - comp < 0 -> { - val v = filter(tagA!!, start[i++].styleValue, null) - FontVariationAxis(tagA, v) - } - else -> { // comp > 0 - val v = filter(tagB!!, null, end[j++].styleValue) - FontVariationAxis(tagB, v) - } + comp == 0 -> filter(tag, start[i++].styleValue, end[j++].styleValue) + comp < 0 -> filter(tag, start[i++].styleValue, axisDefinition!!.defaultValue) + else -> filter(tag, axisDefinition!!.defaultValue, end[j++].styleValue) } - result.add(axis) + // Round axis value to valid intermediate steps. This improves the cache hit rate. + val step = axisDefinition?.animationStep ?: DEFAULT_ANIMATION_STEP + result.add(FontVariationAxis(tag, (axisValue / step).roundToInt() * step)) } return result } - // For the performance reasons, we animate italic with FONT_ITALIC_ANIMATION_STEP. This helps - // Cache hit ratio in the Skia glyph cache. - private fun adjustItalic(value: Float) = - coerceInWithStep(value, FONT_ITALIC_MIN, FONT_ITALIC_MAX, FONT_ITALIC_ANIMATION_STEP) - - private fun coerceInWithStep(v: Float, min: Float, max: Float, step: Float) = - (v.coerceIn(min, max) / step).toInt() * step - companion object { private const val LOG_TAG = "FontInterpolator" private val DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG) private val EMPTY_AXES = arrayOf() + private const val DEFAULT_ANIMATION_STEP = 1f // Returns true if given two font instance can be interpolated. fun canInterpolate(start: Font, end: Font) = diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt index 9545bda80b2d9..9a746870c6ffc 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt @@ -1,12 +1,20 @@ -package com.android.systemui.animation +/* + * Copyright (C) 2024 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. + */ -object GSFAxes { - const val WEIGHT = "wght" - const val WIDTH = "wdth" - const val SLANT = "slnt" - const val ROUND = "ROND" - const val OPTICAL_SIZE = "opsz" -} +package com.android.systemui.animation class FontVariationUtils { private var mWeight = -1 @@ -46,20 +54,20 @@ class FontVariationUtils { } var resultString = "" if (mWeight >= 0) { - resultString += "'${GSFAxes.WEIGHT}' $mWeight" + resultString += "'${GSFAxes.WEIGHT.tag}' $mWeight" } if (mWidth >= 0) { resultString += - (if (resultString.isBlank()) "" else ", ") + "'${GSFAxes.WIDTH}' $mWidth" + (if (resultString.isBlank()) "" else ", ") + "'${GSFAxes.WIDTH.tag}' $mWidth" } if (mOpticalSize >= 0) { resultString += (if (resultString.isBlank()) "" else ", ") + - "'${GSFAxes.OPTICAL_SIZE}' $mOpticalSize" + "'${GSFAxes.OPTICAL_SIZE.tag}' $mOpticalSize" } if (mRoundness >= 0) { resultString += - (if (resultString.isBlank()) "" else ", ") + "'${GSFAxes.ROUND}' $mRoundness" + (if (resultString.isBlank()) "" else ", ") + "'${GSFAxes.ROUND.tag}' $mRoundness" } return if (isUpdated) resultString else "" } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt new file mode 100644 index 0000000000000..f4e03613169a8 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2025 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.animation + +data class AxisDefinition( + val tag: String, + val minValue: Float, + val defaultValue: Float, + val maxValue: Float, + val animationStep: Float, +) + +object GSFAxes { + val WEIGHT = + AxisDefinition( + tag = "wght", + minValue = 1f, + defaultValue = 400f, + maxValue = 1000f, + animationStep = 10f, + ) + + val WIDTH = + AxisDefinition( + tag = "wdth", + minValue = 25f, + defaultValue = 100f, + maxValue = 151f, + animationStep = 1f, + ) + + val SLANT = + AxisDefinition( + tag = "slnt", + minValue = 0f, + defaultValue = 0f, + maxValue = -10f, + animationStep = 0.1f, + ) + + val ROUND = + AxisDefinition( + tag = "ROND", + minValue = 0f, + defaultValue = 0f, + maxValue = 100f, + animationStep = 1f, + ) + + val GRADE = + AxisDefinition( + tag = "GRAD", + minValue = 0f, + defaultValue = 0f, + maxValue = 100f, + animationStep = 1f, + ) + + val OPTICAL_SIZE = + AxisDefinition( + tag = "opsz", + minValue = 6f, + defaultValue = 18f, + maxValue = 144f, + animationStep = 1f, + ) + + // Not a GSF Axis, but present for FontInterpolator compatibility + val ITALIC = + AxisDefinition( + tag = "ITAL", + minValue = 0f, + defaultValue = 0f, + maxValue = 1f, + animationStep = 0.1f, + ) + + private val AXIS_MAP = + listOf(WEIGHT, WIDTH, SLANT, ROUND, GRADE, OPTICAL_SIZE, ITALIC) + .map { def -> def.tag.toLowerCase() to def } + .toMap() + + fun getAxis(axis: String): AxisDefinition? = AXIS_MAP[axis.toLowerCase()] +} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt index 004d1aa1fe93c..ac1c5a8dfaf30 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt @@ -130,39 +130,25 @@ class FlexClockController(private val clockCtx: ClockContext) : ClockController private val FONT_AXES = listOf( - ClockFontAxis( - key = GSFAxes.WEIGHT, + GSFAxes.WEIGHT.toClockAxis( type = AxisType.Float, - minValue = 25f, currentValue = 400f, - maxValue = 1000f, name = "Weight", description = "Glyph Weight", ), - ClockFontAxis( - key = GSFAxes.WIDTH, + GSFAxes.WIDTH.toClockAxis( type = AxisType.Float, - minValue = 25f, currentValue = 85f, - maxValue = 151f, name = "Width", description = "Glyph Width", ), - ClockFontAxis( - key = GSFAxes.ROUND, + GSFAxes.ROUND.toClockAxis( type = AxisType.Boolean, - minValue = 0f, - currentValue = 0f, - maxValue = 100f, name = "Round", description = "Glyph Roundness", ), - ClockFontAxis( - key = GSFAxes.SLANT, + GSFAxes.SLANT.toClockAxis( type = AxisType.Boolean, - minValue = 0f, - currentValue = 0f, - maxValue = -10f, name = "Slant", description = "Glyph Slant", ), @@ -170,10 +156,10 @@ class FlexClockController(private val clockCtx: ClockContext) : ClockController private val LEGACY_FLEX_SETTINGS = listOf( - ClockFontAxisSetting(GSFAxes.WEIGHT, 600f), - ClockFontAxisSetting(GSFAxes.WIDTH, 100f), - ClockFontAxisSetting(GSFAxes.ROUND, 100f), - ClockFontAxisSetting(GSFAxes.SLANT, 0f), + GSFAxes.WEIGHT.toClockAxisSetting(600f), + GSFAxes.WIDTH.toClockAxisSetting(100f), + GSFAxes.ROUND.toClockAxisSetting(100f), + GSFAxes.SLANT.toClockAxisSetting(0f), ) } } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt index b2dbd6552955e..b4c2f5de290f8 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt @@ -132,7 +132,7 @@ class FlexClockFaceController(clockCtx: ClockContext, private val isLargeClock: if (!isLargeClock) { axes = axes.map { axis -> - if (axis.key == GSFAxes.WIDTH && axis.value > SMALL_CLOCK_MAX_WDTH) { + if (axis.key == GSFAxes.WIDTH.tag && axis.value > SMALL_CLOCK_MAX_WDTH) { axis.copy(value = SMALL_CLOCK_MAX_WDTH) } else { axis diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FontUtils.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FontUtils.kt new file mode 100644 index 0000000000000..212b1e29d1b8a --- /dev/null +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FontUtils.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2025 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.shared.clocks + +import com.android.systemui.animation.AxisDefinition +import com.android.systemui.plugins.clocks.AxisType +import com.android.systemui.plugins.clocks.ClockFontAxis +import com.android.systemui.plugins.clocks.ClockFontAxisSetting + +fun AxisDefinition.toClockAxis( + type: AxisType, + currentValue: Float? = null, + name: String, + description: String, +): ClockFontAxis { + return ClockFontAxis( + key = this.tag, + type = type, + maxValue = this.maxValue, + minValue = this.minValue, + currentValue = currentValue ?: this.defaultValue, + name = name, + description = description, + ) +} + +fun AxisDefinition.toClockAxisSetting(value: Float? = null): ClockFontAxisSetting { + return ClockFontAxisSetting(this.tag, value ?: this.defaultValue) +} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt index 8317aa39ef2b7..5b0db225f9cd9 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt @@ -49,6 +49,7 @@ import com.android.systemui.shared.clocks.DigitTranslateAnimator import com.android.systemui.shared.clocks.DimensionParser import com.android.systemui.shared.clocks.FLEX_CLOCK_ID import com.android.systemui.shared.clocks.FontTextStyle +import com.android.systemui.shared.clocks.toClockAxisSetting import java.lang.Thread import kotlin.math.max import kotlin.math.min @@ -594,25 +595,25 @@ open class SimpleDigitalClockTextView( val FIDGET_INTERPOLATOR = PathInterpolator(0.26873f, 0f, 0.45042f, 1f) val FIDGET_DISTS = mapOf( - GSFAxes.WEIGHT to Pair(200f, 500f), - GSFAxes.WIDTH to Pair(30f, 75f), - GSFAxes.ROUND to Pair(0f, 50f), - GSFAxes.SLANT to Pair(0f, -5f), + GSFAxes.WEIGHT.tag to Pair(200f, 500f), + GSFAxes.WIDTH.tag to Pair(30f, 75f), + GSFAxes.ROUND.tag to Pair(0f, 50f), + GSFAxes.SLANT.tag to Pair(0f, -5f), ) val AOD_COLOR = Color.WHITE - val LS_WEIGHT_AXIS = ClockFontAxisSetting(GSFAxes.WEIGHT, 400f) - val AOD_WEIGHT_AXIS = ClockFontAxisSetting(GSFAxes.WEIGHT, 200f) - val WIDTH_AXIS = ClockFontAxisSetting(GSFAxes.WIDTH, 85f) - val ROUND_AXIS = ClockFontAxisSetting(GSFAxes.ROUND, 0f) - val SLANT_AXIS = ClockFontAxisSetting(GSFAxes.SLANT, 0f) + val LS_WEIGHT_AXIS = GSFAxes.WEIGHT.toClockAxisSetting(400f) + val AOD_WEIGHT_AXIS = GSFAxes.WEIGHT.toClockAxisSetting(200f) + val WIDTH_AXIS = GSFAxes.WIDTH.toClockAxisSetting(85f) + val ROUND_AXIS = GSFAxes.ROUND.toClockAxisSetting(0f) + val SLANT_AXIS = GSFAxes.SLANT.toClockAxisSetting(0f) // Axes for Legacy version of the Flex Clock - val FLEX_LS_WEIGHT_AXIS = ClockFontAxisSetting(GSFAxes.WEIGHT, 600f) - val FLEX_AOD_LARGE_WEIGHT_AXIS = ClockFontAxisSetting(GSFAxes.WEIGHT, 74f) - val FLEX_AOD_SMALL_WEIGHT_AXIS = ClockFontAxisSetting(GSFAxes.WEIGHT, 133f) - val FLEX_LS_WIDTH_AXIS = ClockFontAxisSetting(GSFAxes.WIDTH, 100f) - val FLEX_AOD_WIDTH_AXIS = ClockFontAxisSetting(GSFAxes.WIDTH, 43f) - val FLEX_ROUND_AXIS = ClockFontAxisSetting(GSFAxes.ROUND, 100f) + val FLEX_LS_WEIGHT_AXIS = GSFAxes.WEIGHT.toClockAxisSetting(600f) + val FLEX_AOD_LARGE_WEIGHT_AXIS = GSFAxes.WEIGHT.toClockAxisSetting(74f) + val FLEX_AOD_SMALL_WEIGHT_AXIS = GSFAxes.WEIGHT.toClockAxisSetting(133f) + val FLEX_LS_WIDTH_AXIS = GSFAxes.WIDTH.toClockAxisSetting(100f) + val FLEX_AOD_WIDTH_AXIS = GSFAxes.WIDTH.toClockAxisSetting(43f) + val FLEX_ROUND_AXIS = GSFAxes.ROUND.toClockAxisSetting(100f) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/FontVariationUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/FontVariationUtilsTest.kt index f44769d522eb2..8d3640d8d8090 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/FontVariationUtilsTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/FontVariationUtilsTest.kt @@ -21,7 +21,7 @@ class FontVariationUtilsTest : SysuiTestCase() { roundness = 100, ) Assert.assertEquals( - "'${GSFAxes.WEIGHT}' 100, '${GSFAxes.WIDTH}' 100, '${GSFAxes.ROUND}' 100", + "'${GSFAxes.WEIGHT.tag}' 100, '${GSFAxes.WIDTH.tag}' 100, '${GSFAxes.ROUND.tag}' 100", initFvar, ) val updatedFvar = @@ -32,7 +32,8 @@ class FontVariationUtilsTest : SysuiTestCase() { roundness = 100, ) Assert.assertEquals( - "'${GSFAxes.WEIGHT}' 200, '${GSFAxes.WIDTH}' 100, '${GSFAxes.OPTICAL_SIZE}' 0, '${GSFAxes.ROUND}' 100", + "'${GSFAxes.WEIGHT.tag}' 200, '${GSFAxes.WIDTH.tag}' 100," + + " '${GSFAxes.OPTICAL_SIZE.tag}' 0, '${GSFAxes.ROUND.tag}' 100", updatedFvar, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt index 2e634390679a7..c2a495d13c02d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt @@ -64,6 +64,12 @@ class FontInterpolatorTest : SysuiTestCase() { "'wght' 500, 'ital' 0.5, 'GRAD' 450", interp.lerp(startFont, endFont, 0.5f, 0.5f), ) + + // Ensure axes rounded correctly to nearest step + assertSameAxes( + "'wght' 490, 'ital' 0.5, 'GRAD' 446", + interp.lerp(startFont, endFont, 0.492f, 0.492f), + ) } @Test -- GitLab From 2a466400ab2d857bb15d8dee405d68ff63d63656 Mon Sep 17 00:00:00 2001 From: Yiyi Shen Date: Thu, 13 Feb 2025 17:17:21 +0800 Subject: [PATCH 004/111] [Audiosharing] Disable auto pick in ui when developer preview on Test: atest Bug: 383469911 Flag: com.android.settingslib.flags.audio_sharing_developer_option Change-Id: Id3da26924a18585c9aac9cf77b0310202d6c074e --- .../settingslib/bluetooth/BluetoothUtils.java | 2 +- .../bluetooth/LocalBluetoothLeBroadcast.java | 22 ++++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index a00484ac28ab7..ec76dd276ae1b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -1064,7 +1064,7 @@ public class BluetoothUtils { /** Get develop option value for audio sharing preview. */ @WorkerThread - private static boolean getAudioSharingPreviewValue(@Nullable ContentResolver contentResolver) { + public static boolean getAudioSharingPreviewValue(@Nullable ContentResolver contentResolver) { if (contentResolver == null) return false; return Settings.Global.getInt( contentResolver, diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java index 84156429809bd..af5752605a879 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java @@ -142,8 +142,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { private ContentResolver mContentResolver; private ContentObserver mSettingsObserver; // Cached broadcast callbacks being register before service is connected. - private Map mCachedBroadcastCallbackExecutorMap = - new ConcurrentHashMap<>(); + private ConcurrentHashMap + mCachedBroadcastCallbackExecutorMap = new ConcurrentHashMap<>(); private final ServiceListener mServiceListener = new ServiceListener() { @@ -873,7 +873,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { @NonNull @CallbackExecutor Executor executor, @NonNull BluetoothLeBroadcast.Callback callback) { if (mServiceBroadcast == null) { - Log.d(TAG, "registerServiceCallBack failed, the BluetoothLeBroadcast is null."); + Log.d(TAG, "registerServiceCallBack failed, proxy not attached."); mCachedBroadcastCallbackExecutorMap.putIfAbsent(callback, executor); return; } @@ -895,10 +895,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { @NonNull @CallbackExecutor Executor executor, @NonNull BluetoothLeBroadcastAssistant.Callback callback) { if (mServiceBroadcastAssistant == null) { - Log.d( - TAG, - "registerBroadcastAssistantCallback failed, " - + "the BluetoothLeBroadcastAssistant is null."); + Log.d(TAG, "registerBroadcastAssistantCallback failed, proxy not attached."); return; } @@ -913,7 +910,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { public void unregisterServiceCallBack(@NonNull BluetoothLeBroadcast.Callback callback) { mCachedBroadcastCallbackExecutorMap.remove(callback); if (mServiceBroadcast == null) { - Log.d(TAG, "unregisterServiceCallBack failed, the BluetoothLeBroadcast is null."); + Log.d(TAG, "unregisterServiceCallBack failed, proxy not attached."); return; } @@ -932,10 +929,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { private void unregisterBroadcastAssistantCallback( @NonNull BluetoothLeBroadcastAssistant.Callback callback) { if (mServiceBroadcastAssistant == null) { - Log.d( - TAG, - "unregisterBroadcastAssistantCallback, " - + "the BluetoothLeBroadcastAssistant is null."); + Log.d(TAG, "unregisterBroadcastAssistantCallback, proxy not attched."); return; } @@ -1128,7 +1122,9 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { /** Update fallback active device if needed. */ public void updateFallbackActiveDeviceIfNeeded() { - if (Flags.disableAudioSharingAutoPickFallbackInUi()) { + if (Flags.disableAudioSharingAutoPickFallbackInUi() || (mContext != null + && Flags.audioSharingDeveloperOption() + && BluetoothUtils.getAudioSharingPreviewValue(mContext.getContentResolver()))) { Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded, disable flag is on"); return; } -- GitLab From 8b53f4656c9760da39d5b55b86dde5b311ed131d Mon Sep 17 00:00:00 2001 From: John Wu Date: Fri, 27 Dec 2024 00:50:15 +0000 Subject: [PATCH 005/111] [Ravenwood] Enable graphics support Bug: 337110712 Flag: EXEMPT host side change only Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh Test: atest FrameworksCoreTestsRavenwood Test: atest CtsGraphicsTestCasesRavenwood Test: atest CtsResourcesTestCasesRavenwood Test: atest CtsTextTestCasesRavenwood Change-Id: I90a79a92987870d494ed927eb6ba02747e247929 --- core/java/android/app/Instrumentation.java | 13 +- core/java/android/content/res/Resources.java | 2 - .../android/content/res/ResourcesImpl.java | 1 - core/java/android/content/res/TypedArray.java | 1 - .../fonts/FontFamilyUpdateRequest.java | 1 + .../graphics/fonts/FontFileUpdateRequest.java | 1 + .../android/text/AlteredCharSequence.java | 1 + core/java/android/text/AndroidBidi.java | 1 + core/java/android/text/AndroidCharacter.java | 1 + core/java/android/text/Annotation.java | 1 + core/java/android/text/AutoGrowArray.java | 1 + core/java/android/text/AutoText.java | 1 + core/java/android/text/BidiFormatter.java | 1 + core/java/android/text/BoringLayout.java | 1 + .../text/CharSequenceCharacterIterator.java | 1 + core/java/android/text/ClipboardManager.java | 1 + core/java/android/text/DynamicLayout.java | 1 + core/java/android/text/Editable.java | 1 + core/java/android/text/Emoji.java | 1 + core/java/android/text/EmojiConsistency.java | 1 + core/java/android/text/FontConfig.java | 1 + core/java/android/text/GetChars.java | 1 + .../text/GraphemeClusterSegmentFinder.java | 1 + .../java/android/text/GraphicsOperations.java | 1 + core/java/android/text/Highlights.java | 1 + core/java/android/text/Html.java | 41 ++-- core/java/android/text/Hyphenator.java | 1 + core/java/android/text/InputFilter.java | 1 + core/java/android/text/InputType.java | 1 + core/java/android/text/Layout.java | 1 + core/java/android/text/LoginFilter.java | 1 + core/java/android/text/MeasuredParagraph.java | 1 + core/java/android/text/NoCopySpan.java | 1 + core/java/android/text/PackedIntVector.java | 1 + .../java/android/text/PackedObjectVector.java | 1 + core/java/android/text/ParcelableSpan.java | 1 + core/java/android/text/PrecomputedText.java | 1 + core/java/android/text/SegmentFinder.java | 1 + core/java/android/text/Selection.java | 1 + core/java/android/text/SpanColors.java | 1 + core/java/android/text/SpanSet.java | 1 + core/java/android/text/SpanWatcher.java | 1 + core/java/android/text/Spannable.java | 1 + core/java/android/text/SpannableString.java | 1 + .../android/text/SpannableStringBuilder.java | 1 + .../android/text/SpannableStringInternal.java | 1 + core/java/android/text/Spanned.java | 1 + core/java/android/text/SpannedString.java | 1 + core/java/android/text/StaticLayout.java | 1 + .../android/text/TextDirectionHeuristic.java | 1 + .../android/text/TextDirectionHeuristics.java | 1 + core/java/android/text/TextLine.java | 1 + core/java/android/text/TextPaint.java | 1 + core/java/android/text/TextShaper.java | 1 + core/java/android/text/TextUtils.java | 44 +--- core/java/android/text/TextWatcher.java | 1 + core/java/android/text/WordSegmentFinder.java | 1 + core/java/android/text/format/DateFormat.java | 1 + .../text/format/DateIntervalFormat.java | 1 + .../android/text/format/DateTimeFormat.java | 1 + core/java/android/text/format/DateUtils.java | 1 + .../android/text/format/DateUtilsBridge.java | 1 + core/java/android/text/format/Formatter.java | 1 + .../format/RelativeDateTimeFormatter.java | 1 + core/java/android/text/format/Time.java | 1 + .../android/text/format/TimeFormatter.java | 1 + .../text/format/TimeMigrationUtils.java | 1 + .../method/AllCapsTransformationMethod.java | 1 + .../text/method/ArrowKeyMovementMethod.java | 1 + .../android/text/method/BaseKeyListener.java | 1 + .../text/method/BaseMovementMethod.java | 1 + .../text/method/CharacterPickerDialog.java | 1 + .../android/text/method/DateKeyListener.java | 1 + .../text/method/DateTimeKeyListener.java | 1 + .../text/method/DialerKeyListener.java | 1 + .../text/method/DigitsKeyListener.java | 1 + .../HideReturnsTransformationMethod.java | 1 + .../InsertModeTransformationMethod.java | 1 + .../java/android/text/method/KeyListener.java | 1 + .../text/method/LinkMovementMethod.java | 1 + .../text/method/MetaKeyKeyListener.java | 1 + .../android/text/method/MovementMethod.java | 1 + .../text/method/MultiTapKeyListener.java | 1 + .../text/method/NumberKeyListener.java | 1 + .../android/text/method/OffsetMapping.java | 1 + .../method/PasswordTransformationMethod.java | 1 + .../text/method/QwertyKeyListener.java | 1 + .../ReplacementTransformationMethod.java | 1 + .../text/method/ScrollingMovementMethod.java | 1 + .../SingleLineTransformationMethod.java | 1 + .../android/text/method/TextKeyListener.java | 1 + .../android/text/method/TimeKeyListener.java | 1 + core/java/android/text/method/Touch.java | 1 + .../text/method/TransformationMethod.java | 1 + .../text/method/TransformationMethod2.java | 1 + .../TranslationTransformationMethod.java | 1 + .../android/text/method/WordIterator.java | 1 + .../android/text/style/AbsoluteSizeSpan.java | 1 + .../style/AccessibilityClickableSpan.java | 1 + .../style/AccessibilityReplacementSpan.java | 1 + .../text/style/AccessibilityURLSpan.java | 1 + .../android/text/style/AlignmentSpan.java | 1 + .../text/style/BackgroundColorSpan.java | 1 + core/java/android/text/style/BulletSpan.java | 1 + .../android/text/style/CharacterStyle.java | 1 + .../android/text/style/ClickableSpan.java | 1 + .../text/style/ForegroundColorSpan.java | 1 + .../android/text/style/IconMarginSpan.java | 1 + .../android/text/style/LeadingMarginSpan.java | 1 + .../text/style/LineBackgroundSpan.java | 1 + .../text/style/LineBreakConfigSpan.java | 1 + .../android/text/style/LineHeightSpan.java | 1 + core/java/android/text/style/LocaleSpan.java | 1 + .../android/text/style/MaskFilterSpan.java | 1 + .../text/style/MetricAffectingSpan.java | 1 + .../text/style/NoWritingToolsSpan.java | 1 + .../android/text/style/ParagraphStyle.java | 1 + core/java/android/text/style/QuoteSpan.java | 1 + .../android/text/style/RasterizerSpan.java | 1 + .../android/text/style/RelativeSizeSpan.java | 1 + .../android/text/style/ReplacementSpan.java | 1 + core/java/android/text/style/ScaleXSpan.java | 1 + core/java/android/text/style/SpanUtils.java | 1 + .../android/text/style/SpellCheckSpan.java | 1 + .../android/text/style/StrikethroughSpan.java | 1 + core/java/android/text/style/StyleSpan.java | 1 + .../android/text/style/SubscriptSpan.java | 1 + .../text/style/SuggestionRangeSpan.java | 1 + .../android/text/style/SuggestionSpan.java | 1 + .../android/text/style/SuperscriptSpan.java | 1 + core/java/android/text/style/TabStopSpan.java | 1 + .../text/style/TextAppearanceSpan.java | 1 + core/java/android/text/style/TtsSpan.java | 1 + .../java/android/text/style/TypefaceSpan.java | 1 + core/java/android/text/style/URLSpan.java | 1 + .../android/text/style/UnderlineSpan.java | 1 + .../android/text/style/UpdateAppearance.java | 1 + .../java/android/text/style/UpdateLayout.java | 1 + .../android/text/style/WrapTogetherSpan.java | 1 + core/java/android/text/util/Rfc822Token.java | 1 + .../android/text/util/Rfc822Tokenizer.java | 1 + core/jni/Android.bp | 1 + core/tests/coretests/Android.bp | 27 +- .../content/res/FontScaleConverterTest.kt | 5 - .../android/graphics/BitmapFactoryTest.java | 3 + .../src/android/graphics/BitmapTest.java | 3 + .../src/android/graphics/PaintTest.java | 3 + .../graphics/TypefaceSystemFallbackTest.java | 10 +- .../src/android/graphics/TypefaceTest.java | 2 + .../android/text/AndroidCharacterTest.java | 2 + .../src/android/text/SpanColorsTest.java | 2 + .../src/android/text/SpannableTest.java | 10 +- .../src/android/text/StaticLayoutTest.java | 2 + .../src/android/text/TextUtilsTest.java | 4 +- .../android/text/format/DateFormatTest.java | 5 +- .../text/format/DateIntervalFormatTest.java | 2 + .../android/text/format/DateUtilsTest.java | 2 + .../text/format/TimeMigrationUtilsTest.java | 2 + .../src/android/text/format/TimeTest.java | 2 + .../android/text/method/BackspaceTest.java | 2 + .../src/android/text/method/EditorState.java | 3 +- .../text/method/ForwardDeleteTest.java | 2 + .../InsertModeTransformationMethodTest.java | 2 + .../src/android/text/util/LinkifyTest.java | 2 + .../java/android/graphics/AvoidXfermode.java | 1 + .../android/graphics/BLASTBufferQueue.java | 1 + .../java/android/graphics/BaseCanvas.java | 1 + .../android/graphics/BaseRecordingCanvas.java | 1 + graphics/java/android/graphics/Bitmap.java | 1 + .../java/android/graphics/BitmapFactory.java | 1 + .../android/graphics/BitmapRegionDecoder.java | 1 + .../java/android/graphics/BitmapShader.java | 1 + graphics/java/android/graphics/BlendMode.java | 1 + .../graphics/BlendModeColorFilter.java | 1 + .../java/android/graphics/BlurMaskFilter.java | 1 + graphics/java/android/graphics/Camera.java | 1 + graphics/java/android/graphics/Canvas.java | 1 + .../java/android/graphics/CanvasProperty.java | 1 + .../java/android/graphics/ColorFilter.java | 1 + .../graphics/ColorMatrixColorFilter.java | 1 + .../java/android/graphics/Compatibility.java | 1 + .../android/graphics/ComposePathEffect.java | 1 + .../java/android/graphics/ComposeShader.java | 1 + .../android/graphics/CornerPathEffect.java | 1 + .../java/android/graphics/DashPathEffect.java | 1 + .../android/graphics/DiscretePathEffect.java | 1 + .../java/android/graphics/DrawFilter.java | 1 + .../android/graphics/EmbossMaskFilter.java | 1 + .../java/android/graphics/FontFamily.java | 1 + .../java/android/graphics/FontListParser.java | 1 + .../java/android/graphics/ForceDarkType.java | 1 + graphics/java/android/graphics/FrameInfo.java | 1 + graphics/java/android/graphics/Gainmap.java | 1 + .../java/android/graphics/GraphicBuffer.java | 1 + .../java/android/graphics/GraphicsProtos.java | 1 + .../graphics/GraphicsStatsService.java | 1 + .../graphics/HardwareBufferRenderer.java | 1 + .../android/graphics/HardwareRenderer.java | 1 + .../graphics/HardwareRendererObserver.java | 1 + .../java/android/graphics/ImageDecoder.java | 5 + .../java/android/graphics/ImageFormat.java | 1 + .../android/graphics/LayerRasterizer.java | 1 + .../graphics/LeakyTypefaceStorage.java | 1 + .../android/graphics/LightingColorFilter.java | 1 + .../java/android/graphics/LinearGradient.java | 1 + .../java/android/graphics/MaskFilter.java | 1 + graphics/java/android/graphics/Mesh.java | 1 + .../android/graphics/MeshSpecification.java | 1 + graphics/java/android/graphics/Movie.java | 1 + graphics/java/android/graphics/NinePatch.java | 1 + graphics/java/android/graphics/Paint.java | 1 + .../graphics/PaintFlagsDrawFilter.java | 1 + .../android/graphics/PathDashPathEffect.java | 1 + .../java/android/graphics/PathEffect.java | 1 + .../java/android/graphics/PathIterator.java | 16 +- .../java/android/graphics/PathMeasure.java | 1 + graphics/java/android/graphics/Picture.java | 1 + .../android/graphics/PixelXorXfermode.java | 1 + .../java/android/graphics/PorterDuff.java | 1 + .../graphics/PorterDuffColorFilter.java | 1 + .../android/graphics/PorterDuffXfermode.java | 1 + .../java/android/graphics/PostProcessor.java | 1 + .../java/android/graphics/RadialGradient.java | 1 + .../java/android/graphics/Rasterizer.java | 1 + .../android/graphics/RecordingCanvas.java | 1 + graphics/java/android/graphics/Region.java | 1 + .../java/android/graphics/RegionIterator.java | 1 + .../java/android/graphics/RenderEffect.java | 1 + .../java/android/graphics/RenderNode.java | 1 + .../android/graphics/RuntimeColorFilter.java | 1 + .../java/android/graphics/RuntimeShader.java | 1 + .../android/graphics/RuntimeXfermode.java | 1 + graphics/java/android/graphics/Shader.java | 1 + .../java/android/graphics/SumPathEffect.java | 1 + .../java/android/graphics/SurfaceTexture.java | 1 + .../java/android/graphics/SweepGradient.java | 1 + .../android/graphics/TableMaskFilter.java | 1 + .../android/graphics/TemporaryBuffer.java | 1 + .../java/android/graphics/TextureLayer.java | 1 + graphics/java/android/graphics/Typeface.java | 45 +++- graphics/java/android/graphics/Xfermode.java | 1 + graphics/java/android/graphics/YuvImage.java | 1 + .../java/android/graphics/fonts/Font.java | 11 +- .../fonts/FontCustomizationParser.java | 1 + .../android/graphics/fonts/FontFamily.java | 1 + .../android/graphics/fonts/FontFileUtil.java | 1 + .../android/graphics/fonts/FontStyle.java | 1 + .../graphics/fonts/FontVariationAxis.java | 1 + .../android/graphics/fonts/SystemFonts.java | 31 ++- .../android/graphics/text/GraphemeBreak.java | 1 + .../graphics/text/LineBreakConfig.java | 10 +- .../android/graphics/text/LineBreaker.java | 1 + .../android/graphics/text/MeasuredText.java | 1 + .../graphics/text/PositionedGlyphs.java | 1 + .../android/graphics/text/TextRunShaper.java | 1 + libs/hwui/Android.bp | 12 + .../framework-graphics-ravenwood-policies.txt | 1 + libs/hwui/jni/Bitmap.cpp | 12 +- libs/hwui/jni/Region.cpp | 6 +- libs/hwui/jni/ScopedParcel.cpp | 4 +- libs/hwui/jni/ScopedParcel.h | 4 +- libs/hwui/jni/graphics_jni_helpers.h | 1 + ravenwood/Android.bp | 10 + ravenwood/Framework.bp | 4 +- .../test/ravenwood/RavenwoodContext.java | 10 + .../test/ravenwood/RavenwoodNativeLoader.java | 39 ++- ...RavenwoodRuntimeEnvironmentController.java | 13 + .../android/ravenwood/RavenwoodJdkPatch.java | 19 ++ .../ravenwood/RavenwoodRuntimeNative.java | 2 + .../dalvik/system/CloseGuard.java | 198 +++++++++++++++ .../libcore-fake/libcore/io/IoBridge.java | 63 +++++ .../util/NativeAllocationRegistry.java | 63 ++++- ravenwood/runtime-jni/ravenwood_runtime.cpp | 6 + .../ravenwood-annotation-allowed-classes.txt | 231 ++++++++++++++++++ ravenwood/texts/ravenwood-build.prop | 6 +- ravenwood/texts/ravenwood-common-policies.txt | 4 + .../texts/ravenwood-framework-policies.txt | 19 ++ 277 files changed, 1132 insertions(+), 133 deletions(-) create mode 100644 libs/hwui/framework-graphics-ravenwood-policies.txt create mode 100644 ravenwood/runtime-helper-src/libcore-fake/dalvik/system/CloseGuard.java create mode 100644 ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoBridge.java diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index b611acf79bc31..eb9feb95bf3d3 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -50,6 +50,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.ravenwood.annotation.RavenwoodKeep; import android.ravenwood.annotation.RavenwoodKeepPartialClass; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodReplace; import android.util.AndroidRuntimeException; import android.util.Log; @@ -460,6 +461,7 @@ public class Instrumentation { * * @param runner The code to run on the main thread. */ + @RavenwoodReplace(blockedBy = ActivityThread.class) public void runOnMainSync(Runnable runner) { validateNotAppThread(); SyncRunnable sr = new SyncRunnable(runner); @@ -467,6 +469,13 @@ public class Instrumentation { sr.waitForComplete(); } + private void runOnMainSync$ravenwood(Runnable runner) { + validateNotAppThread(); + SyncRunnable sr = new SyncRunnable(runner); + mInstrContext.getMainExecutor().execute(sr); + sr.waitForComplete(); + } + boolean isSdkSandboxAllowedToStartActivities() { return Process.isSdkSandbox() && mThread != null @@ -2442,7 +2451,8 @@ public class Instrumentation { } } - private final void validateNotAppThread() { + @RavenwoodKeep + private void validateNotAppThread() { if (Looper.myLooper() == Looper.getMainLooper()) { throw new RuntimeException( "This method can not be called from the main application thread"); @@ -2586,6 +2596,7 @@ public class Instrumentation { } } + @RavenwoodKeepWholeClass private static final class SyncRunnable implements Runnable { private final Runnable mTarget; private boolean mComplete; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 05596318aef57..2658efab0e44f 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -482,7 +482,6 @@ public class Resources { * * @return Typeface The Typeface data associated with the resource. */ - @RavenwoodThrow(blockedBy = Typeface.class) @NonNull public Typeface getFont(@FontRes int id) throws NotFoundException { final TypedValue value = obtainTempTypedValue(); try { @@ -507,7 +506,6 @@ public class Resources { /** * @hide */ - @RavenwoodThrow(blockedBy = Typeface.class) public void preloadFonts(@ArrayRes int id) { final TypedArray array = obtainTypedArray(id); try { diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 96c71765d1023..ddad54d94cc6c 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -1064,7 +1064,6 @@ public class ResourcesImpl { * Loads a font from XML or resources stream. */ @Nullable - @RavenwoodThrow(blockedBy = Typeface.class) public Typeface loadFont(Resources wrapper, TypedValue value, int id) { if (value.string == null) { throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 79185a10e156c..ee7d008cf3141 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -1043,7 +1043,6 @@ public class TypedArray implements AutoCloseable { * not a font resource. */ @Nullable - @RavenwoodThrow(blockedBy = Typeface.class) public Typeface getFont(@StyleableRes int index) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); diff --git a/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java index bfbcfd828114a..1bf01f4beb1b7 100644 --- a/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java +++ b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java @@ -68,6 +68,7 @@ import java.util.Objects; * @hide */ @SystemApi +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class FontFamilyUpdateRequest { /** diff --git a/core/java/android/graphics/fonts/FontFileUpdateRequest.java b/core/java/android/graphics/fonts/FontFileUpdateRequest.java index cf1dca9652167..1f2be6fa5050b 100644 --- a/core/java/android/graphics/fonts/FontFileUpdateRequest.java +++ b/core/java/android/graphics/fonts/FontFileUpdateRequest.java @@ -28,6 +28,7 @@ import java.util.Objects; * @hide */ @SystemApi +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class FontFileUpdateRequest { private final ParcelFileDescriptor mParcelFileDescriptor; diff --git a/core/java/android/text/AlteredCharSequence.java b/core/java/android/text/AlteredCharSequence.java index 971a47dba6e80..a05c690a9e30a 100644 --- a/core/java/android/text/AlteredCharSequence.java +++ b/core/java/android/text/AlteredCharSequence.java @@ -24,6 +24,7 @@ package android.text; * @deprecated The functionality this class offers is easily implemented outside the framework. */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AlteredCharSequence implements CharSequence, GetChars { diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java index 31da799951720..fcdd50abc02ad 100644 --- a/core/java/android/text/AndroidBidi.java +++ b/core/java/android/text/AndroidBidi.java @@ -28,6 +28,7 @@ import com.android.internal.annotations.VisibleForTesting; * @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AndroidBidi { /** diff --git a/core/java/android/text/AndroidCharacter.java b/core/java/android/text/AndroidCharacter.java index c5f1a01f59271..37c4fdbef915a 100644 --- a/core/java/android/text/AndroidCharacter.java +++ b/core/java/android/text/AndroidCharacter.java @@ -22,6 +22,7 @@ package android.text; * @deprecated Use various methods from {@link android.icu.lang.UCharacter}, instead. */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AndroidCharacter { public static final int EAST_ASIAN_WIDTH_NEUTRAL = 0; diff --git a/core/java/android/text/Annotation.java b/core/java/android/text/Annotation.java index bb5d3ea7da4bc..ac3e5a964a33b 100644 --- a/core/java/android/text/Annotation.java +++ b/core/java/android/text/Annotation.java @@ -23,6 +23,7 @@ import android.os.Parcel; * TextView save/restore cycles and can be used to keep application-specific * data that needs to be maintained for regions of text. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Annotation implements ParcelableSpan { private final String mKey; private final String mValue; diff --git a/core/java/android/text/AutoGrowArray.java b/core/java/android/text/AutoGrowArray.java index e428377a0a313..06c74c3370c1d 100644 --- a/core/java/android/text/AutoGrowArray.java +++ b/core/java/android/text/AutoGrowArray.java @@ -30,6 +30,7 @@ import libcore.util.EmptyArray; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class AutoGrowArray { private static final int MIN_CAPACITY_INCREMENT = 12; private static final int MAX_CAPACITY_TO_BE_KEPT = 10000; diff --git a/core/java/android/text/AutoText.java b/core/java/android/text/AutoText.java index c5339a42cbd1f..d7b0547e6c4ce 100644 --- a/core/java/android/text/AutoText.java +++ b/core/java/android/text/AutoText.java @@ -31,6 +31,7 @@ import java.util.Locale; /** * This class accesses a dictionary of corrections to frequent misspellings. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AutoText { // struct trie { // char c; diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java index dfa172df72ea2..6d4103cee7a61 100644 --- a/core/java/android/text/BidiFormatter.java +++ b/core/java/android/text/BidiFormatter.java @@ -82,6 +82,7 @@ import java.util.Locale; * first-strong estimation algorithm. It can also be configured to use a custom directionality * estimation object. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class BidiFormatter { /** diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java index 4fdcecc4f782f..2b410e6284bf2 100644 --- a/core/java/android/text/BoringLayout.java +++ b/core/java/android/text/BoringLayout.java @@ -45,6 +45,7 @@ import com.android.text.flags.Flags; * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) * Canvas.drawText()} directly.

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback { /** diff --git a/core/java/android/text/CharSequenceCharacterIterator.java b/core/java/android/text/CharSequenceCharacterIterator.java index 9b07d29bd9dd5..1599be8237d44 100644 --- a/core/java/android/text/CharSequenceCharacterIterator.java +++ b/core/java/android/text/CharSequenceCharacterIterator.java @@ -24,6 +24,7 @@ import java.text.CharacterIterator; * An implementation of {@link java.text.CharacterIterator} that iterates over a given CharSequence. * {@hide} */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class CharSequenceCharacterIterator implements CharacterIterator { private final int mBeginIndex, mEndIndex; private int mIndex; diff --git a/core/java/android/text/ClipboardManager.java b/core/java/android/text/ClipboardManager.java index d0309100b0f2e..41990f0fc8dd3 100644 --- a/core/java/android/text/ClipboardManager.java +++ b/core/java/android/text/ClipboardManager.java @@ -21,6 +21,7 @@ package android.text; * {@link android.content.ClipboardManager} for the modern API. */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class ClipboardManager { /** * Returns the text on the clipboard. It will eventually be possible diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index 6b1aef710e504..3b66ce0167c49 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -53,6 +53,7 @@ import java.lang.ref.WeakReference; * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) * Canvas.drawText()} directly.

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DynamicLayout extends Layout { private static final int PRIORITY = 128; private static final int BLOCK_MINIMUM_CHARACTER_LENGTH = 400; diff --git a/core/java/android/text/Editable.java b/core/java/android/text/Editable.java index a942f6ce28793..53d819f52a5c8 100644 --- a/core/java/android/text/Editable.java +++ b/core/java/android/text/Editable.java @@ -22,6 +22,7 @@ package android.text; * to immutable text like Strings). If you make a {@link DynamicLayout} * of an Editable, the layout will be reflowed as the text is changed. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface Editable extends CharSequence, GetChars, Spannable, Appendable { diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java index cf0e3c26daac2..28c37c00d66e8 100644 --- a/core/java/android/text/Emoji.java +++ b/core/java/android/text/Emoji.java @@ -23,6 +23,7 @@ import android.icu.lang.UProperty; * An utility class for Emoji. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Emoji { public static int COMBINING_ENCLOSING_KEYCAP = 0x20E3; diff --git a/core/java/android/text/EmojiConsistency.java b/core/java/android/text/EmojiConsistency.java index dfaa217c0cca7..9823305ec72a2 100644 --- a/core/java/android/text/EmojiConsistency.java +++ b/core/java/android/text/EmojiConsistency.java @@ -48,6 +48,7 @@ import java.util.Set; * *

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class EmojiConsistency { /* Cannot construct */ private EmojiConsistency() { } diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java index 783f3b7aa64bf..5a4d3a8670327 100644 --- a/core/java/android/text/FontConfig.java +++ b/core/java/android/text/FontConfig.java @@ -55,6 +55,7 @@ import java.util.Objects; */ @SystemApi @TestApi +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class FontConfig implements Parcelable { private final @NonNull List mFamilies; private final @NonNull List mAliases; diff --git a/core/java/android/text/GetChars.java b/core/java/android/text/GetChars.java index 348a911a442ff..229f5437e76bd 100644 --- a/core/java/android/text/GetChars.java +++ b/core/java/android/text/GetChars.java @@ -21,6 +21,7 @@ package android.text; * getChars() method like the one in String that is faster than * calling charAt() multiple times. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface GetChars extends CharSequence { diff --git a/core/java/android/text/GraphemeClusterSegmentFinder.java b/core/java/android/text/GraphemeClusterSegmentFinder.java index 0f6fdaf23c656..996223dd1a84f 100644 --- a/core/java/android/text/GraphemeClusterSegmentFinder.java +++ b/core/java/android/text/GraphemeClusterSegmentFinder.java @@ -31,6 +31,7 @@ import android.graphics.text.GraphemeBreak; * @see Unicode Text * Segmentation - Grapheme Cluster Boundaries */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class GraphemeClusterSegmentFinder extends SegmentFinder { private static AutoGrowArray.FloatArray sTempAdvances = null; private final boolean[] mIsGraphemeBreak; diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java index 6c1544644eab0..f7fe805e53a4e 100644 --- a/core/java/android/text/GraphicsOperations.java +++ b/core/java/android/text/GraphicsOperations.java @@ -26,6 +26,7 @@ import android.graphics.Paint; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface GraphicsOperations extends CharSequence { /** * Just like {@link Canvas#drawText}. diff --git a/core/java/android/text/Highlights.java b/core/java/android/text/Highlights.java index 693dbcf84e84e..217a38b6edd5a 100644 --- a/core/java/android/text/Highlights.java +++ b/core/java/android/text/Highlights.java @@ -30,6 +30,7 @@ import java.util.Objects; /** * A class that represents of the highlight of the text. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Highlights { private final List> mHighlights; diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index a42eece57eec9..d412071bf3b93 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -17,13 +17,13 @@ package android.text; import android.app.ActivityThread; -import android.app.Application; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; +import android.ravenwood.annotation.RavenwoodReplace; import android.text.style.AbsoluteSizeSpan; import android.text.style.AlignmentSpan; import android.text.style.BackgroundColorSpan; @@ -65,6 +65,7 @@ import java.util.regex.Pattern; * This class processes HTML strings into displayable styled text. * Not all HTML tags are supported. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Html { /** * Retrieves images for HTML <img> tags. @@ -506,6 +507,15 @@ public class Html { out.append("

\n"); } + @RavenwoodReplace(blockedBy = ActivityThread.class) + private static float getDisplayMetricsDensity() { + return ActivityThread.currentApplication().getResources().getDisplayMetrics().density; + } + + private static float getDisplayMetricsDensity$ravenwood() { + return Resources.getSystem().getDisplayMetrics().density; + } + private static void withinParagraph(StringBuilder out, Spanned text, int start, int end) { int next; for (int i = start; i < end; i = next) { @@ -559,8 +569,7 @@ public class Html { AbsoluteSizeSpan s = ((AbsoluteSizeSpan) style[j]); float sizeDip = s.getSize(); if (!s.getDip()) { - Application application = ActivityThread.currentApplication(); - sizeDip /= application.getResources().getDisplayMetrics().density; + sizeDip /= getDisplayMetricsDensity(); } // px in CSS is the equivalance of dip in Android @@ -669,6 +678,7 @@ public class Html { } } +@android.ravenwood.annotation.RavenwoodKeepWholeClass class HtmlToSpannedConverter implements ContentHandler { private static final float[] HEADING_SIZES = { @@ -843,6 +853,16 @@ class HtmlToSpannedConverter implements ContentHandler { } } + @RavenwoodReplace(blockedBy = ActivityThread.class) + private static int getFontWeightAdjustment() { + return ActivityThread.currentApplication().getResources() + .getConfiguration().fontWeightAdjustment; + } + + private static int getFontWeightAdjustment$ravenwood() { + return Resources.getSystem().getConfiguration().fontWeightAdjustment; + } + private void handleEndTag(String tag) { if (tag.equalsIgnoreCase("br")) { handleBr(mSpannableStringBuilder); @@ -858,17 +878,11 @@ class HtmlToSpannedConverter implements ContentHandler { } else if (tag.equalsIgnoreCase("span")) { endCssStyle(mSpannableStringBuilder); } else if (tag.equalsIgnoreCase("strong")) { - Application application = ActivityThread.currentApplication(); - int fontWeightAdjustment = - application.getResources().getConfiguration().fontWeightAdjustment; end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD, - fontWeightAdjustment)); + getFontWeightAdjustment())); } else if (tag.equalsIgnoreCase("b")) { - Application application = ActivityThread.currentApplication(); - int fontWeightAdjustment = - application.getResources().getConfiguration().fontWeightAdjustment; end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD, - fontWeightAdjustment)); + getFontWeightAdjustment())); } else if (tag.equalsIgnoreCase("em")) { end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC)); } else if (tag.equalsIgnoreCase("cite")) { @@ -1036,11 +1050,8 @@ class HtmlToSpannedConverter implements ContentHandler { // Their ranges should not include the newlines at the end Heading h = getLast(text, Heading.class); if (h != null) { - Application application = ActivityThread.currentApplication(); - int fontWeightAdjustment = - application.getResources().getConfiguration().fontWeightAdjustment; setSpanFromMark(text, h, new RelativeSizeSpan(HEADING_SIZES[h.mLevel]), - new StyleSpan(Typeface.BOLD, fontWeightAdjustment)); + new StyleSpan(Typeface.BOLD, getFontWeightAdjustment())); } endBlockElement(text); diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java index 6f0628ad38e6c..7f9a8a1c08067 100644 --- a/core/java/android/text/Hyphenator.java +++ b/core/java/android/text/Hyphenator.java @@ -21,6 +21,7 @@ package android.text; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Hyphenator { private Hyphenator() {} diff --git a/core/java/android/text/InputFilter.java b/core/java/android/text/InputFilter.java index 96e7bd0fef4cb..ed5de03e5528e 100644 --- a/core/java/android/text/InputFilter.java +++ b/core/java/android/text/InputFilter.java @@ -27,6 +27,7 @@ import java.util.Locale; * InputFilters can be attached to {@link Editable}s to constrain the * changes that can be made to them. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface InputFilter { /** diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java index 4ebecb7494fa2..03c9c023d9ce8 100644 --- a/core/java/android/text/InputType.java +++ b/core/java/android/text/InputType.java @@ -44,6 +44,7 @@ import java.util.List; * TYPE_DATETIME_VARIATION_TIME * */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface InputType { /** * Mask of bits that determine the overall class diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 2fa56137a8a03..08453d09a1ffb 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -69,6 +69,7 @@ import java.util.Locale; * which will be updated as the text changes. * For text that will not change, use a {@link StaticLayout}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class Layout { // These should match the constants in framework/base/libs/hwui/hwui/DrawTextFunctor.h diff --git a/core/java/android/text/LoginFilter.java b/core/java/android/text/LoginFilter.java index 0e4eec4488ee6..94f196f7ef6bd 100644 --- a/core/java/android/text/LoginFilter.java +++ b/core/java/android/text/LoginFilter.java @@ -23,6 +23,7 @@ package android.text; * handle non-BMP characters. */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class LoginFilter implements InputFilter { private boolean mAppendInvalid; // whether to append or ignore invalid characters /** diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java index 31a226341907f..b2e44598a5486 100644 --- a/core/java/android/text/MeasuredParagraph.java +++ b/core/java/android/text/MeasuredParagraph.java @@ -68,6 +68,7 @@ import java.util.Arrays; * @hide */ @TestApi +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class MeasuredParagraph { private static final char OBJECT_REPLACEMENT_CHARACTER = '\uFFFC'; diff --git a/core/java/android/text/NoCopySpan.java b/core/java/android/text/NoCopySpan.java index e754d765e14c0..4cd3d04dc4e64 100644 --- a/core/java/android/text/NoCopySpan.java +++ b/core/java/android/text/NoCopySpan.java @@ -21,6 +21,7 @@ package android.text; * into a new Spanned when performing a slice or copy operation on the original * Spanned it was placed in. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface NoCopySpan { /** * Convenience equivalent for when you would just want a new Object() for diff --git a/core/java/android/text/PackedIntVector.java b/core/java/android/text/PackedIntVector.java index 3e5bf56778539..11dd0c38182b4 100644 --- a/core/java/android/text/PackedIntVector.java +++ b/core/java/android/text/PackedIntVector.java @@ -29,6 +29,7 @@ import com.android.internal.util.GrowingArrayUtils; * @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PackedIntVector { private final int mColumns; private int mRows; diff --git a/core/java/android/text/PackedObjectVector.java b/core/java/android/text/PackedObjectVector.java index b777e16a153d3..beb5ea4ee28cc 100644 --- a/core/java/android/text/PackedObjectVector.java +++ b/core/java/android/text/PackedObjectVector.java @@ -21,6 +21,7 @@ import com.android.internal.util.GrowingArrayUtils; import libcore.util.EmptyArray; +@android.ravenwood.annotation.RavenwoodKeepWholeClass class PackedObjectVector { private int mColumns; diff --git a/core/java/android/text/ParcelableSpan.java b/core/java/android/text/ParcelableSpan.java index d7c1a4bc26e8d..a9a4893d36928 100644 --- a/core/java/android/text/ParcelableSpan.java +++ b/core/java/android/text/ParcelableSpan.java @@ -24,6 +24,7 @@ import android.os.Parcelable; * This can only be used by code in the framework; it is not intended for * applications to implement their own Parcelable spans. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface ParcelableSpan extends Parcelable { /** * Return a special type identifier for this span class. diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java index 5f6a9bd068c9c..71cacd9b199a1 100644 --- a/core/java/android/text/PrecomputedText.java +++ b/core/java/android/text/PrecomputedText.java @@ -75,6 +75,7 @@ import java.util.Objects; * Note that any {@link android.text.NoCopySpan} attached to the original text won't be passed to * PrecomputedText. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PrecomputedText implements Spannable { private static final char LINE_FEED = '\n'; diff --git a/core/java/android/text/SegmentFinder.java b/core/java/android/text/SegmentFinder.java index 047d07a2e3e01..b7ab0e62753a4 100644 --- a/core/java/android/text/SegmentFinder.java +++ b/core/java/android/text/SegmentFinder.java @@ -39,6 +39,7 @@ import java.util.Objects; * * @see Layout#getRangeForRect(RectF, SegmentFinder, Layout.TextInclusionStrategy) */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class SegmentFinder { /** * Return value of previousStartBoundary(int), previousEndBoundary(int), nextStartBoundary(int), diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java index 711578c1482f7..674b473724829 100644 --- a/core/java/android/text/Selection.java +++ b/core/java/android/text/Selection.java @@ -27,6 +27,7 @@ import java.text.BreakIterator; * Utility class for manipulating cursors and selections in CharSequences. * A cursor is a selection where the start and end are at the same offset. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Selection { private Selection() { /* cannot be instantiated */ } diff --git a/core/java/android/text/SpanColors.java b/core/java/android/text/SpanColors.java index fcd242b627008..3b6a0418dcb02 100644 --- a/core/java/android/text/SpanColors.java +++ b/core/java/android/text/SpanColors.java @@ -27,6 +27,7 @@ import android.text.style.CharacterStyle; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SpanColors { public static final @ColorInt int NO_COLOR_FOUND = Color.TRANSPARENT; diff --git a/core/java/android/text/SpanSet.java b/core/java/android/text/SpanSet.java index d464278c714cc..4ad8106eb459a 100644 --- a/core/java/android/text/SpanSet.java +++ b/core/java/android/text/SpanSet.java @@ -31,6 +31,7 @@ import java.util.Arrays; * Note that empty spans are ignored by this class. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SpanSet { private final Class classType; diff --git a/core/java/android/text/SpanWatcher.java b/core/java/android/text/SpanWatcher.java index 01e82c815ac82..31d63206a144b 100644 --- a/core/java/android/text/SpanWatcher.java +++ b/core/java/android/text/SpanWatcher.java @@ -21,6 +21,7 @@ package android.text; * will be called to notify it that other markup objects have been * added, changed, or removed. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface SpanWatcher extends NoCopySpan { /** * This method is called to notify you that the specified object diff --git a/core/java/android/text/Spannable.java b/core/java/android/text/Spannable.java index 8315b2aa52c65..fac5131c035a2 100644 --- a/core/java/android/text/Spannable.java +++ b/core/java/android/text/Spannable.java @@ -21,6 +21,7 @@ package android.text; * attached and detached. Not all Spannable classes have mutable text; * see {@link Editable} for that. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface Spannable extends Spanned { diff --git a/core/java/android/text/SpannableString.java b/core/java/android/text/SpannableString.java index afb5df809bc03..ee04a86a808f6 100644 --- a/core/java/android/text/SpannableString.java +++ b/core/java/android/text/SpannableString.java @@ -21,6 +21,7 @@ package android.text; * markup objects can be attached and detached. * For mutable text, see {@link SpannableStringBuilder}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SpannableString extends SpannableStringInternal implements CharSequence, GetChars, Spannable diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java index 0e61eff86c2ba..f8d7283a94b3c 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -35,6 +35,7 @@ import java.util.IdentityHashMap; /** * This is the class for text whose content and markup can both be changed. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SpannableStringBuilder implements CharSequence, GetChars, Spannable, Editable, Appendable, GraphicsOperations { private final static String TAG = "SpannableStringBuilder"; diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java index f2ab1bb31fbc5..90d83d59eb656 100644 --- a/core/java/android/text/SpannableStringInternal.java +++ b/core/java/android/text/SpannableStringInternal.java @@ -27,6 +27,7 @@ import libcore.util.EmptyArray; import java.lang.reflect.Array; +@android.ravenwood.annotation.RavenwoodKeepWholeClass /* package */ abstract class SpannableStringInternal { /* package */ SpannableStringInternal(CharSequence source, diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java index a0d54c26c6d9d..6706ffd245c14 100644 --- a/core/java/android/text/Spanned.java +++ b/core/java/android/text/Spanned.java @@ -22,6 +22,7 @@ package android.text; * see {@link Spannable} for mutable markup and {@link Editable} for * mutable text. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface Spanned extends CharSequence { diff --git a/core/java/android/text/SpannedString.java b/core/java/android/text/SpannedString.java index acee3c5f1a41a..a3f1ee2e3f209 100644 --- a/core/java/android/text/SpannedString.java +++ b/core/java/android/text/SpannedString.java @@ -22,6 +22,7 @@ package android.text; * For mutable markup, see {@link SpannableString}; for mutable text, * see {@link SpannableStringBuilder}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class SpannedString extends SpannableStringInternal implements CharSequence, GetChars, Spanned diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index a5d52957c40e1..8193cd2beb80b 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -55,6 +55,7 @@ import java.util.Arrays; * float, float, android.graphics.Paint) * Canvas.drawText()} directly.

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class StaticLayout extends Layout { /* * The break iteration is done in native code. The protocol for using the native code is as diff --git a/core/java/android/text/TextDirectionHeuristic.java b/core/java/android/text/TextDirectionHeuristic.java index 8a4ba42bcc917..66cea853cda9c 100644 --- a/core/java/android/text/TextDirectionHeuristic.java +++ b/core/java/android/text/TextDirectionHeuristic.java @@ -19,6 +19,7 @@ package android.text; /** * Interface for objects that use a heuristic for guessing at the paragraph direction by examining text. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface TextDirectionHeuristic { /** * Guess if a chars array is in the RTL direction or not. diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java index 85260f4af2c88..3af8fb7f489df 100644 --- a/core/java/android/text/TextDirectionHeuristics.java +++ b/core/java/android/text/TextDirectionHeuristics.java @@ -32,6 +32,7 @@ import java.nio.CharBuffer; * class. * */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TextDirectionHeuristics { /** diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 3015791ee0a9c..091eb60270020 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -53,6 +53,7 @@ import java.util.ArrayList; * @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TextLine { private static final boolean DEBUG = false; diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java index 73825b13cb6be..ff063f2ac2f49 100644 --- a/core/java/android/text/TextPaint.java +++ b/core/java/android/text/TextPaint.java @@ -25,6 +25,7 @@ import android.graphics.Paint; * TextPaint is an extension of Paint that leaves room for some extra * data used during text measuring and drawing. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TextPaint extends Paint { // Special value 0 means no background paint diff --git a/core/java/android/text/TextShaper.java b/core/java/android/text/TextShaper.java index 6da0b63dbc1f3..6d17401847638 100644 --- a/core/java/android/text/TextShaper.java +++ b/core/java/android/text/TextShaper.java @@ -169,6 +169,7 @@ import android.graphics.text.TextRunShaper; * @see TextShaper#shapeText(CharSequence, int, int, TextDirectionHeuristic, TextPaint, * GlyphsConsumer) */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TextShaper { private TextShaper() {} diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index 6dc82c40ddc51..042966b81b9af 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -34,6 +34,7 @@ import android.icu.text.Edits; import android.icu.util.ULocale; import android.os.Parcel; import android.os.Parcelable; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.sysprop.DisplayProperties; import android.text.style.AbsoluteSizeSpan; import android.text.style.AccessibilityClickableSpan; @@ -85,8 +86,7 @@ import java.util.List; import java.util.Locale; import java.util.regex.Pattern; -@android.ravenwood.annotation.RavenwoodKeepStaticInitializer -@android.ravenwood.annotation.RavenwoodKeepPartialClass +@RavenwoodKeepWholeClass public class TextUtils { private static final String TAG = "TextUtils"; @@ -147,7 +147,6 @@ public class TextUtils { private TextUtils() { /* cannot be instantiated */ } - @android.ravenwood.annotation.RavenwoodKeep public static void getChars(CharSequence s, int start, int end, char[] dest, int destoff) { Class c = s.getClass(); @@ -166,12 +165,10 @@ public class TextUtils { } } - @android.ravenwood.annotation.RavenwoodKeep public static int indexOf(CharSequence s, char ch) { return indexOf(s, ch, 0); } - @android.ravenwood.annotation.RavenwoodKeep public static int indexOf(CharSequence s, char ch, int start) { Class c = s.getClass(); @@ -181,7 +178,6 @@ public class TextUtils { return indexOf(s, ch, start, s.length()); } - @android.ravenwood.annotation.RavenwoodKeep public static int indexOf(CharSequence s, char ch, int start, int end) { Class c = s.getClass(); @@ -219,12 +215,10 @@ public class TextUtils { return -1; } - @android.ravenwood.annotation.RavenwoodKeep public static int lastIndexOf(CharSequence s, char ch) { return lastIndexOf(s, ch, s.length() - 1); } - @android.ravenwood.annotation.RavenwoodKeep public static int lastIndexOf(CharSequence s, char ch, int last) { Class c = s.getClass(); @@ -234,7 +228,6 @@ public class TextUtils { return lastIndexOf(s, ch, 0, last); } - @android.ravenwood.annotation.RavenwoodKeep public static int lastIndexOf(CharSequence s, char ch, int start, int last) { if (last < 0) @@ -280,17 +273,14 @@ public class TextUtils { return -1; } - @android.ravenwood.annotation.RavenwoodKeep public static int indexOf(CharSequence s, CharSequence needle) { return indexOf(s, needle, 0, s.length()); } - @android.ravenwood.annotation.RavenwoodKeep public static int indexOf(CharSequence s, CharSequence needle, int start) { return indexOf(s, needle, start, s.length()); } - @android.ravenwood.annotation.RavenwoodKeep public static int indexOf(CharSequence s, CharSequence needle, int start, int end) { int nlen = needle.length(); @@ -318,7 +308,6 @@ public class TextUtils { return -1; } - @android.ravenwood.annotation.RavenwoodKeep public static boolean regionMatches(CharSequence one, int toffset, CharSequence two, int ooffset, int len) { @@ -351,7 +340,6 @@ public class TextUtils { * in that it does not preserve any style runs in the source sequence, * allowing a more efficient implementation. */ - @android.ravenwood.annotation.RavenwoodKeep public static String substring(CharSequence source, int start, int end) { if (source instanceof String) return ((String) source).substring(start, end); @@ -424,7 +412,6 @@ public class TextUtils { * calling object.toString(). If tokens is null, a NullPointerException will be thrown. If * tokens is an empty array, an empty string will be returned. */ - @android.ravenwood.annotation.RavenwoodKeep public static String join(@NonNull CharSequence delimiter, @NonNull Object[] tokens) { final int length = tokens.length; if (length == 0) { @@ -448,7 +435,6 @@ public class TextUtils { * calling object.toString(). If tokens is null, a NullPointerException will be thrown. If * tokens is empty, an empty string will be returned. */ - @android.ravenwood.annotation.RavenwoodKeep public static String join(@NonNull CharSequence delimiter, @NonNull Iterable tokens) { final Iterator it = tokens.iterator(); if (!it.hasNext()) { @@ -481,7 +467,6 @@ public class TextUtils { * * @throws NullPointerException if expression or text is null */ - @android.ravenwood.annotation.RavenwoodKeep public static String[] split(String text, String expression) { if (text.length() == 0) { return EmptyArray.STRING; @@ -507,7 +492,6 @@ public class TextUtils { * * @throws NullPointerException if expression or text is null */ - @android.ravenwood.annotation.RavenwoodKeep public static String[] split(String text, Pattern pattern) { if (text.length() == 0) { return EmptyArray.STRING; @@ -545,7 +529,6 @@ public class TextUtils { * be returned for the empty string after that delimeter. That is, splitting "a,b," on * comma will return "a", "b", not "a", "b", "". */ - @android.ravenwood.annotation.RavenwoodKeepWholeClass public static class SimpleStringSplitter implements StringSplitter, Iterator { private String mString; private char mDelimiter; @@ -609,31 +592,26 @@ public class TextUtils { * @param str the string to be examined * @return true if str is null or zero length */ - @android.ravenwood.annotation.RavenwoodKeep public static boolean isEmpty(@Nullable CharSequence str) { return str == null || str.length() == 0; } /** {@hide} */ - @android.ravenwood.annotation.RavenwoodKeep public static String nullIfEmpty(@Nullable String str) { return isEmpty(str) ? null : str; } /** {@hide} */ - @android.ravenwood.annotation.RavenwoodKeep public static String emptyIfNull(@Nullable String str) { return str == null ? "" : str; } /** {@hide} */ - @android.ravenwood.annotation.RavenwoodKeep public static String firstNotEmpty(@Nullable String a, @NonNull String b) { return !isEmpty(a) ? a : Preconditions.checkStringNotEmpty(b); } /** {@hide} */ - @android.ravenwood.annotation.RavenwoodKeep public static int length(@Nullable String s) { return s != null ? s.length() : 0; } @@ -642,7 +620,6 @@ public class TextUtils { * @return interned string if it's null. * @hide */ - @android.ravenwood.annotation.RavenwoodKeep public static String safeIntern(String s) { return (s != null) ? s.intern() : null; } @@ -652,7 +629,6 @@ public class TextUtils { * spaces and ASCII control characters were trimmed from the start and end, * as by {@link String#trim}. */ - @android.ravenwood.annotation.RavenwoodKeep public static int getTrimmedLength(CharSequence s) { int len = s.length(); @@ -677,7 +653,6 @@ public class TextUtils { * @param b second CharSequence to check * @return true if a and b are equal */ - @android.ravenwood.annotation.RavenwoodKeep public static boolean equals(@Nullable CharSequence a, @Nullable CharSequence b) { if (a == b) return true; int length; @@ -1713,7 +1688,6 @@ public class TextUtils { return true; } - @android.ravenwood.annotation.RavenwoodKeep /* package */ static char[] obtain(int len) { char[] buf; @@ -1728,7 +1702,6 @@ public class TextUtils { return buf; } - @android.ravenwood.annotation.RavenwoodKeep /* package */ static void recycle(char[] temp) { if (temp.length > 1000) return; @@ -1743,7 +1716,6 @@ public class TextUtils { * @param s the string to be encoded * @return the encoded string */ - @android.ravenwood.annotation.RavenwoodKeep public static String htmlEncode(String s) { StringBuilder sb = new StringBuilder(); char c; @@ -1830,7 +1802,6 @@ public class TextUtils { /** * Returns whether the given CharSequence contains any printable characters. */ - @android.ravenwood.annotation.RavenwoodKeep public static boolean isGraphic(CharSequence str) { final int len = str.length(); for (int cp, i=0; is, diff --git a/core/java/android/text/WordSegmentFinder.java b/core/java/android/text/WordSegmentFinder.java index b0a70eae902a3..b8702d72f29c9 100644 --- a/core/java/android/text/WordSegmentFinder.java +++ b/core/java/android/text/WordSegmentFinder.java @@ -33,6 +33,7 @@ import android.text.method.WordIterator; * @see Unicode Text Segmentation - Word * Boundaries */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class WordSegmentFinder extends SegmentFinder { private final CharSequence mText; private final WordIterator mWordIterator; diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index e6dad27d595b9..ef60d3058c5c6 100644 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -63,6 +63,7 @@ import java.util.TimeZone; * Note that the non-{@code format} methods in this class are implemented by * {@code SimpleDateFormat}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DateFormat { /** * @deprecated Use a literal {@code '} instead. diff --git a/core/java/android/text/format/DateIntervalFormat.java b/core/java/android/text/format/DateIntervalFormat.java index 8dea3228eb0c0..5ec9561b23157 100644 --- a/core/java/android/text/format/DateIntervalFormat.java +++ b/core/java/android/text/format/DateIntervalFormat.java @@ -37,6 +37,7 @@ import java.util.TimeZone; * @hide */ @VisibleForTesting(visibility = PACKAGE) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class DateIntervalFormat { private static final LruCache CACHED_FORMATTERS = diff --git a/core/java/android/text/format/DateTimeFormat.java b/core/java/android/text/format/DateTimeFormat.java index 064d7172c44f8..c8dd61d0d75cb 100644 --- a/core/java/android/text/format/DateTimeFormat.java +++ b/core/java/android/text/format/DateTimeFormat.java @@ -29,6 +29,7 @@ import android.util.LruCache; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass class DateTimeFormat { private static final FormatterCache CACHED_FORMATTERS = new FormatterCache(); diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 518a5498d6edb..12ad764548705 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -44,6 +44,7 @@ import java.util.TimeZone; * This class contains various date-related utilities for creating text for things like * elapsed time and date ranges, strings for days of the week and months, and AM/PM text etc. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DateUtils { private static final Object sLock = new Object(); diff --git a/core/java/android/text/format/DateUtilsBridge.java b/core/java/android/text/format/DateUtilsBridge.java index 92ec9cf6d7362..752a8c0ef40ac 100644 --- a/core/java/android/text/format/DateUtilsBridge.java +++ b/core/java/android/text/format/DateUtilsBridge.java @@ -46,6 +46,7 @@ import com.android.internal.annotations.VisibleForTesting; * @hide */ @VisibleForTesting(visibility = PACKAGE) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class DateUtilsBridge { /** diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index 7653bdb7b2d81..e7783dcb2630d 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -41,6 +41,7 @@ import java.util.Locale; * Utility class to aid in formatting common values that are not covered * by the {@link java.util.Formatter} class in {@link java.util} */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class Formatter { /** {@hide} */ diff --git a/core/java/android/text/format/RelativeDateTimeFormatter.java b/core/java/android/text/format/RelativeDateTimeFormatter.java index 9096469699c1b..6b940f8cb380e 100644 --- a/core/java/android/text/format/RelativeDateTimeFormatter.java +++ b/core/java/android/text/format/RelativeDateTimeFormatter.java @@ -42,6 +42,7 @@ import java.util.Locale; * @hide */ @VisibleForTesting(visibility = PACKAGE) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class RelativeDateTimeFormatter { public static final long SECOND_IN_MILLIS = 1000; diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index bac7c6cf87d35..1beb57389ef5b 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -53,6 +53,7 @@ import java.util.TimeZone; * @deprecated Use {@link java.util.GregorianCalendar} instead. */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Time { private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000"; private static final String Y_M_D_T_H_M_S_000_Z = "%Y-%m-%dT%H:%M:%S.000Z"; diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java index e42ad63346491..dd703d85624f5 100644 --- a/core/java/android/text/format/TimeFormatter.java +++ b/core/java/android/text/format/TimeFormatter.java @@ -40,6 +40,7 @@ import java.util.TimeZone; * *

This class is not thread safe. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass class TimeFormatter { // An arbitrary value outside the range representable by a char. private static final int FORCE_LOWER_CASE = -1; diff --git a/core/java/android/text/format/TimeMigrationUtils.java b/core/java/android/text/format/TimeMigrationUtils.java index 17bac8d67b266..b2f5024c73b74 100644 --- a/core/java/android/text/format/TimeMigrationUtils.java +++ b/core/java/android/text/format/TimeMigrationUtils.java @@ -22,6 +22,7 @@ package android.text.format; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TimeMigrationUtils { private TimeMigrationUtils() {} diff --git a/core/java/android/text/method/AllCapsTransformationMethod.java b/core/java/android/text/method/AllCapsTransformationMethod.java index 305b056aee728..70dcc52691cdf 100644 --- a/core/java/android/text/method/AllCapsTransformationMethod.java +++ b/core/java/android/text/method/AllCapsTransformationMethod.java @@ -33,6 +33,7 @@ import java.util.Locale; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AllCapsTransformationMethod implements TransformationMethod2 { private static final String TAG = "AllCapsTransformationMethod"; diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java index 37474e5645b05..609922073f53e 100644 --- a/core/java/android/text/method/ArrowKeyMovementMethod.java +++ b/core/java/android/text/method/ArrowKeyMovementMethod.java @@ -30,6 +30,7 @@ import android.widget.TextView; * A movement method that provides cursor movement and selection. * Supports displaying the context menu on DPad Center. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ArrowKeyMovementMethod extends BaseMovementMethod implements MovementMethod { private static boolean isSelecting(Spannable buffer) { return ((MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SHIFT_ON) == 1) || diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java index e427908541e54..5ebfd99c6f6eb 100644 --- a/core/java/android/text/method/BaseKeyListener.java +++ b/core/java/android/text/method/BaseKeyListener.java @@ -47,6 +47,7 @@ import java.text.BreakIterator; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class BaseKeyListener extends MetaKeyKeyListener implements KeyListener { /* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete(); diff --git a/core/java/android/text/method/BaseMovementMethod.java b/core/java/android/text/method/BaseMovementMethod.java index 7a4b3a095ae98..0c2e52e04c1f2 100644 --- a/core/java/android/text/method/BaseMovementMethod.java +++ b/core/java/android/text/method/BaseMovementMethod.java @@ -27,6 +27,7 @@ import android.widget.TextView; /** * Base classes for movement methods. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class BaseMovementMethod implements MovementMethod { @Override public boolean canSelectArbitrarily() { diff --git a/core/java/android/text/method/CharacterPickerDialog.java b/core/java/android/text/method/CharacterPickerDialog.java index 7d838e06cd683..f084d03cf6dd8 100644 --- a/core/java/android/text/method/CharacterPickerDialog.java +++ b/core/java/android/text/method/CharacterPickerDialog.java @@ -38,6 +38,7 @@ import com.android.internal.R; /** * Dialog for choosing accented characters related to a base character. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class CharacterPickerDialog extends Dialog implements OnItemClickListener, OnClickListener { private View mView; diff --git a/core/java/android/text/method/DateKeyListener.java b/core/java/android/text/method/DateKeyListener.java index 0accbf6c74e5d..acf182263272e 100644 --- a/core/java/android/text/method/DateKeyListener.java +++ b/core/java/android/text/method/DateKeyListener.java @@ -35,6 +35,7 @@ import java.util.Locale; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DateKeyListener extends NumberKeyListener { public int getInputType() { diff --git a/core/java/android/text/method/DateTimeKeyListener.java b/core/java/android/text/method/DateTimeKeyListener.java index 1593db5de6419..a46ae45433b98 100644 --- a/core/java/android/text/method/DateTimeKeyListener.java +++ b/core/java/android/text/method/DateTimeKeyListener.java @@ -35,6 +35,7 @@ import java.util.Locale; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DateTimeKeyListener extends NumberKeyListener { public int getInputType() { diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java index 17abed6c363a7..9eea51a07593c 100644 --- a/core/java/android/text/method/DialerKeyListener.java +++ b/core/java/android/text/method/DialerKeyListener.java @@ -28,6 +28,7 @@ import android.view.KeyEvent; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DialerKeyListener extends NumberKeyListener { @Override diff --git a/core/java/android/text/method/DigitsKeyListener.java b/core/java/android/text/method/DigitsKeyListener.java index d9f2dcf2e8967..c97d4afef4fa5 100644 --- a/core/java/android/text/method/DigitsKeyListener.java +++ b/core/java/android/text/method/DigitsKeyListener.java @@ -40,6 +40,7 @@ import java.util.Locale; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DigitsKeyListener extends NumberKeyListener { private char[] mAccepted; diff --git a/core/java/android/text/method/HideReturnsTransformationMethod.java b/core/java/android/text/method/HideReturnsTransformationMethod.java index 40ce8714cf383..8b93b3558f86e 100644 --- a/core/java/android/text/method/HideReturnsTransformationMethod.java +++ b/core/java/android/text/method/HideReturnsTransformationMethod.java @@ -24,6 +24,7 @@ import android.os.Build; * to be hidden by displaying them as zero-width non-breaking space * characters (\uFEFF). */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class HideReturnsTransformationMethod extends ReplacementTransformationMethod { private static char[] ORIGINAL = new char[] { '\r' }; diff --git a/core/java/android/text/method/InsertModeTransformationMethod.java b/core/java/android/text/method/InsertModeTransformationMethod.java index 6c6576f8888ef..ace2d256f5b0e 100644 --- a/core/java/android/text/method/InsertModeTransformationMethod.java +++ b/core/java/android/text/method/InsertModeTransformationMethod.java @@ -58,6 +58,7 @@ import java.lang.reflect.Array; * the new transformed text: "hello abc\n\n world", and the highlight range will be [5, 11). * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class InsertModeTransformationMethod implements TransformationMethod, TextWatcher { /** The start offset of the highlight range in the original text, inclusive. */ private int mStart; diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java index ce7054c40d01b..447c4d9432edc 100644 --- a/core/java/android/text/method/KeyListener.java +++ b/core/java/android/text/method/KeyListener.java @@ -34,6 +34,7 @@ import android.view.View; * targetting Jelly Bean or later, and will only deliver it for some * key presses to applications targetting Ice Cream Sandwich or earlier. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface KeyListener { /** * Return the type of text that this key listener is manipulating, diff --git a/core/java/android/text/method/LinkMovementMethod.java b/core/java/android/text/method/LinkMovementMethod.java index 9f4a0aea72078..484bc1ae1a854 100644 --- a/core/java/android/text/method/LinkMovementMethod.java +++ b/core/java/android/text/method/LinkMovementMethod.java @@ -33,6 +33,7 @@ import android.widget.TextView; * A movement method that traverses links in the text buffer and scrolls if necessary. * Supports clicking on links with DPad Center or Enter. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class LinkMovementMethod extends ScrollingMovementMethod { private static final int CLICK = 1; private static final int UP = 2; diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java index d1d7c968411fe..7c9c2f1327931 100644 --- a/core/java/android/text/method/MetaKeyKeyListener.java +++ b/core/java/android/text/method/MetaKeyKeyListener.java @@ -71,6 +71,7 @@ import android.view.View; * } * */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class MetaKeyKeyListener { /** * Flag that indicates that the SHIFT key is on. diff --git a/core/java/android/text/method/MovementMethod.java b/core/java/android/text/method/MovementMethod.java index f6fe575a92650..5ea439d505615 100644 --- a/core/java/android/text/method/MovementMethod.java +++ b/core/java/android/text/method/MovementMethod.java @@ -32,6 +32,7 @@ import android.widget.TextView; * directly by applications. *

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface MovementMethod { public void initialize(TextView widget, Spannable text); public boolean onKeyDown(TextView widget, Spannable text, int keyCode, KeyEvent event); diff --git a/core/java/android/text/method/MultiTapKeyListener.java b/core/java/android/text/method/MultiTapKeyListener.java index 5770482b3feb0..022853abf4504 100644 --- a/core/java/android/text/method/MultiTapKeyListener.java +++ b/core/java/android/text/method/MultiTapKeyListener.java @@ -36,6 +36,7 @@ import android.view.View; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class MultiTapKeyListener extends BaseKeyListener implements SpanWatcher { private static MultiTapKeyListener[] sInstance = diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java index 2b038dd113489..e32ccd48c7e35 100644 --- a/core/java/android/text/method/NumberKeyListener.java +++ b/core/java/android/text/method/NumberKeyListener.java @@ -39,6 +39,7 @@ import java.util.Locale; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class NumberKeyListener extends BaseKeyListener implements InputFilter { diff --git a/core/java/android/text/method/OffsetMapping.java b/core/java/android/text/method/OffsetMapping.java index fcf3de6784fbe..99613d3ae3004 100644 --- a/core/java/android/text/method/OffsetMapping.java +++ b/core/java/android/text/method/OffsetMapping.java @@ -27,6 +27,7 @@ import java.lang.annotation.RetentionPolicy; * {@link TransformationMethod} that alters the text length. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface OffsetMapping { /** * The mapping strategy for a character offset. diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java index 53553be6e5a8b..4a61d9aa1bd06 100644 --- a/core/java/android/text/method/PasswordTransformationMethod.java +++ b/core/java/android/text/method/PasswordTransformationMethod.java @@ -33,6 +33,7 @@ import android.view.View; import java.lang.ref.WeakReference; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PasswordTransformationMethod implements TransformationMethod, TextWatcher { diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java index c43864d0f215e..27c58ea3a56e3 100644 --- a/core/java/android/text/method/QwertyKeyListener.java +++ b/core/java/android/text/method/QwertyKeyListener.java @@ -37,6 +37,7 @@ import android.view.View; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class QwertyKeyListener extends BaseKeyListener { private static QwertyKeyListener[] sInstance = new QwertyKeyListener[Capitalize.values().length * 2]; diff --git a/core/java/android/text/method/ReplacementTransformationMethod.java b/core/java/android/text/method/ReplacementTransformationMethod.java index d6f879aa43538..05899d79b02e1 100644 --- a/core/java/android/text/method/ReplacementTransformationMethod.java +++ b/core/java/android/text/method/ReplacementTransformationMethod.java @@ -30,6 +30,7 @@ import android.view.View; * array to be replaced by the corresponding characters in the * {@link #getReplacement} array. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class ReplacementTransformationMethod implements TransformationMethod { diff --git a/core/java/android/text/method/ScrollingMovementMethod.java b/core/java/android/text/method/ScrollingMovementMethod.java index 4f422cbf51cb2..2e0eda96b7f60 100644 --- a/core/java/android/text/method/ScrollingMovementMethod.java +++ b/core/java/android/text/method/ScrollingMovementMethod.java @@ -25,6 +25,7 @@ import android.widget.TextView; /** * A movement method that interprets movement keys by scrolling the text buffer. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ScrollingMovementMethod extends BaseMovementMethod implements MovementMethod { @Override protected boolean left(TextView widget, Spannable buffer) { diff --git a/core/java/android/text/method/SingleLineTransformationMethod.java b/core/java/android/text/method/SingleLineTransformationMethod.java index 818526a7d795f..d6eff86920f87 100644 --- a/core/java/android/text/method/SingleLineTransformationMethod.java +++ b/core/java/android/text/method/SingleLineTransformationMethod.java @@ -21,6 +21,7 @@ package android.text.method; * displayed as spaces instead of causing line breaks, and causes * carriage return characters (\r) to have no appearance. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SingleLineTransformationMethod extends ReplacementTransformationMethod { private static char[] ORIGINAL = new char[] { '\n', '\r' }; diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java index 2eb917b6fd574..1b0ae61c62a4f 100644 --- a/core/java/android/text/method/TextKeyListener.java +++ b/core/java/android/text/method/TextKeyListener.java @@ -43,6 +43,7 @@ import java.lang.ref.WeakReference; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TextKeyListener extends BaseKeyListener implements SpanWatcher { private static TextKeyListener[] sInstance = new TextKeyListener[Capitalize.values().length * 2]; diff --git a/core/java/android/text/method/TimeKeyListener.java b/core/java/android/text/method/TimeKeyListener.java index f11f40099d9c2..337611c79e3e8 100644 --- a/core/java/android/text/method/TimeKeyListener.java +++ b/core/java/android/text/method/TimeKeyListener.java @@ -35,6 +35,7 @@ import java.util.Locale; * with hardware keyboards. Software input methods have no obligation to trigger * the methods in this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TimeKeyListener extends NumberKeyListener { public int getInputType() { diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java index 44811cb3ef8b9..85aadba5da2bc 100644 --- a/core/java/android/text/method/Touch.java +++ b/core/java/android/text/method/Touch.java @@ -25,6 +25,7 @@ import android.view.MotionEvent; import android.view.ViewConfiguration; import android.widget.TextView; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Touch { private Touch() { } diff --git a/core/java/android/text/method/TransformationMethod.java b/core/java/android/text/method/TransformationMethod.java index 8f3b334abbbda..5246baa39d14c 100644 --- a/core/java/android/text/method/TransformationMethod.java +++ b/core/java/android/text/method/TransformationMethod.java @@ -24,6 +24,7 @@ import android.view.View; * characters of passwords with dots, or keeping the newline characters * from causing line breaks in single-line text fields. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface TransformationMethod { /** diff --git a/core/java/android/text/method/TransformationMethod2.java b/core/java/android/text/method/TransformationMethod2.java index 8d5ec246640e0..6e0feb419f008 100644 --- a/core/java/android/text/method/TransformationMethod2.java +++ b/core/java/android/text/method/TransformationMethod2.java @@ -23,6 +23,7 @@ import android.compat.annotation.UnsupportedAppUsage; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface TransformationMethod2 extends TransformationMethod { /** * Relax the contract of TransformationMethod to allow length changes, diff --git a/core/java/android/text/method/TranslationTransformationMethod.java b/core/java/android/text/method/TranslationTransformationMethod.java index 43d186ee9d218..8f43d3dd1f6f5 100644 --- a/core/java/android/text/method/TranslationTransformationMethod.java +++ b/core/java/android/text/method/TranslationTransformationMethod.java @@ -33,6 +33,7 @@ import java.util.regex.Pattern; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TranslationTransformationMethod implements TransformationMethod2 { private static final String TAG = "TranslationTransformationMethod"; diff --git a/core/java/android/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java index 2956f84613880..d57fa9b55312c 100644 --- a/core/java/android/text/method/WordIterator.java +++ b/core/java/android/text/method/WordIterator.java @@ -37,6 +37,7 @@ import java.util.Locale; * Also provides methods to determine word boundaries. * {@hide} */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class WordIterator implements Selection.PositionIterator { // Size of the window for the word iterator, should be greater than the longest word's length private static final int WINDOW_WIDTH = 50; diff --git a/core/java/android/text/style/AbsoluteSizeSpan.java b/core/java/android/text/style/AbsoluteSizeSpan.java index 6d4f05a84a037..1bc5d71fcd372 100644 --- a/core/java/android/text/style/AbsoluteSizeSpan.java +++ b/core/java/android/text/style/AbsoluteSizeSpan.java @@ -32,6 +32,7 @@ import android.text.TextUtils; * *
Text with text size updated.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan { private final int mSize; diff --git a/core/java/android/text/style/AccessibilityClickableSpan.java b/core/java/android/text/style/AccessibilityClickableSpan.java index ee8d156f9aac0..5741f2ae2864d 100644 --- a/core/java/android/text/style/AccessibilityClickableSpan.java +++ b/core/java/android/text/style/AccessibilityClickableSpan.java @@ -43,6 +43,7 @@ import com.android.internal.R; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AccessibilityClickableSpan extends ClickableSpan implements ParcelableSpan { // The id of the span this one replaces diff --git a/core/java/android/text/style/AccessibilityReplacementSpan.java b/core/java/android/text/style/AccessibilityReplacementSpan.java index e4fc14790b534..af3a324668d02 100644 --- a/core/java/android/text/style/AccessibilityReplacementSpan.java +++ b/core/java/android/text/style/AccessibilityReplacementSpan.java @@ -31,6 +31,7 @@ import android.view.accessibility.AccessibilityNodeInfo; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AccessibilityReplacementSpan extends ReplacementSpan implements ParcelableSpan { diff --git a/core/java/android/text/style/AccessibilityURLSpan.java b/core/java/android/text/style/AccessibilityURLSpan.java index e280bdf8b3398..1fb76e776b56f 100644 --- a/core/java/android/text/style/AccessibilityURLSpan.java +++ b/core/java/android/text/style/AccessibilityURLSpan.java @@ -27,6 +27,7 @@ import android.view.accessibility.AccessibilityNodeInfo; * @hide */ @SuppressWarnings("ParcelableCreator") +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AccessibilityURLSpan extends URLSpan implements Parcelable { final AccessibilityClickableSpan mAccessibilityClickableSpan; diff --git a/core/java/android/text/style/AlignmentSpan.java b/core/java/android/text/style/AlignmentSpan.java index 31db78a51c75b..53cbd63a32c72 100644 --- a/core/java/android/text/style/AlignmentSpan.java +++ b/core/java/android/text/style/AlignmentSpan.java @@ -25,6 +25,7 @@ import android.text.TextUtils; /** * Span that allows defining the alignment of text at the paragraph level. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface AlignmentSpan extends ParagraphStyle { /** diff --git a/core/java/android/text/style/BackgroundColorSpan.java b/core/java/android/text/style/BackgroundColorSpan.java index 13647d92a8975..bb04d0ff6178e 100644 --- a/core/java/android/text/style/BackgroundColorSpan.java +++ b/core/java/android/text/style/BackgroundColorSpan.java @@ -34,6 +34,7 @@ import android.text.TextUtils; * *
Set a background color for the text.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class BackgroundColorSpan extends CharacterStyle implements UpdateAppearance, ParcelableSpan { diff --git a/core/java/android/text/style/BulletSpan.java b/core/java/android/text/style/BulletSpan.java index f70e6c56b5c9e..24ae6e25fa59d 100644 --- a/core/java/android/text/style/BulletSpan.java +++ b/core/java/android/text/style/BulletSpan.java @@ -63,6 +63,7 @@ import android.text.TextUtils; * *
Customized BulletSpan.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class BulletSpan implements LeadingMarginSpan, ParcelableSpan { // Bullet is slightly bigger to avoid aliasing artifacts on mdpi devices. private static final int STANDARD_BULLET_RADIUS = 4; diff --git a/core/java/android/text/style/CharacterStyle.java b/core/java/android/text/style/CharacterStyle.java index 5b95f1a7816a3..2ea05e6ecde03 100644 --- a/core/java/android/text/style/CharacterStyle.java +++ b/core/java/android/text/style/CharacterStyle.java @@ -23,6 +23,7 @@ import android.text.TextPaint; * class. Most extend its subclass {@link MetricAffectingSpan}, but simple * ones may just implement {@link UpdateAppearance}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class CharacterStyle { public abstract void updateDrawState(TextPaint tp); diff --git a/core/java/android/text/style/ClickableSpan.java b/core/java/android/text/style/ClickableSpan.java index 238da55526b0a..9e35d75c88335 100644 --- a/core/java/android/text/style/ClickableSpan.java +++ b/core/java/android/text/style/ClickableSpan.java @@ -36,6 +36,7 @@ import android.view.View; * *
Text with ClickableSpan.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance { private static int sIdCounter = 0; diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java index 5c9742622549f..337c49fddf169 100644 --- a/core/java/android/text/style/ForegroundColorSpan.java +++ b/core/java/android/text/style/ForegroundColorSpan.java @@ -34,6 +34,7 @@ import android.text.TextUtils; * *
Set a text color.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ForegroundColorSpan extends CharacterStyle implements UpdateAppearance, ParcelableSpan { diff --git a/core/java/android/text/style/IconMarginSpan.java b/core/java/android/text/style/IconMarginSpan.java index a6c513971ffb9..cc946e98ece92 100644 --- a/core/java/android/text/style/IconMarginSpan.java +++ b/core/java/android/text/style/IconMarginSpan.java @@ -44,6 +44,7 @@ import android.text.Spanned; * @see DrawableMarginSpan for working with a {@link android.graphics.drawable.Drawable} instead of * a {@link Bitmap}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class IconMarginSpan implements LeadingMarginSpan, LineHeightSpan { @NonNull diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java index 5bd2d60bb34f7..60c45784f6804 100644 --- a/core/java/android/text/style/LeadingMarginSpan.java +++ b/core/java/android/text/style/LeadingMarginSpan.java @@ -32,6 +32,7 @@ import android.text.TextUtils; * LeadingMarginSpans should be attached from the first character to the last * character of a single paragraph. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface LeadingMarginSpan extends ParagraphStyle { diff --git a/core/java/android/text/style/LineBackgroundSpan.java b/core/java/android/text/style/LineBackgroundSpan.java index 7cb91477738e6..c2d38ce92290a 100644 --- a/core/java/android/text/style/LineBackgroundSpan.java +++ b/core/java/android/text/style/LineBackgroundSpan.java @@ -28,6 +28,7 @@ import android.text.TextUtils; /** * Used to change the background of lines where the span is attached to. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface LineBackgroundSpan extends ParagraphStyle { /** diff --git a/core/java/android/text/style/LineBreakConfigSpan.java b/core/java/android/text/style/LineBreakConfigSpan.java index eeb6383892715..1af1eed86e1fc 100644 --- a/core/java/android/text/style/LineBreakConfigSpan.java +++ b/core/java/android/text/style/LineBreakConfigSpan.java @@ -31,6 +31,7 @@ import java.util.Objects; * LineBreakSpan for changing line break style of the specific region of the text. */ @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class LineBreakConfigSpan implements ParcelableSpan { private final LineBreakConfig mLineBreakConfig; diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java index ae565d1c3317a..71e8932c4abae 100644 --- a/core/java/android/text/style/LineHeightSpan.java +++ b/core/java/android/text/style/LineHeightSpan.java @@ -30,6 +30,7 @@ import com.android.internal.util.Preconditions; /** * The classes that affect the line height of paragraph should implement this interface. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface LineHeightSpan extends ParagraphStyle, WrapTogetherSpan { /** * Classes that implement this should define how the height is being calculated. diff --git a/core/java/android/text/style/LocaleSpan.java b/core/java/android/text/style/LocaleSpan.java index 489ceeaa55429..be5525a2f41a6 100644 --- a/core/java/android/text/style/LocaleSpan.java +++ b/core/java/android/text/style/LocaleSpan.java @@ -32,6 +32,7 @@ import java.util.Locale; /** * Changes the {@link Locale} of the text to which the span is attached. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class LocaleSpan extends MetricAffectingSpan implements ParcelableSpan { @NonNull private final LocaleList mLocales; diff --git a/core/java/android/text/style/MaskFilterSpan.java b/core/java/android/text/style/MaskFilterSpan.java index 587d1b4497dc0..44db012953b3a 100644 --- a/core/java/android/text/style/MaskFilterSpan.java +++ b/core/java/android/text/style/MaskFilterSpan.java @@ -30,6 +30,7 @@ import android.text.TextPaint; * *
Text blurred with the MaskFilterSpan.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class MaskFilterSpan extends CharacterStyle implements UpdateAppearance { private MaskFilter mFilter; diff --git a/core/java/android/text/style/MetricAffectingSpan.java b/core/java/android/text/style/MetricAffectingSpan.java index 61b7947af6389..f30fdc15ae39e 100644 --- a/core/java/android/text/style/MetricAffectingSpan.java +++ b/core/java/android/text/style/MetricAffectingSpan.java @@ -23,6 +23,7 @@ import android.text.TextPaint; * The classes that affect character-level text formatting in a way that * changes the width or height of characters extend this class. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class MetricAffectingSpan extends CharacterStyle implements UpdateLayout { diff --git a/core/java/android/text/style/NoWritingToolsSpan.java b/core/java/android/text/style/NoWritingToolsSpan.java index 90f85aa69faa5..c7dfcfa6dc0b9 100644 --- a/core/java/android/text/style/NoWritingToolsSpan.java +++ b/core/java/android/text/style/NoWritingToolsSpan.java @@ -32,6 +32,7 @@ import android.text.TextUtils; * tools should only rewrite the user input text, and not modify the quoted text. */ @FlaggedApi(FLAG_WRITING_TOOLS) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class NoWritingToolsSpan implements ParcelableSpan { /** diff --git a/core/java/android/text/style/ParagraphStyle.java b/core/java/android/text/style/ParagraphStyle.java index 423156eca3de3..27c1e261b116b 100644 --- a/core/java/android/text/style/ParagraphStyle.java +++ b/core/java/android/text/style/ParagraphStyle.java @@ -20,6 +20,7 @@ package android.text.style; * The classes that affect paragraph-level text formatting implement * this interface. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface ParagraphStyle { diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java index 393ede653cb1a..99c95749205a1 100644 --- a/core/java/android/text/style/QuoteSpan.java +++ b/core/java/android/text/style/QuoteSpan.java @@ -57,6 +57,7 @@ import android.text.TextUtils; * *
Customized QuoteSpan.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan { /** * Default stripe width in pixels. diff --git a/core/java/android/text/style/RasterizerSpan.java b/core/java/android/text/style/RasterizerSpan.java index f0be50ab065cd..cf8599c4f1b1b 100644 --- a/core/java/android/text/style/RasterizerSpan.java +++ b/core/java/android/text/style/RasterizerSpan.java @@ -22,6 +22,7 @@ import android.text.TextPaint; /** * @removed Rasterizer is not supported for hw-accerlerated and PDF rendering */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class RasterizerSpan extends CharacterStyle implements UpdateAppearance { private Rasterizer mRasterizer; diff --git a/core/java/android/text/style/RelativeSizeSpan.java b/core/java/android/text/style/RelativeSizeSpan.java index 5c91b201d28c3..38d5d38ae704d 100644 --- a/core/java/android/text/style/RelativeSizeSpan.java +++ b/core/java/android/text/style/RelativeSizeSpan.java @@ -34,6 +34,7 @@ import android.text.TextUtils; * *
Text increased by 50% with RelativeSizeSpan.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class RelativeSizeSpan extends MetricAffectingSpan implements ParcelableSpan { private final float mProportion; diff --git a/core/java/android/text/style/ReplacementSpan.java b/core/java/android/text/style/ReplacementSpan.java index 9430fd3a26c0e..a6fe1fe729371 100644 --- a/core/java/android/text/style/ReplacementSpan.java +++ b/core/java/android/text/style/ReplacementSpan.java @@ -23,6 +23,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.text.TextPaint; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class ReplacementSpan extends MetricAffectingSpan { private CharSequence mContentDescription = null; diff --git a/core/java/android/text/style/ScaleXSpan.java b/core/java/android/text/style/ScaleXSpan.java index d022b071b4d7a..009973ee5306c 100644 --- a/core/java/android/text/style/ScaleXSpan.java +++ b/core/java/android/text/style/ScaleXSpan.java @@ -36,6 +36,7 @@ import android.text.TextUtils; * *
Text scaled by 100% with ScaleXSpan.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ScaleXSpan extends MetricAffectingSpan implements ParcelableSpan { private final float mProportion; diff --git a/core/java/android/text/style/SpanUtils.java b/core/java/android/text/style/SpanUtils.java index 6b4bd1a763583..21a96cdfe3b1b 100644 --- a/core/java/android/text/style/SpanUtils.java +++ b/core/java/android/text/style/SpanUtils.java @@ -30,6 +30,7 @@ import java.util.List; /** * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SpanUtils { private SpanUtils() {} // Do not instantiate diff --git a/core/java/android/text/style/SpellCheckSpan.java b/core/java/android/text/style/SpellCheckSpan.java index e8ec3c6fb55c6..39cd279d3d18c 100644 --- a/core/java/android/text/style/SpellCheckSpan.java +++ b/core/java/android/text/style/SpellCheckSpan.java @@ -28,6 +28,7 @@ import android.text.TextUtils; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SpellCheckSpan implements ParcelableSpan { private boolean mSpellCheckInProgress; diff --git a/core/java/android/text/style/StrikethroughSpan.java b/core/java/android/text/style/StrikethroughSpan.java index 65ee34717232c..3654870ee0889 100644 --- a/core/java/android/text/style/StrikethroughSpan.java +++ b/core/java/android/text/style/StrikethroughSpan.java @@ -32,6 +32,7 @@ import android.text.TextUtils; * *
Strikethrough text.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class StrikethroughSpan extends CharacterStyle implements UpdateAppearance, ParcelableSpan { diff --git a/core/java/android/text/style/StyleSpan.java b/core/java/android/text/style/StyleSpan.java index 378682b9c8909..c01e13443ad1d 100644 --- a/core/java/android/text/style/StyleSpan.java +++ b/core/java/android/text/style/StyleSpan.java @@ -44,6 +44,7 @@ import android.text.TextUtils; * *
Text styled bold and italic with the StyleSpan.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { private final int mStyle; diff --git a/core/java/android/text/style/SubscriptSpan.java b/core/java/android/text/style/SubscriptSpan.java index 729a9ad73e754..54c765d902a4d 100644 --- a/core/java/android/text/style/SubscriptSpan.java +++ b/core/java/android/text/style/SubscriptSpan.java @@ -37,6 +37,7 @@ import android.text.TextUtils; * Note: Since the span affects the position of the text, if the text is on the last line of a * TextView, it may appear cut. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SubscriptSpan extends MetricAffectingSpan implements ParcelableSpan { /** diff --git a/core/java/android/text/style/SuggestionRangeSpan.java b/core/java/android/text/style/SuggestionRangeSpan.java index 1eee99aaac62e..640fae4d1a3ac 100644 --- a/core/java/android/text/style/SuggestionRangeSpan.java +++ b/core/java/android/text/style/SuggestionRangeSpan.java @@ -27,6 +27,7 @@ import android.text.TextUtils; * A SuggestionRangeSpan is used to show which part of an EditText is affected by a suggestion * popup window. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpan { private int mBackgroundColor; diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java index 0cf96f617f4a8..d819062428f9c 100644 --- a/core/java/android/text/style/SuggestionSpan.java +++ b/core/java/android/text/style/SuggestionSpan.java @@ -48,6 +48,7 @@ import java.util.Locale; * * @see TextView#isSuggestionsEnabled() */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { private static final String TAG = "SuggestionSpan"; diff --git a/core/java/android/text/style/SuperscriptSpan.java b/core/java/android/text/style/SuperscriptSpan.java index 561022352ffd7..d3b339c02e92b 100644 --- a/core/java/android/text/style/SuperscriptSpan.java +++ b/core/java/android/text/style/SuperscriptSpan.java @@ -35,6 +35,7 @@ import android.text.TextUtils; * TextView, it may appear cut. This can be avoided by decreasing the text size with an {@link * AbsoluteSizeSpan} */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SuperscriptSpan extends MetricAffectingSpan implements ParcelableSpan { /** * Creates a {@link SuperscriptSpan}. diff --git a/core/java/android/text/style/TabStopSpan.java b/core/java/android/text/style/TabStopSpan.java index 812847594ad89..e6733a2aac916 100644 --- a/core/java/android/text/style/TabStopSpan.java +++ b/core/java/android/text/style/TabStopSpan.java @@ -24,6 +24,7 @@ import android.annotation.Px; * the leading margin of the line. TabStopSpan will only affect the first tab * encountered on the first line of the text. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface TabStopSpan extends ParagraphStyle { /** diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java index 245a9dbc9f6c4..7ede3499dc4d9 100644 --- a/core/java/android/text/style/TextAppearanceSpan.java +++ b/core/java/android/text/style/TextAppearanceSpan.java @@ -58,6 +58,7 @@ import android.text.TextUtils; * @attr ref android.R.styleable#TextAppearance_fontVariationSettings * */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan { private final String mFamilyName; private final int mStyle; diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java index e0d4ec1ca8268..6d776d14fb002 100644 --- a/core/java/android/text/style/TtsSpan.java +++ b/core/java/android/text/style/TtsSpan.java @@ -42,6 +42,7 @@ import java.util.Locale; * The inner classes are there for convenience and provide builders for each * TtsSpan type. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TtsSpan implements ParcelableSpan { private final String mType; private final PersistableBundle mArgs; diff --git a/core/java/android/text/style/TypefaceSpan.java b/core/java/android/text/style/TypefaceSpan.java index bdfc772c03281..86f7f76386290 100644 --- a/core/java/android/text/style/TypefaceSpan.java +++ b/core/java/android/text/style/TypefaceSpan.java @@ -50,6 +50,7 @@ import android.text.TextUtils; *
Text with TypefaceSpans constructed based on a font from resource and * from a font family.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan { @Nullable diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java index 9969d29a857d5..f06627d0cbe12 100644 --- a/core/java/android/text/style/URLSpan.java +++ b/core/java/android/text/style/URLSpan.java @@ -41,6 +41,7 @@ import android.view.View; * *
Text with URLSpan.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class URLSpan extends ClickableSpan implements ParcelableSpan { private final String mURL; diff --git a/core/java/android/text/style/UnderlineSpan.java b/core/java/android/text/style/UnderlineSpan.java index 075e70b7fbf5a..b3bb142d1dc89 100644 --- a/core/java/android/text/style/UnderlineSpan.java +++ b/core/java/android/text/style/UnderlineSpan.java @@ -32,6 +32,7 @@ import android.text.TextUtils; * *
Underlined text.
*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class UnderlineSpan extends CharacterStyle implements UpdateAppearance, ParcelableSpan { diff --git a/core/java/android/text/style/UpdateAppearance.java b/core/java/android/text/style/UpdateAppearance.java index 7112347fcfbf4..7b0a6d372122e 100644 --- a/core/java/android/text/style/UpdateAppearance.java +++ b/core/java/android/text/style/UpdateAppearance.java @@ -22,5 +22,6 @@ package android.text.style; * that if the class also impacts size or other metrics, it should instead * implement {@link UpdateLayout}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface UpdateAppearance { } diff --git a/core/java/android/text/style/UpdateLayout.java b/core/java/android/text/style/UpdateLayout.java index 591075ecb9726..5af4141cc8c2a 100644 --- a/core/java/android/text/style/UpdateLayout.java +++ b/core/java/android/text/style/UpdateLayout.java @@ -22,4 +22,5 @@ package android.text.style; * this interface. This interface also includes {@link UpdateAppearance} * since such a change implicitly also impacts the appearance. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface UpdateLayout extends UpdateAppearance { } diff --git a/core/java/android/text/style/WrapTogetherSpan.java b/core/java/android/text/style/WrapTogetherSpan.java index 11721a8c32534..cf74c1bae3b77 100644 --- a/core/java/android/text/style/WrapTogetherSpan.java +++ b/core/java/android/text/style/WrapTogetherSpan.java @@ -16,6 +16,7 @@ package android.text.style; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface WrapTogetherSpan extends ParagraphStyle { diff --git a/core/java/android/text/util/Rfc822Token.java b/core/java/android/text/util/Rfc822Token.java index 2f207db9d494e..d6e987b2952ec 100644 --- a/core/java/android/text/util/Rfc822Token.java +++ b/core/java/android/text/util/Rfc822Token.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; * This class stores an RFC 822-like name, address, and comment, * and provides methods to convert them to quoted strings. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Rfc822Token { @Nullable private String mName, mAddress, mComment; diff --git a/core/java/android/text/util/Rfc822Tokenizer.java b/core/java/android/text/util/Rfc822Tokenizer.java index 68334e4d927c6..8a9252ac9506e 100644 --- a/core/java/android/text/util/Rfc822Tokenizer.java +++ b/core/java/android/text/util/Rfc822Tokenizer.java @@ -27,6 +27,7 @@ import java.util.Collection; * a string of addresses (such as might be typed into such a field) * into a series of Rfc822Tokens. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Rfc822Tokenizer implements MultiAutoCompleteTextView.Tokenizer { /** diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 06702e2fa4bf9..0c18de92a3918 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -489,6 +489,7 @@ cc_library_shared_for_libandroid_runtime { "libsqlite", "libgui_window_info_static", "libbinder", + "libbinder_ndk", "libhidlbase", // libhwbinder is in here ], version_script: "platform/linux/libandroid_runtime_export.txt", diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 4c49ff849d494..05fb5735972ee 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -249,8 +249,14 @@ android_library { android_ravenwood_test { name: "FrameworksCoreTestsRavenwood", libs: [ - "android.test.base.stubs.system", - "android.test.runner.stubs.system", + "android.test.base.stubs", + "android.test.mock.stubs", + "android.test.runner.stubs", + "android.view.flags-aconfig-java", + "ext", + "framework", + "framework-res", + "org.apache.http.legacy.stubs", ], static_libs: [ "androidx.annotation_annotation", @@ -264,6 +270,7 @@ android_ravenwood_test { "flag-junit", "flag-junit", "perfetto_trace_java_protos", + "platform-compat-test-rules", "platform-test-annotations", "testng", ], @@ -278,8 +285,12 @@ android_ravenwood_test { "src/android/content/res/*.java", "src/android/content/res/*.kt", "src/android/database/CursorWindowTest.java", + "src/android/graphics/*.java", + "src/android/graphics/*.kt", "src/android/os/**/*.java", "src/android/telephony/PinResultTest.java", + "src/android/text/**/*.java", + "src/android/text/**/*.kt", "src/android/util/**/*.java", "src/android/view/DisplayAdjustmentsTests.java", "src/android/view/DisplayInfoTest.java", @@ -288,20 +299,21 @@ android_ravenwood_test { "src/com/android/internal/os/**/*.java", "src/com/android/internal/power/EnergyConsumerStatsTest.java", "src/com/android/internal/ravenwood/**/*.java", - - // Pull in R.java from FrameworksCoreTests-resonly, not from FrameworksCoreTests, - // to avoid having a dependency to FrameworksCoreTests. - // This way, when updating source files and running this test, we don't need to - // rebuild the entire FrameworksCoreTests, which would be slow. "src/com/android/internal/util/**/*.java", ":FrameworksCoreTestDoubles-sources", ":FrameworksCoreTests-aidl", ":FrameworksCoreTests-helpers", + + // Pull in R.java from FrameworksCoreTests-resonly, not from FrameworksCoreTests, + // to avoid having a dependency to FrameworksCoreTests. + // This way, when updating source files and running this test, we don't need to + // rebuild the entire FrameworksCoreTests, which would be slow. ":FrameworksCoreTests-resonly{.aapt.srcjar}", ], exclude_srcs: [ "src/android/content/res/FontScaleConverterActivityTest.java", + "src/android/graphics/GraphicsPerformanceTests.java", ], resource_apk: "FrameworksCoreTests-resonly", aidl: { @@ -313,6 +325,7 @@ android_ravenwood_test { "res/xml/power_profile_test_cpu_legacy.xml", "res/xml/power_profile_test_modem.xml", ], + sdk_version: "core_platform", auto_gen_config: true, team: "trendy_team_ravenwood", } diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt index 0e5d92688123b..2c614424a9a54 100644 --- a/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt +++ b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt @@ -17,10 +17,8 @@ package android.content.res import android.platform.test.annotations.Presubmit -import android.platform.test.ravenwood.RavenwoodRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertWithMessage -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -28,9 +26,6 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class FontScaleConverterTest { - @get:Rule - val ravenwoodRule: RavenwoodRule = RavenwoodRule.Builder().build() - @Test fun straightInterpolation() { val table = createTable(8f to 8f, 10f to 10f, 20f to 20f) diff --git a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java index 84bdbe03df134..263307ee3df72 100644 --- a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java +++ b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java @@ -20,7 +20,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import android.os.MemoryFile; import android.os.ParcelFileDescriptor; +import android.platform.test.annotations.DisabledOnRavenwood; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -37,6 +39,7 @@ public class BitmapFactoryTest { // tests that we can decode bitmaps from MemoryFiles @SmallTest @Test + @DisabledOnRavenwood(blockedBy = MemoryFile.class) public void testBitmapParcelFileDescriptor() throws Exception { Bitmap bitmap1 = Bitmap.createBitmap( new int[] { Color.BLUE }, 1, 1, Bitmap.Config.RGB_565); diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java index 0126d367eb204..61c3d7813e889 100644 --- a/core/tests/coretests/src/android/graphics/BitmapTest.java +++ b/core/tests/coretests/src/android/graphics/BitmapTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.hardware.HardwareBuffer; +import android.platform.test.annotations.DisabledOnRavenwood; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -252,6 +253,7 @@ public class BitmapTest { | GraphicBuffer.USAGE_SW_WRITE_OFTEN; @Test + @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) public void testWrapHardwareBufferWithSrgbColorSpace() { GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888, GRAPHICS_USAGE); Canvas canvas = buffer.lockCanvas(); @@ -265,6 +267,7 @@ public class BitmapTest { } @Test + @DisabledOnRavenwood(blockedBy = HardwareBuffer.class) public void testWrapHardwareBufferWithDisplayP3ColorSpace() { GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888, GRAPHICS_USAGE); Canvas canvas = buffer.lockCanvas(); diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java index 56760d77e28b8..deb5157bb3392 100644 --- a/core/tests/coretests/src/android/graphics/PaintTest.java +++ b/core/tests/coretests/src/android/graphics/PaintTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -97,6 +98,7 @@ public class PaintTest { @SmallTest @Test + @DisabledOnRavenwood(bug = 391381043) public void testHintingWidth() { final Typeface fontTypeface = Typeface.createFromAsset( InstrumentationRegistry.getInstrumentation().getContext().getAssets(), FONT_PATH); @@ -143,6 +145,7 @@ public class PaintTest { } @Test + @DisabledOnRavenwood(bug = 391381043) public void testHasGlyph_variationSelectors() { final Typeface fontTypeface = Typeface.createFromAsset( InstrumentationRegistry.getInstrumentation().getContext().getAssets(), diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java index 2b6eda8f09883..dc3376e09b156 100644 --- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java +++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java @@ -35,9 +35,9 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.text.FontConfig; import android.util.ArrayMap; -import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.text.flags.Flags; @@ -63,9 +63,6 @@ import java.util.Map; @SmallTest @RunWith(AndroidJUnit4.class) public class TypefaceSystemFallbackTest { - private static final String SYSTEM_FONT_DIR = "/system/fonts/"; - private static final String SYSTEM_FONTS_XML = "/system/etc/fonts.xml"; - private static final String[] TEST_FONT_FILES = { "a3em.ttf", // Supports "a","b","c". The width of "a" is 3em, others are 1em. "b3em.ttf", // Supports "a","b","c". The width of "b" is 3em, others are 1em. @@ -118,8 +115,6 @@ public class TypefaceSystemFallbackTest { @Before public void setUp() { - final AssetManager am = - InstrumentationRegistry.getInstrumentation().getContext().getAssets(); for (final String fontFile : TEST_FONT_FILES) { final String sourceInAsset = "fonts/" + fontFile; copyAssetToFile(sourceInAsset, new File(TEST_FONT_DIR, fontFile)); @@ -216,7 +211,8 @@ public class TypefaceSystemFallbackTest { FontConfig fontConfig; try { fontConfig = FontListParser.parse( - SYSTEM_FONTS_XML, SYSTEM_FONT_DIR, null, TEST_OEM_DIR, null, 0, 0); + SystemFonts.LEGACY_FONTS_XML, SystemFonts.SYSTEM_FONT_DIR, + null, TEST_OEM_DIR, null, 0, 0); } catch (IOException | XmlPullParserException e) { throw new RuntimeException(e); } diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java index 80efa511d1630..0c8b5ab5f3f96 100644 --- a/core/tests/coretests/src/android/graphics/TypefaceTest.java +++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java @@ -26,6 +26,7 @@ import android.content.res.Resources; import android.graphics.fonts.FontFamily; import android.graphics.fonts.SystemFonts; import android.os.SharedMemory; +import android.platform.test.annotations.DisabledOnRavenwood; import android.text.FontConfig; import android.util.ArrayMap; @@ -196,6 +197,7 @@ public class TypefaceTest { @SmallTest @Test + @DisabledOnRavenwood(blockedBy = SharedMemory.class) public void testSerialize() throws Exception { FontConfig fontConfig = SystemFonts.getSystemPreinstalledFontConfig(); Map fallbackMap = SystemFonts.buildSystemFallback(fontConfig); diff --git a/core/tests/coretests/src/android/text/AndroidCharacterTest.java b/core/tests/coretests/src/android/text/AndroidCharacterTest.java index 1c5986a838fc3..819a5fb8fd402 100644 --- a/core/tests/coretests/src/android/text/AndroidCharacterTest.java +++ b/core/tests/coretests/src/android/text/AndroidCharacterTest.java @@ -18,6 +18,7 @@ package android.text; import static org.junit.Assert.assertArrayEquals; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -26,6 +27,7 @@ import org.junit.Test; @Presubmit @SmallTest +@DisabledOnRavenwood(reason = "No need to make j.l.Character match behavior of AndroidCharacter") public class AndroidCharacterTest { @Test diff --git a/core/tests/coretests/src/android/text/SpanColorsTest.java b/core/tests/coretests/src/android/text/SpanColorsTest.java index d2cb8c160d216..4cdbd08863102 100644 --- a/core/tests/coretests/src/android/text/SpanColorsTest.java +++ b/core/tests/coretests/src/android/text/SpanColorsTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import android.graphics.Color; import android.graphics.drawable.ShapeDrawable; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; @@ -35,6 +36,7 @@ import org.junit.runner.RunWith; @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) +@DisabledOnRavenwood(blockedBy = ShapeDrawable.class) public class SpanColorsTest { private final TextPaint mWorkPaint = new TextPaint(); private SpanColors mSpanColors; diff --git a/core/tests/coretests/src/android/text/SpannableTest.java b/core/tests/coretests/src/android/text/SpannableTest.java index a3e6a78123247..710d1e2a3314e 100644 --- a/core/tests/coretests/src/android/text/SpannableTest.java +++ b/core/tests/coretests/src/android/text/SpannableTest.java @@ -16,10 +16,10 @@ package android.text; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.platform.test.annotations.Presubmit; -import android.test.MoreAsserts; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -50,13 +50,13 @@ public abstract class SpannableTest { // but other spans are not, unless the query region is empty, in // in which case any abutting spans are returned. spans = spannable.getSpans(0, 1, Object.class); - MoreAsserts.assertEquals(new Object[]{emptySpan}, spans); + assertArrayEquals(new Object[]{emptySpan}, spans); spans = spannable.getSpans(0, 2, Object.class); - MoreAsserts.assertEquals(new Object[]{emptySpan, unemptySpan}, spans); + assertArrayEquals(new Object[]{emptySpan, unemptySpan}, spans); spans = spannable.getSpans(1, 2, Object.class); - MoreAsserts.assertEquals(new Object[]{emptySpan, unemptySpan}, spans); + assertArrayEquals(new Object[]{emptySpan, unemptySpan}, spans); spans = spannable.getSpans(2, 2, Object.class); - MoreAsserts.assertEquals(new Object[]{unemptySpan}, spans); + assertArrayEquals(new Object[]{unemptySpan}, spans); } @Test diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java index 3541900dcacf5..55f38b2fc2bd5 100644 --- a/core/tests/coretests/src/android/text/StaticLayoutTest.java +++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java @@ -25,6 +25,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; import android.os.LocaleList; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import android.text.Layout.Alignment; import android.text.method.EditorState; @@ -726,6 +727,7 @@ public class StaticLayoutTest { } @Test + @DisabledOnRavenwood(bug = 391342883) public void testLocaleSpanAffectsHyphenation() { TextPaint paint = new TextPaint(); paint.setTextLocale(Locale.US); diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java index f552265cc5078..e38c8800169ac 100644 --- a/core/tests/coretests/src/android/text/TextUtilsTest.java +++ b/core/tests/coretests/src/android/text/TextUtilsTest.java @@ -18,6 +18,7 @@ package android.text; import static android.text.TextUtils.formatSimple; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -28,7 +29,6 @@ import static org.junit.Assert.fail; import android.os.Parcel; import android.platform.test.annotations.Presubmit; -import android.test.MoreAsserts; import android.text.style.StyleSpan; import android.text.util.Rfc822Token; import android.text.util.Rfc822Tokenizer; @@ -237,7 +237,7 @@ public class TextUtilsTest { for (String s : splitter) { strings.add(s); } - MoreAsserts.assertEquals(expectedStrings, strings.toArray(new String[]{})); + assertArrayEquals(expectedStrings, strings.toArray(new String[]{})); } @Test diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java index 59af6dd20478b..c16393c2643d7 100644 --- a/core/tests/coretests/src/android/text/format/DateFormatTest.java +++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java @@ -74,8 +74,9 @@ public class DateFormatTest { DateFormatSymbols dfs = DateFormat.getIcuDateFormatSymbols(Locale.US); assertEquals("AM", dfs.getAmPmStrings()[0]); assertEquals("PM", dfs.getAmPmStrings()[1]); - assertEquals("a", dfs.getAmpmNarrowStrings()[0]); - assertEquals("p", dfs.getAmpmNarrowStrings()[1]); + // getAmpmNarrowStrings() is a @CorePlatformApi that we should stop using in framework + // assertEquals("a", dfs.getAmpmNarrowStrings()[0]); + // assertEquals("p", dfs.getAmpmNarrowStrings()[1]); } @Test diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java index a07d399218e30..e54273479b808 100644 --- a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java +++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java @@ -40,6 +40,7 @@ import static org.junit.Assert.assertTrue; import android.icu.util.Calendar; import android.icu.util.TimeZone; import android.icu.util.ULocale; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -686,6 +687,7 @@ public class DateIntervalFormatTest { } @Test + @DisabledOnRavenwood(bug = 391381043) public void testIsLibcoreVFlagEnabled() { // This flag has been fully ramped. It should never be false. assertTrue(DateIntervalFormat.isLibcoreVFlagEnabled()); diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java index 47be893eb3e9b..a853d4a0c0512 100644 --- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java +++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals; import android.content.res.Configuration; import android.content.res.Resources; import android.os.LocaleList; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -116,6 +117,7 @@ public class DateUtilsTest { } @Test + @DisabledOnRavenwood(reason = "DateFormat.set24HourTimePref is not available on host JVM") public void testFormatSameDayTime() { // This test assumes a default DateFormat.is24Hour setting. DateFormat.set24HourTimePref(null); diff --git a/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java b/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java index c8cb5f38b1856..49f3373d06597 100644 --- a/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java +++ b/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java @@ -18,6 +18,7 @@ package android.text.format; import static org.junit.Assert.assertEquals; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -72,6 +73,7 @@ public class TimeMigrationUtilsTest { * Compares TimeMigrationUtils.formatSimpleDateTime() with the code it is replacing. */ @Test + @DisabledOnRavenwood(blockedBy = Time.class) public void formatMillisAsDateTime_matchesOldBehavior() { // A selection of interesting locales. Locale[] locales = new Locale[] { diff --git a/core/tests/coretests/src/android/text/format/TimeTest.java b/core/tests/coretests/src/android/text/format/TimeTest.java index 6138ea1926dd6..29c58998a635f 100644 --- a/core/tests/coretests/src/android/text/format/TimeTest.java +++ b/core/tests/coretests/src/android/text/format/TimeTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import android.util.Log; import android.util.TimeFormatException; @@ -34,6 +35,7 @@ import org.junit.runner.RunWith; @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) +@DisabledOnRavenwood(blockedBy = Time.class) public class TimeTest { @Test diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java index a7ff244507cbf..646e8f92fbb3d 100644 --- a/core/tests/coretests/src/android/text/method/BackspaceTest.java +++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java @@ -16,6 +16,7 @@ package android.text.method; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import android.text.InputType; import android.util.KeyUtils; @@ -41,6 +42,7 @@ import org.junit.runner.RunWith; @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) +@DisabledOnRavenwood(blockedBy = EditText.class) public class BackspaceTest { private EditText mTextView; diff --git a/core/tests/coretests/src/android/text/method/EditorState.java b/core/tests/coretests/src/android/text/method/EditorState.java index 4eff7a49ac7b9..633fa112c0163 100644 --- a/core/tests/coretests/src/android/text/method/EditorState.java +++ b/core/tests/coretests/src/android/text/method/EditorState.java @@ -16,7 +16,7 @@ package android.text.method; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -181,4 +181,3 @@ public class EditorState { Assert.assertEquals(expected.mSelectionEnd, mSelectionEnd); } } - diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java index 1e4024d92f973..8044fd7a34323 100644 --- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java +++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java @@ -16,6 +16,7 @@ package android.text.method; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import android.text.InputType; import android.util.KeyUtils; @@ -40,6 +41,7 @@ import org.junit.runner.RunWith; @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) +@DisabledOnRavenwood(blockedBy = EditText.class) public class ForwardDeleteTest { private EditText mTextView; diff --git a/core/tests/coretests/src/android/text/method/InsertModeTransformationMethodTest.java b/core/tests/coretests/src/android/text/method/InsertModeTransformationMethodTest.java index e2c19024a8408..37ad204ad64c0 100644 --- a/core/tests/coretests/src/android/text/method/InsertModeTransformationMethodTest.java +++ b/core/tests/coretests/src/android/text/method/InsertModeTransformationMethodTest.java @@ -19,6 +19,7 @@ package android.text.method; import static com.google.common.truth.Truth.assertThat; import android.content.Context; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; @@ -44,6 +45,7 @@ import org.junit.runner.RunWith; @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) +@DisabledOnRavenwood(blockedBy = View.class) public class InsertModeTransformationMethodTest { private static View sView; private static final String TEXT = "abc def"; diff --git a/core/tests/coretests/src/android/text/util/LinkifyTest.java b/core/tests/coretests/src/android/text/util/LinkifyTest.java index 52f3b2e0534fe..98bdb0b53df61 100644 --- a/core/tests/coretests/src/android/text/util/LinkifyTest.java +++ b/core/tests/coretests/src/android/text/util/LinkifyTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue; import android.content.Context; import android.content.res.Configuration; import android.os.LocaleList; +import android.platform.test.annotations.DisabledOnRavenwood; import android.text.Spannable; import android.text.SpannableString; import android.text.method.LinkMovementMethod; @@ -46,6 +47,7 @@ import java.util.Locale; */ @SmallTest @RunWith(AndroidJUnit4.class) +@DisabledOnRavenwood(blockedBy = Linkify.class) public class LinkifyTest { private static final LocaleList LOCALE_LIST_US = new LocaleList(Locale.US); diff --git a/graphics/java/android/graphics/AvoidXfermode.java b/graphics/java/android/graphics/AvoidXfermode.java index 683c157024275..5296ee8488721 100644 --- a/graphics/java/android/graphics/AvoidXfermode.java +++ b/graphics/java/android/graphics/AvoidXfermode.java @@ -23,6 +23,7 @@ package android.graphics; * @removed */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AvoidXfermode extends Xfermode { // these need to match the enum in AvoidXfermode.h on the native side diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java index 9b9be244cf904..9f605342e378e 100644 --- a/graphics/java/android/graphics/BLASTBufferQueue.java +++ b/graphics/java/android/graphics/BLASTBufferQueue.java @@ -26,6 +26,7 @@ import java.util.function.Consumer; /** * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class BLASTBufferQueue { // Note: This field is accessed by native code. public long mNativeObject; // BLASTBufferQueue* diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java index a2a0f49368885..0ca58cc07213e 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -48,6 +48,7 @@ import java.util.Objects; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public abstract class BaseCanvas { /** * Should only be assigned in constructors (or setBitmap if software canvas), diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java index 5b1fa7b15e6d1..0511bd15dd134 100644 --- a/graphics/java/android/graphics/BaseRecordingCanvas.java +++ b/graphics/java/android/graphics/BaseRecordingCanvas.java @@ -44,6 +44,7 @@ import java.util.Objects; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class BaseRecordingCanvas extends Canvas { public BaseRecordingCanvas(long nativeCanvas) { diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 0c4ea79dd5be3..cd5a54c2fd3f1 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -51,6 +51,7 @@ import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.WeakHashMap; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class Bitmap implements Parcelable { private static final String TAG = "Bitmap"; diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 1c2014183bb76..a5535c8d8485a 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -41,6 +41,7 @@ import java.io.InputStream; * Creates Bitmap objects from various sources, including files, streams, * and byte-arrays. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class BitmapFactory { private static final int DECODE_BUFFER_SIZE = 16 * 1024; diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java index 29112af9516b4..9b3f7158a3e56 100644 --- a/graphics/java/android/graphics/BitmapRegionDecoder.java +++ b/graphics/java/android/graphics/BitmapRegionDecoder.java @@ -37,6 +37,7 @@ import java.io.InputStream; * to get a decoded Bitmap of the specified region. * */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class BitmapRegionDecoder { private long mNativeBitmapRegionDecoder; private boolean mRecycled; diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index dcfff62459abc..ac3543a403cc0 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -31,6 +31,7 @@ import java.lang.annotation.RetentionPolicy; * Shader used to draw a bitmap as a texture. The bitmap can be repeated or * mirrored by setting the tiling mode. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class BitmapShader extends Shader { /** * Prevent garbage collection. diff --git a/graphics/java/android/graphics/BlendMode.java b/graphics/java/android/graphics/BlendMode.java index c6ae680d01bfb..c07af4e23b6fe 100644 --- a/graphics/java/android/graphics/BlendMode.java +++ b/graphics/java/android/graphics/BlendMode.java @@ -19,6 +19,7 @@ package android.graphics; import android.annotation.NonNull; import android.annotation.Nullable; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public enum BlendMode { /** diff --git a/graphics/java/android/graphics/BlendModeColorFilter.java b/graphics/java/android/graphics/BlendModeColorFilter.java index d4e23732bdc36..d5dd0d3c53304 100644 --- a/graphics/java/android/graphics/BlendModeColorFilter.java +++ b/graphics/java/android/graphics/BlendModeColorFilter.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; * A color filter that can be used to tint the source pixels using a single * color and a specific {@link BlendMode}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class BlendModeColorFilter extends ColorFilter { @ColorInt final int mColor; diff --git a/graphics/java/android/graphics/BlurMaskFilter.java b/graphics/java/android/graphics/BlurMaskFilter.java index f3064f8720418..22ed524e8ec06 100644 --- a/graphics/java/android/graphics/BlurMaskFilter.java +++ b/graphics/java/android/graphics/BlurMaskFilter.java @@ -22,6 +22,7 @@ package android.graphics; * inside, or straddles, the original mask's border, is controlled by the * Blur enum. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class BlurMaskFilter extends MaskFilter { public enum Blur { diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java index 46640d7222ca6..27b695c8c77fa 100644 --- a/graphics/java/android/graphics/Camera.java +++ b/graphics/java/android/graphics/Camera.java @@ -21,6 +21,7 @@ package android.graphics; * generate a matrix that can be applied, for instance, on a * {@link Canvas}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Camera { /** * Creates a new camera, with empty transformations. diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 28c2ca36fd2e8..9137150b104c6 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -54,6 +54,7 @@ import java.lang.annotation.RetentionPolicy; * * Canvas and Drawables developer guide.

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Canvas extends BaseCanvas { private static int sCompatibilityVersion = 0; private static boolean sCompatibilityRestore = false; diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java index e949584b0659d..755161d387cc9 100644 --- a/graphics/java/android/graphics/CanvasProperty.java +++ b/graphics/java/android/graphics/CanvasProperty.java @@ -25,6 +25,7 @@ import com.android.internal.util.VirtualRefBasePtr; * TODO: Make public? * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class CanvasProperty { private VirtualRefBasePtr mProperty; diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java index 7050325997b66..918f26dfe6401 100644 --- a/graphics/java/android/graphics/ColorFilter.java +++ b/graphics/java/android/graphics/ColorFilter.java @@ -23,6 +23,7 @@ import libcore.util.NativeAllocationRegistry; * each pixel drawn with that paint. This is an abstract class that should * never be used directly. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ColorFilter { private static class NoImagePreloadHolder { diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java index bfdf3187c5754..cb78a83849947 100644 --- a/graphics/java/android/graphics/ColorMatrixColorFilter.java +++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java @@ -27,6 +27,7 @@ import android.os.Build; * * @see ColorMatrix */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ColorMatrixColorFilter extends ColorFilter { @UnsupportedAppUsage private final ColorMatrix mMatrix = new ColorMatrix(); diff --git a/graphics/java/android/graphics/Compatibility.java b/graphics/java/android/graphics/Compatibility.java index 747fbf111b4b7..f89a4f7810c1a 100644 --- a/graphics/java/android/graphics/Compatibility.java +++ b/graphics/java/android/graphics/Compatibility.java @@ -21,6 +21,7 @@ package android.graphics; * specified by the app. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class Compatibility { private Compatibility() {} diff --git a/graphics/java/android/graphics/ComposePathEffect.java b/graphics/java/android/graphics/ComposePathEffect.java index 7d59ecea948ec..b380d2e78d4c6 100644 --- a/graphics/java/android/graphics/ComposePathEffect.java +++ b/graphics/java/android/graphics/ComposePathEffect.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ComposePathEffect extends PathEffect { /** diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java index e7145686247e8..57a11d232ac56 100644 --- a/graphics/java/android/graphics/ComposeShader.java +++ b/graphics/java/android/graphics/ComposeShader.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; /** A subclass of shader that returns the composition of two other shaders, combined by an {@link android.graphics.Xfermode} subclass. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ComposeShader extends Shader { Shader mShaderA; diff --git a/graphics/java/android/graphics/CornerPathEffect.java b/graphics/java/android/graphics/CornerPathEffect.java index 8f4d7d9b1c49d..37f0d2979e5e5 100644 --- a/graphics/java/android/graphics/CornerPathEffect.java +++ b/graphics/java/android/graphics/CornerPathEffect.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class CornerPathEffect extends PathEffect { /** diff --git a/graphics/java/android/graphics/DashPathEffect.java b/graphics/java/android/graphics/DashPathEffect.java index ef3ebe8089cab..ff3c376be29de 100644 --- a/graphics/java/android/graphics/DashPathEffect.java +++ b/graphics/java/android/graphics/DashPathEffect.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DashPathEffect extends PathEffect { /** diff --git a/graphics/java/android/graphics/DiscretePathEffect.java b/graphics/java/android/graphics/DiscretePathEffect.java index 3b3c9c9be6c26..77f984589896e 100644 --- a/graphics/java/android/graphics/DiscretePathEffect.java +++ b/graphics/java/android/graphics/DiscretePathEffect.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DiscretePathEffect extends PathEffect { /** diff --git a/graphics/java/android/graphics/DrawFilter.java b/graphics/java/android/graphics/DrawFilter.java index c7fdcb22c71d4..505a830d725b6 100644 --- a/graphics/java/android/graphics/DrawFilter.java +++ b/graphics/java/android/graphics/DrawFilter.java @@ -22,6 +22,7 @@ package android.graphics; * can disable/enable antialiasing, or change the color for everything this is * drawn. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class DrawFilter { /** diff --git a/graphics/java/android/graphics/EmbossMaskFilter.java b/graphics/java/android/graphics/EmbossMaskFilter.java index 003678ae5a3cb..f0a661f57291a 100644 --- a/graphics/java/android/graphics/EmbossMaskFilter.java +++ b/graphics/java/android/graphics/EmbossMaskFilter.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class EmbossMaskFilter extends MaskFilter { /** * Create an emboss maskfilter diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java index 88f0e8ef8a94d..09022ee35e649 100644 --- a/graphics/java/android/graphics/FontFamily.java +++ b/graphics/java/android/graphics/FontFamily.java @@ -41,6 +41,7 @@ import java.nio.channels.FileChannel; * @deprecated Use {@link android.graphics.fonts.FontFamily} instead. */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class FontFamily { private static String TAG = "FontFamily"; diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 13c4a94cb9b66..8d0f12866bcfd 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -48,6 +48,7 @@ import java.util.regex.Pattern; * Parser for font config files. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class FontListParser { private static final String TAG = "FontListParser"; diff --git a/graphics/java/android/graphics/ForceDarkType.java b/graphics/java/android/graphics/ForceDarkType.java index 396b03703bb98..d21aef30a45c0 100644 --- a/graphics/java/android/graphics/ForceDarkType.java +++ b/graphics/java/android/graphics/ForceDarkType.java @@ -29,6 +29,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ForceDarkType { /** * Force dark disabled: normal, default operation. diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java index 3b8f466303442..520213892d014 100644 --- a/graphics/java/android/graphics/FrameInfo.java +++ b/graphics/java/android/graphics/FrameInfo.java @@ -38,6 +38,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class FrameInfo { public long[] frameInfo = new long[FRAME_INFO_SIZE]; diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java index 63ca3b8313ce0..7fc13db85659f 100644 --- a/graphics/java/android/graphics/Gainmap.java +++ b/graphics/java/android/graphics/Gainmap.java @@ -86,6 +86,7 @@ import java.lang.annotation.RetentionPolicy; * for these functions cancels out and does not affect the result, so other bases may be used * if preferred. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class Gainmap implements Parcelable { /** @hide */ diff --git a/graphics/java/android/graphics/GraphicBuffer.java b/graphics/java/android/graphics/GraphicBuffer.java index 6705b25ab0ece..4982851c65de9 100644 --- a/graphics/java/android/graphics/GraphicBuffer.java +++ b/graphics/java/android/graphics/GraphicBuffer.java @@ -28,6 +28,7 @@ import android.os.Parcelable; * @hide */ @SuppressWarnings("UnusedDeclaration") +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class GraphicBuffer implements Parcelable { // Note: keep usage flags in sync with GraphicBuffer.h and gralloc.h public static final int USAGE_SW_READ_NEVER = 0x0; diff --git a/graphics/java/android/graphics/GraphicsProtos.java b/graphics/java/android/graphics/GraphicsProtos.java index 6bc41d39ff98c..fa7eaf9468452 100644 --- a/graphics/java/android/graphics/GraphicsProtos.java +++ b/graphics/java/android/graphics/GraphicsProtos.java @@ -24,6 +24,7 @@ import android.util.proto.ProtoOutputStream; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class GraphicsProtos { /** GraphicsProtos can never be an instance */ private GraphicsProtos() {} diff --git a/graphics/java/android/graphics/GraphicsStatsService.java b/graphics/java/android/graphics/GraphicsStatsService.java index 7a012bcde7995..d0b9998e18c8b 100644 --- a/graphics/java/android/graphics/GraphicsStatsService.java +++ b/graphics/java/android/graphics/GraphicsStatsService.java @@ -74,6 +74,7 @@ import java.util.TimeZone; * for the process to use. * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class GraphicsStatsService extends IGraphicsStats.Stub { public static final String GRAPHICS_STATS_SERVICE = "graphicsstats"; diff --git a/graphics/java/android/graphics/HardwareBufferRenderer.java b/graphics/java/android/graphics/HardwareBufferRenderer.java index e04f13c9b9223..81798709b7c60 100644 --- a/graphics/java/android/graphics/HardwareBufferRenderer.java +++ b/graphics/java/android/graphics/HardwareBufferRenderer.java @@ -55,6 +55,7 @@ import java.util.function.Consumer; * HardwareBufferRenderer will never clear contents before each draw invocation so previous contents * in the {@link HardwareBuffer} target will be preserved across renders. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class HardwareBufferRenderer implements AutoCloseable { private static final ColorSpace DEFAULT_COLORSPACE = ColorSpace.get(Named.SRGB); diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index 65854dd51a91c..79d559bf77b45 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -79,6 +79,7 @@ import sun.misc.Cleaner; * Failure to do so will cause the render thread to stall on that surface, blocking all * HardwareRenderer instances.

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class HardwareRenderer { private static final String LOG_TAG = "HardwareRenderer"; diff --git a/graphics/java/android/graphics/HardwareRendererObserver.java b/graphics/java/android/graphics/HardwareRendererObserver.java index d5a6a2fe158ad..99263780f4070 100644 --- a/graphics/java/android/graphics/HardwareRendererObserver.java +++ b/graphics/java/android/graphics/HardwareRendererObserver.java @@ -28,6 +28,7 @@ import java.lang.ref.WeakReference; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class HardwareRendererObserver { private final long[] mFrameMetrics; private final Handler mHandler; diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 6395179967244..419929a390072 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -44,6 +44,7 @@ import android.media.MediaFormat; import android.net.Uri; import android.os.Build; import android.os.Trace; +import android.ravenwood.annotation.RavenwoodIgnore; import android.system.ErrnoException; import android.system.Os; import android.util.DisplayMetrics; @@ -173,6 +174,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * }); * */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class ImageDecoder implements AutoCloseable { /** * Source of encoded image data. @@ -1987,6 +1989,7 @@ public final class ImageDecoder implements AutoCloseable { * Check if HEVC decoder is supported by the device. */ @SuppressWarnings("AndroidFrameworkCompatChange") + @RavenwoodIgnore(blockedBy = MediaCodecList.class) private static boolean isHevcDecoderSupported() { synchronized (sIsHevcDecoderSupportedLock) { if (sIsHevcDecoderSupportedInitialized) { @@ -2010,6 +2013,7 @@ public final class ImageDecoder implements AutoCloseable { * Checks if the device supports decoding 10-bit AV1. */ @SuppressWarnings("AndroidFrameworkCompatChange") // This is not an app-visible API. + @RavenwoodIgnore(blockedBy = MediaCodecList.class) private static boolean isP010SupportedForAV1() { synchronized (sIsP010SupportedLock) { if (sIsP010SupportedFlagsInitialized) { @@ -2025,6 +2029,7 @@ public final class ImageDecoder implements AutoCloseable { * This method is called by JNI. */ @SuppressWarnings("unused") + @RavenwoodIgnore(blockedBy = MediaCodecList.class) private static boolean isP010SupportedForHEVC() { synchronized (sIsP010SupportedLock) { if (sIsP010SupportedFlagsInitialized) { diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index b4899f975f43f..4c9f5ac6ba923 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -24,6 +24,7 @@ import com.android.internal.camera.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ImageFormat { /** @hide */ @Retention(RetentionPolicy.SOURCE) diff --git a/graphics/java/android/graphics/LayerRasterizer.java b/graphics/java/android/graphics/LayerRasterizer.java index 25155ab284fb0..1a44248d01b04 100644 --- a/graphics/java/android/graphics/LayerRasterizer.java +++ b/graphics/java/android/graphics/LayerRasterizer.java @@ -20,6 +20,7 @@ package android.graphics; * @removed feature is not supported by hw-accerlerated or PDF backends */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class LayerRasterizer extends Rasterizer { public LayerRasterizer() { } diff --git a/graphics/java/android/graphics/LeakyTypefaceStorage.java b/graphics/java/android/graphics/LeakyTypefaceStorage.java index 618e60d442d73..25a843696cc56 100644 --- a/graphics/java/android/graphics/LeakyTypefaceStorage.java +++ b/graphics/java/android/graphics/LeakyTypefaceStorage.java @@ -32,6 +32,7 @@ import java.util.ArrayList; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class LeakyTypefaceStorage { private static final Object sLock = new Object(); diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java index fe73a1a70b9c7..1afdc7706396a 100644 --- a/graphics/java/android/graphics/LightingColorFilter.java +++ b/graphics/java/android/graphics/LightingColorFilter.java @@ -40,6 +40,7 @@ import android.os.Build; * * The result is pinned to the [0..255] range for each channel. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class LightingColorFilter extends ColorFilter { @ColorInt private int mMul; diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java index 087937144b976..c6566c9b27fe2 100644 --- a/graphics/java/android/graphics/LinearGradient.java +++ b/graphics/java/android/graphics/LinearGradient.java @@ -24,6 +24,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class LinearGradient extends Shader { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private float mX0; diff --git a/graphics/java/android/graphics/MaskFilter.java b/graphics/java/android/graphics/MaskFilter.java index d4743155729ea..b490650e4d0ca 100644 --- a/graphics/java/android/graphics/MaskFilter.java +++ b/graphics/java/android/graphics/MaskFilter.java @@ -21,6 +21,7 @@ package android.graphics; * an alpha-channel mask before drawing it. A subclass of MaskFilter may be * installed into a Paint. Blur and emboss are implemented as subclasses of MaskFilter. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class MaskFilter { protected void finalize() throws Throwable { diff --git a/graphics/java/android/graphics/Mesh.java b/graphics/java/android/graphics/Mesh.java index 6be8332e784b3..f4d841b161fab 100644 --- a/graphics/java/android/graphics/Mesh.java +++ b/graphics/java/android/graphics/Mesh.java @@ -37,6 +37,7 @@ import java.nio.ShortBuffer; * for the mesh. Once generated, a mesh object can be drawn through * {@link Canvas#drawMesh(Mesh, BlendMode, Paint)} */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Mesh { private long mNativeMeshWrapper; private boolean mIsIndexed; diff --git a/graphics/java/android/graphics/MeshSpecification.java b/graphics/java/android/graphics/MeshSpecification.java index b1aae7f37c31b..9c7e948dfc1b9 100644 --- a/graphics/java/android/graphics/MeshSpecification.java +++ b/graphics/java/android/graphics/MeshSpecification.java @@ -72,6 +72,7 @@ import java.lang.annotation.RetentionPolicy; * These should be kept in mind when generating a mesh specification, as exceeding them will * lead to errors. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class MeshSpecification { long mNativeMeshSpec; diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java index 9c9535d16aabc..cefe391f2d2cc 100644 --- a/graphics/java/android/graphics/Movie.java +++ b/graphics/java/android/graphics/Movie.java @@ -27,6 +27,7 @@ import java.io.InputStream; * @deprecated Prefer {@link android.graphics.drawable.AnimatedImageDrawable}. */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Movie { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long mNativeMovie; diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java index 382269f74366e..00df23fe76bac 100644 --- a/graphics/java/android/graphics/NinePatch.java +++ b/graphics/java/android/graphics/NinePatch.java @@ -32,6 +32,7 @@ import android.compat.annotation.UnsupportedAppUsage; * using a WYSIWYG graphics editor. *

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class NinePatch { /** * Struct of inset information attached to a 9 patch bitmap. diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 3d4dccf095f52..a0ca0988e03c3 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -66,6 +66,7 @@ import java.util.Objects; * The Paint class holds the style and color information about how to draw * geometries, text and bitmaps. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Paint { private static final String TAG = "Paint"; diff --git a/graphics/java/android/graphics/PaintFlagsDrawFilter.java b/graphics/java/android/graphics/PaintFlagsDrawFilter.java index 232661113b5ac..f4c49b11ea960 100644 --- a/graphics/java/android/graphics/PaintFlagsDrawFilter.java +++ b/graphics/java/android/graphics/PaintFlagsDrawFilter.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PaintFlagsDrawFilter extends DrawFilter { /** * Subclass of DrawFilter that affects every paint by first clearing diff --git a/graphics/java/android/graphics/PathDashPathEffect.java b/graphics/java/android/graphics/PathDashPathEffect.java index 2b6a6edcc266f..dc92e6caabcd5 100644 --- a/graphics/java/android/graphics/PathDashPathEffect.java +++ b/graphics/java/android/graphics/PathDashPathEffect.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PathDashPathEffect extends PathEffect { public enum Style { diff --git a/graphics/java/android/graphics/PathEffect.java b/graphics/java/android/graphics/PathEffect.java index 3292501e6324f..9bb71935cfd0d 100644 --- a/graphics/java/android/graphics/PathEffect.java +++ b/graphics/java/android/graphics/PathEffect.java @@ -21,6 +21,7 @@ package android.graphics; * the geometry of a drawing primitive before it is transformed by the * canvas' matrix and drawn. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PathEffect { protected void finalize() throws Throwable { diff --git a/graphics/java/android/graphics/PathIterator.java b/graphics/java/android/graphics/PathIterator.java index d7caabf9f91bc..1ed70d02d140f 100644 --- a/graphics/java/android/graphics/PathIterator.java +++ b/graphics/java/android/graphics/PathIterator.java @@ -34,6 +34,7 @@ import java.util.Iterator; * PathIterator can be used to query a given {@link Path} object, to discover its * operations and point values. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PathIterator implements Iterator { private final float[] mPointsArray; @@ -47,9 +48,11 @@ public class PathIterator implements Iterator { private static final boolean IS_DALVIK = "dalvik".equalsIgnoreCase( System.getProperty("java.vm.name")); - private static final NativeAllocationRegistry sRegistry = - NativeAllocationRegistry.createMalloced( - PathIterator.class.getClassLoader(), nGetFinalizer()); + private static class NoImagePreloadHolder { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + PathIterator.class.getClassLoader(), nGetFinalizer()); + } /** * The Verb indicates the operation for a given segment of a path. These @@ -69,6 +72,11 @@ public class PathIterator implements Iterator { public static final int VERB_CLOSE = 5; public static final int VERB_DONE = 6; + + static { + // Keep exist in bytecode + } + /** * Returns a {@link PathIterator} object for this path, which can be used to query the * data (operations and points) in the path. Iterators can only be used on Path objects @@ -90,7 +98,7 @@ public class PathIterator implements Iterator { mPointsArray = new float[POINT_ARRAY_SIZE]; mPointsAddress = 0; } - sRegistry.registerNativeAllocation(this, mNativeIterator); + NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeIterator); } /** diff --git a/graphics/java/android/graphics/PathMeasure.java b/graphics/java/android/graphics/PathMeasure.java index 2c6cfa5c2e3d2..4d123db41ee74 100644 --- a/graphics/java/android/graphics/PathMeasure.java +++ b/graphics/java/android/graphics/PathMeasure.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PathMeasure { private Path mPath; diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java index ee4165b8da050..54eb2bc659bc2 100644 --- a/graphics/java/android/graphics/Picture.java +++ b/graphics/java/android/graphics/Picture.java @@ -33,6 +33,7 @@ import java.io.OutputStream; *

Note: Prior to API level 23 a picture cannot * be replayed on a hardware accelerated canvas.

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Picture { private PictureCanvas mRecordingCanvas; // TODO: Figure out if this was a false-positive diff --git a/graphics/java/android/graphics/PixelXorXfermode.java b/graphics/java/android/graphics/PixelXorXfermode.java index 27884e07ecfb0..64278525bb1f6 100644 --- a/graphics/java/android/graphics/PixelXorXfermode.java +++ b/graphics/java/android/graphics/PixelXorXfermode.java @@ -20,6 +20,7 @@ package android.graphics; * @removed */ @Deprecated +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PixelXorXfermode extends Xfermode { public PixelXorXfermode(int opColor) { diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java index eb940e2f90175..730a804e17c35 100644 --- a/graphics/java/android/graphics/PorterDuff.java +++ b/graphics/java/android/graphics/PorterDuff.java @@ -26,6 +26,7 @@ import android.compat.annotation.UnsupportedAppUsage; * * Consider using {@link BlendMode} instead as it provides a wider variety of tinting options */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PorterDuff { /** * {@usesMathJax} diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java index 0700f217ecf04..777ef6ce906b9 100644 --- a/graphics/java/android/graphics/PorterDuffColorFilter.java +++ b/graphics/java/android/graphics/PorterDuffColorFilter.java @@ -25,6 +25,7 @@ import android.os.Build; * A color filter that can be used to tint the source pixels using a single * color and a specific {@link PorterDuff Porter-Duff composite mode}. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PorterDuffColorFilter extends ColorFilter { @ColorInt private int mColor; diff --git a/graphics/java/android/graphics/PorterDuffXfermode.java b/graphics/java/android/graphics/PorterDuffXfermode.java index 83d0507a50749..e10d7370d6f90 100644 --- a/graphics/java/android/graphics/PorterDuffXfermode.java +++ b/graphics/java/android/graphics/PorterDuffXfermode.java @@ -23,6 +23,7 @@ package android.graphics; * information on the available alpha compositing and blending modes.

* */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class PorterDuffXfermode extends Xfermode { /** * Create an xfermode that uses the specified porter-duff mode. diff --git a/graphics/java/android/graphics/PostProcessor.java b/graphics/java/android/graphics/PostProcessor.java index 6fed39b9975d6..066214ac6cd60 100644 --- a/graphics/java/android/graphics/PostProcessor.java +++ b/graphics/java/android/graphics/PostProcessor.java @@ -37,6 +37,7 @@ import android.graphics.drawable.Drawable; * *

Supplied to ImageDecoder via {@link ImageDecoder#setPostProcessor setPostProcessor}.

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public interface PostProcessor { /** * Do any processing after (for example) decoding. diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java index e582e66e16278..06e92eae9c82b 100644 --- a/graphics/java/android/graphics/RadialGradient.java +++ b/graphics/java/android/graphics/RadialGradient.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class RadialGradient extends Shader { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private float mX; diff --git a/graphics/java/android/graphics/Rasterizer.java b/graphics/java/android/graphics/Rasterizer.java index 575095426563b..5e67da50a40d9 100644 --- a/graphics/java/android/graphics/Rasterizer.java +++ b/graphics/java/android/graphics/Rasterizer.java @@ -24,6 +24,7 @@ package android.graphics; /** * @removed feature is not supported by hw-accerlerated or PDF backends */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Rasterizer { protected void finalize() throws Throwable { } diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java index cc5b3b94e0fa3..a56f461e511a8 100644 --- a/graphics/java/android/graphics/RecordingCanvas.java +++ b/graphics/java/android/graphics/RecordingCanvas.java @@ -33,6 +33,7 @@ import dalvik.annotation.optimization.CriticalNative; * {@link RenderNode#endRecording()} is called. It must not be retained beyond that as it is * internally reused. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class RecordingCanvas extends BaseRecordingCanvas { // The recording canvas pool should be large enough to handle a deeply nested // view hierarchy because display lists are generated recursively. diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java index 29708738d2db6..e2215d4bf3006 100644 --- a/graphics/java/android/graphics/Region.java +++ b/graphics/java/android/graphics/Region.java @@ -23,6 +23,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.Pools.SynchronizedPool; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Region implements Parcelable { private static final int MAX_POOL_SIZE = 10; diff --git a/graphics/java/android/graphics/RegionIterator.java b/graphics/java/android/graphics/RegionIterator.java index 443b23c1b5fc7..5d74487e5a8e4 100644 --- a/graphics/java/android/graphics/RegionIterator.java +++ b/graphics/java/android/graphics/RegionIterator.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class RegionIterator { /** diff --git a/graphics/java/android/graphics/RenderEffect.java b/graphics/java/android/graphics/RenderEffect.java index b8a46856601e4..06bfb82ef6304 100644 --- a/graphics/java/android/graphics/RenderEffect.java +++ b/graphics/java/android/graphics/RenderEffect.java @@ -30,6 +30,7 @@ import libcore.util.NativeAllocationRegistry; * Additionally a {@link RenderEffect} can be applied to a View's backing RenderNode through * {@link android.view.View#setRenderEffect(RenderEffect)} */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class RenderEffect { private static class RenderEffectHolder { diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index 03a8b306f99d6..fa41876187cf2 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -192,6 +192,7 @@ import java.lang.ref.WeakReference; * top-level content is desired, and finally calling {@link Surface#unlockCanvasAndPost(Canvas)}. *

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class RenderNode { // Use a Holder to allow static initialization in the boot image. diff --git a/graphics/java/android/graphics/RuntimeColorFilter.java b/graphics/java/android/graphics/RuntimeColorFilter.java index a64acfe767a9f..06aecc3f2c49b 100644 --- a/graphics/java/android/graphics/RuntimeColorFilter.java +++ b/graphics/java/android/graphics/RuntimeColorFilter.java @@ -37,6 +37,7 @@ import com.android.graphics.hwui.flags.Flags; * */ @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class RuntimeColorFilter extends ColorFilter { private String mAgsl; diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java index db2376e008f57..6464f72490c42 100644 --- a/graphics/java/android/graphics/RuntimeShader.java +++ b/graphics/java/android/graphics/RuntimeShader.java @@ -248,6 +248,7 @@ import libcore.util.NativeAllocationRegistry; * the bitmap), remember that the coordinates are local to the canvas.

* */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class RuntimeShader extends Shader { private static class NoImagePreloadHolder { diff --git a/graphics/java/android/graphics/RuntimeXfermode.java b/graphics/java/android/graphics/RuntimeXfermode.java index c8a0b1a113399..1e20bd352244d 100644 --- a/graphics/java/android/graphics/RuntimeXfermode.java +++ b/graphics/java/android/graphics/RuntimeXfermode.java @@ -39,6 +39,7 @@ import libcore.util.NativeAllocationRegistry; * */ @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class RuntimeXfermode extends Xfermode { private static class NoImagePreloadHolder { diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index 4d6beadc0fdda..369fab45bf69b 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -29,6 +29,7 @@ import libcore.util.NativeAllocationRegistry; * paint.setShader(shader). After that any object (other than a bitmap) that is * drawn with that paint will get its color(s) from the shader. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Shader { private static class NoImagePreloadHolder { diff --git a/graphics/java/android/graphics/SumPathEffect.java b/graphics/java/android/graphics/SumPathEffect.java index 8fedc317c4283..3543e101fb38b 100644 --- a/graphics/java/android/graphics/SumPathEffect.java +++ b/graphics/java/android/graphics/SumPathEffect.java @@ -16,6 +16,7 @@ package android.graphics; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SumPathEffect extends PathEffect { /** diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index 5caedba364be7..df384ead58fb4 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -78,6 +78,7 @@ import java.lang.ref.WeakReference; * frame-available callback is called on an arbitrary thread, so unless special care is taken {@link * #updateTexImage} should not be called directly from the callback. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SurfaceTexture { private final Looper mCreatorLooper; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java index 3a29395b1717c..94219259a69db 100644 --- a/graphics/java/android/graphics/SweepGradient.java +++ b/graphics/java/android/graphics/SweepGradient.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class SweepGradient extends Shader { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private float mCx; diff --git a/graphics/java/android/graphics/TableMaskFilter.java b/graphics/java/android/graphics/TableMaskFilter.java index 204f9705852a9..ca7627c400319 100644 --- a/graphics/java/android/graphics/TableMaskFilter.java +++ b/graphics/java/android/graphics/TableMaskFilter.java @@ -21,6 +21,7 @@ import android.compat.annotation.UnsupportedAppUsage; /** * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TableMaskFilter extends MaskFilter { public TableMaskFilter(byte[] table) { diff --git a/graphics/java/android/graphics/TemporaryBuffer.java b/graphics/java/android/graphics/TemporaryBuffer.java index ef3f7f704e0d3..681c48ea9f715 100644 --- a/graphics/java/android/graphics/TemporaryBuffer.java +++ b/graphics/java/android/graphics/TemporaryBuffer.java @@ -23,6 +23,7 @@ import com.android.internal.util.ArrayUtils; /** * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TemporaryBuffer { @UnsupportedAppUsage public static char[] obtain(int len) { diff --git a/graphics/java/android/graphics/TextureLayer.java b/graphics/java/android/graphics/TextureLayer.java index ac1bd69020622..981b78a7b5b8a 100644 --- a/graphics/java/android/graphics/TextureLayer.java +++ b/graphics/java/android/graphics/TextureLayer.java @@ -29,6 +29,7 @@ import com.android.internal.util.VirtualRefBasePtr; * * @hide TODO: Make this a SystemApi for b/155905258 */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class TextureLayer implements AutoCloseable { private HardwareRenderer mRenderer; private VirtualRefBasePtr mFinalizer; diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 874b847c709c8..d1aca34c7b8d6 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -42,6 +42,7 @@ import android.os.SystemProperties; import android.os.Trace; import android.provider.FontRequest; import android.provider.FontsContract; +import android.ravenwood.annotation.RavenwoodReplace; import android.system.ErrnoException; import android.system.OsConstants; import android.text.FontConfig; @@ -86,6 +87,7 @@ import java.util.Objects; * textSize, textSkewX, textScaleX to specify * how text appears when drawn (and measured). */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Typeface { private static String TAG = "Typeface"; @@ -93,9 +95,11 @@ public class Typeface { /** @hide */ public static final boolean ENABLE_LAZY_TYPEFACE_INITIALIZATION = true; - private static final NativeAllocationRegistry sRegistry = - NativeAllocationRegistry.createMalloced( - Typeface.class.getClassLoader(), nativeGetReleaseFunc()); + private static class NoImagePreloadHolder { + static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + Typeface.class.getClassLoader(), nativeGetReleaseFunc()); + } /** The default NORMAL typeface object */ public static final Typeface DEFAULT = null; @@ -1284,7 +1288,7 @@ public class Typeface { } native_instance = ni; - mCleaner = sRegistry.registerNativeAllocation(this, native_instance); + mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance); mStyle = nativeGetStyle(ni); mWeight = nativeGetWeight(ni); mIsVariationInstance = nativeIsVariationInstance(ni); @@ -1560,9 +1564,23 @@ public class Typeface { } static { + staticInitializer(); + } + + @RavenwoodReplace(reason = "Prevent circular reference on host side JVM", bug = 337329128) + private static void staticInitializer() { + init(); + } + + private static void staticInitializer$ravenwood() { + /* no-op */ + } + + /** @hide */ + public static void init() { // Preload Roboto-Regular.ttf in Zygote for improving app launch performance. - preloadFontFile("/system/fonts/Roboto-Regular.ttf"); - preloadFontFile("/system/fonts/RobotoStatic-Regular.ttf"); + preloadFontFile(SystemFonts.SYSTEM_FONT_DIR + "Roboto-Regular.ttf"); + preloadFontFile(SystemFonts.SYSTEM_FONT_DIR + "RobotoStatic-Regular.ttf"); String locale = SystemProperties.get("persist.sys.locale", "en-US"); String script = ULocale.addLikelySubtags(ULocale.forLanguageTag(locale)).getScript(); @@ -1642,6 +1660,21 @@ public class Typeface { setSystemFontMap(typefaceMap); } + /** + * {@link #loadPreinstalledSystemFontMap()} does not actually initialize the native + * system font APIs. Add a new method to actually load the font files without going + * through SharedMemory. + * + * @hide + */ + public static void loadNativeSystemFonts() { + synchronized (SYSTEM_FONT_MAP_LOCK) { + for (var type : sSystemFontMap.values()) { + nativeAddFontCollections(type.native_instance); + } + } + } + static { if (!ENABLE_LAZY_TYPEFACE_INITIALIZATION) { loadPreinstalledSystemFontMap(); diff --git a/graphics/java/android/graphics/Xfermode.java b/graphics/java/android/graphics/Xfermode.java index fb689e4cb9c29..eda9e3c1055df 100644 --- a/graphics/java/android/graphics/Xfermode.java +++ b/graphics/java/android/graphics/Xfermode.java @@ -28,4 +28,5 @@ package android.graphics; * specified in the Modes enum. When an Xfermode is assigned to a Paint, then * objects drawn with that paint have the xfermode applied. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Xfermode {} diff --git a/graphics/java/android/graphics/YuvImage.java b/graphics/java/android/graphics/YuvImage.java index b0c7f202f23ae..2b7f40493e8d8 100644 --- a/graphics/java/android/graphics/YuvImage.java +++ b/graphics/java/android/graphics/YuvImage.java @@ -32,6 +32,7 @@ import java.io.OutputStream; * To compress a rectangle region in the YUV data, users have to specify the * region by left, top, width and height. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class YuvImage { /** diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index 2893177aafc5d..8be340005543a 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -44,6 +44,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.util.Arrays; import java.util.Collections; @@ -54,6 +55,7 @@ import java.util.Set; /** * A font class can be used for creating FontFamily. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class Font { private static final String TAG = "Font"; @@ -293,7 +295,14 @@ public final class Font { int capacity = assetStream.available(); ByteBuffer buffer = ByteBuffer.allocateDirect(capacity); buffer.order(ByteOrder.nativeOrder()); - assetStream.read(buffer.array(), buffer.arrayOffset(), assetStream.available()); + if (buffer.hasArray()) { + assetStream.read(buffer.array(), buffer.arrayOffset(), assetStream.available()); + } else { + // Direct buffer does not have a backing array on Ravenwood, + // wrap it with a channel and read from it + var ch = Channels.newChannel(assetStream); + ch.read(buffer.duplicate()); + } if (assetStream.read() != -1) { throw new IOException("Unable to access full contents of " + path); diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java index b7bf0553bcc6a..732a5f3bfce4c 100644 --- a/graphics/java/android/graphics/fonts/FontCustomizationParser.java +++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java @@ -43,6 +43,7 @@ import java.util.Map; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class FontCustomizationParser { private static final String TAG = "FontCustomizationParser"; diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java index 5a7b0bbca3998..0ab46398c9242 100644 --- a/graphics/java/android/graphics/fonts/FontFamily.java +++ b/graphics/java/android/graphics/fonts/FontFamily.java @@ -66,6 +66,7 @@ import java.util.Set; *

* */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class FontFamily { private static final String TAG = "FontFamily"; diff --git a/graphics/java/android/graphics/fonts/FontFileUtil.java b/graphics/java/android/graphics/fonts/FontFileUtil.java index abcafb666576b..305ab3b39995c 100644 --- a/graphics/java/android/graphics/fonts/FontFileUtil.java +++ b/graphics/java/android/graphics/fonts/FontFileUtil.java @@ -32,6 +32,7 @@ import java.util.Set; * Provides a utility for font file operations. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class FontFileUtil { private FontFileUtil() {} // Do not instantiate diff --git a/graphics/java/android/graphics/fonts/FontStyle.java b/graphics/java/android/graphics/fonts/FontStyle.java index 48969aa710594..b3ddbed645ffa 100644 --- a/graphics/java/android/graphics/fonts/FontStyle.java +++ b/graphics/java/android/graphics/fonts/FontStyle.java @@ -44,6 +44,7 @@ import java.util.Objects; *

* */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class FontStyle { private static final String TAG = "FontStyle"; diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java index 30a248bb3e0e5..1d715940d6288 100644 --- a/graphics/java/android/graphics/fonts/FontVariationAxis.java +++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java @@ -31,6 +31,7 @@ import java.util.regex.Pattern; /** * Class that holds information about single font variation axis. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class FontVariationAxis { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final int mTag; diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 0e25c346064c5..599c42659ece7 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -25,6 +25,7 @@ import android.annotation.Nullable; import android.graphics.FontListParser; import android.graphics.Typeface; import android.os.LocaleList; +import android.ravenwood.annotation.RavenwoodReplace; import android.text.FontConfig; import android.util.ArrayMap; import android.util.Log; @@ -32,6 +33,7 @@ import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.ravenwood.RavenwoodEnvironment; import org.xmlpull.v1.XmlPullParserException; @@ -50,23 +52,46 @@ import java.util.Set; /** * Provides the system font configurations. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class SystemFonts { private static final String TAG = "SystemFonts"; - private static final String FONTS_XML = "/system/etc/font_fallback.xml"; - private static final String LEGACY_FONTS_XML = "/system/etc/fonts.xml"; + private static final String FONTS_XML = getFontsXmlDir() + "font_fallback.xml"; + /** @hide */ + public static final String LEGACY_FONTS_XML = getFontsXmlDir() + "fonts.xml"; /** @hide */ - public static final String SYSTEM_FONT_DIR = "/system/fonts/"; + public static final String SYSTEM_FONT_DIR = getSystemFontDir(); private static final String OEM_XML = "/product/etc/fonts_customization.xml"; /** @hide */ public static final String OEM_FONT_DIR = "/product/fonts/"; + private static final String DEVICE_FONTS_XML_DIR = "/system/etc/"; + private static final String DEVICE_FONT_DIR = "/system/fonts/"; + private SystemFonts() {} // Do not instansiate. private static final Object LOCK = new Object(); private static @GuardedBy("sLock") Set sAvailableFonts; + @RavenwoodReplace + private static String getFontsXmlDir() { + return DEVICE_FONTS_XML_DIR; + } + + private static String getFontsXmlDir$ravenwood() { + return RavenwoodEnvironment.getInstance().getRavenwoodRuntimePath() + "fonts/"; + } + + @RavenwoodReplace + private static String getSystemFontDir() { + return DEVICE_FONT_DIR; + } + + private static String getSystemFontDir$ravenwood() { + return RavenwoodEnvironment.getInstance().getRavenwoodRuntimePath() + "fonts/"; + } + /** * Returns all available font files in the system. * diff --git a/graphics/java/android/graphics/text/GraphemeBreak.java b/graphics/java/android/graphics/text/GraphemeBreak.java index f82b2fd659ccb..0bc1e3b0cae34 100644 --- a/graphics/java/android/graphics/text/GraphemeBreak.java +++ b/graphics/java/android/graphics/text/GraphemeBreak.java @@ -17,6 +17,7 @@ package android.graphics.text; /** @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class GraphemeBreak { private GraphemeBreak() { } diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java index 5a1086cef4072..fa3cfbdd4e970 100644 --- a/graphics/java/android/graphics/text/LineBreakConfig.java +++ b/graphics/java/android/graphics/text/LineBreakConfig.java @@ -24,12 +24,13 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; -import android.app.ActivityThread; import android.os.Build; import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; +import dalvik.system.VMRuntime; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -41,6 +42,7 @@ import java.util.Objects; * * line-break property for more information. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class LineBreakConfig implements Parcelable { /** * No hyphenation preference is specified. @@ -484,8 +486,7 @@ public final class LineBreakConfig implements Parcelable { * @hide */ public static @LineBreakStyle int getResolvedLineBreakStyle(@Nullable LineBreakConfig config) { - final int targetSdkVersion = ActivityThread.currentApplication().getApplicationInfo() - .targetSdkVersion; + final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion(); final int defaultStyle; final int vicVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM; if (targetSdkVersion >= vicVersion) { @@ -519,8 +520,7 @@ public final class LineBreakConfig implements Parcelable { */ public static @LineBreakWordStyle int getResolvedLineBreakWordStyle( @Nullable LineBreakConfig config) { - final int targetSdkVersion = ActivityThread.currentApplication().getApplicationInfo() - .targetSdkVersion; + final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion(); final int defaultWordStyle; final int vicVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM; if (targetSdkVersion >= vicVersion) { diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java index 94de066c91826..29135b8373526 100644 --- a/graphics/java/android/graphics/text/LineBreaker.java +++ b/graphics/java/android/graphics/text/LineBreaker.java @@ -91,6 +91,7 @@ import java.lang.annotation.RetentionPolicy; * *

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class LineBreaker { /** @hide */ @IntDef(prefix = { "BREAK_STRATEGY_" }, value = { diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java index 884268a4b85cf..f58d5311fa30e 100644 --- a/graphics/java/android/graphics/text/MeasuredText.java +++ b/graphics/java/android/graphics/text/MeasuredText.java @@ -56,6 +56,7 @@ import java.util.Objects; * *

*/ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class MeasuredText { private static final String TAG = "MeasuredText"; diff --git a/graphics/java/android/graphics/text/PositionedGlyphs.java b/graphics/java/android/graphics/text/PositionedGlyphs.java index 43216ba6e0873..31125ffa7bd43 100644 --- a/graphics/java/android/graphics/text/PositionedGlyphs.java +++ b/graphics/java/android/graphics/text/PositionedGlyphs.java @@ -46,6 +46,7 @@ import java.util.Objects; * @see TextRunShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint) * @see TextRunShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint) */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class PositionedGlyphs { private static class NoImagePreloadHolder { private static final NativeAllocationRegistry REGISTRY = diff --git a/graphics/java/android/graphics/text/TextRunShaper.java b/graphics/java/android/graphics/text/TextRunShaper.java index 19ea04a480460..f1e3d67e99254 100644 --- a/graphics/java/android/graphics/text/TextRunShaper.java +++ b/graphics/java/android/graphics/text/TextRunShaper.java @@ -40,6 +40,7 @@ import com.android.internal.util.Preconditions; * @see android.text.TextShaper#shapeText(CharSequence, int, int, TextDirectionHeuristic, TextPaint, * TextShaper.GlyphsConsumer) */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class TextRunShaper { private TextRunShaper() {} // Do not instantiate diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index bb2a53bc04d6b..38ac8ab7135e3 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -232,6 +232,14 @@ java_sdk_library { unsafe_ignore_missing_latest_api: true, } +filegroup { + name: "framework-graphics-ravenwood-policies", + srcs: [ + "framework-graphics-ravenwood-policies.txt", + ], + visibility: ["//frameworks/base/ravenwood"], +} + filegroup { name: "framework-graphics-srcs", srcs: [ @@ -461,6 +469,10 @@ cc_defaults { }, linux: { srcs: ["platform/linux/utils/SharedLib.cpp"], + shared_libs: [ + "libbinder", + "libbinder_ndk", + ], }, darwin: { srcs: ["platform/darwin/utils/SharedLib.cpp"], diff --git a/libs/hwui/framework-graphics-ravenwood-policies.txt b/libs/hwui/framework-graphics-ravenwood-policies.txt new file mode 100644 index 0000000000000..7296225ccfe8b --- /dev/null +++ b/libs/hwui/framework-graphics-ravenwood-policies.txt @@ -0,0 +1 @@ +class android.graphics.ColorMatrix keepclass diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp index cfde0b28c0d58..27d4ac7cef4b2 100644 --- a/libs/hwui/jni/Bitmap.cpp +++ b/libs/hwui/jni/Bitmap.cpp @@ -613,7 +613,7 @@ static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, /////////////////////////////////////////////////////////////////////////////// // TODO: Move somewhere else -#ifdef __ANDROID__ // Layoutlib does not support parcel +#ifdef __linux__ // Only Linux support parcel #define ON_ERROR_RETURN(X) \ if ((error = (X)) != STATUS_OK) return error @@ -717,7 +717,7 @@ static binder_status_t writeBlob(AParcel* parcel, uint64_t bitmapId, const SkBit #undef ON_ERROR_RETURN -#endif // __ANDROID__ // Layoutlib does not support parcel +#endif // __linux__ // Only Linux support parcel // This is the maximum possible size because the SkColorSpace must be // representable (and therefore serializable) using a matrix and numerical @@ -733,7 +733,7 @@ static bool validateImageInfo(const SkImageInfo& info, int32_t rowBytes) { } static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { -#ifdef __ANDROID__ // Layoutlib does not support parcel +#ifdef __linux__ // Only Linux support parcel if (parcel == NULL) { jniThrowNullPointerException(env, "parcel cannot be null"); return NULL; @@ -836,14 +836,14 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable), nullptr, nullptr, density, sourceId); #else - jniThrowRuntimeException(env, "Cannot use parcels outside of Android"); + jniThrowRuntimeException(env, "Cannot use parcels outside of Linux"); return NULL; #endif } static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, jlong bitmapHandle, jint density, jobject parcel) { -#ifdef __ANDROID__ // Layoutlib does not support parcel +#ifdef __linux__ // Only Linux support parcel if (parcel == NULL) { ALOGD("------- writeToParcel null parcel\n"); return JNI_FALSE; @@ -901,7 +901,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, jlong bitmapHandle, j } return JNI_TRUE; #else - doThrowRE(env, "Cannot use parcels outside of Android"); + doThrowRE(env, "Cannot use parcels outside of Linux"); return JNI_FALSE; #endif } diff --git a/libs/hwui/jni/Region.cpp b/libs/hwui/jni/Region.cpp index 1e064b8205916..76986eeb079dd 100644 --- a/libs/hwui/jni/Region.cpp +++ b/libs/hwui/jni/Region.cpp @@ -18,7 +18,7 @@ #include "SkPath.h" #include "GraphicsJNI.h" -#ifdef __ANDROID__ // Layoutlib does not support parcel +#ifdef __linux__ // Only Linux support parcel #include #include #include @@ -202,7 +202,7 @@ static jstring Region_toString(JNIEnv* env, jobject clazz, jlong regionHandle) { static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) { -#ifdef __ANDROID__ // Layoutlib does not support parcel +#ifdef __linux__ // Only Linux support parcel if (parcel == nullptr) { return 0; } @@ -230,7 +230,7 @@ static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, jlong regionHandle, jobject parcel) { -#ifdef __ANDROID__ // Layoutlib does not support parcel +#ifdef __linux__ // Only Linux support parcel const SkRegion* region = reinterpret_cast(regionHandle); if (parcel == nullptr) { return JNI_FALSE; diff --git a/libs/hwui/jni/ScopedParcel.cpp b/libs/hwui/jni/ScopedParcel.cpp index 95e4e01d8df85..52cd988344b0e 100644 --- a/libs/hwui/jni/ScopedParcel.cpp +++ b/libs/hwui/jni/ScopedParcel.cpp @@ -15,7 +15,7 @@ */ #include "ScopedParcel.h" -#ifdef __ANDROID__ // Layoutlib does not support parcel +#ifdef __linux__ // Only Linux support parcel using namespace android; @@ -92,4 +92,4 @@ void ScopedParcel::writeData(const std::optional>& optData) { AParcel_writeByteArray(mParcel, nullptr, -1); } } -#endif // __ANDROID__ // Layoutlib does not support parcel +#endif // __linux__ // Only Linux support parcel diff --git a/libs/hwui/jni/ScopedParcel.h b/libs/hwui/jni/ScopedParcel.h index f2f138fda43cb..f2b793a354d75 100644 --- a/libs/hwui/jni/ScopedParcel.h +++ b/libs/hwui/jni/ScopedParcel.h @@ -15,7 +15,7 @@ */ #include "SkData.h" -#ifdef __ANDROID__ // Layoutlib does not support parcel +#ifdef __linux__ // Only Linux support parcel #include #include #include @@ -64,4 +64,4 @@ enum class BlobType : int32_t { ASHMEM, }; -#endif // __ANDROID__ // Layoutlib does not support parcel \ No newline at end of file +#endif // __linux__ // Only Linux support parcel diff --git a/libs/hwui/jni/graphics_jni_helpers.h b/libs/hwui/jni/graphics_jni_helpers.h index 91db134af18f9..ff26ec1771bd0 100644 --- a/libs/hwui/jni/graphics_jni_helpers.h +++ b/libs/hwui/jni/graphics_jni_helpers.h @@ -21,6 +21,7 @@ #include #include #include +#include #include // Host targets (layoutlib) do not differentiate between regular and critical native methods, diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 65550f2b42736..ccbc46fdb03b4 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -121,6 +121,7 @@ java_library { name: "ravenwood-helper-framework-runtime", srcs: [ "runtime-helper-src/framework/**/*.java", + ":framework-graphics-srcs", ], static_libs: [ "ravenwood-runtime-common", @@ -278,6 +279,7 @@ cc_library_host_shared { cc_library_host_shared { name: "libravenwood_runtime", defaults: ["ravenwood_jni_defaults"], + header_libs: ["libicuuc_headers"], srcs: [ "runtime-jni/ravenwood_runtime.cpp", "runtime-jni/ravenwood_os_constants.cpp", @@ -372,6 +374,13 @@ platform_compat_config { visibility: ["//visibility:private"], } +java_library { + name: "ext-ravenwood", + installable: false, + static_libs: ["ext"], + visibility: ["//visibility:private"], +} + filegroup { name: "ravenwood-data", device_common_srcs: [ @@ -637,6 +646,7 @@ android_ravenwood_libgroup { libs: [ "100-framework-minus-apex.ravenwood", "200-kxml2-android", + "ext-ravenwood", "ravenwood-runtime-common-ravenwood", diff --git a/ravenwood/Framework.bp b/ravenwood/Framework.bp index 71496b0d57666..e36677189e02e 100644 --- a/ravenwood/Framework.bp +++ b/ravenwood/Framework.bp @@ -419,11 +419,13 @@ java_genrule { "--out-impl-jar $(location ravenwood.jar) " + "--in-jar $(location :framework-graphics.impl{.jar}) " + - "--policy-override-file $(location :ravenwood-common-policies) ", + "--policy-override-file $(location :ravenwood-common-policies) " + + "--policy-override-file $(location :framework-graphics-ravenwood-policies) ", srcs: [ ":framework-graphics.impl{.jar}", ":ravenwood-common-policies", + ":framework-graphics-ravenwood-policies", ":ravenwood-standard-options", ], out: [ diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java index a3326337d4857..9e6b12f60add2 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java @@ -230,6 +230,16 @@ public class RavenwoodContext extends RavenwoodBaseContext { return mAppContext; } + @Override + public boolean isRestricted() { + return false; + } + + @Override + public boolean canLoadUnsafeResources() { + return true; + } + /** * Wrap the given {@link Supplier} to become memoized. * diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java index a208d6dce2ce1..7e935d0451aee 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java @@ -48,6 +48,7 @@ public final class RavenwoodNativeLoader { android.content.res.AssetManager.class, android.content.res.StringBlock.class, android.content.res.XmlBlock.class, + android.text.AndroidCharacter.class, }; /** @@ -61,15 +62,49 @@ public final class RavenwoodNativeLoader { android.graphics.Path.class, android.graphics.Color.class, android.graphics.ColorSpace.class, + android.graphics.Bitmap.class, + android.graphics.BitmapFactory.class, + android.graphics.BitmapRegionDecoder.class, + android.graphics.Camera.class, + android.graphics.Canvas.class, + android.graphics.CanvasProperty.class, + android.graphics.ColorFilter.class, + android.graphics.DrawFilter.class, + android.graphics.FontFamily.class, + android.graphics.Gainmap.class, + android.graphics.ImageDecoder.class, + android.graphics.MaskFilter.class, + android.graphics.NinePatch.class, + android.graphics.Paint.class, + android.graphics.PathEffect.class, + android.graphics.PathIterator.class, + android.graphics.PathMeasure.class, + android.graphics.Picture.class, + android.graphics.RecordingCanvas.class, + android.graphics.Region.class, + android.graphics.RenderNode.class, + android.graphics.Shader.class, + android.graphics.RenderEffect.class, + android.graphics.Typeface.class, + android.graphics.YuvImage.class, + android.graphics.fonts.Font.class, + android.graphics.fonts.FontFamily.class, + android.graphics.text.LineBreaker.class, + android.graphics.text.MeasuredText.class, + android.graphics.text.TextRunShaper.class, + android.graphics.text.GraphemeBreak.class, + android.util.PathParser.class, }; /** * Extra strings needed to pass to register_android_graphics_classes(). * - * `android.graphics.Graphics` is not actually a class, so we just hardcode it here. + * Several entries are not actually a class, so we just hardcode them here. */ public final static String[] GRAPHICS_EXTRA_INIT_PARAMS = new String[] { - "android.graphics.Graphics" + "android.graphics.Graphics", + "android.graphics.ByteBufferStreamAdaptor", + "android.graphics.CreateJavaOutputStreamAdaptor" }; private RavenwoodNativeLoader() { diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java index ae88bb234e9d6..f205d238c6934 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java @@ -43,6 +43,7 @@ import android.app.UiAutomation; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.Resources; +import android.graphics.Typeface; import android.icu.util.ULocale; import android.os.Binder; import android.os.Build; @@ -246,6 +247,13 @@ public class RavenwoodRuntimeEnvironmentController { // Do the basic set up for the android sysprops. RavenwoodSystemProperties.initialize(); + // Set ICU data file + String icuData = RavenwoodCommonUtils.getRavenwoodRuntimePath() + + "ravenwood-data/" + + RavenwoodRuntimeNative.getIcuDataName() + + ".dat"; + RavenwoodRuntimeNative.setSystemProperty("ro.icu.data.path", icuData); + // Enable all log levels for native logging, until we'll have a way to change the native // side log level at runtime. // Do this after loading RAVENWOOD_NATIVE_RUNTIME_NAME (which backs Os.setenv()), @@ -268,6 +276,11 @@ public class RavenwoodRuntimeEnvironmentController { Objects.requireNonNull(Build.TYPE); Objects.requireNonNull(Build.VERSION.SDK); + // Fonts can only be initialized once + Typeface.init(); + Typeface.loadPreinstalledSystemFontMap(); + Typeface.loadNativeSystemFonts(); + System.setProperty(RAVENWOOD_VERSION_JAVA_SYSPROP, "1"); // This will let AndroidJUnit4 use the original runner. System.setProperty("android.junit.runner", diff --git a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodJdkPatch.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodJdkPatch.java index 96aed4b3401de..d5a96ddc3a981 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodJdkPatch.java +++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodJdkPatch.java @@ -20,6 +20,7 @@ import com.android.ravenwood.common.JvmWorkaround; import java.io.FileDescriptor; import java.util.LinkedHashMap; import java.util.Map; +import java.util.regex.Pattern; /** * Class to host APIs that exist in libcore, but not in standard JRE. @@ -46,4 +47,22 @@ public class RavenwoodJdkPatch { final var it = map.entrySet().iterator(); return it.hasNext() ? it.next() : null; } + + /** + * Implements Pattern.compile(String) + * + * ART always assumes UNICODE_CHARACTER_CLASS is set. + */ + public static Pattern compilePattern(String regex) { + return Pattern.compile(regex, Pattern.UNICODE_CHARACTER_CLASS); + } + + /** + * Implements Pattern.compile(String, int) + * + * ART always assumes UNICODE_CHARACTER_CLASS is set. + */ + public static Pattern compilePattern(String regex, int flag) { + return Pattern.compile(regex, flag | Pattern.UNICODE_CHARACTER_CLASS); + } } diff --git a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java index acbcdf1926dbd..0d82a8691881c 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java +++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java @@ -66,6 +66,8 @@ public class RavenwoodRuntimeNative { public static native int gettid(); + public static native String getIcuDataName(); + public static long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException { return nLseek(JvmWorkaround.getInstance().getFdInt(fd), offset, whence); } diff --git a/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/CloseGuard.java b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/CloseGuard.java new file mode 100644 index 0000000000000..82bab64f22f38 --- /dev/null +++ b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/CloseGuard.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2010 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 dalvik.system; + +/** + * A no-op copy of libcore/dalvik/src/main/java/dalvik/system/CloseGuard.java + */ +public final class CloseGuard { + + /** + * Returns a CloseGuard instance. {@code #open(String)} can be used to set + * up the instance to warn on failure to close. + * + * @return {@link CloseGuard} instance. + * + * @hide + */ + public static CloseGuard get() { + return new CloseGuard(); + } + + /** + * Enables/disables stack capture and tracking. A call stack is captured + * during open(), and open/close events are reported to the Tracker, only + * if enabled is true. If a stack trace was captured, the {@link + * #getReporter() reporter} is informed of unclosed resources; otherwise a + * one-line warning is logged. + * + * @param enabled whether stack capture and tracking is enabled. + * + * @hide + */ + public static void setEnabled(boolean enabled) { + } + + /** + * True if CloseGuard stack capture and tracking are enabled. + * + * @hide + */ + public static boolean isEnabled() { + return false; + } + + /** + * Used to replace default Reporter used to warn of CloseGuard + * violations when stack tracking is enabled. Must be non-null. + * + * @param rep replacement for default Reporter. + * + * @hide + */ + public static void setReporter(Reporter rep) { + if (rep == null) { + throw new NullPointerException("reporter == null"); + } + } + + /** + * Returns non-null CloseGuard.Reporter. + * + * @return CloseGuard's Reporter. + * + * @hide + */ + public static Reporter getReporter() { + return null; + } + + /** + * Sets the {@link Tracker} that is notified when resources are allocated and released. + * The Tracker is invoked only if CloseGuard {@link #isEnabled()} held when {@link #open()} + * was called. A null argument disables tracking. + * + *

This is only intended for use by {@code dalvik.system.CloseGuardSupport} class and so + * MUST NOT be used for any other purposes. + * + * @hide + */ + public static void setTracker(Tracker tracker) { + } + + /** + * Returns {@link #setTracker(Tracker) last Tracker that was set}, or null to indicate + * there is none. + * + *

This is only intended for use by {@code dalvik.system.CloseGuardSupport} class and so + * MUST NOT be used for any other purposes. + * + * @hide + */ + public static Tracker getTracker() { + return null; + } + + private CloseGuard() {} + + /** + * {@code open} initializes the instance with a warning that the caller + * should have explicitly called the {@code closer} method instead of + * relying on finalization. + * + * @param closer non-null name of explicit termination method. Printed by warnIfOpen. + * @throws NullPointerException if closer is null. + * + * @hide + */ + public void open(String closer) { + openWithCallSite(closer, null /* callsite */); + } + + /** + * Like {@link #open(String)}, but with explicit callsite string being passed in for better + * performance. + *

+ * This only has better performance than {@link #open(String)} if {@link #isEnabled()} returns {@code true}, which + * usually shouldn't happen on release builds. + * + * @param closer Non-null name of explicit termination method. Printed by warnIfOpen. + * @param callsite Non-null string uniquely identifying the callsite. + * + * @hide + */ + public void openWithCallSite(String closer, String callsite) { + } + + // We keep either an allocation stack containing the closer String or, when + // in disabled state, just the closer String. + // We keep them in a single field only to minimize overhead. + private Object /* String or Throwable */ closerNameOrAllocationInfo; + + /** + * Marks this CloseGuard instance as closed to avoid warnings on + * finalization. + * + * @hide + */ + public void close() { + } + + /** + * Logs a warning if the caller did not properly cleanup by calling an + * explicit close method before finalization. If CloseGuard was enabled + * when the CloseGuard was created, passes the stacktrace associated with + * the allocation to the current reporter. If it was not enabled, it just + * directly logs a brief message. + * + * @hide + */ + public void warnIfOpen() { + } + + + /** + * Interface to allow customization of tracking behaviour. + * + *

This is only intended for use by {@code dalvik.system.CloseGuardSupport} class and so + * MUST NOT be used for any other purposes. + * + * @hide + */ + public interface Tracker { + void open(Throwable allocationSite); + void close(Throwable allocationSite); + } + + /** + * Interface to allow customization of reporting behavior. + * @hide + */ + public interface Reporter { + /** + * + * @hide + */ + void report(String message, Throwable allocationSite); + + /** + * + * @hide + */ + default void report(String message) {} + } +} diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoBridge.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoBridge.java new file mode 100644 index 0000000000000..2a1ee2542982c --- /dev/null +++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoBridge.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 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 libcore.io; + +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; + +import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class IoBridge { + + public static void closeAndSignalBlockedThreads(FileDescriptor fd) throws IOException { + if (fd == null) { + return; + } + try { + Os.close(fd); + } catch (ErrnoException errnoException) { + throw errnoException.rethrowAsIOException(); + } + } + + public static FileDescriptor open(String path, int flags) throws FileNotFoundException { + FileDescriptor fd = null; + try { + fd = Os.open(path, flags, 0666); + // Posix open(2) fails with EISDIR only if you ask for write permission. + // Java disallows reading directories too.f + if (OsConstants.S_ISDIR(Os.fstat(fd).st_mode)) { + throw new ErrnoException("open", OsConstants.EISDIR); + } + return fd; + } catch (ErrnoException errnoException) { + try { + if (fd != null) { + closeAndSignalBlockedThreads(fd); + } + } catch (IOException ignored) { + } + FileNotFoundException ex = new FileNotFoundException(path + ": " + + errnoException.getMessage()); + ex.initCause(errnoException); + throw ex; + } + } +} diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java index ad86135de32ef..cf1a5138cbc65 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java +++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java @@ -35,6 +35,11 @@ public class NativeAllocationRegistry { return new NativeAllocationRegistry(classLoader, freeFunction, size); } + public static NativeAllocationRegistry createNonmalloced( + Class clazz, long freeFunction, long size) { + return new NativeAllocationRegistry(clazz.getClassLoader(), freeFunction, size); + } + public static NativeAllocationRegistry createMalloced( ClassLoader classLoader, long freeFunction, long size) { return new NativeAllocationRegistry(classLoader, freeFunction, size); @@ -45,6 +50,11 @@ public class NativeAllocationRegistry { return new NativeAllocationRegistry(classLoader, freeFunction, 0); } + public static NativeAllocationRegistry createMalloced( + Class clazz, long freeFunction, long size) { + return new NativeAllocationRegistry(clazz.getClassLoader(), freeFunction, size); + } + public NativeAllocationRegistry(ClassLoader classLoader, long freeFunction, long size) { if (size < 0) { throw new IllegalArgumentException("Invalid native allocation size: " + size); @@ -52,6 +62,37 @@ public class NativeAllocationRegistry { mFreeFunction = freeFunction; } + private class CleanerThunk implements Runnable { + private long nativePtr; + + public CleanerThunk() { + nativePtr = 0; + } + + public void setNativePtr(long ptr) { + nativePtr = ptr; + } + + @Override + public void run() { + if (nativePtr != 0) { + applyFreeFunction(mFreeFunction, nativePtr); + } + } + } + + private static class CleanableRunner implements Runnable { + private final Cleaner.Cleanable mCleanable; + + public CleanableRunner(Cleaner.Cleanable cleanable) { + mCleanable = cleanable; + } + + public void run() { + mCleanable.clean(); + } + } + public Runnable registerNativeAllocation(Object referent, long nativePtr) { if (referent == null) { throw new IllegalArgumentException("referent is null"); @@ -60,13 +101,25 @@ public class NativeAllocationRegistry { throw new IllegalArgumentException("nativePtr is null"); } - final Runnable releaser = () -> { - RavenwoodRuntimeNative.applyFreeFunction(mFreeFunction, nativePtr); - }; - sCleaner.register(referent, releaser); + final CleanerThunk thunk; + final CleanableRunner result; + try { + thunk = new CleanerThunk(); + final var cleanable = sCleaner.register(referent, thunk); + result = new CleanableRunner(cleanable); + } catch (VirtualMachineError vme /* probably OutOfMemoryError */) { + applyFreeFunction(mFreeFunction, nativePtr); + throw vme; + } + // Enable the cleaner only after we can no longer throw anything, including OOME. + thunk.setNativePtr(nativePtr); // Ensure that cleaner doesn't get invoked before we enable it. Reference.reachabilityFence(referent); - return releaser; + return result; + } + + public static void applyFreeFunction(long freeFunction, long nativePtr) { + RavenwoodRuntimeNative.applyFreeFunction(freeFunction, nativePtr); } } diff --git a/ravenwood/runtime-jni/ravenwood_runtime.cpp b/ravenwood/runtime-jni/ravenwood_runtime.cpp index 8d8ed7119e848..01ebdc9535390 100644 --- a/ravenwood/runtime-jni/ravenwood_runtime.cpp +++ b/ravenwood/runtime-jni/ravenwood_runtime.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -183,6 +184,10 @@ static jint Linux_gettid(JNIEnv* env, jobject) { return syscall(__NR_gettid); } +static jstring getIcuDataName(JNIEnv* env, jclass clazz) { + return env->NewStringUTF(U_ICUDATA_NAME); +} + // ---- Registration ---- extern void register_android_system_OsConstants(JNIEnv* env); @@ -201,6 +206,7 @@ static const JNINativeMethod sMethods[] = { "setenv", "(Ljava/lang/String;Ljava/lang/String;Z)V", (void*)Linux_setenv }, { "getpid", "()I", (void*)Linux_getpid }, { "gettid", "()I", (void*)Linux_gettid }, + { "getIcuDataName", "()Ljava/lang/String;", (void*)getIcuDataName }, }; extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt index e202d0ecfa232..7462cc2f384a1 100644 --- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt +++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt @@ -259,6 +259,8 @@ android.database.sqlite.SQLiteClosable android.database.sqlite.SQLiteException android.text.TextUtils +android.text.Html +android.text.HtmlToSpannedConverter android.accounts.Account @@ -278,6 +280,10 @@ android.graphics.PointF android.graphics.Rect android.graphics.RectF +android.graphics.fonts.SystemFonts + +android.graphics.text.LineBreakConfig + android.content.ContentProvider android.app.ActivityManager @@ -383,3 +389,228 @@ android.app.compat.* com.android.server.compat.* com.android.internal.compat.* android.app.AppCompatCallbacks +android.graphics.AvoidXfermode +android.graphics.BLASTBufferQueue +android.graphics.BaseCanvas +android.graphics.BaseRecordingCanvas +android.graphics.Bitmap +android.graphics.BitmapFactory +android.graphics.BitmapRegionDecoder +android.graphics.BitmapShader +android.graphics.BlendMode +android.graphics.BlendModeColorFilter +android.graphics.BlurMaskFilter +android.graphics.Camera +android.graphics.Canvas +android.graphics.CanvasProperty +android.graphics.ColorFilter +android.graphics.ColorMatrix +android.graphics.ColorMatrixColorFilter +android.graphics.Compatibility +android.graphics.ComposePathEffect +android.graphics.ComposeShader +android.graphics.CornerPathEffect +android.graphics.DashPathEffect +android.graphics.DiscretePathEffect +android.graphics.DrawFilter +android.graphics.EmbossMaskFilter +android.graphics.FontFamily +android.graphics.FontListParser +android.graphics.ForceDarkType +android.graphics.FrameInfo +android.graphics.Gainmap +android.graphics.GraphicBuffer +android.graphics.GraphicsProtos +android.graphics.GraphicsStatsService +android.graphics.HardwareBufferRenderer +android.graphics.HardwareRenderer +android.graphics.HardwareRendererObserver +android.graphics.ImageDecoder +android.graphics.ImageFormat +android.graphics.LayerRasterizer +android.graphics.LeakyTypefaceStorage +android.graphics.LightingColorFilter +android.graphics.LinearGradient +android.graphics.MaskFilter +android.graphics.Mesh +android.graphics.MeshSpecification +android.graphics.Movie +android.graphics.NinePatch +android.graphics.Paint +android.graphics.PaintFlagsDrawFilter +android.graphics.PathDashPathEffect +android.graphics.PathEffect +android.graphics.PathIterator +android.graphics.PathMeasure +android.graphics.Picture +android.graphics.PixelXorXfermode +android.graphics.PorterDuff +android.graphics.PorterDuffColorFilter +android.graphics.PorterDuffXfermode +android.graphics.PostProcessor +android.graphics.RadialGradient +android.graphics.Rasterizer +android.graphics.RecordingCanvas +android.graphics.Region +android.graphics.RegionIterator +android.graphics.RenderEffect +android.graphics.RenderNode +android.graphics.RuntimeColorFilter +android.graphics.RuntimeShader +android.graphics.RuntimeXfermode +android.graphics.Shader +android.graphics.SumPathEffect +android.graphics.SurfaceTexture +android.graphics.SweepGradient +android.graphics.TableMaskFilter +android.graphics.TemporaryBuffer +android.graphics.TextureLayer +android.graphics.Typeface +android.graphics.Xfermode +android.graphics.YuvImage +android.graphics.fonts.Font +android.graphics.fonts.FontCustomizationParser +android.graphics.fonts.FontFamily +android.graphics.fonts.FontFamilyUpdateRequest +android.graphics.fonts.FontFileUpdateRequest +android.graphics.fonts.FontFileUtil +android.graphics.fonts.FontStyle +android.graphics.fonts.FontVariationAxis +android.graphics.text.GraphemeBreak +android.graphics.text.LineBreaker +android.graphics.text.MeasuredText +android.graphics.text.PositionedGlyphs +android.graphics.text.TextRunShaper +android.text.AlteredCharSequence +android.text.AndroidBidi +android.text.AndroidCharacter +android.text.Annotation +android.text.AutoGrowArray +android.text.AutoText +android.text.BidiFormatter +android.text.BoringLayout +android.text.CharSequenceCharacterIterator +android.text.ClipboardManager +android.text.DynamicLayout +android.text.Editable +android.text.Emoji +android.text.EmojiConsistency +android.text.FontConfig +android.text.GetChars +android.text.GraphemeClusterSegmentFinder +android.text.GraphicsOperations +android.text.Highlights +android.text.Hyphenator +android.text.InputFilter +android.text.InputType +android.text.Layout +android.text.LoginFilter +android.text.MeasuredParagraph +android.text.NoCopySpan +android.text.PackedIntVector +android.text.PackedObjectVector +android.text.ParcelableSpan +android.text.PrecomputedText +android.text.SegmentFinder +android.text.Selection +android.text.SpanColors +android.text.SpanSet +android.text.SpanWatcher +android.text.Spannable +android.text.SpannableString +android.text.SpannableStringBuilder +android.text.SpannableStringInternal +android.text.Spanned +android.text.SpannedString +android.text.StaticLayout +android.text.TextDirectionHeuristic +android.text.TextDirectionHeuristics +android.text.TextLine +android.text.TextPaint +android.text.TextShaper +android.text.TextWatcher +android.text.WordSegmentFinder +android.text.format.DateFormat +android.text.format.DateIntervalFormat +android.text.format.DateTimeFormat +android.text.format.DateUtils +android.text.format.DateUtilsBridge +android.text.format.Formatter +android.text.format.RelativeDateTimeFormatter +android.text.format.Time +android.text.format.TimeFormatter +android.text.format.TimeMigrationUtils +android.text.method.AllCapsTransformationMethod +android.text.method.ArrowKeyMovementMethod +android.text.method.BaseKeyListener +android.text.method.BaseMovementMethod +android.text.method.CharacterPickerDialog +android.text.method.DateKeyListener +android.text.method.DateTimeKeyListener +android.text.method.DialerKeyListener +android.text.method.DigitsKeyListener +android.text.method.HideReturnsTransformationMethod +android.text.method.InsertModeTransformationMethod +android.text.method.KeyListener +android.text.method.LinkMovementMethod +android.text.method.MetaKeyKeyListener +android.text.method.MovementMethod +android.text.method.MultiTapKeyListener +android.text.method.NumberKeyListener +android.text.method.OffsetMapping +android.text.method.PasswordTransformationMethod +android.text.method.QwertyKeyListener +android.text.method.ReplacementTransformationMethod +android.text.method.ScrollingMovementMethod +android.text.method.SingleLineTransformationMethod +android.text.method.TextKeyListener +android.text.method.TimeKeyListener +android.text.method.Touch +android.text.method.TransformationMethod +android.text.method.TransformationMethod2 +android.text.method.TranslationTransformationMethod +android.text.method.WordIterator +android.text.style.AbsoluteSizeSpan +android.text.style.AccessibilityClickableSpan +android.text.style.AccessibilityReplacementSpan +android.text.style.AccessibilityURLSpan +android.text.style.AlignmentSpan +android.text.style.BackgroundColorSpan +android.text.style.BulletSpan +android.text.style.CharacterStyle +android.text.style.ClickableSpan +android.text.style.ForegroundColorSpan +android.text.style.IconMarginSpan +android.text.style.LeadingMarginSpan +android.text.style.LineBackgroundSpan +android.text.style.LineBreakConfigSpan +android.text.style.LineHeightSpan +android.text.style.LocaleSpan +android.text.style.MaskFilterSpan +android.text.style.MetricAffectingSpan +android.text.style.NoWritingToolsSpan +android.text.style.ParagraphStyle +android.text.style.QuoteSpan +android.text.style.RasterizerSpan +android.text.style.RelativeSizeSpan +android.text.style.ReplacementSpan +android.text.style.ScaleXSpan +android.text.style.SpanUtils +android.text.style.SpellCheckSpan +android.text.style.StrikethroughSpan +android.text.style.StyleSpan +android.text.style.SubscriptSpan +android.text.style.SuggestionRangeSpan +android.text.style.SuggestionSpan +android.text.style.SuperscriptSpan +android.text.style.TabStopSpan +android.text.style.TextAppearanceSpan +android.text.style.TtsSpan +android.text.style.TypefaceSpan +android.text.style.URLSpan +android.text.style.UnderlineSpan +android.text.style.UpdateAppearance +android.text.style.UpdateLayout +android.text.style.WrapTogetherSpan +android.text.util.Rfc822Token +android.text.util.Rfc822Tokenizer diff --git a/ravenwood/texts/ravenwood-build.prop b/ravenwood/texts/ravenwood-build.prop index 7cc4454a6e567..37c50f11f73f9 100644 --- a/ravenwood/texts/ravenwood-build.prop +++ b/ravenwood/texts/ravenwood-build.prop @@ -8,7 +8,11 @@ ro.soc.manufacturer=Android ro.soc.model=Ravenwood ro.debuggable=1 -# The ones starting with "ro.product" or "ro.bild" will be copied to all "partitions" too. +# For the graphics stack +ro.hwui.max_texture_allocation_size=104857600 +persist.sys.locale=en-US + +# The ones starting with "ro.product" or "ro.build" will be copied to all "partitions" too. # See RavenwoodSystemProperties. ro.product.brand=Android ro.product.device=Ravenwood diff --git a/ravenwood/texts/ravenwood-common-policies.txt b/ravenwood/texts/ravenwood-common-policies.txt index fd4ea6cf40c2f..f0f4b8580f7df 100644 --- a/ravenwood/texts/ravenwood-common-policies.txt +++ b/ravenwood/texts/ravenwood-common-policies.txt @@ -21,3 +21,7 @@ class java.io.FileDescriptor # no-pta method setInt$ @com.android.ravenwood.RavenwoodJdkPatch.setInt$ class java.util.LinkedHashMap # no-pta method eldest @com.android.ravenwood.RavenwoodJdkPatch.eldest + +# Always set flag UNICODE_CHARACTER_CLASS when compiling regex +class java.util.regex.Pattern keep + method compile @com.android.ravenwood.RavenwoodJdkPatch.compilePattern diff --git a/ravenwood/texts/ravenwood-framework-policies.txt b/ravenwood/texts/ravenwood-framework-policies.txt index fff9e6ad41d5b..0695316543aec 100644 --- a/ravenwood/texts/ravenwood-framework-policies.txt +++ b/ravenwood/texts/ravenwood-framework-policies.txt @@ -63,3 +63,22 @@ class android.text.ClipboardManager keep # no-pta # Just enough to allow ResourcesManager to run class android.hardware.display.DisplayManagerGlobal keep # no-pta method getInstance ()Landroid/hardware/display/DisplayManagerGlobal; ignore # no-pta + +# Bare minimum to support running ImageDecoderTest +class android.graphics.drawable.Drawable$ConstantState keepclass # no-pta +class android.graphics.drawable.BitmapDrawable$BitmapState keepclass # no-pta +class android.graphics.drawable.BitmapDrawable keep # no-pta + method (Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V keep + method init * keep + method updateLocalState * keep + method computeBitmapSize * keep + method getIntrinsicWidth * keep + method getIntrinsicHeight * keep + method getBitmap * keep +class android.graphics.drawable.Drawable keep # no-pta + method ()V keep + method resolveDensity * keep + method updateBlendModeFilter * ignore + +class android.os.StrictMode keep # no-pta + method noteSlowCall (Ljava/lang/String;)V ignore -- GitLab From 6a91d1399e1185f7eb9c31c6aca498b31bf916e7 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 18 Feb 2025 13:12:48 -0800 Subject: [PATCH 006/111] Cleaned up the flag enforce_telephony_feature_mapping Cleaned up the 24Q3 flag enforce_telephony_feature_mapping Test: Basic telephony functionality tests Test: atest EuiccProfileInfoTest Bug: 297989574 Flag: EXEMPT flag cleanup Change-Id: I16f344dcfc8bd588e56b2a20b792dd5039f2375d --- .../injector/SystemEmergencyHelper.java | 32 +++++++---------- .../soundtrigger/PhoneCallStateHandler.java | 35 +++++++------------ 2 files changed, 24 insertions(+), 43 deletions(-) diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java index 177eefb2ef2a3..3f75b11befc23 100644 --- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java +++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java @@ -29,7 +29,6 @@ import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.flags.Flags; import com.android.server.FgThread; import java.util.Objects; @@ -107,26 +106,19 @@ public class SystemEmergencyHelper extends EmergencyHelper { boolean isInExtensionTime = mEmergencyCallEndRealtimeMs != Long.MIN_VALUE && (SystemClock.elapsedRealtime() - mEmergencyCallEndRealtimeMs) < extensionTimeMs; - if (!Flags.enforceTelephonyFeatureMapping()) { - return mIsInEmergencyCall - || isInExtensionTime - || mTelephonyManager.getEmergencyCallbackMode() - || mTelephonyManager.isInEmergencySmsMode(); - } else { - boolean emergencyCallbackMode = false; - boolean emergencySmsMode = false; - PackageManager pm = mContext.getPackageManager(); - if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CALLING)) { - emergencyCallbackMode = mTelephonyManager.getEmergencyCallbackMode(); - } - if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)) { - emergencySmsMode = mTelephonyManager.isInEmergencySmsMode(); - } - return mIsInEmergencyCall - || isInExtensionTime - || emergencyCallbackMode - || emergencySmsMode; + boolean emergencyCallbackMode = false; + boolean emergencySmsMode = false; + PackageManager pm = mContext.getPackageManager(); + if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CALLING)) { + emergencyCallbackMode = mTelephonyManager.getEmergencyCallbackMode(); + } + if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)) { + emergencySmsMode = mTelephonyManager.isInEmergencySmsMode(); } + return mIsInEmergencyCall + || isInExtensionTime + || emergencyCallbackMode + || emergencySmsMode; } private class EmergencyCallTelephonyCallback extends TelephonyCallback implements diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java index 49ad46131b0dd..df43ed973fe7b 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java @@ -24,7 +24,6 @@ import android.telephony.TelephonyManager; import android.util.Slog; import com.android.internal.annotations.GuardedBy; -import com.android.internal.telephony.flags.Flags; import java.util.ArrayList; import java.util.List; @@ -119,28 +118,18 @@ public class PhoneCallStateHandler { private boolean checkCallStatus() { List infoList = mSubscriptionManager.getActiveSubscriptionInfoList(); if (infoList == null) return false; - if (!Flags.enforceTelephonyFeatureMapping()) { - return infoList.stream() - .filter(s -> (s.getSubscriptionId() - != SubscriptionManager.INVALID_SUBSCRIPTION_ID)) - .anyMatch(s -> isCallOngoingFromState( - mTelephonyManager - .createForSubscriptionId(s.getSubscriptionId()) - .getCallStateForSubscription())); - } else { - return infoList.stream() - .filter(s -> (s.getSubscriptionId() - != SubscriptionManager.INVALID_SUBSCRIPTION_ID)) - .anyMatch(s -> { - try { - return isCallOngoingFromState(mTelephonyManager - .createForSubscriptionId(s.getSubscriptionId()) - .getCallStateForSubscription()); - } catch (UnsupportedOperationException e) { - return false; - } - }); - } + return infoList.stream() + .filter(s -> (s.getSubscriptionId() + != SubscriptionManager.INVALID_SUBSCRIPTION_ID)) + .anyMatch(s -> { + try { + return isCallOngoingFromState(mTelephonyManager + .createForSubscriptionId(s.getSubscriptionId()) + .getCallStateForSubscription()); + } catch (UnsupportedOperationException e) { + return false; + } + }); } private void updateTelephonyListeners() { -- GitLab From 30bb277163fd24de3fab6fd9a3566a25c57f1a0e Mon Sep 17 00:00:00 2001 From: Owner Cleanup Bot Date: Tue, 18 Feb 2025 15:13:24 -0800 Subject: [PATCH 007/111] [owners] Remove mns@google.com from core/java/android/view/textclassifier/intent/OWNERS This suggested change is automatically generated based on group memberships and affiliations. Please approve this change and vote the highest CR. This will keep the OWNERs file tidy. We ask that you do not ignore this change and approve it unless you know a reason the OWNER should remain. It can always be reverted if needed. If this change is in error, vote the lowest CR value (i.e. reject the CL) and the bot will abandon it. See the owner's recent review activity for context: https://android-review.googlesource.com/q/mns@google.com To report an issue, file a bug in the Infra>Codereview component. Change-Id: Ide39736558874e4ef86ae0bbcc009366dfac880c --- core/java/android/view/textclassifier/intent/OWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/view/textclassifier/intent/OWNERS b/core/java/android/view/textclassifier/intent/OWNERS index 3465fe62784f1..dc18514ce949c 100644 --- a/core/java/android/view/textclassifier/intent/OWNERS +++ b/core/java/android/view/textclassifier/intent/OWNERS @@ -1,6 +1,5 @@ # Bug component: 709498 -mns@google.com toki@google.com svetoslavganov@android.com svetoslavganov@google.com -- GitLab From 8472ff33822e51858708ef781bedcddb25276e17 Mon Sep 17 00:00:00 2001 From: Owner Cleanup Bot Date: Tue, 18 Feb 2025 15:13:41 -0800 Subject: [PATCH 008/111] [owners] Remove bonianchen@google.com from packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS This suggested change is automatically generated based on group memberships and affiliations. Please approve this change and vote the highest CR. This will keep the OWNERs file tidy. We ask that you do not ignore this change and approve it unless you know a reason the OWNER should remain. It can always be reverted if needed. If this change is in error, vote the lowest CR value (i.e. reject the CL) and the bot will abandon it. See the owner's recent review activity for context: https://android-review.googlesource.com/q/bonianchen@google.com To report an issue, file a bug in the Infra>Codereview component. Change-Id: Id2e1d6ae355220f21afd1c3129f37cd5ae0a4f61 --- packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS b/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS index 372eb81fdee28..921ffedb337c2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS +++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS @@ -1,5 +1,4 @@ # Default reviewers for this and subdirectories. -bonianchen@google.com changbetty@google.com wengsu@google.com zoeychen@google.com -- GitLab From 5a3fde5c6fedca6f5803ab751ef7273a3bf46fe3 Mon Sep 17 00:00:00 2001 From: Anton Potapov Date: Wed, 5 Feb 2025 14:56:19 +0000 Subject: [PATCH 009/111] Migrate Volume Dialog UI events to the new infra Flag: com.android.systemui.volume_redesign Bug: 369993959 Test: manual on the phone Change-Id: Id1ea268377b72fa9eb34d76995e922dd9963b2db --- .../com/android/systemui/volume/Events.java | 14 ++--- .../VolumeDialogRingerDrawerViewModel.kt | 14 +++++ .../VolumeDialogSettingsButtonViewModel.kt | 4 ++ .../ui/VolumeDialogSliderViewBinder.kt | 13 +++- .../viewmodel/VolumeDialogSliderViewModel.kt | 23 ++++++- .../volume/dialog/ui/VolumeDialogUiEvent.kt | 60 +++++++++++++++++++ .../viewmodel/VolumeDialogPluginViewModel.kt | 33 +++++++++- ...VolumeDialogRingerDrawerViewModelKosmos.kt | 2 + ...lumeDialogSettingsButtonViewModelKosmos.kt | 2 + .../VolumeDialogSliderViewModelKosmos.kt | 2 + 10 files changed, 154 insertions(+), 13 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/volume/dialog/ui/VolumeDialogUiEvent.kt diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java index e10d1cb833fac..b8eb5189408e2 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/Events.java +++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java @@ -37,16 +37,16 @@ import java.util.Arrays; public class Events { private static final String TAG = Util.logTag(Events.class); - public static final int EVENT_SHOW_DIALOG = 0; // (reason|int) (keyguard|bool) - public static final int EVENT_DISMISS_DIALOG = 1; // (reason|int) + @Deprecated public static final int EVENT_SHOW_DIALOG = 0; // (reason|int) (keyguard|bool) + @Deprecated public static final int EVENT_DISMISS_DIALOG = 1; // (reason|int) public static final int EVENT_ACTIVE_STREAM_CHANGED = 2; // (stream|int) public static final int EVENT_EXPAND = 3; // (expand|bool) public static final int EVENT_KEY = 4; // (stream|int) (lastAudibleStreamVolume) public static final int EVENT_COLLECTION_STARTED = 5; public static final int EVENT_COLLECTION_STOPPED = 6; - public static final int EVENT_ICON_CLICK = 7; // (stream|int) (icon_state|int) - public static final int EVENT_SETTINGS_CLICK = 8; - public static final int EVENT_TOUCH_LEVEL_CHANGED = 9; // (stream|int) (level|int) + @Deprecated public static final int EVENT_ICON_CLICK = 7; // (stream|int) (icon_state|int) + @Deprecated public static final int EVENT_SETTINGS_CLICK = 8; + @Deprecated public static final int EVENT_TOUCH_LEVEL_CHANGED = 9; // (stream|int) (level|int) public static final int EVENT_LEVEL_CHANGED = 10; // (stream|int) (level|int) public static final int EVENT_INTERNAL_RINGER_MODE_CHANGED = 11; // (mode|int) public static final int EVENT_EXTERNAL_RINGER_MODE_CHANGED = 12; // (mode|int) @@ -55,12 +55,12 @@ public class Events { public static final int EVENT_MUTE_CHANGED = 15; // (stream|int) (muted|bool) public static final int EVENT_TOUCH_LEVEL_DONE = 16; // (stream|int) (level|int) public static final int EVENT_ZEN_CONFIG_CHANGED = 17; // (allow/disallow|string) - public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode) + @Deprecated public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode) public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool) public static final int EVENT_DISMISS_USB_OVERHEAT_ALARM = 20; // (reason|int) (keyguard|bool) public static final int EVENT_ODI_CAPTIONS_CLICK = 21; public static final int EVENT_ODI_CAPTIONS_TOOLTIP_CLICK = 22; - public static final int EVENT_SLIDER_TOUCH_TRACKING = 23; // (tracking|bool) + @Deprecated public static final int EVENT_SLIDER_TOUCH_TRACKING = 23; // (tracking|bool) private static final String[] EVENT_TAGS = { "show_dialog", diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt index b0d6d62289c7c..69a939ae078e0 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt @@ -25,6 +25,7 @@ import android.media.AudioManager.STREAM_RING import android.os.VibrationEffect import android.widget.Toast import com.android.internal.R as internalR +import com.android.internal.logging.UiEventLogger import com.android.settingslib.Utils import com.android.settingslib.notification.domain.interactor.NotificationsSoundPolicyInteractor import com.android.settingslib.volume.shared.model.AudioStream @@ -43,6 +44,7 @@ import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibili import com.android.systemui.volume.dialog.ringer.domain.VolumeDialogRingerInteractor import com.android.systemui.volume.dialog.ringer.shared.model.VolumeDialogRingerModel import com.android.systemui.volume.dialog.shared.VolumeDialogLogger +import com.android.systemui.volume.dialog.ui.VolumeDialogUiEvent import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope @@ -73,6 +75,7 @@ constructor( private val volumeDialogLogger: VolumeDialogLogger, private val visibilityInteractor: VolumeDialogVisibilityInteractor, configurationController: ConfigurationController, + private val uiEventLogger: UiEventLogger, private val systemClock: SystemClock, ) { @@ -112,6 +115,7 @@ constructor( .build() private var lastClickTime = 0L + init { ringerViewModel .onEach { viewModelState -> @@ -137,6 +141,7 @@ constructor( provideTouchFeedback(ringerMode) maybeShowToast(ringerMode) ringerInteractor.setRingerMode(ringerMode) + ringerMode.toVolumeDialogUiEvent()?.let(uiEventLogger::log) } visibilityInteractor.resetDismissTimeout() drawerState.value = @@ -312,3 +317,12 @@ constructor( } } } + +private fun RingerMode.toVolumeDialogUiEvent(): VolumeDialogUiEvent? { + return when (value) { + RINGER_MODE_NORMAL -> VolumeDialogUiEvent.RINGER_MODE_NORMAL + RINGER_MODE_VIBRATE -> VolumeDialogUiEvent.RINGER_MODE_VIBRATE + RINGER_MODE_SILENT -> VolumeDialogUiEvent.RINGER_MODE_SILENT + else -> null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt index 0e4e707df923a..94c66cccbc592 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt @@ -32,12 +32,14 @@ import com.airbnb.lottie.SimpleColorFilter import com.airbnb.lottie.model.KeyPath import com.airbnb.lottie.value.LottieValueCallback import com.android.internal.R as internalR +import com.android.internal.logging.UiEventLogger import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.UiBackground import com.android.systemui.lottie.await import com.android.systemui.res.R import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog import com.android.systemui.volume.dialog.settings.domain.VolumeDialogSettingsButtonInteractor +import com.android.systemui.volume.dialog.ui.VolumeDialogUiEvent import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor import com.android.systemui.volume.panel.shared.model.filterData @@ -71,6 +73,7 @@ constructor( mediaOutputInteractor: MediaOutputInteractor, private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor, private val interactor: VolumeDialogSettingsButtonInteractor, + private val uiEventLogger: UiEventLogger, ) { @SuppressLint("UseCompatLoadingForDrawables") @@ -160,6 +163,7 @@ constructor( fun onButtonClicked() { interactor.onButtonClicked() + uiEventLogger.log(VolumeDialogUiEvent.VOLUME_DIALOG_SETTINGS_CLICK) } private data class PlaybackStates(val isPreviousActive: Boolean?, val isCurrentActive: Boolean) diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt index 2c9ee54878e55..17387e76aa159 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt @@ -23,6 +23,7 @@ import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.interaction.DragInteraction import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.padding @@ -59,7 +60,6 @@ import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSlide import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigsProvider import javax.inject.Inject import kotlin.math.round -import kotlin.math.roundToInt import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.isActive @@ -138,7 +138,7 @@ private fun VolumeDialogSlider( ) .also { sliderState -> sliderState.onValueChangeFinished = { - viewModel.onStreamChangeFinished(sliderState.value.roundToInt()) + viewModel.onSliderChangeFinished(sliderState.value) hapticsViewModel?.onValueChangeEnded() } sliderState.onValueChange = { newValue -> @@ -163,6 +163,15 @@ private fun VolumeDialogSlider( hapticsViewModel?.onValueChange(value) } } + LaunchedEffect(interactionSource) { + interactionSource.interactions.collect { + when (it) { + is DragInteraction.Start -> viewModel.onSliderDragStarted() + is DragInteraction.Cancel -> viewModel.onSliderDragFinished() + is DragInteraction.Stop -> viewModel.onSliderDragFinished() + } + } + } VerticalSlider( state = sliderState, diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt index 9ac052af95d9c..19b2880b9496d 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt @@ -19,6 +19,7 @@ package com.android.systemui.volume.dialog.sliders.ui.viewmodel import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.pointer.PointerEvent import androidx.compose.ui.input.pointer.PointerEventType +import com.android.internal.logging.UiEventLogger import com.android.systemui.util.time.SystemClock import com.android.systemui.volume.Events import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog @@ -30,6 +31,7 @@ import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialog import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInteractor import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType import com.android.systemui.volume.dialog.sliders.shared.model.SliderInputEvent +import com.android.systemui.volume.dialog.ui.VolumeDialogUiEvent import javax.inject.Inject import kotlin.math.roundToInt import kotlinx.coroutines.CoroutineScope @@ -69,6 +71,7 @@ constructor( private val inputEventsInteractor: VolumeDialogSliderInputEventsInteractor, private val systemClock: SystemClock, private val logger: VolumeDialogLogger, + private val uiEventLogger: UiEventLogger, ) { private val userVolumeUpdates = MutableStateFlow(null) @@ -99,9 +102,11 @@ constructor( isMuted = isMuted, isRoutedToBluetooth = routedToBluetooth, ) + is VolumeDialogSliderType.RemoteMediaStream -> { volumeDialogSliderIconProvider.getCastIcon(isMuted) } + is VolumeDialogSliderType.AudioSharingStream -> { volumeDialogSliderIconProvider.getAudioSharingIcon(isMuted) } @@ -135,8 +140,19 @@ constructor( } } - fun onStreamChangeFinished(volume: Int) { - logger.onVolumeSliderAdjustmentFinished(volume = volume, stream = sliderType.audioStream) + fun onSliderDragStarted() { + uiEventLogger.log(VolumeDialogUiEvent.VOLUME_DIALOG_SLIDER_STARTED_TRACKING_TOUCH) + } + + fun onSliderDragFinished() { + uiEventLogger.log(VolumeDialogUiEvent.VOLUME_DIALOG_SLIDER_STOPPED_TRACKING_TOUCH) + } + + fun onSliderChangeFinished(volume: Float) { + logger.onVolumeSliderAdjustmentFinished( + volume = volume.roundToInt(), + stream = sliderType.audioStream, + ) } fun onTouchEvent(pointerEvent: PointerEvent) { @@ -146,14 +162,17 @@ constructor( inputEventsInteractor.onTouchEvent( SliderInputEvent.Touch.Start(position.x, position.y) ) + PointerEventType.Move -> inputEventsInteractor.onTouchEvent( SliderInputEvent.Touch.Move(position.x, position.y) ) + PointerEventType.Scroll -> inputEventsInteractor.onTouchEvent( SliderInputEvent.Touch.Move(position.x, position.y) ) + PointerEventType.Release -> inputEventsInteractor.onTouchEvent( SliderInputEvent.Touch.End(position.x, position.y) diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/VolumeDialogUiEvent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/VolumeDialogUiEvent.kt new file mode 100644 index 0000000000000..cf1b69ed6cba9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/VolumeDialogUiEvent.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2025 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.volume.dialog.ui + +import com.android.internal.logging.UiEvent +import com.android.internal.logging.UiEventLogger + +/** UI events for Volume Dialog. */ +enum class VolumeDialogUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum { + @UiEvent(doc = "The ringer mode was toggled to silent") RINGER_MODE_SILENT(154), + @UiEvent(doc = "The ringer mode was toggled to vibrate") RINGER_MODE_VIBRATE(155), + @UiEvent(doc = "The ringer mode was toggled to normal") RINGER_MODE_NORMAL(334), + @UiEvent(doc = "The volume dialog settings icon was clicked") VOLUME_DIALOG_SETTINGS_CLICK(143), + @UiEvent(doc = "The volume dialog was shown because the volume changed") + VOLUME_DIALOG_SHOW_VOLUME_CHANGED(128), + @UiEvent(doc = "The volume dialog was shown because the volume changed remotely") + VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED(129), + @UiEvent(doc = "The volume dialog was shown because the usb high temperature alarm changed") + VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED(130), + @UiEvent(doc = "The volume dialog was dismissed because of a touch outside the dialog") + VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE(134), + @UiEvent( + doc = + "The system asked the volume dialog to close, e.g. for a navigation bar " + + "touch, or ActivityManager ACTION_CLOSE_SYSTEM_DIALOGS broadcast." + ) + VOLUME_DIALOG_DISMISS_SYSTEM(135), + @UiEvent(doc = "The volume dialog was dismissed because it timed out") + VOLUME_DIALOG_DISMISS_TIMEOUT(136), + @UiEvent(doc = "The volume dialog was dismissed because the screen turned off") + VOLUME_DIALOG_DISMISS_SCREEN_OFF(137), + @UiEvent(doc = "The volume dialog was dismissed because the settings icon was clicked") + VOLUME_DIALOG_DISMISS_SETTINGS(138), + @UiEvent(doc = "The volume dialog was dismissed because the stream no longer exists") + VOLUME_DIALOG_DISMISS_STREAM_GONE(140), + @UiEvent( + doc = "The volume dialog was dismissed because the usb high temperature alarm " + "changed" + ) + VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED(142), + @UiEvent(doc = "The right-most slider started tracking touch") + VOLUME_DIALOG_SLIDER_STARTED_TRACKING_TOUCH(1620), + @UiEvent(doc = "The right-most slider stopped tracking touch") + VOLUME_DIALOG_SLIDER_STOPPED_TRACKING_TOUCH(1621); + + override fun getId() = metricId +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt index 1765f0111e082..6d16300bf56e3 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt @@ -16,6 +16,7 @@ package com.android.systemui.volume.dialog.ui.viewmodel +import com.android.internal.logging.UiEventLogger import com.android.systemui.volume.Events import com.android.systemui.volume.dialog.VolumeDialog import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin @@ -26,6 +27,7 @@ import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibili import com.android.systemui.volume.dialog.shared.VolumeDialogLogger import com.android.systemui.volume.dialog.shared.model.CsdWarningConfigModel import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel +import com.android.systemui.volume.dialog.ui.VolumeDialogUiEvent import javax.inject.Inject import javax.inject.Provider import kotlinx.coroutines.CoroutineScope @@ -44,6 +46,7 @@ constructor( private val volumeDialogProvider: Provider, private val logger: VolumeDialogLogger, val csdWarningConfigModel: CsdWarningConfigModel, + private val uiEventLogger: UiEventLogger, ) { fun launchVolumeDialog() { @@ -52,11 +55,11 @@ constructor( with(visibilityModel) { if (this is VolumeDialogVisibilityModel.Visible) { showDialog() - Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, keyguardLocked) + toVolumeDialogUiEvent()?.let(uiEventLogger::log) logger.onShow(reason) } if (this is VolumeDialogVisibilityModel.Dismissed) { - Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason) + toVolumeDialogUiEvent()?.let(uiEventLogger::log) logger.onDismiss(reason) } } @@ -86,3 +89,29 @@ constructor( .show() } } + +private fun VolumeDialogVisibilityModel.Dismissed.toVolumeDialogUiEvent(): VolumeDialogUiEvent? { + return when (reason) { + Events.DISMISS_REASON_TOUCH_OUTSIDE -> + VolumeDialogUiEvent.VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE + Events.DISMISS_REASON_VOLUME_CONTROLLER -> VolumeDialogUiEvent.VOLUME_DIALOG_DISMISS_SYSTEM + Events.DISMISS_REASON_TIMEOUT -> VolumeDialogUiEvent.VOLUME_DIALOG_DISMISS_TIMEOUT + Events.DISMISS_REASON_SCREEN_OFF -> VolumeDialogUiEvent.VOLUME_DIALOG_DISMISS_SCREEN_OFF + Events.DISMISS_REASON_SETTINGS_CLICKED -> VolumeDialogUiEvent.VOLUME_DIALOG_DISMISS_SETTINGS + Events.DISMISS_STREAM_GONE -> VolumeDialogUiEvent.VOLUME_DIALOG_DISMISS_STREAM_GONE + Events.DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED -> + VolumeDialogUiEvent.VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED + else -> null + } +} + +private fun VolumeDialogVisibilityModel.Visible.toVolumeDialogUiEvent(): VolumeDialogUiEvent? { + return when (reason) { + Events.SHOW_REASON_VOLUME_CHANGED -> VolumeDialogUiEvent.VOLUME_DIALOG_SHOW_VOLUME_CHANGED + Events.SHOW_REASON_REMOTE_VOLUME_CHANGED -> + VolumeDialogUiEvent.VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED + Events.SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED -> + VolumeDialogUiEvent.VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED + else -> null + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt index 9f3150f7366a0..919d36b3dec17 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.volume.dialog.ringer.ui.viewmodel import android.content.applicationContext +import com.android.internal.logging.uiEventLogger import com.android.systemui.haptics.vibratorHelper import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope @@ -41,6 +42,7 @@ val Kosmos.volumeDialogRingerDrawerViewModel by volumeDialogLogger = volumeDialogLogger, visibilityInteractor = volumeDialogVisibilityInteractor, configurationController = configurationController, + uiEventLogger = uiEventLogger, systemClock = fakeSystemClock, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModelKosmos.kt index 0ae3b037b50a0..a17611b998c09 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModelKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.volume.dialog.settings.ui.viewmodel import android.content.applicationContext +import com.android.internal.logging.uiEventLogger import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testScope @@ -33,5 +34,6 @@ val Kosmos.volumeDialogSettingsButtonViewModel by mediaOutputInteractor, mediaDeviceSessionInteractor, volumeDialogSettingsButtonInteractor, + uiEventLogger, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModelKosmos.kt index 90bbb28ff5197..c9396f5ccde98 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModelKosmos.kt @@ -16,6 +16,7 @@ package com.android.systemui.volume.dialog.sliders.ui.viewmodel +import com.android.internal.logging.uiEventLogger import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.util.time.systemClock @@ -35,6 +36,7 @@ val Kosmos.volumeDialogSliderViewModel by coroutineScope = applicationCoroutineScope, volumeDialogSliderIconProvider = volumeDialogSliderIconProvider, systemClock = systemClock, + uiEventLogger = uiEventLogger, logger = volumeDialogLogger, ) } -- GitLab From 5c6fd9b60ca0aa5314c7009130af587e01766759 Mon Sep 17 00:00:00 2001 From: Gustav Sennton Date: Tue, 4 Feb 2025 17:27:24 +0000 Subject: [PATCH 010/111] Desktop-Minimize: move CUJ handling to MinimizeAnimator - Move CUJ handling for the Desktop window minimize animation from DesktopTasksLimiter to MinimizeAnimator. - Also add ShellAnimationThread Handler to be able to pass such a Handler to InteractionJankMonitor for the minimize-window animation in FreeformTaskTransitionHandler. Flag: NONE jank/logging only change Test: manual (perfetto) Bug: 374206096 Bug: 385051575 Change-Id: Id2bb7fa223ebdafb301c853941282f9c8a533b57 --- .../shell/shared/animation/Interpolators.java | 6 + .../shared/animation/MinimizeAnimator.kt | 50 ++++++-- .../dagger/WMShellConcurrencyModule.java | 29 +++-- .../wm/shell/dagger/WMShellModule.java | 10 +- .../DesktopMinimizationTransitionHandler.kt | 36 +++++- .../shell/desktopmode/DesktopTasksLimiter.kt | 25 +--- .../FreeformTaskTransitionHandler.java | 48 ++++--- ...esktopMinimizationTransitionHandlerTest.kt | 8 +- .../desktopmode/DesktopTasksLimiterTest.kt | 82 ------------ .../shared/animation/MinimizeAnimatorTest.kt | 118 ++++++++++++++++++ 10 files changed, 255 insertions(+), 157 deletions(-) create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/animation/MinimizeAnimatorTest.kt diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java index e92c1eb81e895..43dd9b73b352d 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java @@ -73,6 +73,12 @@ public class Interpolators { public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator( 0.05f, 0.7f, 0.1f, 1f); + /** + * The standard accelerating interpolator that should be used on every regular movement of + * content that is disappearing e.g. when moving off screen. + */ + public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(0.3f, 0f, 1f, 1f); + /** * The standard decelerating interpolator that should be used on every regular movement of * content that is appearing e.g. when coming from off screen. diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/MinimizeAnimator.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/MinimizeAnimator.kt index 0586e265ecedf..4ecace0292cfa 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/MinimizeAnimator.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/MinimizeAnimator.kt @@ -19,52 +19,76 @@ package com.android.wm.shell.shared.animation import android.animation.Animator import android.animation.AnimatorSet import android.animation.ValueAnimator -import android.util.DisplayMetrics +import android.content.Context +import android.os.Handler +import android.view.Choreographer import android.view.SurfaceControl.Transaction -import android.view.animation.LinearInterpolator -import android.view.animation.PathInterpolator import android.window.TransitionInfo.Change +import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW +import com.android.internal.jank.InteractionJankMonitor /** Creates minimization animation */ object MinimizeAnimator { private const val MINIMIZE_ANIM_ALPHA_DURATION_MS = 100L - private val STANDARD_ACCELERATE = PathInterpolator(0.3f, 0f, 1f, 1f) - private val minimizeBoundsAnimationDef = WindowAnimator.BoundsAnimationParams( durationMs = 200, endOffsetYDp = 12f, endScale = 0.97f, - interpolator = STANDARD_ACCELERATE, + interpolator = Interpolators.STANDARD_ACCELERATE, ) + /** + * Creates a minimize animator for given task [Change]. + * + * @param onAnimFinish finish-callback for the animation, note that this is called on the same + * thread as the animation itself. + * @param animationHandler the Handler that the animation is running on. + */ @JvmStatic fun create( - displayMetrics: DisplayMetrics, + context: Context, change: Change, transaction: Transaction, onAnimFinish: (Animator) -> Unit, + interactionJankMonitor: InteractionJankMonitor, + animationHandler: Handler, ): Animator { val boundsAnimator = WindowAnimator.createBoundsAnimator( - displayMetrics, + context.resources.displayMetrics, minimizeBoundsAnimationDef, change, transaction, ) val alphaAnimator = ValueAnimator.ofFloat(1f, 0f).apply { duration = MINIMIZE_ANIM_ALPHA_DURATION_MS - interpolator = LinearInterpolator() + interpolator = Interpolators.LINEAR addUpdateListener { animation -> - transaction.setAlpha(change.leash, animation.animatedValue as Float).apply() + transaction + .setAlpha(change.leash, animation.animatedValue as Float) + .setFrameTimeline(Choreographer.getInstance().vsyncId) + .apply() } } val listener = object : Animator.AnimatorListener { - override fun onAnimationEnd(animator: Animator) = onAnimFinish(animator) - override fun onAnimationCancel(animator: Animator) = Unit + override fun onAnimationStart(animator: Animator) { + interactionJankMonitor.begin( + change.leash, + context, + animationHandler, + CUJ_DESKTOP_MODE_MINIMIZE_WINDOW, + ) + } + override fun onAnimationCancel(animator: Animator) { + interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) + } override fun onAnimationRepeat(animator: Animator) = Unit - override fun onAnimationStart(animator: Animator) = Unit + override fun onAnimationEnd(animator: Animator) { + interactionJankMonitor.end(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) + onAnimFinish(animator) + } } return AnimatorSet().apply { playTogether(boundsAnimator, alphaAnimator) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java index ee3e39e715587..e9dc6132f5f41 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java @@ -162,22 +162,31 @@ public abstract class WMShellConcurrencyModule { } } - /** - * Provide a Shell animation-thread Executor. - */ + /** Provide a Shell animation-thread Handler. */ @WMSingleton @Provides @ShellAnimationThread - public static ShellExecutor provideShellAnimationExecutor() { - HandlerThread shellAnimationThread = new HandlerThread("wmshell.anim", - THREAD_PRIORITY_DISPLAY); - shellAnimationThread.start(); + public static Handler provideShellAnimationHandler() { + HandlerThread animThread = new HandlerThread("wmshell.anim", THREAD_PRIORITY_DISPLAY); + animThread.start(); if (Build.IS_DEBUGGABLE) { - shellAnimationThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER); - shellAnimationThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS, + animThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER); + animThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS, MSGQ_SLOW_DELIVERY_THRESHOLD_MS); } - return new HandlerExecutor(Handler.createAsync(shellAnimationThread.getLooper())); + return Handler.createAsync(animThread.getLooper()); + } + + /** + * Provide a Shell animation-thread Executor. + */ + @WMSingleton + @Provides + @ShellAnimationThread + public static ShellExecutor provideShellAnimationExecutor( + @ShellAnimationThread Handler animHandler + ) { + return new HandlerExecutor(animHandler); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 2fd8c27d5970c..79adea6749aa5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -428,9 +428,10 @@ public abstract class WMShellModule { Transitions transitions, DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor, - @ShellAnimationThread ShellExecutor animExecutor) { + @ShellAnimationThread ShellExecutor animExecutor, + @ShellAnimationThread Handler animHandler) { return new FreeformTaskTransitionHandler( - transitions, displayController, mainExecutor, animExecutor); + transitions, displayController, mainExecutor, animExecutor, animHandler); } @WMSingleton @@ -1083,9 +1084,10 @@ public abstract class WMShellModule { static DesktopMinimizationTransitionHandler provideDesktopMinimizationTransitionHandler( @ShellMainThread ShellExecutor mainExecutor, @ShellAnimationThread ShellExecutor animExecutor, - DisplayController displayController) { + DisplayController displayController, + @ShellAnimationThread Handler mainHandler) { return new DesktopMinimizationTransitionHandler(mainExecutor, animExecutor, - displayController); + displayController, mainHandler); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt index 728638d9bbd30..7074e8bc9cce1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt @@ -18,14 +18,17 @@ package com.android.wm.shell.desktopmode import android.animation.Animator import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.os.Handler import android.os.IBinder -import android.util.DisplayMetrics import android.view.SurfaceControl.Transaction import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction +import com.android.internal.jank.InteractionJankMonitor +import com.android.internal.protolog.ProtoLog import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.animation.MinimizeAnimator.create import com.android.wm.shell.transition.Transitions @@ -41,6 +44,7 @@ class DesktopMinimizationTransitionHandler( private val mainExecutor: ShellExecutor, private val animExecutor: ShellExecutor, private val displayController: DisplayController, + private val animHandler: Handler, ) : Transitions.TransitionHandler { /** Shouldn't handle anything */ @@ -90,10 +94,30 @@ class DesktopMinimizationTransitionHandler( val t = Transaction() val sc = change.leash finishTransaction.hide(sc) - val displayMetrics: DisplayMetrics? = - change.taskInfo?.let { - displayController.getDisplayContext(it.displayId)?.getResources()?.displayMetrics - } - return displayMetrics?.let { create(it, change, t, onAnimFinish) } + val displayContext = + change.taskInfo?.let { displayController.getDisplayContext(it.displayId) } + if (displayContext == null) { + logW( + "displayContext is null for taskId=${change.taskInfo?.taskId}, " + + "displayId=${change.taskInfo?.displayId}" + ) + return null + } + return create( + displayContext, + change, + t, + onAnimFinish, + InteractionJankMonitor.getInstance(), + animHandler, + ) + } + + private companion object { + private fun logW(msg: String, vararg arguments: Any?) { + ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + const val TAG = "DesktopMinimizationTransitionHandler" } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt index 81b136dd1569c..f9ab359e952d0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt @@ -26,7 +26,6 @@ import android.window.DesktopModeFlags import android.window.TransitionInfo import android.window.WindowContainerTransaction import androidx.annotation.VisibleForTesting -import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW import com.android.internal.jank.InteractionJankMonitor import com.android.internal.protolog.ProtoLog import com.android.wm.shell.ShellTaskOrganizer @@ -176,28 +175,13 @@ class DesktopTasksLimiter( return taskChange.mode == TRANSIT_TO_BACK } - override fun onTransitionStarting(transition: IBinder) { - val mActiveTaskDetails = activeTransitionTokensAndTasks[transition] - val info = mActiveTaskDetails?.transitionInfo ?: return - val minimizeChange = getMinimizeChange(info, mActiveTaskDetails.taskId) ?: return - // Begin minimize window CUJ instrumentation. - interactionJankMonitor.begin( - minimizeChange.leash, - context, - handler, - CUJ_DESKTOP_MODE_MINIMIZE_WINDOW, - ) - } - private fun getMinimizeChange(info: TransitionInfo, taskId: Int): TransitionInfo.Change? = info.changes.find { change -> change.taskInfo?.taskId == taskId && change.mode == TRANSIT_TO_BACK } override fun onTransitionMerged(merged: IBinder, playing: IBinder) { - if (activeTransitionTokensAndTasks.remove(merged) != null) { - interactionJankMonitor.end(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) - } + activeTransitionTokensAndTasks.remove(merged) pendingTransitionTokensAndTasks.remove(merged)?.let { taskToTransfer -> pendingTransitionTokensAndTasks[playing] = taskToTransfer } @@ -209,13 +193,6 @@ class DesktopTasksLimiter( } override fun onTransitionFinished(transition: IBinder, aborted: Boolean) { - if (activeTransitionTokensAndTasks.remove(transition) != null) { - if (aborted) { - interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) - } else { - interactionJankMonitor.end(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) - } - } pendingTransitionTokensAndTasks.remove(transition) activeUnminimizeTransitionTokensAndTasks.remove(transition) pendingUnminimizeTransitionTokensAndTasks.remove(transition) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java index b60fb5e7bfdd3..16e411e1fc074 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java @@ -25,10 +25,12 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.ActivityManager; import android.app.WindowConfiguration; +import android.content.Context; import android.graphics.Rect; +import android.os.Handler; import android.os.IBinder; import android.util.ArrayMap; -import android.util.DisplayMetrics; +import android.util.Log; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.TransitionInfo; @@ -38,6 +40,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.jank.InteractionJankMonitor; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.shared.animation.MinimizeAnimator; @@ -52,11 +55,13 @@ import java.util.List; */ public class FreeformTaskTransitionHandler implements Transitions.TransitionHandler, FreeformTaskTransitionStarter { + private static final String TAG = "FreeformTaskTransitionHandler"; private static final int CLOSE_ANIM_DURATION = 400; private final Transitions mTransitions; private final DisplayController mDisplayController; private final ShellExecutor mMainExecutor; private final ShellExecutor mAnimExecutor; + private final Handler mAnimHandler; private final List mPendingTransitionTokens = new ArrayList<>(); @@ -66,11 +71,13 @@ public class FreeformTaskTransitionHandler Transitions transitions, DisplayController displayController, ShellExecutor mainExecutor, - ShellExecutor animExecutor) { + ShellExecutor animExecutor, + Handler animHandler) { mTransitions = transitions; mDisplayController = displayController; mMainExecutor = mainExecutor; mAnimExecutor = animExecutor; + mAnimHandler = animHandler; } @Override @@ -123,13 +130,11 @@ public class FreeformTaskTransitionHandler @NonNull Transitions.TransitionFinishCallback finishCallback) { boolean transitionHandled = false; final ArrayList animations = new ArrayList<>(); - final Runnable onAnimFinish = () -> { + final Runnable onAnimFinish = () -> mMainExecutor.execute(() -> { if (!animations.isEmpty()) return; - mMainExecutor.execute(() -> { - mAnimations.remove(transition); - finishCallback.onTransitionFinished(null /* wct */); - }); - }; + mAnimations.remove(transition); + finishCallback.onTransitionFinished(null /* wct */); + }); for (TransitionInfo.Change change : info.getChanges()) { if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) { continue; @@ -234,18 +239,25 @@ public class FreeformTaskTransitionHandler SurfaceControl.Transaction t = new SurfaceControl.Transaction(); SurfaceControl sc = change.getLeash(); finishT.hide(sc); - final DisplayMetrics displayMetrics = - mDisplayController - .getDisplayContext(taskInfo.displayId).getResources().getDisplayMetrics(); + final Context displayContext = + mDisplayController.getDisplayContext(taskInfo.displayId); + if (displayContext == null) { + Log.w(TAG, "No displayContext for displayId=" + taskInfo.displayId); + return false; + } final Animator animator = MinimizeAnimator.create( - displayMetrics, + displayContext, change, t, (anim) -> { - animations.remove(anim); - onAnimFinish.run(); + mMainExecutor.execute(() -> { + animations.remove(anim); + onAnimFinish.run(); + }); return null; - }); + }, + InteractionJankMonitor.getInstance(), + mAnimHandler); animations.add(animator); return true; } @@ -277,8 +289,10 @@ public class FreeformTaskTransitionHandler new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - animations.remove(animator); - onAnimFinish.run(); + mMainExecutor.execute(() -> { + animations.remove(animator); + onAnimFinish.run(); + }); } }); animations.add(animator); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandlerTest.kt index 4c3325d4d1de4..0d1c57221fb9c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandlerTest.kt @@ -21,6 +21,7 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WindowingMode +import android.os.Handler import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.SurfaceControl @@ -56,7 +57,12 @@ class DesktopMinimizationTransitionHandlerTest : ShellTestCase() { @Before fun setUp() { handler = - DesktopMinimizationTransitionHandler(testExecutor, testExecutor, displayController) + DesktopMinimizationTransitionHandler( + testExecutor, + testExecutor, + displayController, + mock(), + ) whenever(displayController.getDisplayContext(any())).thenReturn(mContext) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt index d33209dbc30e4..62e3c544e3907 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt @@ -37,7 +37,6 @@ import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.StaticMockitoSession -import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW import com.android.internal.jank.InteractionJankMonitor import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION import com.android.wm.shell.ShellTaskOrganizer @@ -72,8 +71,6 @@ import org.mockito.Mockito.any import org.mockito.Mockito.mock import org.mockito.Mockito.spy import org.mockito.Mockito.`when` -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify import org.mockito.quality.Strictness /** @@ -520,85 +517,6 @@ class DesktopTasksLimiterTest : ShellTestCase() { assertThat(minimizedTask).isEqualTo(tasks.last().taskId) } - @Test - fun minimizeTransitionReadyAndFinished_logsJankInstrumentationBeginAndEnd() { - desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) - desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) - (1.. setUpFreeformTask() } - val transition = Binder() - val task = setUpFreeformTask() - addPendingMinimizeChange(transition, taskId = task.taskId) - - callOnTransitionReady( - transition, - TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(), - ) - - desktopTasksLimiter.getTransitionObserver().onTransitionStarting(transition) - - verify(interactionJankMonitor) - .begin(any(), eq(mContext), eq(handler), eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) - - desktopTasksLimiter - .getTransitionObserver() - .onTransitionFinished(transition, /* aborted= */ false) - - verify(interactionJankMonitor).end(eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) - } - - @Test - fun minimizeTransitionReadyAndAborted_logsJankInstrumentationBeginAndCancel() { - desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) - desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) - (1.. setUpFreeformTask() } - val transition = Binder() - val task = setUpFreeformTask() - addPendingMinimizeChange(transition, taskId = task.taskId) - - callOnTransitionReady( - transition, - TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(), - ) - - desktopTasksLimiter.getTransitionObserver().onTransitionStarting(transition) - - verify(interactionJankMonitor) - .begin(any(), eq(mContext), eq(handler), eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) - - desktopTasksLimiter - .getTransitionObserver() - .onTransitionFinished(transition, /* aborted= */ true) - - verify(interactionJankMonitor).cancel(eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) - } - - @Test - fun minimizeTransitionReadyAndMerged_logsJankInstrumentationBeginAndEnd() { - desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) - desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) - (1.. setUpFreeformTask() } - val mergedTransition = Binder() - val newTransition = Binder() - val task = setUpFreeformTask() - addPendingMinimizeChange(mergedTransition, taskId = task.taskId) - - callOnTransitionReady( - mergedTransition, - TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(), - ) - - desktopTasksLimiter.getTransitionObserver().onTransitionStarting(mergedTransition) - - verify(interactionJankMonitor) - .begin(any(), eq(mContext), eq(handler), eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) - - desktopTasksLimiter - .getTransitionObserver() - .onTransitionMerged(mergedTransition, newTransition) - - verify(interactionJankMonitor).end(eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) - } - @Test fun getMinimizingTask_noPendingTransition_returnsNull() { val transition = Binder() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/animation/MinimizeAnimatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/animation/MinimizeAnimatorTest.kt new file mode 100644 index 0000000000000..ba609d4322fc6 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/animation/MinimizeAnimatorTest.kt @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2025 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.wm.shell.shared.animation + +import android.animation.Animator +import android.animation.AnimatorSet +import android.animation.ValueAnimator +import android.content.Context +import android.content.res.Resources +import android.os.Handler +import android.util.DisplayMetrics +import android.view.SurfaceControl +import android.view.SurfaceControl.Transaction +import android.window.TransitionInfo +import android.window.WindowContainerToken +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread +import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW +import com.android.internal.jank.InteractionJankMonitor +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyFloat +import org.mockito.ArgumentMatchers.anyLong +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class MinimizeAnimatorTest { + private val context = mock() + private val resources = mock() + private val transaction = mock() + private val leash = mock() + private val interactionJankMonitor = mock() + private val animationHandler = mock() + + private val displayMetrics = DisplayMetrics().apply { density = 1f } + + @Before + fun setup() { + whenever(context.resources).thenReturn(resources) + whenever(resources.displayMetrics).thenReturn(displayMetrics) + whenever(transaction.setAlpha(any(), anyFloat())).thenReturn(transaction) + whenever(transaction.setPosition(any(), anyFloat(), anyFloat())).thenReturn(transaction) + whenever(transaction.setScale(any(), anyFloat(), anyFloat())).thenReturn(transaction) + whenever(transaction.setFrameTimeline(anyLong())).thenReturn(transaction) + } + + @Test + fun create_returnsBoundsAndAlphaAnimators() { + val change = TransitionInfo.Change(mock(), leash) + + val animator = createAnimator(change) + + assertThat(animator).isInstanceOf(AnimatorSet::class.java) + val animatorSet = animator as AnimatorSet + assertThat(animatorSet.childAnimations).hasSize(2) + assertIsBoundsAnimator(animatorSet.childAnimations[0]) + assertIsAlphaAnimator(animatorSet.childAnimations[1]) + } + + @Test + fun create_doesNotlogJankInstrumentation() = runOnUiThread { + val change = TransitionInfo.Change(mock(), leash) + + createAnimator(change) + + verify(interactionJankMonitor, never()).begin( + leash, context, animationHandler, CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) + } + + @Test + fun onAnimationStart_logsJankInstrumentation() = runOnUiThread { + val change = TransitionInfo.Change(mock(), leash) + + createAnimator(change).start() + + verify(interactionJankMonitor).begin( + leash, context, animationHandler, CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) + } + + private fun createAnimator(change: TransitionInfo.Change): Animator = + MinimizeAnimator.create(context, change, transaction, {}, interactionJankMonitor, + animationHandler) + + private fun assertIsBoundsAnimator(animator: Animator) { + assertThat(animator).isInstanceOf(ValueAnimator::class.java) + assertThat(animator.duration).isEqualTo(200) + assertThat(animator.interpolator).isEqualTo(Interpolators.STANDARD_ACCELERATE) + } + + private fun assertIsAlphaAnimator(animator: Animator) { + assertThat(animator).isInstanceOf(ValueAnimator::class.java) + assertThat(animator.duration).isEqualTo(100) + assertThat(animator.interpolator).isEqualTo(Interpolators.LINEAR) + } +} + -- GitLab From 4d3dfb14937619c260a1adfce4bf6db7e90a7935 Mon Sep 17 00:00:00 2001 From: Gustav Sennton Date: Tue, 18 Feb 2025 13:31:50 +0000 Subject: [PATCH 011/111] Use animHandler for CUJ_DESKTOP_MODE_CLOSE_TASK The close-animation runs on the animation thread, so we should pass the animation handler to InteractionJankMonitor. Bug: 357811393 Test: manual (perfetto) Flag: NONE jank/logging change Change-Id: I3882338ce5fa9f94a3c9b40a3dbcff5b82507c88 --- .../Shell/src/com/android/wm/shell/dagger/WMShellModule.java | 5 +++-- .../shell/desktopmode/CloseDesktopTaskTransitionHandler.kt | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 79adea6749aa5..02a080017fa6b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -1075,8 +1075,9 @@ public abstract class WMShellModule { Context context, @ShellMainThread ShellExecutor mainExecutor, @ShellAnimationThread ShellExecutor animExecutor, - @ShellMainThread Handler handler) { - return new CloseDesktopTaskTransitionHandler(context, mainExecutor, animExecutor, handler); + @ShellAnimationThread Handler animHandler) { + return new CloseDesktopTaskTransitionHandler(context, mainExecutor, animExecutor, + animHandler); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandler.kt index 1ce093e02a4ab..b22a46edbf3ac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandler.kt @@ -37,7 +37,6 @@ import com.android.app.animation.Interpolators import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_CLOSE_TASK import com.android.internal.jank.InteractionJankMonitor import com.android.wm.shell.common.ShellExecutor -import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.transition.Transitions import java.util.function.Supplier @@ -49,7 +48,7 @@ constructor( private val mainExecutor: ShellExecutor, private val animExecutor: ShellExecutor, private val transactionSupplier: Supplier = Supplier { Transaction() }, - @ShellMainThread private val handler: Handler, + private val animHandler: Handler, ) : Transitions.TransitionHandler { private val runningAnimations = mutableMapOf>() @@ -95,7 +94,7 @@ constructor( interactionJankMonitor.begin( lastChangeLeash, context, - handler, + animHandler, CUJ_DESKTOP_MODE_CLOSE_TASK, ) } -- GitLab From e710c85e01f9d994c24c92ca0c3b14e718e917b8 Mon Sep 17 00:00:00 2001 From: Shai Barack Date: Wed, 19 Feb 2025 09:16:47 -0800 Subject: [PATCH 012/111] Reland "Don't fall back to legacy MessageQueue when Instrumenting" This reverts commit af846352b51895a270240fbace6e7845b4cf7646. Reason for revert: fixed underlying issue, see b/397595841 Change-Id: Ie2d6f8b9628e066affbf0a5980173231de191418 Flag: android.os.message_queue_testability Bug: 112000181 --- .../android/os/CombinedMessageQueue/MessageQueue.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 8471fcea701d2..4ec2887a96d30 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -126,7 +126,7 @@ public final class MessageQueue { MessageQueue(boolean quitAllowed) { initIsProcessAllowedToUseConcurrent(); - mUseConcurrent = sIsProcessAllowedToUseConcurrent && !isInstrumenting(); + mUseConcurrent = sIsProcessAllowedToUseConcurrent; mQuitAllowed = quitAllowed; mPtr = nativeInit(); } @@ -201,15 +201,6 @@ public final class MessageQueue { return; } - private static boolean isInstrumenting() { - final ActivityThread activityThread = ActivityThread.currentActivityThread(); - if (activityThread == null) { - return false; - } - final Instrumentation instrumentation = activityThread.getInstrumentation(); - return instrumentation != null && instrumentation.isInstrumenting(); - } - @Override protected void finalize() throws Throwable { try { -- GitLab From 4c017ba6b682946ba1eeb7f86fe1aeedf4ada884 Mon Sep 17 00:00:00 2001 From: Ahmad Khalil Date: Wed, 19 Feb 2025 18:07:16 +0000 Subject: [PATCH 013/111] Adding config library with host support Bug: 397344593 Flag: android.os.vibrator.primitive_composition_absolute_delay Test: N/A Change-Id: I8f41cab82978fda15e8828482b219bd48b940bb8 --- AconfigFlags.bp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 8b95679f318f5..8bfac03060b54 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -610,6 +610,13 @@ cc_aconfig_library { vendor_available: true, } +java_aconfig_library { + name: "android.os.vibrator.flags-aconfig-java-host", + aconfig_declarations: "android.os.vibrator.flags-aconfig", + host_supported: true, + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + // View aconfig_declarations { name: "android.view.flags-aconfig", -- GitLab From 14416f7365dbe780812204337bf62c74963dea57 Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Wed, 19 Feb 2025 11:16:34 -0800 Subject: [PATCH 014/111] Switch to PictureInPictureParams#isSameAspectRatio Switch to PictureInPictureParams#isSameAspectRatio on Shell side, the same check has been applied in CTS tests. Flag: EXEMPT bugfix Bug: 352118806 Test: atest PinnedStackTests Change-Id: Ie40d69945414e0e9462cb2310b70492a2e7137b4 --- .../android/wm/shell/common/pip/PipBoundsAlgorithm.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java index 8e026f04ac311..04e8d8dee520f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java @@ -24,6 +24,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.graphics.Rect; import android.util.DisplayMetrics; +import android.util.Rational; import android.util.Size; import android.view.Gravity; @@ -41,9 +42,6 @@ public class PipBoundsAlgorithm { private static final String TAG = PipBoundsAlgorithm.class.getSimpleName(); private static final float INVALID_SNAP_FRACTION = -1f; - // The same value (with the same name) is used in Launcher. - private static final float PIP_ASPECT_RATIO_MISMATCH_THRESHOLD = 0.01f; - @NonNull private final PipBoundsState mPipBoundsState; @NonNull protected final PipDisplayLayoutState mPipDisplayLayoutState; @NonNull protected final SizeSpecSource mSizeSpecSource; @@ -223,9 +221,8 @@ public class PipBoundsAlgorithm { + " than destination(%s)", sourceRectHint, destinationBounds); return false; } - final float reportedRatio = destinationBounds.width() / (float) destinationBounds.height(); - final float inferredRatio = sourceRectHint.width() / (float) sourceRectHint.height(); - if (Math.abs(reportedRatio - inferredRatio) > PIP_ASPECT_RATIO_MISMATCH_THRESHOLD) { + if (!PictureInPictureParams.isSameAspectRatio(sourceRectHint, + new Rational(destinationBounds.width(), destinationBounds.height()))) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "isSourceRectHintValidForEnterPip=false, hint(%s) does not match" + " destination(%s) aspect ratio", sourceRectHint, destinationBounds); -- GitLab From a6374ea45d5252c47a97452e2b9a4d3784558eac Mon Sep 17 00:00:00 2001 From: Yuhan Yang Date: Fri, 14 Feb 2025 18:26:10 +0000 Subject: [PATCH 015/111] Add autoclick to shortcut features map Bug: 390460480 Test: verified manually on test devices. Flag: com.android.server.accessibility.enable_autoclick_indicator Change-Id: If6710459946ee5db13afd238378c5a38e84811c8 --- .../AccessibilityShortcutController.java | 9 ++++++++- .../dialog/AccessibilityTargetHelper.java | 14 ++++++++++++++ core/res/res/values/strings.xml | 3 +++ core/res/res/values/symbols.xml | 1 + 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index a27eeb8fdd634..1281a78d4fa23 100644 --- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -97,6 +97,8 @@ public class AccessibilityShortcutController { new ComponentName("com.android.server.accessibility", "ReduceBrightColors"); public static final ComponentName FONT_SIZE_COMPONENT_NAME = new ComponentName("com.android.server.accessibility", "FontSize"); + public static final ComponentName AUTOCLICK_COMPONENT_NAME = + new ComponentName("com.android.server.accessibility", "Autoclick"); // The component name for the sub setting of Accessibility button in Accessibility settings public static final ComponentName ACCESSIBILITY_BUTTON_COMPONENT_NAME = @@ -163,7 +165,7 @@ public class AccessibilityShortcutController { getFrameworkShortcutFeaturesMap() { if (sFrameworkShortcutFeaturesMap == null) { - Map featuresMap = new ArrayMap<>(4); + Map featuresMap = new ArrayMap<>(8); featuresMap.put(COLOR_INVERSION_COMPONENT_NAME, new ToggleableFrameworkFeatureInfo( Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, @@ -174,6 +176,11 @@ public class AccessibilityShortcutController { Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, "1" /* Value to enable */, "0" /* Value to disable */, R.string.color_correction_feature_name)); + featuresMap.put(AUTOCLICK_COMPONENT_NAME, + new ToggleableFrameworkFeatureInfo( + Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, + "1" /* Value to enable */, "0" /* Value to disable */, + R.string.autoclick_feature_name)); if (SUPPORT_ONE_HANDED_MODE) { featuresMap.put(ONE_HANDED_COMPONENT_NAME, new ToggleableFrameworkFeatureInfo( diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java index b187eb42366f5..6498c53a63e23 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java @@ -17,6 +17,7 @@ package com.android.internal.accessibility.dialog; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; +import static com.android.internal.accessibility.AccessibilityShortcutController.AUTOCLICK_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; @@ -214,6 +215,19 @@ public final class AccessibilityTargetHelper { Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); targets.add(colorInversion); + // TODO(b/394683600): Update Icon with the autoclick asset. + final ToggleAllowListingFeatureTarget autoclick = + new ToggleAllowListingFeatureTarget(context, + shortcutType, + isShortcutContained(context, shortcutType, + AUTOCLICK_COMPONENT_NAME.flattenToString()), + AUTOCLICK_COMPONENT_NAME.flattenToString(), + uid, + context.getString(R.string.autoclick_feature_name), + context.getDrawable(R.drawable.ic_accessibility_generic), + Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED); + targets.add(autoclick); + if (SUPPORT_ONE_HANDED_MODE) { final ToggleAllowListingFeatureTarget oneHandedMode = new ToggleAllowListingFeatureTarget(context, diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index abbba9d1bffad..d4f0e69ad0d46 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4960,6 +4960,9 @@ Hearing devices + + Autoclick + Disconnected diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index cc2897a2779e2..ca47587bfe9cd 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3787,6 +3787,7 @@ + -- GitLab From 05b077d21a9a7200eb3fe48362cf317f3577d7b6 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Tue, 11 Feb 2025 09:46:00 +0000 Subject: [PATCH 016/111] HubEndpoint: reject session if no lifecycle cb - Fix typo Test: N/A Flag: EXEMPT bug fix Bug: 388331996 Change-Id: I6b0aa64e81fd61faca233d57d73d8447d9eae844 --- .../java/android/hardware/contexthub/HubEndpoint.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java index b7edef619a675..47ba51d98323f 100644 --- a/core/java/android/hardware/contexthub/HubEndpoint.java +++ b/core/java/android/hardware/contexthub/HubEndpoint.java @@ -126,7 +126,16 @@ public class HubEndpoint { if (sessionExists) { Log.w( TAG, - "onSessionOpenComplete: session already exists, id=" + sessionId); + "onSessionOpenRequest: session already exists, id=" + sessionId); + } + + if (mLifecycleCallback == null) { + Log.w( + TAG, + "onSessionOpenRequest: " + + "failed to open session, no lifecycle callback attached", + new Exception()); + rejectSession(sessionId); } if (!sessionExists && mLifecycleCallback != null) { -- GitLab From 812d5ec9d59999aecced029451c9a54397c811b8 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Tue, 11 Feb 2025 10:44:51 +0000 Subject: [PATCH 017/111] contexthub: reject endpoint registration with null cb - Throw IllegalArgumentException when this happens - Add @NonNull annotations for IContextHubEndpointCallback usages Test: build Flag: EXEMPT bug fix Bug: 385223561 Change-Id: I5db7666188f576d5f33dada6b7fe836feb7e5427 --- .../contexthub/ContextHubEndpointBroker.java | 27 +++++++++---------- .../contexthub/ContextHubEndpointManager.java | 3 ++- .../contexthub/ContextHubService.java | 4 +++ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java index 1a29150cd40c4..940bcb4c6ba16 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java @@ -16,6 +16,7 @@ package com.android.server.location.contexthub; +import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.hardware.contexthub.EndpointInfo; @@ -64,7 +65,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub * Internal interface used to invoke client callbacks. */ interface CallbackConsumer { - void accept(IContextHubEndpointCallback callback) throws RemoteException; + void accept(@NonNull IContextHubEndpointCallback callback) throws RemoteException; } /** The context of the service. */ @@ -86,7 +87,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub private final EndpointInfo mHalEndpointInfo; /** The remote callback interface for this endpoint. */ - private final IContextHubEndpointCallback mContextHubEndpointCallback; + @NonNull private final IContextHubEndpointCallback mContextHubEndpointCallback; /** True if this endpoint is registered with the service/HAL. */ @GuardedBy("mRegistrationLock") @@ -158,7 +159,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub IEndpointCommunication hubInterface, ContextHubEndpointManager endpointManager, EndpointInfo halEndpointInfo, - IContextHubEndpointCallback callback, + @NonNull IContextHubEndpointCallback callback, String packageName, String attributionTag, ContextHubTransactionManager transactionManager) { @@ -419,9 +420,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } /* package */ void attachDeathRecipient() throws RemoteException { - if (mContextHubEndpointCallback != null) { - mContextHubEndpointCallback.asBinder().linkToDeath(this, 0 /* flags */); - } + mContextHubEndpointCallback.asBinder().linkToDeath(this, 0 /* flags */); } /* package */ void onEndpointSessionOpenRequest( @@ -664,15 +663,13 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub * @return false if the callback threw a RemoteException */ private boolean invokeCallback(CallbackConsumer consumer) { - if (mContextHubEndpointCallback != null) { - acquireWakeLock(); - try { - consumer.accept(mContextHubEndpointCallback); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException while calling endpoint callback", e); - releaseWakeLock(); - return false; - } + acquireWakeLock(); + try { + consumer.accept(mContextHubEndpointCallback); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException while calling endpoint callback", e); + releaseWakeLock(); + return false; } return true; } diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java index 30bb8f3fa188a..8ab581e1fb7ae 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java @@ -17,6 +17,7 @@ package com.android.server.location.contexthub; import android.annotation.IntDef; +import android.annotation.NonNull; import android.content.Context; import android.hardware.contexthub.ContextHubInfo; import android.hardware.contexthub.EndpointInfo; @@ -240,7 +241,7 @@ import java.util.function.Consumer; */ /* package */ IContextHubEndpoint registerEndpoint( HubEndpointInfo pendingEndpointInfo, - IContextHubEndpointCallback callback, + @NonNull IContextHubEndpointCallback callback, String packageName, String attributionTag) throws RemoteException { diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java index bf7351cb11dba..2c0c55bd8df4f 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java @@ -792,6 +792,10 @@ public class ContextHubService extends IContextHubService.Stub { Log.e(TAG, "Endpoint manager failed to initialize"); throw new UnsupportedOperationException("Endpoint registration is not supported"); } + if (callback == null) { + Log.e(TAG, "Endpoint callback is invalid"); + throw new IllegalArgumentException("registerEndpoint must have a non-null callback"); + } return mEndpointManager.registerEndpoint( pendingHubEndpointInfo, callback, packageName, attributionTag); } -- GitLab From 53f64acf1d48abda0326d382672615fb34c5679e Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Fri, 7 Feb 2025 14:19:54 -0800 Subject: [PATCH 018/111] Add a flag for unifying taskview listener Flag: com.android.wm.shell.enable_bubble_task_view_listener Test: treehugger Bug: 272102927 Change-Id: Iacb6150cb57c998e9f8583d1a128713dec4e3ec9 --- libs/WindowManager/Shell/aconfig/multitasking.aconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index a08f88a5b937d..1e72d64397d73 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -184,3 +184,13 @@ flag { description: "Try out bubble bar on phones" bug: "394869612" } + +flag { + name: "enable_bubble_task_view_listener" + namespace: "multitasking" + description: "Use the same taskview listener for bubble bar and floating" + bug: "272102927" + metadata { + purpose: PURPOSE_BUGFIX + } +} -- GitLab From 95ae381d08bf603d2f6b89df723f23da97aa0de2 Mon Sep 17 00:00:00 2001 From: Adam Bookatz Date: Wed, 19 Feb 2025 15:08:20 -0800 Subject: [PATCH 019/111] Fix canAddPrivateProfile @RequiresPermission The @RequiresPermission is marked as conditional, but it isn't conditional. Change-Id: Icd2bb44f19176c935e86c6f43c21d7a808810a7d Test: N/A, just documentation Flag: EXEMPT documentation only --- core/api/test-current.txt | 2 +- core/java/android/os/UserManager.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 89b377314887b..4ad6befd396e3 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2585,7 +2585,7 @@ package android.os { } public class UserManager { - method @FlaggedApi("android.os.allow_private_profile") @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public boolean canAddPrivateProfile(); + method @FlaggedApi("android.os.allow_private_profile") @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean canAddPrivateProfile(); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createProfileForUser(@Nullable String, @NonNull String, int, int, @Nullable String[]); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createRestrictedProfile(@Nullable String); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 33bf4a29ecc6c..767019d977582 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -3324,8 +3324,7 @@ public class UserManager { @FlaggedApi(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE) @RequiresPermission(anyOf = { Manifest.permission.MANAGE_USERS, - Manifest.permission.CREATE_USERS}, - conditional = true) + Manifest.permission.CREATE_USERS}) @UserHandleAware public boolean canAddPrivateProfile() { if (!android.multiuser.Flags.enablePrivateSpaceFeatures()) return false; -- GitLab From 907dd476de2a80cddbc30c6d98ca6d77d482ae33 Mon Sep 17 00:00:00 2001 From: Ats Jenk Date: Wed, 19 Feb 2025 13:48:58 -0800 Subject: [PATCH 020/111] Fix hotseat visibility after dragging task to bubble Desktop drag handler sends a transition at the beginning to transiently launch home task. This transition is ignored by the home transition observer and we do not update home visibility in this case. As this would otherwise cause flickers with launcher UI elements during drag. When the desktop drag ends in a bubble drag zone, we send a new transition to convert the task to a bubble. If the task was the only task running on home, we now will have home showing and the bubbled task showing. But since home was made visible by the drag start transition, home task is not part of the second transition changes. It is already considered visible. This broke the existing logic with handling home visibility as we were expecting the second transition to include information about the home task. As a fix, keep track of the desired home visibility state when desktop drag starts. And if the subsequent transition to convert the task to bubble does not contain information about home, apply the home visibility that was calculated at the start of drag. If the convert to bubble transition does include home task and it triggers a change to home visibility, apply this instead and discard the home visibility pending update from the start of the drag. This second case is required in case there are two tasks running on top of home. When desktop drag starts, home will be brought to front transiently. And when drag ends with a transition to convert the dragged task to bubble, the transition changes will include a change to move the home task behind the second fullscreen task. We need to honor this case and send an update that home is not visible. Bug: 396475362 Flag: com.android.wm.shell.enable_bubble_to_fullscreen Test: atest HomeTransitionObserver Test: manual, open an app, drag it to a bubble, check that hotseat is shown in launcher Change-Id: I197ac9b96c4312f3da12bdad21b5844b414847c2 --- .../transition/HomeTransitionObserver.java | 78 ++++++++++++++--- .../HomeTransitionObserverTest.java | 84 +++++++++++++++++++ 2 files changed, 150 insertions(+), 12 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java index 1917996d48fb7..938885cc1684d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java @@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; import static com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP; +import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE; import static com.android.wm.shell.transition.Transitions.TransitionObserver; import android.annotation.NonNull; @@ -35,6 +36,7 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SingleInstanceRemoteListener; import com.android.wm.shell.shared.IHomeTransitionListener; import com.android.wm.shell.shared.TransitionUtil; +import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper; /** * The {@link TransitionObserver} that observes for transitions involving the home @@ -48,6 +50,8 @@ public class HomeTransitionObserver implements TransitionObserver, private @NonNull final Context mContext; private @NonNull final ShellExecutor mMainExecutor; + private Boolean mPendingHomeVisibilityUpdate; + public HomeTransitionObserver(@NonNull Context context, @NonNull ShellExecutor mainExecutor) { mContext = context; @@ -59,28 +63,78 @@ public class HomeTransitionObserver implements TransitionObserver, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { + if (BubbleAnythingFlagHelper.enableBubbleToFullscreen()) { + handleTransitionReadyWithBubbleAnything(info); + } else { + handleTransitionReady(info); + } + } + + private void handleTransitionReady(@NonNull TransitionInfo info) { for (TransitionInfo.Change change : info.getChanges()) { final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); - if (info.getType() == TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP - || taskInfo == null + if (taskInfo == null + || info.getType() == TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP || taskInfo.displayId != DEFAULT_DISPLAY || taskInfo.taskId == -1 || !taskInfo.isRunning) { continue; } + Boolean homeVisibilityUpdate = getHomeVisibilityUpdate(info, change, taskInfo); + if (homeVisibilityUpdate != null) { + notifyHomeVisibilityChanged(homeVisibilityUpdate); + } + } + } + + private void handleTransitionReadyWithBubbleAnything(@NonNull TransitionInfo info) { + Boolean homeVisibilityUpdate = null; + for (TransitionInfo.Change change : info.getChanges()) { + final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); + if (taskInfo == null + || taskInfo.displayId != DEFAULT_DISPLAY + || taskInfo.taskId == -1 + || !taskInfo.isRunning) { + continue; + } + + Boolean update = getHomeVisibilityUpdate(info, change, taskInfo); + if (update != null) { + homeVisibilityUpdate = update; + } + } + + if (info.getType() == TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP) { + // Do not apply at the start of desktop drag as that updates launcher UI visibility. + // Store the value and apply with a next transition if needed. + mPendingHomeVisibilityUpdate = homeVisibilityUpdate; + return; + } + + if (info.getType() == TRANSIT_CONVERT_TO_BUBBLE && homeVisibilityUpdate == null) { + // We are converting to bubble and we did not get a change to home visibility in this + // transition. Apply the value from start of drag. + homeVisibilityUpdate = mPendingHomeVisibilityUpdate; + } + if (homeVisibilityUpdate != null) { + mPendingHomeVisibilityUpdate = null; + notifyHomeVisibilityChanged(homeVisibilityUpdate); + } + } - final int mode = change.getMode(); - final boolean isBackGesture = change.hasFlags(FLAG_BACK_GESTURE_ANIMATED); - if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) { - final boolean gestureToHomeTransition = isBackGesture - && TransitionUtil.isClosingType(info.getType()); - if (gestureToHomeTransition || TransitionUtil.isClosingMode(mode) - || (!isBackGesture && TransitionUtil.isOpeningMode(mode))) { - notifyHomeVisibilityChanged(gestureToHomeTransition - || TransitionUtil.isOpeningType(mode)); - } + private Boolean getHomeVisibilityUpdate(TransitionInfo info, + TransitionInfo.Change change, ActivityManager.RunningTaskInfo taskInfo) { + final int mode = change.getMode(); + final boolean isBackGesture = change.hasFlags(FLAG_BACK_GESTURE_ANIMATED); + if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) { + final boolean gestureToHomeTransition = isBackGesture + && TransitionUtil.isClosingType(info.getType()); + if (gestureToHomeTransition || TransitionUtil.isClosingMode(mode) + || (!isBackGesture && TransitionUtil.isOpeningMode(mode))) { + return gestureToHomeTransition || TransitionUtil.isOpeningType(mode); } } + return null; } @Override diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java index 6f28e656d060d..3099b0f5cf66e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java @@ -17,36 +17,44 @@ package com.android.wm.shell.transition; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION; import static android.view.WindowManager.TRANSIT_TO_BACK; +import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP; +import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.WindowConfiguration.ActivityType; import android.content.Context; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.platform.test.annotations.EnableFlags; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionInfo.TransitionMode; +import android.window.WindowContainerToken; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.wm.shell.Flags; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestShellExecutor; @@ -187,6 +195,72 @@ public class HomeTransitionObserverTest extends ShellTestCase { verify(mListener, times(0)).onHomeVisibilityChanged(anyBoolean()); } + @Test + @EnableFlags({Flags.FLAG_ENABLE_BUBBLE_TO_FULLSCREEN, Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE}) + public void testDragTaskToBubbleOverHome_notifiesHomeIsVisible() throws RemoteException { + ActivityManager.RunningTaskInfo homeTask = createTaskInfo(1, ACTIVITY_TYPE_HOME); + ActivityManager.RunningTaskInfo bubbleTask = createTaskInfo(2, ACTIVITY_TYPE_STANDARD); + + TransitionInfo startDragTransition = + new TransitionInfoBuilder(TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP) + .addChange(TRANSIT_TO_FRONT, homeTask) + .addChange(TRANSIT_TO_BACK, bubbleTask) + .build(); + + // Start drag to desktop which brings home to front + mHomeTransitionObserver.onTransitionReady(new Binder(), startDragTransition, + MockTransactionPool.create(), MockTransactionPool.create()); + // Does not notify home visibility yet + verify(mListener, never()).onHomeVisibilityChanged(anyBoolean()); + + TransitionInfo convertToBubbleTransition = + new TransitionInfoBuilder(TRANSIT_CONVERT_TO_BUBBLE) + .addChange(TRANSIT_TO_FRONT, bubbleTask) + .build(); + + // Convert to bubble. Transition does not include changes for home task + mHomeTransitionObserver.onTransitionReady(new Binder(), convertToBubbleTransition, + MockTransactionPool.create(), MockTransactionPool.create()); + + // Notifies home visibility change that was pending from the start of drag + verify(mListener).onHomeVisibilityChanged(true); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_BUBBLE_TO_FULLSCREEN, Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE}) + public void testDragTaskToBubbleOverOtherTask_notifiesHomeIsNotVisible() + throws RemoteException { + ActivityManager.RunningTaskInfo homeTask = createTaskInfo(1, ACTIVITY_TYPE_HOME); + ActivityManager.RunningTaskInfo bubbleTask = createTaskInfo(2, ACTIVITY_TYPE_STANDARD); + ActivityManager.RunningTaskInfo otherTask = createTaskInfo(3, ACTIVITY_TYPE_STANDARD); + + TransitionInfo startDragTransition = + new TransitionInfoBuilder(TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP) + .addChange(TRANSIT_TO_FRONT, homeTask) + .addChange(TRANSIT_TO_BACK, bubbleTask) + .build(); + + // Start drag to desktop which brings home to front + mHomeTransitionObserver.onTransitionReady(new Binder(), startDragTransition, + MockTransactionPool.create(), MockTransactionPool.create()); + // Does not notify home visibility yet + verify(mListener, never()).onHomeVisibilityChanged(anyBoolean()); + + TransitionInfo convertToBubbleTransition = + new TransitionInfoBuilder(TRANSIT_CONVERT_TO_BUBBLE) + .addChange(TRANSIT_TO_FRONT, bubbleTask) + .addChange(TRANSIT_TO_FRONT, otherTask) + .addChange(TRANSIT_TO_BACK, homeTask) + .build(); + + // Convert to bubble. Transition includes home task to back which updates home visibility + mHomeTransitionObserver.onTransitionReady(new Binder(), convertToBubbleTransition, + MockTransactionPool.create(), MockTransactionPool.create()); + + // Notifies home visibility change due to home moving to back in the second transition + verify(mListener).onHomeVisibilityChanged(false); + } + @Test public void testHomeActivityWithBackGestureNotifiesHomeIsVisibleAfterClose() throws RemoteException { @@ -227,4 +301,14 @@ public class HomeTransitionObserverTest extends ShellTestCase { when(change.getMode()).thenReturn(mode); taskInfo.isRunning = isRunning; } + + private static ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int activityType) { + ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); + taskInfo.taskId = taskId; + taskInfo.topActivityType = activityType; + taskInfo.configuration.windowConfiguration.setActivityType(activityType); + taskInfo.token = mock(WindowContainerToken.class); + taskInfo.isRunning = true; + return taskInfo; + } } -- GitLab From 567e8a795366388863a8e0d72412c110de9aa141 Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Fri, 7 Feb 2025 14:22:02 -0800 Subject: [PATCH 021/111] Use BubbleTaskViewListener for floating bubbles (behind a flag) Flag: com.android.wm.shell.enable_bubble_task_view_listener Test: manual - enable the flag and use floating bubbles, try basic interactions - expand, switch, dismiss, hit back Bug: 272102927 Change-Id: Ide2298ce36c91eabb8603354ebe874a932ec1b82 --- .../wm/shell/bubbles/BubbleExpandedView.java | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 3f607a9c52ef3..f9fef9b45c398 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -197,6 +197,8 @@ public class BubbleExpandedView extends LinearLayout { */ private final FrameLayout mExpandedViewContainer = new FrameLayout(getContext()); + private TaskView.Listener mCurrentTaskViewListener; + private final TaskView.Listener mTaskViewListener = new TaskView.Listener() { private boolean mInitialized = false; private boolean mDestroyed = false; @@ -453,7 +455,34 @@ public class BubbleExpandedView extends LinearLayout { mTaskView = bubbleTaskView.getTaskView(); // reset the insets that might left after TaskView is shown in BubbleBarExpandedView mTaskView.setCaptionInsets(null); - bubbleTaskView.setDelegateListener(mTaskViewListener); + if (Flags.enableBubbleTaskViewListener()) { + mCurrentTaskViewListener = new BubbleTaskViewListener(mContext, bubbleTaskView, + /* viewParent= */ this, expandedViewManager, + new BubbleTaskViewListener.Callback() { + @Override + public void onTaskCreated() { + setContentVisibility(true); + } + + @Override + public void onContentVisibilityChanged(boolean visible) { + setContentVisibility(visible); + } + + @Override + public void onBackPressed() { + mStackView.onBackPressed(); + } + + @Override + public void onTaskRemovalStarted() { + // nothing to do / handled in listener. + } + }); + } else { + mCurrentTaskViewListener = mTaskViewListener; + bubbleTaskView.setDelegateListener(mCurrentTaskViewListener); + } // set a fixed width so it is not recalculated as part of a rotation. the width will be // updated manually after the rotation. @@ -464,9 +493,12 @@ public class BubbleExpandedView extends LinearLayout { } mExpandedViewContainer.addView(mTaskView, lp); bringChildToFront(mTaskView); - if (bubbleTaskView.isCreated()) { - mTaskViewListener.onTaskCreated( - bubbleTaskView.getTaskId(), bubbleTaskView.getComponentName()); + + if (!Flags.enableBubbleTaskViewListener()) { + if (bubbleTaskView.isCreated()) { + mCurrentTaskViewListener.onTaskCreated( + bubbleTaskView.getTaskId(), bubbleTaskView.getComponentName()); + } } } } @@ -897,7 +929,12 @@ public class BubbleExpandedView extends LinearLayout { Log.w(TAG, "Stack is null for bubble: " + bubble); return; } - boolean isNew = mBubble == null || didBackingContentChange(bubble); + boolean isNew; + if (mCurrentTaskViewListener instanceof BubbleTaskViewListener) { + isNew = ((BubbleTaskViewListener) mCurrentTaskViewListener).setBubble(bubble); + } else { + isNew = mBubble == null || didBackingContentChange(bubble); + } boolean isUpdate = bubble != null && mBubble != null && bubble.getKey().equals(mBubble.getKey()); ProtoLog.d(WM_SHELL_BUBBLES, "BubbleExpandedView - update bubble=%s; isNew=%b; isUpdate=%b", -- GitLab From 7918518f4ee449249db1c13f850e0fb42e3f3269 Mon Sep 17 00:00:00 2001 From: Ben Lin Date: Fri, 14 Feb 2025 16:03:25 -0800 Subject: [PATCH 022/111] Add `enable_projected_display_desktop_mode` flag. Bug: 384568161 Change-Id: I48325a1d51228b29785977edd7da9fd44ff1fe14 Test: m Flag: com.android.window.flags.enable_projected_display_desktop_mode --- .../android/window/flags/lse_desktop_experience.aconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 8265d2523d6f1..96fb001211a48 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -778,3 +778,10 @@ flag { description: "Show recent apps in the taskbar overflow." bug: "368119679" } + +flag { + name: "enable_projected_display_desktop_mode" + namespace: "lse_desktop_experience" + description: "Enable Desktop Mode on Projected Mode devices but constrained to the external display." + bug: "384568161" +} \ No newline at end of file -- GitLab From 9b9999a025017f2b8d02b5719fdd8fcc464bf31e Mon Sep 17 00:00:00 2001 From: Chandru S Date: Thu, 20 Feb 2025 04:55:39 +0000 Subject: [PATCH 023/111] Fix race condition between app launch animation and shade expansion Whenever an app is launched from shade, ActivityTransitionAnimator#onTransitionAnimationStart sets blursDisabledForAppLaunch to true This is reset to false when ActivityTransitionAnimator#onTransitionAnimationEnd is invoked. When ActivityTransitionAnimator#onTransitionAnimationEnd is invoked before shadeExpansion becomes 0, a non-zero blur radius is computed and applied, this causes a one frame flicker when we launch an app from shade on an unlocked device. Flag: com.android.systemui.bouncer_ui_revamp Test: verified manually Bug: 396054791 Change-Id: I35e33fc0200e9cd176fc9c622e826dd8765d2e2e --- .../NotificationShadeDepthController.kt | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index 6aa2fe29e768b..3db004848d221 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -110,6 +110,10 @@ constructor( private var prevTimestamp: Long = -1 private var prevShadeDirection = 0 private var prevShadeVelocity = 0f + // tracks whether app launch transition is in progress. This involves two independent factors + // that control blur, shade expansion and app launch animation from outside sysui. + // They can complete out of order, this flag will be reset by the animation that finishes later. + private var appLaunchTransitionIsInProgress = false // Only for dumpsys private var lastAppliedBlur = 0 @@ -158,6 +162,18 @@ constructor( if (field == value) { return } + // Set this to true now, this will be reset when the next shade expansion finishes or + // when the app launch finishes, whichever happens later. + if (value) { + appLaunchTransitionIsInProgress = true + } else { + // App was launching and now it has finished launching + if (shadeExpansion == 0.0f) { + // this means shade expansion finished before app launch was done. + // reset the flag here + appLaunchTransitionIsInProgress = false + } + } field = value scheduleUpdate() @@ -172,6 +188,12 @@ constructor( shadeAnimation.animateTo(0) shadeAnimation.finishIfRunning() } + @Deprecated( + message = + "This might get reset to false before shade expansion is fully done, " + + "consider using areBlursDisabledForAppLaunch" + ) + get() = field private var zoomOutCalculatedFromShadeRadius: Float = 0.0f @@ -183,6 +205,11 @@ constructor( scheduleUpdate() } + private val areBlursDisabledForAppLaunch: Boolean + get() = + blursDisabledForAppLaunch || + (Flags.bouncerUiRevamp() && appLaunchTransitionIsInProgress) + /** Force stop blur effect when necessary. */ private var scrimsVisible: Boolean = false set(value) { @@ -221,7 +248,7 @@ constructor( combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress)) var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius) - if (blursDisabledForAppLaunch || blursDisabledForUnlock) { + if (areBlursDisabledForAppLaunch || blursDisabledForUnlock) { shadeRadius = 0f } @@ -259,7 +286,7 @@ constructor( private val shouldBlurBeOpaque: Boolean get() = if (Flags.notificationShadeBlur()) false - else scrimsVisible && !blursDisabledForAppLaunch + else scrimsVisible && !areBlursDisabledForAppLaunch /** Callback that updates the window blur value and is called only once per frame. */ @VisibleForTesting @@ -442,6 +469,13 @@ constructor( val shadeDirection = sign(diff).toInt() val shadeVelocity = MathUtils.constrain(VELOCITY_SCALE * diff / deltaTime, MIN_VELOCITY, MAX_VELOCITY) + if (expansion == 0.0f && appLaunchTransitionIsInProgress && !blursDisabledForAppLaunch) { + // Shade expansion finished but the app launch is already done, then this should mark + // the transition as done. + Log.d(TAG, "appLaunchTransitionIsInProgress is now false from shade expansion event") + appLaunchTransitionIsInProgress = false + } + updateShadeAnimationBlur(expansion, tracking, shadeVelocity, shadeDirection) prevShadeDirection = shadeDirection @@ -553,6 +587,7 @@ constructor( it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}") it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius") it.println("blursDisabledForAppLaunch: $blursDisabledForAppLaunch") + it.println("appLaunchTransitionIsInProgress: $appLaunchTransitionIsInProgress") it.println("qsPanelExpansion: $qsPanelExpansion") it.println("transitionToFullShadeProgress: $transitionToFullShadeProgress") it.println("lastAppliedBlur: $lastAppliedBlur") -- GitLab From 8951b6a57ed5279c1dd9ba57d1d8cb7c85c61a8d Mon Sep 17 00:00:00 2001 From: amehfooz Date: Thu, 20 Feb 2025 05:42:42 +0000 Subject: [PATCH 024/111] [SB][Chips] Update OngoingActivityChipsViewModelTest This CL updats OngoingActivityChipsViewModelTest to use helper methods to make the tests pass when StatusBarChipsModernization is enabled. Bug: 372657935 Flag: com.android.systemui.status_bar_chips_modernization Test: atest OngoingActivityChipsViewModelTest Change-Id: Ic4b8803f7d682256f638e39300fa3126176080c6 --- .../OngoingActivityChipsViewModelTest.kt | 75 ++++++++----------- 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt index 626dcd5b0864d..719924c865fd9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt @@ -22,15 +22,18 @@ import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon -import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.mediaprojection.data.model.MediaProjectionState import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask @@ -48,16 +51,13 @@ import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization -import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository -import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel -import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel +import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.addOngoingCallState +import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.removeOngoingCallState import com.android.systemui.testKosmos import com.android.systemui.util.time.fakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.test.runCurrent -import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -72,15 +72,14 @@ import org.mockito.kotlin.whenever /** Tests for [OngoingActivityChipsViewModel] when the [StatusBarNotifChips] flag is disabled. */ @SmallTest @RunWith(AndroidJUnit4::class) +@EnableFlags(StatusBarChipsModernization.FLAG_NAME) @DisableFlags(StatusBarNotifChips.FLAG_NAME) class OngoingActivityChipsViewModelTest : SysuiTestCase() { - private val kosmos = testKosmos() - private val testScope = kosmos.testScope + private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val systemClock = kosmos.fakeSystemClock private val screenRecordState = kosmos.screenRecordRepository.screenRecordState private val mediaProjectionState = kosmos.fakeMediaProjectionRepository.mediaProjectionState - private val callRepo = kosmos.ongoingCallRepository private val mockSystemUIDialog = mock() private val chipBackgroundView = mock() @@ -96,7 +95,7 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { private val mockExpandable: Expandable = mock().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) } - private val underTest = kosmos.ongoingActivityChipsViewModel + private val Kosmos.underTest by Kosmos.Fixture { ongoingActivityChipsViewModel } @Before fun setUp() { @@ -111,10 +110,10 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_allHidden_hidden() = - testScope.runTest { + kosmos.runTest { screenRecordState.value = ScreenRecordModel.DoingNothing mediaProjectionState.value = MediaProjectionState.NotProjecting - callRepo.setOngoingCallState(OngoingCallModel.NoCall) + removeOngoingCallState("testKey") val latest by collectLastValue(underTest.primaryChip) @@ -123,10 +122,10 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_screenRecordShow_restHidden_screenRecordShown() = - testScope.runTest { + kosmos.runTest { screenRecordState.value = ScreenRecordModel.Recording mediaProjectionState.value = MediaProjectionState.NotProjecting - callRepo.setOngoingCallState(OngoingCallModel.NoCall) + removeOngoingCallState("testKey") val latest by collectLastValue(underTest.primaryChip) @@ -135,10 +134,10 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_screenRecordShowAndCallShow_screenRecordShown() = - testScope.runTest { + kosmos.runTest { screenRecordState.value = ScreenRecordModel.Recording - callRepo.setOngoingCallState(inCallModel(startTimeMs = 34)) + addOngoingCallState() val latest by collectLastValue(underTest.primaryChip) @@ -147,11 +146,11 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_screenRecordShowAndShareToAppShow_screenRecordShown() = - testScope.runTest { + kosmos.runTest { screenRecordState.value = ScreenRecordModel.Recording mediaProjectionState.value = MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE) - callRepo.setOngoingCallState(OngoingCallModel.NoCall) + removeOngoingCallState("testKey") val latest by collectLastValue(underTest.primaryChip) @@ -160,11 +159,11 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_shareToAppShowAndCallShow_shareToAppShown() = - testScope.runTest { + kosmos.runTest { screenRecordState.value = ScreenRecordModel.DoingNothing mediaProjectionState.value = MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE) - callRepo.setOngoingCallState(inCallModel(startTimeMs = 34)) + addOngoingCallState() val latest by collectLastValue(underTest.primaryChip) @@ -173,15 +172,13 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_screenRecordAndShareToAppAndCastToOtherHideAndCallShown_callShown() = - testScope.runTest { + kosmos.runTest { val notificationKey = "call" screenRecordState.value = ScreenRecordModel.DoingNothing // MediaProjection covers both share-to-app and cast-to-other-device mediaProjectionState.value = MediaProjectionState.NotProjecting - callRepo.setOngoingCallState( - inCallModel(startTimeMs = 34, notificationKey = notificationKey) - ) + addOngoingCallState(key = notificationKey) val latest by collectLastValue(underTest.primaryChip) @@ -190,12 +187,10 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_higherPriorityChipAdded_lowerPriorityChipReplaced() = - testScope.runTest { + kosmos.runTest { // Start with just the lowest priority chip shown val callNotificationKey = "call" - callRepo.setOngoingCallState( - inCallModel(startTimeMs = 34, notificationKey = callNotificationKey) - ) + addOngoingCallState(key = callNotificationKey) // And everything else hidden mediaProjectionState.value = MediaProjectionState.NotProjecting screenRecordState.value = ScreenRecordModel.DoingNothing @@ -224,15 +219,13 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_highestPriorityChipRemoved_showsNextPriorityChip() = - testScope.runTest { + kosmos.runTest { // WHEN all chips are active screenRecordState.value = ScreenRecordModel.Recording mediaProjectionState.value = MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE) val callNotificationKey = "call" - callRepo.setOngoingCallState( - inCallModel(startTimeMs = 34, notificationKey = callNotificationKey) - ) + addOngoingCallState(key = callNotificationKey) val latest by collectLastValue(underTest.primaryChip) @@ -255,17 +248,15 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { /** Regression test for b/347726238. */ @Test fun primaryChip_timerDoesNotResetAfterSubscribersRestart() = - testScope.runTest { + kosmos.runTest { var latest: OngoingActivityChipModel? = null - val job1 = underTest.primaryChip.onEach { latest = it }.launchIn(this) + val job1 = underTest.primaryChip.onEach { latest = it }.launchIn(kosmos.testScope) // Start a chip with a timer systemClock.setElapsedRealtime(1234) screenRecordState.value = ScreenRecordModel.Recording - runCurrent() - assertThat((latest as OngoingActivityChipModel.Active.Timer).startTimeMs) .isEqualTo(1234) @@ -276,9 +267,7 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { systemClock.setElapsedRealtime(5678) // WHEN we re-subscribe to the chip flow - val job2 = underTest.primaryChip.onEach { latest = it }.launchIn(this) - - runCurrent() + val job2 = underTest.primaryChip.onEach { latest = it }.launchIn(kosmos.testScope) // THEN the old start time is still used assertThat((latest as OngoingActivityChipModel.Active.Timer).startTimeMs) @@ -289,14 +278,14 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_screenRecordStoppedViaDialog_chipHiddenWithoutAnimation() = - testScope.runTest { + kosmos.runTest { screenRecordState.value = ScreenRecordModel.Recording mediaProjectionState.value = MediaProjectionState.Projecting.EntireScreen( NORMAL_PACKAGE, hostDeviceName = "Recording Display", ) - callRepo.setOngoingCallState(OngoingCallModel.NoCall) + removeOngoingCallState("testKey") val latest by collectLastValue(underTest.primaryChip) @@ -319,11 +308,11 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { @Test fun primaryChip_projectionStoppedViaDialog_chipHiddenWithoutAnimation() = - testScope.runTest { + kosmos.runTest { mediaProjectionState.value = MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE) screenRecordState.value = ScreenRecordModel.DoingNothing - callRepo.setOngoingCallState(OngoingCallModel.NoCall) + removeOngoingCallState("testKey") val latest by collectLastValue(underTest.primaryChip) -- GitLab From 6b2953431f644bb3114e843926b9c97652c84fc7 Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Tue, 11 Feb 2025 17:18:27 +0800 Subject: [PATCH 025/111] Clean up move_animation_options_to_change Bug: 327332488 Test: presubmit Flag: EXEMPT remove flag Change-Id: I2b4d8c93be50bf013e1863f1b95507013973d24e --- .../java/android/window/TransitionFilter.java | 6 +- core/java/android/window/TransitionInfo.java | 38 ---------- .../window/flags/windowing_sdk.aconfig | 10 --- .../extensions/embedding/SplitPresenter.java | 3 +- .../ActivityEmbeddingAnimationRunner.java | 14 ++-- .../ActivityEmbeddingAnimationSpec.java | 44 +++++------- .../ActivityEmbeddingController.java | 4 -- .../shell/transition/DefaultMixedHandler.java | 4 -- .../transition/DefaultTransitionHandler.java | 16 +---- .../transition/TransitionAnimationHelper.java | 18 +---- ...ActivityEmbeddingAnimationRunnerTests.java | 53 -------------- .../ActivityEmbeddingControllerTests.java | 34 --------- .../com/android/server/wm/Transition.java | 70 ++++++++----------- .../android/server/wm/TransitionTests.java | 24 ------- 14 files changed, 62 insertions(+), 276 deletions(-) diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java index 61fc6226f822e..d8d20119a6023 100644 --- a/core/java/android/window/TransitionFilter.java +++ b/core/java/android/window/TransitionFilter.java @@ -31,8 +31,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.view.WindowManager; -import com.android.window.flags.Flags; - /** * A parcelable filter that can be used for rerouting transitions to a remote. This is a local * representation so that the transition system doesn't need to make blocking queries over @@ -261,9 +259,7 @@ public final class TransitionFilter implements Parcelable { // only applies to activity/task && (change.getTaskInfo() != null || change.getActivityComponent() != null)) { - final TransitionInfo.AnimationOptions opts = - Flags.moveAnimationOptionsToChange() ? change.getAnimationOptions() - : info.getAnimationOptions(); + final TransitionInfo.AnimationOptions opts = change.getAnimationOptions(); if (opts != null) { boolean canActuallyOverride = change.getTaskInfo() == null || opts.getOverrideTaskTransition(); diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 4f34aa36a2043..32175f122d611 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -57,8 +57,6 @@ import android.view.Surface; import android.view.SurfaceControl; import android.view.WindowManager; -import com.android.window.flags.Flags; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -220,10 +218,6 @@ public final class TransitionInfo implements Parcelable { private final ArrayList mChanges = new ArrayList<>(); private final ArrayList mRoots = new ArrayList<>(); - // TODO(b/327332488): Clean-up usages after the flag is fully enabled. - @Deprecated - private AnimationOptions mOptions; - /** This is only a BEST-EFFORT id used for log correlation. DO NOT USE for any real work! */ private int mDebugId = -1; @@ -238,7 +232,6 @@ public final class TransitionInfo implements Parcelable { mFlags = in.readInt(); in.readTypedList(mChanges, Change.CREATOR); in.readTypedList(mRoots, Root.CREATOR); - mOptions = in.readTypedObject(AnimationOptions.CREATOR); mDebugId = in.readInt(); mTrack = in.readInt(); } @@ -250,7 +243,6 @@ public final class TransitionInfo implements Parcelable { dest.writeInt(mFlags); dest.writeTypedList(mChanges); dest.writeTypedList(mRoots, flags); - dest.writeTypedObject(mOptions, flags); dest.writeInt(mDebugId); dest.writeInt(mTrack); } @@ -286,18 +278,6 @@ public final class TransitionInfo implements Parcelable { mRoots.add(other); } - /** - * @deprecated Set {@link AnimationOptions} to change. This method is only used if - * {@link Flags#FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE} is disabled. - */ - @Deprecated - public void setAnimationOptions(@Nullable AnimationOptions options) { - if (Flags.moveAnimationOptionsToChange()) { - return; - } - mOptions = options; - } - public @TransitionType int getType() { return mType; } @@ -359,16 +339,6 @@ public final class TransitionInfo implements Parcelable { return mRoots.get(0).mLeash; } - /** - * @deprecated Use {@link Change#getAnimationOptions()} instead. This method is called only - * if {@link Flags#FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE} is disabled. - */ - @Deprecated - @Nullable - public AnimationOptions getAnimationOptions() { - return mOptions; - } - /** * @return the list of {@link Change}s in this transition. The list is sorted top-to-bottom * in Z (meaning index 0 is the top-most container). @@ -455,9 +425,6 @@ public final class TransitionInfo implements Parcelable { StringBuilder sb = new StringBuilder(); sb.append("{id=").append(mDebugId).append(" t=").append(transitTypeToString(mType)) .append(" f=0x").append(Integer.toHexString(mFlags)).append(" trk=").append(mTrack); - if (mOptions != null) { - sb.append(" opt=").append(mOptions); - } sb.append(" r=["); for (int i = 0; i < mRoots.size(); ++i) { if (i > 0) { @@ -656,8 +623,6 @@ public final class TransitionInfo implements Parcelable { for (int i = 0; i < mRoots.size(); ++i) { out.mRoots.add(mRoots.get(i).localRemoteCopy()); } - // Doesn't have any native stuff, so no need for actual copy - out.mOptions = mOptions; return out; } @@ -860,9 +825,6 @@ public final class TransitionInfo implements Parcelable { * Sets {@link AnimationOptions} to override animation. */ public void setAnimationOptions(@Nullable AnimationOptions options) { - if (!Flags.moveAnimationOptionsToChange()) { - return; - } mAnimationOptions = options; } diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index 54d0eeffc9bbc..6e45d3dc659fc 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -60,16 +60,6 @@ flag { bug: "293658614" } -flag { - namespace: "windowing_sdk" - name: "move_animation_options_to_change" - description: "Move AnimationOptions from TransitionInfo to each Change" - bug: "327332488" - metadata { - purpose: PURPOSE_BUGFIX - } -} - flag { namespace: "windowing_sdk" name: "rear_display_disable_force_desktop_system_decorations" diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index eb59d6efdeff5..7ab9e2e65b76c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -705,8 +705,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { } private static boolean isOverlayTransitionSupported() { - return Flags.moveAnimationOptionsToChange() - && Flags.activityEmbeddingOverlayPresentationFlag(); + return Flags.activityEmbeddingOverlayPresentationFlag(); } @NonNull diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java index f269b3831aab3..78f5154c0ecb1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java @@ -364,7 +364,7 @@ class ActivityEmbeddingAnimationRunner { @NonNull SurfaceControl.Transaction finishTransaction, @NonNull List adapters) { for (ActivityEmbeddingAnimationAdapter adapter : adapters) { - final int backgroundColor = getTransitionBackgroundColorIfSet(info, adapter.mChange, + final int backgroundColor = getTransitionBackgroundColorIfSet(adapter.mChange, adapter.mAnimation, 0 /* defaultColor */); if (backgroundColor != 0) { // We only need to show one color. @@ -436,8 +436,8 @@ class ActivityEmbeddingAnimationRunner { final TransitionInfo.AnimationOptions options = boundsAnimationChange .getAnimationOptions(); if (options != null) { - final Animation overrideAnimation = mAnimationSpec.loadCustomAnimationFromOptions( - options, TRANSIT_CHANGE); + final Animation overrideAnimation = + mAnimationSpec.loadCustomAnimation(options, TRANSIT_CHANGE); if (overrideAnimation != null) { overrideShowBackdrop = overrideAnimation.getShowBackdrop(); } @@ -447,7 +447,7 @@ class ActivityEmbeddingAnimationRunner { // There are two animations in the array. The first one is for the start leash // (snapshot), and the second one is for the end leash (TaskFragment). final Animation[] animations = - mAnimationSpec.createChangeBoundsChangeAnimations(info, change, parentBounds); + mAnimationSpec.createChangeBoundsChangeAnimations(change, parentBounds); // Jump cut if either animation has zero for duration. for (Animation animation : animations) { if (shouldUseJumpCutForAnimation(animation)) { @@ -500,12 +500,10 @@ class ActivityEmbeddingAnimationRunner { // window without bounds change. animation = ActivityEmbeddingAnimationSpec.createNoopAnimation(change); } else if (TransitionUtil.isClosingType(change.getMode())) { - animation = - mAnimationSpec.createChangeBoundsCloseAnimation(info, change, parentBounds); + animation = mAnimationSpec.createChangeBoundsCloseAnimation(change, parentBounds); shouldShowBackgroundColor = false; } else { - animation = - mAnimationSpec.createChangeBoundsOpenAnimation(info, change, parentBounds); + animation = mAnimationSpec.createChangeBoundsOpenAnimation(change, parentBounds); shouldShowBackgroundColor = false; } if (shouldUseJumpCutForAnimation(animation)) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java index 77799e99607b9..2b9eda40cdbbc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java @@ -42,7 +42,6 @@ import android.view.animation.TranslateAnimation; import android.window.TransitionInfo; import com.android.internal.policy.TransitionAnimation; -import com.android.window.flags.Flags; import com.android.wm.shell.shared.TransitionUtil; /** Animation spec for ActivityEmbedding transition. */ @@ -94,9 +93,10 @@ class ActivityEmbeddingAnimationSpec { /** Animation for window that is opening in a change transition. */ @NonNull - Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo info, - @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) { - final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE); + Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo.Change change, + @NonNull Rect parentBounds) { + final Animation customAnimation = + loadCustomAnimation(change.getAnimationOptions(), TRANSIT_CHANGE); if (customAnimation != null) { return customAnimation; } @@ -126,9 +126,10 @@ class ActivityEmbeddingAnimationSpec { /** Animation for window that is closing in a change transition. */ @NonNull - Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo info, - @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) { - final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE); + Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo.Change change, + @NonNull Rect parentBounds) { + final Animation customAnimation = + loadCustomAnimation(change.getAnimationOptions(), TRANSIT_CHANGE); if (customAnimation != null) { return customAnimation; } @@ -162,12 +163,13 @@ class ActivityEmbeddingAnimationSpec { * the second one is for the end leash. */ @NonNull - Animation[] createChangeBoundsChangeAnimations(@NonNull TransitionInfo info, - @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) { + Animation[] createChangeBoundsChangeAnimations(@NonNull TransitionInfo.Change change, + @NonNull Rect parentBounds) { // TODO(b/293658614): Support more complicated animations that may need more than a noop // animation as the start leash. final Animation noopAnimation = createNoopAnimation(change); - final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE); + final Animation customAnimation = + loadCustomAnimation(change.getAnimationOptions(), TRANSIT_CHANGE); if (customAnimation != null) { return new Animation[]{noopAnimation, customAnimation}; } @@ -221,7 +223,8 @@ class ActivityEmbeddingAnimationSpec { Animation loadOpenAnimation(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = TransitionUtil.isOpeningType(change.getMode()); - final Animation customAnimation = loadCustomAnimation(info, change, change.getMode()); + final Animation customAnimation = + loadCustomAnimation(change.getAnimationOptions(), change.getMode()); final Animation animation; if (customAnimation != null) { animation = customAnimation; @@ -248,7 +251,8 @@ class ActivityEmbeddingAnimationSpec { Animation loadCloseAnimation(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = TransitionUtil.isOpeningType(change.getMode()); - final Animation customAnimation = loadCustomAnimation(info, change, change.getMode()); + final Animation customAnimation = + loadCustomAnimation(change.getAnimationOptions(), change.getMode()); final Animation animation; if (customAnimation != null) { animation = customAnimation; @@ -280,20 +284,8 @@ class ActivityEmbeddingAnimationSpec { } @Nullable - private Animation loadCustomAnimation(@NonNull TransitionInfo info, - @NonNull TransitionInfo.Change change, @WindowManager.TransitionType int mode) { - final TransitionInfo.AnimationOptions options; - if (Flags.moveAnimationOptionsToChange()) { - options = change.getAnimationOptions(); - } else { - options = info.getAnimationOptions(); - } - return loadCustomAnimationFromOptions(options, mode); - } - - @Nullable - Animation loadCustomAnimationFromOptions(@Nullable TransitionInfo.AnimationOptions options, - @WindowManager.TransitionType int mode) { + Animation loadCustomAnimation(@Nullable TransitionInfo.AnimationOptions options, + @WindowManager.TransitionType int mode) { if (options == null || options.getType() != ANIM_CUSTOM) { return null; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java index 55ed5fa4b56f4..3a95333309ac5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java @@ -40,7 +40,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; -import com.android.window.flags.Flags; import com.android.wm.shell.shared.TransitionUtil; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; @@ -123,9 +122,6 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle } private boolean shouldAnimateAnimationOptions(@NonNull TransitionInfo info) { - if (!Flags.moveAnimationOptionsToChange()) { - return shouldAnimateAnimationOptions(info.getAnimationOptions()); - } for (TransitionInfo.Change change : info.getChanges()) { if (!shouldAnimateAnimationOptions(change.getAnimationOptions())) { // If any of override animation is not supported, don't animate the transition. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java index 743bd052995eb..347dcff865299 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java @@ -40,7 +40,6 @@ import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.internal.protolog.ProtoLog; -import com.android.window.flags.Flags; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.activityembedding.ActivityEmbeddingController; import com.android.wm.shell.common.ComponentUtils; @@ -439,9 +438,6 @@ public class DefaultMixedHandler implements MixedTransitionHandler, for (int i = 0; i < info.getRootCount(); ++i) { out.addRoot(info.getRoot(i)); } - if (!Flags.moveAnimationOptionsToChange()) { - out.setAnimationOptions(info.getAnimationOptions()); - } return out; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 01428e60582e3..e9c6adec75d7c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -539,7 +539,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { cornerRadius = 0; } - backgroundColorForTransition = getTransitionBackgroundColorIfSet(info, change, a, + backgroundColorForTransition = getTransitionBackgroundColorIfSet(change, a, backgroundColorForTransition); if (!isTask && a.getExtensionEdges() != 0x0) { @@ -606,12 +606,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { mTransactionPool, mMainExecutor, animRelOffset, cornerRadius, clipRect); - final TransitionInfo.AnimationOptions options; - if (Flags.moveAnimationOptionsToChange()) { - options = change.getAnimationOptions(); - } else { - options = info.getAnimationOptions(); - } + final TransitionInfo.AnimationOptions options = change.getAnimationOptions(); if (options != null) { attachThumbnail(animations, onAnimFinish, change, options, cornerRadius); } @@ -834,12 +829,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { final boolean isOpeningType = TransitionUtil.isOpeningType(type); final boolean enter = TransitionUtil.isOpeningType(changeMode); final boolean isTask = change.getTaskInfo() != null; - final TransitionInfo.AnimationOptions options; - if (Flags.moveAnimationOptionsToChange()) { - options = change.getAnimationOptions(); - } else { - options = info.getAnimationOptions(); - } + final TransitionInfo.AnimationOptions options = change.getAnimationOptions(); final int overrideType = options != null ? options.getType() : ANIM_NONE; final int userId = options != null ? options.getUserId() : UserHandle.USER_CURRENT; final Rect endBounds = TransitionUtil.isClosingType(changeMode) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java index 4feb4753096ec..7984bcedc4e55 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java @@ -58,7 +58,6 @@ import android.window.TransitionInfo; import com.android.internal.R; import com.android.internal.policy.TransitionAnimation; import com.android.internal.protolog.ProtoLog; -import com.android.window.flags.Flags; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.TransitionUtil; @@ -78,12 +77,7 @@ public class TransitionAnimationHelper { final boolean isFreeform = isTask && change.getTaskInfo().isFreeform(); final boolean isCoveredByOpaqueFullscreenChange = isCoveredByOpaqueFullscreenChange(info, change); - final TransitionInfo.AnimationOptions options; - if (Flags.moveAnimationOptionsToChange()) { - options = change.getAnimationOptions(); - } else { - options = info.getAnimationOptions(); - } + final TransitionInfo.AnimationOptions options = change.getAnimationOptions(); final int overrideType = options != null ? options.getType() : ANIM_NONE; int animAttr = 0; boolean translucent = false; @@ -279,16 +273,10 @@ public class TransitionAnimationHelper { * the given transition animation. */ @ColorInt - public static int getTransitionBackgroundColorIfSet(@NonNull TransitionInfo info, - @NonNull TransitionInfo.Change change, @NonNull Animation a, - @ColorInt int defaultColor) { + public static int getTransitionBackgroundColorIfSet(@NonNull TransitionInfo.Change change, + @NonNull Animation a, @ColorInt int defaultColor) { if (!a.getShowBackdrop()) { return defaultColor; - } - if (!Flags.moveAnimationOptionsToChange() && info.getAnimationOptions() != null - && info.getAnimationOptions().getBackgroundColor() != 0) { - // If available use the background color provided through AnimationOptions - return info.getAnimationOptions().getBackgroundColor(); } else if (a.getBackdropColor() != 0) { // Otherwise fallback on the background color provided through the animation // definition. diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java index 94dc774a6737a..d4d8d93abf7d5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java @@ -39,7 +39,6 @@ import android.animation.Animator; import android.annotation.NonNull; import android.graphics.Point; import android.graphics.Rect; -import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; @@ -77,7 +76,6 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim doNothing().when(mController).onAnimationFinished(any()); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testStartAnimation() { final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0) @@ -103,7 +101,6 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim verify(mController).onAnimationFinished(mTransition); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testChangesBehindStartingWindow() { final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0) @@ -118,7 +115,6 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim assertEquals(0, animator.getDuration()); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testTransitionTypeDragResize() { final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TASK_FRAGMENT_DRAG_RESIZE, 0) @@ -133,25 +129,6 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim assertEquals(0, animator.getDuration()); } - @DisableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) - @Test - public void testInvalidCustomAnimation_disableAnimationOptionsPerChange() { - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0) - .addChange(createChange(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY, TRANSIT_OPEN)) - .build(); - info.setAnimationOptions(TransitionInfo.AnimationOptions - .makeCustomAnimOptions("packageName", 0 /* enterResId */, 0 /* exitResId */, - 0 /* backgroundColor */, false /* overrideTaskTransition */)); - final Animator animator = mAnimRunner.createAnimator( - info, mStartTransaction, mFinishTransaction, - () -> mFinishCallback.onTransitionFinished(null /* wct */), - new ArrayList<>()); - - // An invalid custom animation is equivalent to jump-cut. - assertEquals(0, animator.getDuration()); - } - - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testInvalidCustomAnimation_enableAnimationOptionsPerChange() { final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0) @@ -169,36 +146,6 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim assertEquals(0, animator.getDuration()); } - @DisableFlags(Flags.FLAG_ACTIVITY_EMBEDDING_OVERLAY_PRESENTATION_FLAG) - @Test - public void testCalculateParentBounds_flagDisabled() { - final Rect parentBounds = new Rect(0, 0, 2000, 2000); - final Rect primaryBounds = new Rect(); - final Rect secondaryBounds = new Rect(); - parentBounds.splitVertically(primaryBounds, secondaryBounds); - - final TransitionInfo.Change change = createChange(0 /* flags */); - change.setStartAbsBounds(secondaryBounds); - - final TransitionInfo.Change boundsAnimationChange = createChange(0 /* flags */); - boundsAnimationChange.setStartAbsBounds(primaryBounds); - boundsAnimationChange.setEndAbsBounds(primaryBounds); - final Rect actualParentBounds = new Rect(); - - calculateParentBounds(change, boundsAnimationChange, actualParentBounds); - - assertEquals(parentBounds, actualParentBounds); - - actualParentBounds.setEmpty(); - - boundsAnimationChange.setStartAbsBounds(secondaryBounds); - boundsAnimationChange.setEndAbsBounds(primaryBounds); - - calculateParentBounds(boundsAnimationChange, boundsAnimationChange, actualParentBounds); - - assertEquals(parentBounds, actualParentBounds); - } - // TODO(b/243518738): Rewrite with TestParameter @EnableFlags(Flags.FLAG_ACTIVITY_EMBEDDING_OVERLAY_PRESENTATION_FLAG) @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java index 9f29ef71930a9..53a13d0d4ffd7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java @@ -32,8 +32,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Rect; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; import android.view.SurfaceControl; import android.window.TransitionInfo; @@ -41,7 +39,6 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import com.android.window.flags.Flags; import com.android.wm.shell.transition.TransitionInfoBuilder; import org.junit.Before; @@ -69,13 +66,11 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation any()); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testInstantiate() { verify(mShellInit).addInitCallback(any(), any()); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testOnInit() { mController.onInit(); @@ -83,7 +78,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation verify(mTransitions).addHandler(mController); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testSetAnimScaleSetting() { mController.setAnimScaleSetting(1.0f); @@ -92,7 +86,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation verify(mAnimSpec).setAnimScaleSetting(1.0f); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testStartAnimation_containsNonActivityEmbeddingChange() { final TransitionInfo.Change nonEmbeddedOpen = createChange(0 /* flags */); @@ -129,7 +122,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation assertFalse(info2.getChanges().contains(nonEmbeddedClose)); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testStartAnimation_containsOnlyFillTaskActivityEmbeddingChange() { final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0) @@ -146,7 +138,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation verifyNoMoreInteractions(mFinishCallback); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testStartAnimation_containsActivityEmbeddingSplitChange() { // Change that occupies only part of the Task. @@ -164,7 +155,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation verifyNoMoreInteractions(mFinishTransaction); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testStartAnimation_containsChangeEnterActivityEmbeddingSplit() { // Change that is entering ActivityEmbedding split. @@ -181,7 +171,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation verifyNoMoreInteractions(mFinishTransaction); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testStartAnimation_containsChangeExitActivityEmbeddingSplit() { // Change that is exiting ActivityEmbedding split. @@ -198,27 +187,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation verifyNoMoreInteractions(mFinishTransaction); } - @DisableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) - @Test - public void testShouldAnimate_containsAnimationOptions_disableAnimOptionsPerChange() { - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0) - .addChange(createEmbeddedChange(EMBEDDED_RIGHT_BOUNDS, TASK_BOUNDS, TASK_BOUNDS)) - .build(); - - info.setAnimationOptions(TransitionInfo.AnimationOptions - .makeCustomAnimOptions("packageName", 0 /* enterResId */, 0 /* exitResId */, - 0 /* backgroundColor */, false /* overrideTaskTransition */)); - assertTrue(mController.shouldAnimate(info)); - - info.setAnimationOptions(TransitionInfo.AnimationOptions - .makeSceneTransitionAnimOptions()); - assertFalse(mController.shouldAnimate(info)); - - info.setAnimationOptions(TransitionInfo.AnimationOptions.makeCrossProfileAnimOptions()); - assertFalse(mController.shouldAnimate(info)); - } - - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testShouldAnimate_containsAnimationOptions_enableAnimOptionsPerChange() { final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0) @@ -239,7 +207,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation assertFalse(mController.shouldAnimate(info)); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @UiThreadTest @Test public void testMergeAnimation() { @@ -278,7 +245,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation verify(mFinishCallback).onTransitionFinished(any()); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testOnAnimationFinished() { // Should not call finish when there is no transition. diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 5217a759c6ae1..d04135f6c55da 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -2026,23 +2026,18 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (mOverrideOptions == null) { return; } - - if (!Flags.moveAnimationOptionsToChange()) { - info.setAnimationOptions(mOverrideOptions); - } else { - final List changes = info.getChanges(); - for (int i = changes.size() - 1; i >= 0; --i) { - final WindowContainer container = mTargets.get(i).mContainer; - if (container.asActivityRecord() != null - || shouldApplyAnimOptionsToTask(container.asTask())) { - changes.get(i).setAnimationOptions(mOverrideOptions); - // TODO(b/295805497): Extract mBackgroundColor from AnimationOptions. - changes.get(i).setBackgroundColor(mOverrideOptions.getBackgroundColor()); - } else if (shouldApplyAnimOptionsToEmbeddedTf(container.asTaskFragment())) { - // We only override AnimationOptions because backgroundColor should be from - // TaskFragmentAnimationParams. - changes.get(i).setAnimationOptions(mOverrideOptions); - } + final List changes = info.getChanges(); + for (int i = changes.size() - 1; i >= 0; --i) { + final WindowContainer container = mTargets.get(i).mContainer; + if (container.asActivityRecord() != null + || shouldApplyAnimOptionsToTask(container.asTask())) { + changes.get(i).setAnimationOptions(mOverrideOptions); + // TODO(b/295805497): Extract mBackgroundColor from AnimationOptions. + changes.get(i).setBackgroundColor(mOverrideOptions.getBackgroundColor()); + } else if (shouldApplyAnimOptionsToEmbeddedTf(container.asTaskFragment())) { + // We only override AnimationOptions because backgroundColor should be from + // TaskFragmentAnimationParams. + changes.get(i).setAnimationOptions(mOverrideOptions); } } updateActivityTargetForCrossProfileAnimation(info); @@ -2933,9 +2928,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { final AnimationOptions animOptionsForActivityTransition = calculateAnimationOptionsForActivityTransition(type, sortedTargets); - if (!Flags.moveAnimationOptionsToChange() && animOptionsForActivityTransition != null) { - out.setAnimationOptions(animOptionsForActivityTransition); - } final ArraySet occludedAtEndContainers = new ArraySet<>(); // Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order. @@ -3059,28 +3051,26 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } AnimationOptions animOptions = null; - if (Flags.moveAnimationOptionsToChange()) { - if (activityRecord != null && animOptionsForActivityTransition != null) { - animOptions = animOptionsForActivityTransition; - } else if (Flags.activityEmbeddingOverlayPresentationFlag() - && isEmbeddedTaskFragment) { - final TaskFragmentAnimationParams params = taskFragment.getAnimationParams(); - if (params.hasOverrideAnimation()) { - // Only set AnimationOptions if there's any animation override. - // We use separated field for backgroundColor, and - // AnimationOptions#backgroundColor will be removed in long term. - animOptions = AnimationOptions.makeCustomAnimOptions( - taskFragment.getTask().getBasePackageName(), - params.getOpenAnimationResId(), params.getChangeAnimationResId(), - params.getCloseAnimationResId(), 0 /* backgroundColor */, - false /* overrideTaskTransition */); - animOptions.setUserId(taskFragment.getTask().mUserId); - } - } - if (animOptions != null) { - change.setAnimationOptions(animOptions); + if (activityRecord != null && animOptionsForActivityTransition != null) { + animOptions = animOptionsForActivityTransition; + } else if (Flags.activityEmbeddingOverlayPresentationFlag() + && isEmbeddedTaskFragment) { + final TaskFragmentAnimationParams params = taskFragment.getAnimationParams(); + if (params.hasOverrideAnimation()) { + // Only set AnimationOptions if there's any animation override. + // We use separated field for backgroundColor, and + // AnimationOptions#backgroundColor will be removed in long term. + animOptions = AnimationOptions.makeCustomAnimOptions( + taskFragment.getTask().getBasePackageName(), + params.getOpenAnimationResId(), params.getChangeAnimationResId(), + params.getCloseAnimationResId(), 0 /* backgroundColor */, + false /* overrideTaskTransition */); + animOptions.setUserId(taskFragment.getTask().mUserId); } } + if (animOptions != null) { + change.setAnimationOptions(animOptions); + } if (activityRecord != null) { change.setActivityComponent(activityRecord.mActivityComponent); diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 2ee34d3a4b366..b9f88cd73e9dc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -82,8 +82,6 @@ import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; import android.util.ArraySet; @@ -104,7 +102,6 @@ import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import com.android.internal.graphics.ColorUtils; -import com.android.window.flags.Flags; import org.junit.Test; import org.junit.runner.RunWith; @@ -2009,21 +2006,6 @@ public class TransitionTests extends WindowTestsBase { assertEquals(expectedBackgroundColor, info.getChanges().get(1).getBackgroundColor()); } - @DisableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) - @Test - public void testOverrideAnimationOptionsToInfoIfNecessary_disableAnimOptionsPerChange() { - ActivityRecord r = initializeOverrideAnimationOptionsTest(); - TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions - .makeCommonAnimOptions("testPackage"); - mTransition.setOverrideAnimation(options, r, null /* startCallback */, - null /* finishCallback */); - - mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo); - - assertEquals(options, mInfo.getAnimationOptions()); - } - - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testOverrideAnimationOptionsToInfoIfNecessary_fromStyleAnimOptions() { ActivityRecord r = initializeOverrideAnimationOptionsTest(); @@ -2049,7 +2031,6 @@ public class TransitionTests extends WindowTestsBase { options, activityChange.getAnimationOptions()); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testOverrideAnimationOptionsToInfoIfNecessary_sceneAnimOptions() { ActivityRecord r = initializeOverrideAnimationOptionsTest(); @@ -2075,7 +2056,6 @@ public class TransitionTests extends WindowTestsBase { options, activityChange.getAnimationOptions()); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testOverrideAnimationOptionsToInfoIfNecessary_crossProfileAnimOptions() { ActivityRecord r = initializeOverrideAnimationOptionsTest(); @@ -2103,7 +2083,6 @@ public class TransitionTests extends WindowTestsBase { assertTrue(activityChange.hasFlags(FLAG_CROSS_PROFILE_OWNER_THUMBNAIL)); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testOverrideAnimationOptionsToInfoIfNecessary_customAnimOptions() { ActivityRecord r = initializeOverrideAnimationOptionsTest(); @@ -2136,7 +2115,6 @@ public class TransitionTests extends WindowTestsBase { options.getBackgroundColor(), activityChange.getBackgroundColor()); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testOverrideAnimationOptionsToInfoIfNecessary_haveTaskFragmentAnimParams() { ActivityRecord r = initializeOverrideAnimationOptionsTest(); @@ -2185,7 +2163,6 @@ public class TransitionTests extends WindowTestsBase { options.getBackgroundColor(), activityChange.getBackgroundColor()); } - @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE) @Test public void testOverrideAnimationOptionsToInfoIfNecessary_customAnimOptionsWithTaskOverride() { ActivityRecord r = initializeOverrideAnimationOptionsTest(); @@ -2415,7 +2392,6 @@ public class TransitionTests extends WindowTestsBase { } @Test - @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS) public void testMoveDisplayToTop() { // Set up two displays, each of which has a task. DisplayContent otherDisplay = createNewDisplay(); -- GitLab From 11f10d71be9179627e7b75f4045c9fa7b7cedccb Mon Sep 17 00:00:00 2001 From: Ze Li Date: Thu, 20 Feb 2025 15:32:27 +0800 Subject: [PATCH 026/111] [Battery refactor] Move stylus related functions to BluetoothUtils as util functions. Test: com.android.settingslib.bluetooth.BluetoothUtilsTest Bug: 397847825 Flag: EXEMPT utils function Change-Id: I9e7d4d167ce303fb6f4c28851128192948ec0570 --- .../settingslib/bluetooth/BluetoothUtils.java | 51 +++++++++++ .../bluetooth/BluetoothUtilsTest.java | 84 ++++++++++++++++--- 2 files changed, 123 insertions(+), 12 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index 522a436b07320..335f4a8293a02 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -23,6 +23,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.hardware.input.InputManager; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioManager; @@ -34,6 +35,7 @@ import android.sysprop.BluetoothProperties; import android.text.TextUtils; import android.util.Log; import android.util.Pair; +import android.view.InputDevice; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; @@ -1193,4 +1195,53 @@ public class BluetoothUtils { } device.setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, fastPairCustomizedMeta.getBytes()); } + + /** + * Returns the {@link InputDevice} of the given bluetooth address if the device is a input + * device. + * + * @param address The address of the bluetooth device + * @return The {@link InputDevice} of the given address if applicable + */ + @Nullable + public static InputDevice getInputDevice(Context context, String address) { + InputManager im = context.getSystemService(InputManager.class); + + if (im != null) { + for (int deviceId : im.getInputDeviceIds()) { + String btAddress = im.getInputDeviceBluetoothAddress(deviceId); + + if (btAddress != null && btAddress.equals(address)) { + return im.getInputDevice(deviceId); + } + } + } + return null; + } + + /** + * Identifies whether a device is a stylus using the associated {@link InputDevice} or + * {@link CachedBluetoothDevice}. + * InputDevices are only available when the device is USI or Bluetooth-connected, whereas + * CachedBluetoothDevices are available for Bluetooth devices when connected or paired, + * so to handle all cases, both are needed. + * + * @param inputDevice The associated input device of the stylus + * @param cachedBluetoothDevice The associated bluetooth device of the stylus + */ + public static boolean isDeviceStylus(@Nullable InputDevice inputDevice, + @Nullable CachedBluetoothDevice cachedBluetoothDevice) { + if (inputDevice != null && inputDevice.supportsSource(InputDevice.SOURCE_STYLUS)) { + return true; + } + + if (cachedBluetoothDevice != null) { + BluetoothDevice bluetoothDevice = cachedBluetoothDevice.getDevice(); + String deviceType = BluetoothUtils.getStringMetaData(bluetoothDevice, + BluetoothDevice.METADATA_DEVICE_TYPE); + return TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_STYLUS); + } + + return false; + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java index ebe6128e55821..0325c0ec79154 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java @@ -15,7 +15,9 @@ */ package com.android.settingslib.bluetooth; +import static com.android.settingslib.bluetooth.BluetoothUtils.getInputDevice; import static com.android.settingslib.bluetooth.BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice; +import static com.android.settingslib.bluetooth.BluetoothUtils.isDeviceStylus; import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.UNKNOWN_VALUE_PLACEHOLDER; import static com.android.settingslib.flags.Flags.FLAG_ENABLE_DETERMINING_ADVANCED_DETAILS_HEADER_WITH_METADATA; @@ -42,6 +44,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; +import android.hardware.input.InputManager; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioManager; @@ -51,6 +54,7 @@ import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.util.Pair; +import android.view.InputDevice; import com.android.internal.R; import com.android.settingslib.flags.Flags; @@ -97,14 +101,18 @@ public class BluetoothUtilsTest { @Mock private LocalBluetoothLeBroadcastAssistant mAssistant; @Mock private CachedBluetoothDeviceManager mDeviceManager; @Mock private BluetoothLeBroadcastReceiveState mLeBroadcastReceiveState; + @Mock + private InputManager mInputManager; private Context mContext; private ShadowBluetoothAdapter mShadowBluetoothAdapter; + private final InputDevice mInputDevice = mock(InputDevice.class); private static final String STRING_METADATA = "string_metadata"; private static final String LE_AUDIO_SHARING_METADATA = "le_audio_sharing"; private static final String BOOL_METADATA = "true"; private static final String INT_METADATA = "25"; private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25; + private static final int TEST_DEVICE_ID = 123; private static final String KEY_HEARABLE_CONTROL_SLICE = "HEARABLE_CONTROL_SLICE_WITH_WIDTH"; private static final String CONTROL_METADATA = "" @@ -115,6 +123,7 @@ public class BluetoothUtilsTest { private static final String FAKE_TEMP_BOND_METADATA = "fake"; private static final String TEST_EXCLUSIVE_MANAGER_PACKAGE = "com.test.manager"; private static final String TEST_EXCLUSIVE_MANAGER_COMPONENT = "com.test.manager/.component"; + private static final String TEST_ADDRESS = "11:22:33:44:55:66"; private static final int TEST_BROADCAST_ID = 25; @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -134,6 +143,10 @@ public class BluetoothUtilsTest { when(mA2dpProfile.getProfileId()).thenReturn(BluetoothProfile.A2DP); when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO); when(mHearingAid.getProfileId()).thenReturn(BluetoothProfile.HEARING_AID); + when(mContext.getSystemService(InputManager.class)).thenReturn(mInputManager); + when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{TEST_DEVICE_ID}); + when(mInputManager.getInputDeviceBluetoothAddress(TEST_DEVICE_ID)).thenReturn(TEST_ADDRESS); + when(mInputManager.getInputDevice(TEST_DEVICE_ID)).thenReturn(mInputDevice); } @Test @@ -1097,9 +1110,8 @@ public class BluetoothUtilsTest { @Test public void getAudioDeviceAttributesForSpatialAudio_bleHeadset() { - String address = "11:22:33:44:55:66"; when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); - when(mCachedBluetoothDevice.getAddress()).thenReturn(address); + when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_ADDRESS); when(mCachedBluetoothDevice.getProfiles()).thenReturn(List.of(mLeAudioProfile)); when(mLeAudioProfile.isEnabled(mBluetoothDevice)).thenReturn(true); @@ -1112,14 +1124,13 @@ public class BluetoothUtilsTest { new AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_HEADSET, - address)); + TEST_ADDRESS)); } @Test public void getAudioDeviceAttributesForSpatialAudio_bleSpeaker() { - String address = "11:22:33:44:55:66"; when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); - when(mCachedBluetoothDevice.getAddress()).thenReturn(address); + when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_ADDRESS); when(mCachedBluetoothDevice.getProfiles()).thenReturn(List.of(mLeAudioProfile)); when(mLeAudioProfile.isEnabled(mBluetoothDevice)).thenReturn(true); @@ -1132,14 +1143,14 @@ public class BluetoothUtilsTest { new AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_SPEAKER, - address)); + TEST_ADDRESS)); } @Test public void getAudioDeviceAttributesForSpatialAudio_a2dp() { - String address = "11:22:33:44:55:66"; + when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); - when(mCachedBluetoothDevice.getAddress()).thenReturn(address); + when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_ADDRESS); when(mCachedBluetoothDevice.getProfiles()).thenReturn(List.of(mA2dpProfile)); when(mA2dpProfile.isEnabled(mBluetoothDevice)).thenReturn(true); @@ -1152,14 +1163,13 @@ public class BluetoothUtilsTest { new AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, - address)); + TEST_ADDRESS)); } @Test public void getAudioDeviceAttributesForSpatialAudio_hearingAid() { - String address = "11:22:33:44:55:66"; when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); - when(mCachedBluetoothDevice.getAddress()).thenReturn(address); + when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_ADDRESS); when(mCachedBluetoothDevice.getProfiles()).thenReturn(List.of(mHearingAid)); when(mHearingAid.isEnabled(mBluetoothDevice)).thenReturn(true); @@ -1172,7 +1182,7 @@ public class BluetoothUtilsTest { new AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HEARING_AID, - address)); + TEST_ADDRESS)); } @Test @@ -1375,4 +1385,54 @@ public class BluetoothUtilsTest { verify(mBluetoothDevice).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, TEMP_BOND_METADATA.getBytes()); } + + @Test + public void getInputDevice_addressNotMatched_returnsNull() { + assertThat(getInputDevice(mContext, "123")).isNull(); + } + + @Test + public void getInputDevice_isInputDevice_returnsInputDevice() { + assertThat(getInputDevice(mContext, TEST_ADDRESS)).isEqualTo(mInputDevice); + } + + @Test + public void isDeviceStylus_noDevices_false() { + assertThat(isDeviceStylus(null, null)).isFalse(); + } + + @Test + public void isDeviceStylus_nonStylusInputDevice_false() { + InputDevice inputDevice = new InputDevice.Builder() + .setSources(InputDevice.SOURCE_DPAD) + .build(); + + assertThat(isDeviceStylus(inputDevice, null)).isFalse(); + } + + @Test + public void isDeviceStylus_stylusInputDevice_true() { + InputDevice inputDevice = new InputDevice.Builder() + .setSources(InputDevice.SOURCE_STYLUS) + .build(); + + assertThat(isDeviceStylus(inputDevice, null)).isTrue(); + } + + @Test + public void isDeviceStylus_nonStylusBluetoothDevice_false() { + when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn( + BluetoothDevice.DEVICE_TYPE_WATCH.getBytes()); + + assertThat(isDeviceStylus(null, mCachedBluetoothDevice)).isFalse(); + } + + @Test + public void isDeviceStylus_stylusBluetoothDevice_true() { + when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn( + BluetoothDevice.DEVICE_TYPE_STYLUS.getBytes()); + when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); + + assertThat(isDeviceStylus(null, mCachedBluetoothDevice)).isTrue(); + } } -- GitLab From 3d5873681c3ef0f546c7a2170a8265747389a2fd Mon Sep 17 00:00:00 2001 From: Angela Wang Date: Thu, 20 Feb 2025 11:12:23 +0000 Subject: [PATCH 027/111] Fix AmbientVolumeControllerTest failed Flag: EXEMPT bugfix Bug: 397874606 Test: atest AmbientVolumeControllerTest Change-Id: Idf9139e16193c76362a261c92b5b9cc6131feb96 --- .../settingslib/bluetooth/AmbientVolumeControllerTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeControllerTest.java index abc1d226972b7..e4381ae0a6639 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeControllerTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.when; import android.bluetooth.AudioInputControl; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; import android.content.Context; import androidx.test.core.app.ApplicationProvider; @@ -67,6 +68,9 @@ public class AmbientVolumeControllerTest { @Before public void setUp() { when(mProfileManager.getVolumeControlProfile()).thenReturn(mVolumeControlProfile); + when(mVolumeControlProfile.isProfileReady()).thenReturn(true); + when(mVolumeControlProfile.getConnectionStatus(mDevice)).thenReturn( + BluetoothProfile.STATE_CONNECTED); when(mDevice.getAddress()).thenReturn(TEST_ADDRESS); when(mDevice.isConnected()).thenReturn(true); mVolumeController = new AmbientVolumeController(mProfileManager, mCallback); @@ -74,8 +78,6 @@ public class AmbientVolumeControllerTest { @Test public void onServiceConnected_notifyCallback() { - when(mVolumeControlProfile.isProfileReady()).thenReturn(true); - mVolumeController.onServiceConnected(); verify(mCallback).onVolumeControlServiceConnected(); -- GitLab From fe05a0b30a377ad23f17256a6947402d014f018d Mon Sep 17 00:00:00 2001 From: Toshiki Kikuchi Date: Wed, 19 Feb 2025 21:38:41 +0900 Subject: [PATCH 028/111] Setup desktop when entering desktop by app-initiated transition This CL setup the desktop env (e.g., bring up DesktopWallpaper) when an app is launched (or moved to top) into the desktop by app-initiated transition when the desktop session is not activated. We probably want to consolidate the logic with handleFreeformTaskLaunch but this CL is the hot fix. Flag: com.android.window.flags.enable_display_windowing_mode_switching Bug: 397249847 Test: DesktopTasksControllerTest Change-Id: Ia778bff76eaccadb1adb9558c4b529a145d48ea3 --- .../desktopmode/DesktopTasksController.kt | 69 +++++++++++++--- .../desktopmode/DesktopTasksControllerTest.kt | 80 ++++++++++++++++++- 2 files changed, 132 insertions(+), 17 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 93058db0c171a..0da611e02def6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -1055,7 +1055,8 @@ class DesktopTasksController( ) } - private fun startLaunchTransition( + @VisibleForTesting + fun startLaunchTransition( transitionType: Int, wct: WindowContainerTransaction, launchingTaskId: Int?, @@ -1063,34 +1064,52 @@ class DesktopTasksController( displayId: Int = DEFAULT_DISPLAY, unminimizeReason: UnminimizeReason = UnminimizeReason.UNKNOWN, ): IBinder { + // TODO: b/397619806 - Consolidate sharable logic with [handleFreeformTaskLaunch]. + var launchTransaction = wct val taskIdToMinimize = addAndGetMinimizeChanges( displayId, - wct, + launchTransaction, newTaskId = launchingTaskId, launchingNewIntent = launchingTaskId == null, ) val exitImmersiveResult = desktopImmersiveController.exitImmersiveIfApplicable( - wct = wct, + wct = launchTransaction, displayId = displayId, excludeTaskId = launchingTaskId, reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH, ) + var deskIdToActivate: Int? = null + if ( + DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue && + !isDesktopModeShowing(displayId) + ) { + deskIdToActivate = + checkNotNull( + launchingTaskId?.let { taskRepository.getDeskIdForTask(it) } + ?: getDefaultDeskId(displayId) + ) + val activateDeskWct = WindowContainerTransaction() + addDeskActivationChanges(deskIdToActivate, activateDeskWct) + // Desk activation must be handled before app launch-related transactions. + activateDeskWct.merge(launchTransaction, /* transfer= */ true) + launchTransaction = activateDeskWct + } val t = if (remoteTransition == null) { desktopMixedTransitionHandler.startLaunchTransition( transitionType = transitionType, - wct = wct, + wct = launchTransaction, taskId = launchingTaskId, minimizingTaskId = taskIdToMinimize, exitingImmersiveTask = exitImmersiveResult.asExit()?.exitingTask, ) } else if (taskIdToMinimize == null) { val remoteTransitionHandler = OneShotRemoteHandler(mainExecutor, remoteTransition) - transitions.startTransition(transitionType, wct, remoteTransitionHandler).also { - remoteTransitionHandler.setTransition(it) - } + transitions + .startTransition(transitionType, launchTransaction, remoteTransitionHandler) + .also { remoteTransitionHandler.setTransition(it) } } else { val remoteTransitionHandler = DesktopWindowLimitRemoteHandler( @@ -1099,9 +1118,9 @@ class DesktopTasksController( remoteTransition, taskIdToMinimize, ) - transitions.startTransition(transitionType, wct, remoteTransitionHandler).also { - remoteTransitionHandler.setTransition(it) - } + transitions + .startTransition(transitionType, launchTransaction, remoteTransitionHandler) + .also { remoteTransitionHandler.setTransition(it) } } if (taskIdToMinimize != null) { addPendingMinimizeTransition(t, taskIdToMinimize, MinimizeReason.TASK_LIMIT) @@ -1109,6 +1128,24 @@ class DesktopTasksController( if (launchingTaskId != null && taskRepository.isMinimizedTask(launchingTaskId)) { addPendingUnminimizeTransition(t, displayId, launchingTaskId, unminimizeReason) } + if ( + DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue && + deskIdToActivate != null + ) { + if (DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue) { + desksTransitionObserver.addPendingTransition( + DeskTransition.ActivateDesk( + token = t, + displayId = displayId, + deskId = deskIdToActivate, + ) + ) + } + + desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted( + FREEFORM_ANIMATION_DURATION + ) + } exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t) return t } @@ -2665,10 +2702,9 @@ class DesktopTasksController( activateDesk(deskId, remoteTransition) } - /** Activates the given desk. */ - fun activateDesk(deskId: Int, remoteTransition: RemoteTransition? = null) { + /** Activates the given desk but without starting a transition. */ + fun addDeskActivationChanges(deskId: Int, wct: WindowContainerTransaction) { val displayId = taskRepository.getDisplayForDesk(deskId) - val wct = WindowContainerTransaction() if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { prepareForDeskActivation(displayId, wct) desksOrganizer.activateDesk(wct, deskId) @@ -2681,6 +2717,13 @@ class DesktopTasksController( } else { bringDesktopAppsToFront(displayId, wct) } + } + + /** Activates the given desk. */ + fun activateDesk(deskId: Int, remoteTransition: RemoteTransition? = null) { + val displayId = taskRepository.getDisplayForDesk(deskId) + val wct = WindowContainerTransaction() + addDeskActivationChanges(deskId, wct) val transitionType = transitionType(remoteTransition) val handler = diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index fcd92ac2678ad..950d38a633953 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -2477,8 +2477,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveTaskToFront(task.taskId, unminimizeReason = UnminimizeReason.UNKNOWN) val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN) - assertThat(wct.hierarchyOps).hasSize(1) - wct.assertLaunchTaskAt(0, task.taskId, WINDOWING_MODE_FREEFORM) + wct.assertLaunchTask(task.taskId, WINDOWING_MODE_FREEFORM) } @Test @@ -6240,6 +6239,61 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() assertThat(taskRepository.getNumberOfDesks(DEFAULT_DISPLAY)).isEqualTo(currentDeskCount + 1) } + @Test + @EnableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY, + Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, + ) + fun startLaunchTransition_desktopNotShowing_movesWallpaperToFront() { + val launchingTask = createFreeformTask() + val wct = WindowContainerTransaction() + wct.reorder(launchingTask.token, /* onTop= */ true) + whenever( + desktopMixedTransitionHandler.startLaunchTransition( + eq(TRANSIT_OPEN), + any(), + anyOrNull(), + anyOrNull(), + anyOrNull(), + ) + ) + .thenReturn(Binder()) + + controller.startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null) + + val latestWct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN) + val launchingTaskReorderIndex = latestWct.indexOfReorder(launchingTask, toTop = true) + val wallpaperReorderIndex = latestWct.indexOfReorder(wallpaperToken, toTop = true) + assertThat(launchingTaskReorderIndex).isNotEqualTo(-1) + assertThat(wallpaperReorderIndex).isNotEqualTo(-1) + assertThat(launchingTaskReorderIndex).isGreaterThan(wallpaperReorderIndex) + } + + @Test + @EnableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY, + Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, + ) + fun startLaunchTransition_desktopShowing_doesNotReorderWallpaper() { + val wct = WindowContainerTransaction() + whenever( + desktopMixedTransitionHandler.startLaunchTransition( + eq(TRANSIT_OPEN), + any(), + anyOrNull(), + anyOrNull(), + anyOrNull(), + ) + ) + .thenReturn(Binder()) + + setUpFreeformTask() + controller.startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null) + + val latestWct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN) + assertNull(latestWct.hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() }) + } + private class RunOnStartTransitionCallback : ((IBinder) -> Unit) { var invocations = 0 private set @@ -6626,13 +6680,20 @@ private fun WindowContainerTransaction.assertWithoutHop( } private fun WindowContainerTransaction.indexOfReorder( - task: RunningTaskInfo, + token: WindowContainerToken, toTop: Boolean? = null, ): Int { - val hop = hierarchyOps.singleOrNull(ReorderPredicate(task.token, toTop)) ?: return -1 + val hop = hierarchyOps.singleOrNull(ReorderPredicate(token, toTop)) ?: return -1 return hierarchyOps.indexOf(hop) } +private fun WindowContainerTransaction.indexOfReorder( + task: RunningTaskInfo, + toTop: Boolean? = null, +): Int { + return indexOfReorder(task.token, toTop) +} + private class ReorderPredicate(val token: WindowContainerToken, val toTop: Boolean? = null) : ((WindowContainerTransaction.HierarchyOp) -> Boolean) { override fun invoke(hop: WindowContainerTransaction.HierarchyOp): Boolean = @@ -6750,6 +6811,17 @@ private fun WindowContainerTransaction.assertPendingIntentAt(index: Int, intent: assertThat(op.pendingIntent?.intent?.categories).isEqualTo(intent.categories) } +private fun WindowContainerTransaction.assertLaunchTask(taskId: Int, windowingMode: Int) { + val keyLaunchWindowingMode = "android.activity.windowingMode" + + assertHop { hop -> + hop.type == HIERARCHY_OP_TYPE_LAUNCH_TASK && + hop.launchOptions?.getInt(LAUNCH_KEY_TASK_ID) == taskId && + hop.launchOptions?.getInt(keyLaunchWindowingMode, WINDOWING_MODE_UNDEFINED) == + windowingMode + } +} + private fun WindowContainerTransaction.assertLaunchTaskAt( index: Int, taskId: Int, -- GitLab From 4b04c4f50f7c9f617733990aae1d8c50515aeec0 Mon Sep 17 00:00:00 2001 From: Felix Stern Date: Thu, 20 Feb 2025 07:00:49 -0800 Subject: [PATCH 029/111] Wait for IME window to be drawn in testSurfaceRemovedAfterHideSoftInput Fix: 397916079 Flag: android.view.inputmethod.refactor_insets_controller Test: atest com.android.inputmethodservice.InputMethodServiceTest#testSurfaceRemovedAfterHideSoftInput Change-Id: I1e4d35c201fe34a20f0a1e4b12cd82263c86305b --- .../android/inputmethodservice/InputMethodServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java index 856466675a28f..037d90ce5df0e 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java @@ -267,8 +267,8 @@ public class InputMethodServiceTest { final var window = mInputMethodService.getWindow().getWindow(); assertWithMessage("IME window exists").that(window).isNotNull(); - assertWithMessage("IME window showing").that( - window.getDecorView().getVisibility()).isEqualTo(View.VISIBLE); + eventually(() -> assertWithMessage("IME window showing").that( + window.getDecorView().getVisibility()).isEqualTo(View.VISIBLE)); mActivity.getWindow().getDecorView().setWindowInsetsAnimationCallback( new WindowInsetsAnimation.Callback( -- GitLab From 6329f3e8070aa630308f45cd40c67314b83bb9bb Mon Sep 17 00:00:00 2001 From: Owner Cleanup Bot Date: Thu, 20 Feb 2025 07:49:02 -0800 Subject: [PATCH 030/111] [owners] Remove arcwang@google.com from packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS This suggested change is automatically generated based on group memberships and affiliations. Please approve this change and vote the highest CR. This will keep the OWNERs file tidy. We ask that you do not ignore this change and approve it unless you know a reason the OWNER should remain. It can always be reverted if needed. If this change is in error, vote the lowest CR value (i.e. reject the CL) and the bot will abandon it. See the owner's recent review activity for context: https://android-review.googlesource.com/q/arcwang@google.com To report an issue, file a bug in the Infra>Codereview component. Change-Id: I92fa4505afa87da52d8e39e3597272c226cac36c --- .../SettingsLib/src/com/android/settingslib/connectivity/OWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS index 9f15c1bb5081c..b676d8daad52a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS +++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS @@ -1,6 +1,5 @@ # Default reviewers for this and subdirectories. andychou@google.com -arcwang@google.com changbetty@google.com qal@google.com wengsu@google.com -- GitLab From 5e050679706d8ee23cdca61b54dc5725ad3eed19 Mon Sep 17 00:00:00 2001 From: Mina Granic Date: Wed, 5 Feb 2025 18:26:56 +0000 Subject: [PATCH 031/111] Add an opt-out property for camera compat freeform treatment. The name has been chosen to be future-proof for other windowing modes and platforms. Flag: com.android.window.flags.enable_camera_compat_for_desktop_windowing_opt_out Test: atest WmTests:AppCompatCameraOverridesTest Fixes: 328616176 Change-Id: I2c7e9cfde4ba139e46c070d2cbc08e853416ef0e --- core/java/android/view/WindowManager.java | 37 +++++++++++++++++++ .../server/wm/AppCompatCameraOverrides.java | 37 +++++++++++++++++-- .../wm/AppCompatCameraOverridesTest.java | 30 +++++++++++++++ 3 files changed, 100 insertions(+), 4 deletions(-) diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 93eed370004b6..24647f459ab5e 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1198,6 +1198,43 @@ public interface WindowManager extends ViewManager { String PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE = "android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE"; + /** + * Application-level [PackageManager][android.content.pm.PackageManager.Property] tag that (when + * set to false) informs the system the app has opted out of the camera compatibility treatment + * for fixed-orientation apps, which simulates running on a portrait device, in the orientation + * requested by the app. + * + *

This treatment aims to mitigate camera issues on large screens, like stretched or sideways + * previews. It simulates running on a portrait device by: + *

    + *
  • Letterboxing the app window, + *
  • Cropping the camera buffer to match the app's requested orientation, + *
  • Setting the camera sensor orientation to portrait. + *
  • Setting the display rotation to match the app's requested orientation, given portrait + * natural orientation, + *
  • Refreshes the activity to trigger new camera setup, with sandboxed values. + *
+ * + *

To opt out of the camera compatibility treatment, add this property to your app manifest + * and set the value to {@code false}. + * + *

Not setting this property at all, or setting this property to {@code true} has no effect. + * + *

Syntax: + *

+     * <application>
+     *   <property
+     *     android:name="android.window.PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION"
+     *     android:value="true|false"/>
+     * </application>
+     * 
+ * + * @hide + */ + //TODO(b/394590412): Make this property public. + String PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION = + "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION"; + /** * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property} * for an app to inform the system that the app should be excluded from the compatibility diff --git a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java index 47d30c98120c7..5eed54704f36d 100644 --- a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java @@ -23,6 +23,7 @@ import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFR import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA; import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION; +import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE; @@ -32,6 +33,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.AppCompatUtils.isChangeEnabled; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.server.wm.utils.OptPropFactory; import com.android.window.flags.Flags; @@ -60,6 +62,8 @@ class AppCompatCameraOverrides { private final OptPropFactory.OptProp mCameraCompatEnableRefreshViaPauseOptProp; @NonNull private final OptPropFactory.OptProp mCameraCompatAllowForceRotationOptProp; + @Nullable + private final OptPropFactory.OptProp mCameraCompatAllowOrientationTreatmentOptProp; AppCompatCameraOverrides(@NonNull ActivityRecord activityRecord, @NonNull AppCompatConfiguration appCompatConfiguration, @@ -80,6 +84,10 @@ class AppCompatCameraOverrides { mCameraCompatAllowForceRotationOptProp = optPropBuilder.create( PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, isCameraCompatTreatmentEnabled); + mCameraCompatAllowOrientationTreatmentOptProp = + Flags.enableCameraCompatForDesktopWindowingOptOut() ? optPropBuilder.create( + PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION, + isCameraCompatTreatmentEnabled) : null; } /** @@ -168,10 +176,31 @@ class AppCompatCameraOverrides { * */ boolean shouldApplyFreeformTreatmentForCameraCompat() { - return Flags.enableCameraCompatForDesktopWindowing() && (isChangeEnabled(mActivityRecord, - OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT) - || mActivityRecord.mWmService.mAppCompatConfiguration - .isCameraCompatFreeformWindowingTreatmentEnabled()); + return Flags.enableCameraCompatForDesktopWindowing() + && (shouldEnableCameraCompatFreeformTreatmentForApp() + || shouldEnableCameraCompatFreeformTreatmentForAllApps()); + } + + private boolean shouldEnableCameraCompatFreeformTreatmentForApp() { + if (mCameraCompatAllowOrientationTreatmentOptProp != null) { + return mCameraCompatAllowOrientationTreatmentOptProp + .shouldEnableWithOptOutOverrideAndProperty(isChangeEnabled(mActivityRecord, + OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT)); + } else { + return isChangeEnabled(mActivityRecord, + OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT); + } + } + + /** + * Returns whether camera compat treatment should be enabled for all apps targeted for treatment + * (usually fixed-orientation apps). + * + *

This can be enabled via adb only. + */ + private boolean shouldEnableCameraCompatFreeformTreatmentForAllApps() { + return mActivityRecord.mWmService.mAppCompatConfiguration + .isCameraCompatFreeformWindowingTreatmentEnabled(); } boolean isOverrideOrientationOnlyForCameraEnabled() { diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java index 4ad1cd192eb6b..d4be7f812cb5f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java @@ -23,12 +23,14 @@ import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFR import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA; import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION; +import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING; +import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING_OPT_OUT; import android.compat.testing.PlatformCompatChangeRule; import android.platform.test.annotations.DisableFlags; @@ -237,6 +239,34 @@ public class AppCompatCameraOverridesTest extends WindowTestsBase { }); } + @Test + @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT}) + @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING, + FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING_OPT_OUT}) + public void testShouldApplyCameraCompatFreeformTreatment_propertyFalse_returnsFalse() { + runTestScenario((robot) -> { + robot.activity().createActivityWithComponentInNewTask(); + + robot.prop().disable(PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION); + + robot.checkShouldApplyFreeformTreatmentForCameraCompat(false); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT}) + @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING) + @DisableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING_OPT_OUT) + public void testShouldApplyCameraCompatFreeformTreatment_optOutFlagNotEnabled_optOutIgnored() { + runTestScenario((robot) -> { + robot.activity().createActivityWithComponentInNewTask(); + + robot.prop().disable(PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION); + + robot.checkShouldApplyFreeformTreatmentForCameraCompat(true); + }); + } + @Test @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT}) @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING) -- GitLab From e20bb1b52b52d4655a01ce99ec40328eb19bd04c Mon Sep 17 00:00:00 2001 From: Mina Granic Date: Mon, 17 Feb 2025 11:21:58 +0000 Subject: [PATCH 032/111] Add a flag to launch the opt-out property for Camera Compat for freeform. Flag: com.android.window.flags.enable_camera_compat_for_desktop_windowing_opt_out_api Test: EXEMPT flag Bug: 397165621 Change-Id: I1a15f05249d29bfd615fa6bc67cbedf306c5c0e5 --- .../android/window/flags/lse_desktop_experience.aconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index b137bb02b4181..30bb67c9b98a4 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -194,6 +194,13 @@ flag { } } +flag { + name: "enable_camera_compat_for_desktop_windowing_opt_out_api" + namespace: "lse_desktop_experience" + description: "Introduces a developer API to opt-out of Camera Compat treatment for fixed-orientation apps in desktop windowing mode" + bug: "397165621" +} + flag { name: "enable_task_stack_observer_in_shell" namespace: "lse_desktop_experience" -- GitLab From 122a8ac238926efeee21c83324b237ee684b3d9d Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Tue, 4 Feb 2025 04:56:56 +0000 Subject: [PATCH 033/111] Add logic to determine if a wallpaper is compatible with a display Also fix a bug that the fallback wallpaper isn't used after setting a new wallpaper due to the wallpaper connection hasn't established yet. Test: atests FrameworksMockingServicesTests:WallpaperManagerServiceTests Flag: android.app.enable_connected_displays_wallpaper Bug: 384519749 Bug: 384521079 Change-Id: I392a072e87a6977e89a9b8e884d7a2f07d1c0708 --- .../server/wallpaper/WallpaperCropper.java | 53 +++++ .../wallpaper/WallpaperManagerService.java | 26 +-- .../wallpaper/WallpaperCropperTest.java | 194 ++++++++++++++++++ .../WallpaperManagerServiceTests.java | 100 +++++---- 4 files changed, 317 insertions(+), 56 deletions(-) diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java index b3e68a35764b2..8e8455ad52888 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java @@ -16,6 +16,8 @@ package com.android.server.wallpaper; +import static android.app.WallpaperManager.ORIENTATION_LANDSCAPE; +import static android.app.WallpaperManager.ORIENTATION_SQUARE_LANDSCAPE; import static android.app.WallpaperManager.ORIENTATION_UNKNOWN; import static android.app.WallpaperManager.getOrientation; import static android.app.WallpaperManager.getRotatedOrientation; @@ -28,6 +30,7 @@ import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER; import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir; import static com.android.window.flags.Flags.multiCrop; +import android.app.WallpaperManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.ImageDecoder; @@ -821,4 +824,54 @@ public class WallpaperCropper { } } } + + /** + * Returns true if a wallpaper is compatible with a given display with ID, {@code displayId}. + * + *

A wallpaper is compatible with a display if any of the following are true + *

    the display is a default display + *
      the wallpaper is a stock wallpaper
    + *
      the wallpaper size is at least 3/4 of the display resolution and, in landscape displays, + * the wallpaper has an aspect ratio of at least 11:13.
    + */ + @VisibleForTesting + boolean isWallpaperCompatibleForDisplay(int displayId, WallpaperData wallpaperData) { + if (displayId == DEFAULT_DISPLAY) { + return true; + } + + File wallpaperFile = wallpaperData.getWallpaperFile(); + if (!wallpaperFile.exists()) { + // Assumption: Stock wallpaper is suitable for all display sizes. + return true; + } + + DisplayInfo displayInfo = mWallpaperDisplayHelper.getDisplayInfo(displayId); + Point displaySize = new Point(displayInfo.logicalWidth, displayInfo.logicalHeight); + int displayOrientation = WallpaperManager.getOrientation(displaySize); + + Point wallpaperImageSize = new Point( + (int) Math.ceil(wallpaperData.cropHint.width() / wallpaperData.mSampleSize), + (int) Math.ceil(wallpaperData.cropHint.height() / wallpaperData.mSampleSize)); + if (wallpaperImageSize.equals(0, 0)) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(wallpaperFile.getAbsolutePath(), options); + wallpaperImageSize.set(options.outWidth, options.outHeight); + } + + double maxDisplayToImageRatio = Math.max((double) displaySize.x / wallpaperImageSize.x, + (double) displaySize.y / wallpaperImageSize.y); + if (maxDisplayToImageRatio > 1.5) { + return false; + } + + // For displays in landscape, we only support images with an aspect ratio >= 11:13 + if (displayOrientation == ORIENTATION_LANDSCAPE) { + return ((double) wallpaperImageSize.x / wallpaperImageSize.y) >= 11.0 / 13; + } + + // For other orientations, we don't enforce any aspect ratio. + return true; + } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 69b2b9b326ba4..d620e98d3437f 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -118,7 +118,6 @@ import android.service.wallpaper.WallpaperService; import android.system.ErrnoException; import android.system.Os; import android.text.TextUtils; -import android.util.ArraySet; import android.util.EventLog; import android.util.IntArray; import android.util.Slog; @@ -161,7 +160,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; @@ -743,10 +741,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub final WallpaperDisplayHelper mWallpaperDisplayHelper; final WallpaperCropper mWallpaperCropper; - // TODO(b/384519749): Remove this set after we introduce the aspect ratio check. - private final Set mWallpaperCompatibleDisplaysForTest = new ArraySet<>(); - - private boolean isWallpaperCompatibleForDisplay(int displayId, WallpaperConnection connection) { + @VisibleForTesting + boolean isWallpaperCompatibleForDisplay(int displayId, WallpaperConnection connection) { if (connection == null) { return false; } @@ -757,26 +753,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Image wallpaper if (isDeviceEligibleForDesktopExperienceWallpaper(mContext)) { - // TODO(b/384519749): check display's resolution and image wallpaper cropped image - // aspect ratio. - return displayId == DEFAULT_DISPLAY - || mWallpaperCompatibleDisplaysForTest.contains(displayId); + return mWallpaperCropper.isWallpaperCompatibleForDisplay(displayId, + connection.mWallpaper); } // When enableConnectedDisplaysWallpaper is off, we assume the image wallpaper supports all // usable displays. return true; } - @VisibleForTesting - void addWallpaperCompatibleDisplayForTest(int displayId) { - mWallpaperCompatibleDisplaysForTest.add(displayId); - } - - @VisibleForTesting - void removeWallpaperCompatibleDisplayForTest(int displayId) { - mWallpaperCompatibleDisplaysForTest.remove(displayId); - } - private void updateFallbackConnection(int clientUid) { if (mLastWallpaper == null || mFallbackWallpaper == null) return; final WallpaperConnection systemConnection = mLastWallpaper.connection; @@ -844,7 +828,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // `which` flag. DisplayConnector fallbackConnector = mFallbackWallpaper.connection.getDisplayConnectorOrCreate(displayId); - if (fallbackConnector != null && fallbackConnector.mEngine != null) { + if (fallbackConnector != null) { fallbackConnector.mWhich = which; fallbackConnector.connectLocked(mFallbackWallpaper.connection, mFallbackWallpaper); diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java index b53f6fbee1835..49c37f163ff2b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java @@ -16,6 +16,7 @@ package com.android.server.wallpaper; +import static android.app.WallpaperManager.FLAG_SYSTEM; import static android.app.WallpaperManager.ORIENTATION_LANDSCAPE; import static android.app.WallpaperManager.ORIENTATION_UNKNOWN; import static android.app.WallpaperManager.ORIENTATION_PORTRAIT; @@ -23,13 +24,20 @@ import static android.app.WallpaperManager.ORIENTATION_SQUARE_LANDSCAPE; import static android.app.WallpaperManager.ORIENTATION_SQUARE_PORTRAIT; import static android.app.WallpaperManager.getOrientation; import static android.app.WallpaperManager.getRotatedOrientation; +import static android.os.UserHandle.USER_SYSTEM; +import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.window.flags.Flags.FLAG_MULTI_CROP; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -37,15 +45,29 @@ import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; +import android.util.Log; import android.util.SparseArray; +import android.view.Display; +import android.view.DisplayInfo; import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.dx.mockito.inline.extended.StaticMockitoSession; + +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.quality.Strictness; +import java.io.File; +import java.io.IOException; import java.util.Comparator; import java.util.List; @@ -57,6 +79,7 @@ import java.util.List; @RunWith(AndroidJUnit4.class) @RequiresFlagsEnabled(FLAG_MULTI_CROP) public class WallpaperCropperTest { + private static final String TAG = "WallpaperCropperTest"; @Mock private WallpaperDisplayHelper mWallpaperDisplayHelper; @@ -94,6 +117,8 @@ public class WallpaperCropperTest { private static final List> ALL_FOLDABLE_DISPLAYS = List.of( FOLDABLE_ONE, FOLDABLE_TWO, FOLDABLE_THREE, FOLDABLE_FOUR); + private static StaticMockitoSession sMockitoSession; + private SparseArray mDisplaySizes = new SparseArray<>(); private int mFolded = ORIENTATION_UNKNOWN; private int mFoldedRotated = ORIENTATION_UNKNOWN; @@ -103,12 +128,53 @@ public class WallpaperCropperTest { private static final List ALL_MODES = List.of( WallpaperCropper.ADD, WallpaperCropper.REMOVE, WallpaperCropper.BALANCE); + private final SparseArray mTempDirs = new SparseArray<>(); + + private final TemporaryFolder mFolder = new TemporaryFolder(); + + @Rule + public RuleChain rules = RuleChain.outerRule(mFolder); + + @BeforeClass + public static void setUpClass() { + sMockitoSession = mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(WallpaperUtils.class) + .startMocking(); + } + + @AfterClass + public static void tearDownClass() { + if (sMockitoSession != null) { + sMockitoSession.finishMocking(); + sMockitoSession = null; + } + } + @Before public void setUp() { initMocks(this); + ExtendedMockito.doAnswer(invocation -> { + int userId = (invocation.getArgument(0)); + return getWallpaperTestDir(userId); + }).when(() -> WallpaperUtils.getWallpaperDir(anyInt())); + mWallpaperCropper = new WallpaperCropper(mWallpaperDisplayHelper); } + private File getWallpaperTestDir(int userId) { + File tempDir = mTempDirs.get(userId); + if (tempDir == null) { + try { + tempDir = mFolder.newFolder(String.valueOf(userId)); + mTempDirs.append(userId, tempDir); + } catch (IOException e) { + Log.e(TAG, "getWallpaperTestDir failed at userId= " + userId); + } + } + return tempDir; + } + private void setUpWithDisplays(List displaySizes) { mDisplaySizes = new SparseArray<>(); displaySizes.forEach(size -> { @@ -632,6 +698,134 @@ public class WallpaperCropperTest { } } + // Test isWallpaperCompatibleForDisplay always return true for the default display. + @Test + public void isWallpaperCompatibleForDisplay_defaultDisplay_returnTrue() + throws Exception { + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = 2560; + displayInfo.logicalHeight = 1044; + doReturn(displayInfo).when(mWallpaperDisplayHelper).getDisplayInfo(eq(DEFAULT_DISPLAY)); + WallpaperData wallpaperData = createWallpaperData(/* isStockWallpaper = */ false, + new Point(100, 100)); + + assertThat( + mWallpaperCropper.isWallpaperCompatibleForDisplay(DEFAULT_DISPLAY, + wallpaperData)).isTrue(); + } + + // Test isWallpaperCompatibleForDisplay always return true for the stock wallpaper. + @Test + public void isWallpaperCompatibleForDisplay_stockWallpaper_returnTrue() + throws Exception { + final int displayId = 2; + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = 2560; + displayInfo.logicalHeight = 1044; + doReturn(displayInfo).when(mWallpaperDisplayHelper).getDisplayInfo(eq(displayId)); + WallpaperData wallpaperData = createWallpaperData(/* isStockWallpaper = */ true, + new Point(100, 100)); + + assertThat( + mWallpaperCropper.isWallpaperCompatibleForDisplay(displayId, + wallpaperData)).isTrue(); + } + + // Test isWallpaperCompatibleForDisplay wallpaper is suitable for the display and wallpaper + // aspect ratio meets the hard-coded aspect ratio. + @Test + public void isWallpaperCompatibleForDisplay_wallpaperSizeSuitableForDisplayAndMeetAspectRatio_returnTrue() + throws Exception { + final int displayId = 2; + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = 2560; + displayInfo.logicalHeight = 1044; + doReturn(displayInfo).when(mWallpaperDisplayHelper).getDisplayInfo(eq(displayId)); + WallpaperData wallpaperData = createWallpaperData(/* isStockWallpaper = */ false, + new Point(4000, 3000)); + + assertThat( + mWallpaperCropper.isWallpaperCompatibleForDisplay(displayId, + wallpaperData)).isTrue(); + } + + // Test isWallpaperCompatibleForDisplay wallpaper is not suitable for the display and wallpaper + // aspect ratio meets the hard-coded aspect ratio. + @Test + public void isWallpaperCompatibleForDisplay_wallpaperSizeNotSuitableForDisplayAndMeetAspectRatio_returnFalse() + throws Exception { + final int displayId = 2; + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = 2560; + displayInfo.logicalHeight = 1044; + doReturn(displayInfo).when(mWallpaperDisplayHelper).getDisplayInfo(eq(displayId)); + WallpaperData wallpaperData = createWallpaperData(/* isStockWallpaper = */ false, + new Point(1000, 500)); + + assertThat( + mWallpaperCropper.isWallpaperCompatibleForDisplay(displayId, + wallpaperData)).isFalse(); + } + + // Test isWallpaperCompatibleForDisplay wallpaper is suitable for the display and wallpaper + // aspect ratio doesn't meet the hard-coded aspect ratio. + @Test + public void isWallpaperCompatibleForDisplay_wallpaperSizeSuitableForDisplayAndDoNotMeetAspectRatio_returnFalse() + throws Exception { + final int displayId = 2; + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = 2560; + displayInfo.logicalHeight = 1044; + doReturn(displayInfo).when(mWallpaperDisplayHelper).getDisplayInfo(eq(displayId)); + WallpaperData wallpaperData = createWallpaperData(/* isStockWallpaper = */ false, + new Point(2000, 4000)); + + assertThat( + mWallpaperCropper.isWallpaperCompatibleForDisplay(displayId, + wallpaperData)).isFalse(); + } + + // Test isWallpaperCompatibleForDisplay, portrait display, wallpaper is suitable for the display + // and wallpaper aspect ratio doesn't meet the hard-coded aspect ratio. + @Test + public void isWallpaperCompatibleForDisplay_portraitDisplay_wallpaperSizeSuitableForDisplayAndMeetAspectRatio_returnTrue() + throws Exception { + final int displayId = 2; + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = 1044; + displayInfo.logicalHeight = 2560; + doReturn(displayInfo).when(mWallpaperDisplayHelper).getDisplayInfo(eq(displayId)); + WallpaperData wallpaperData = createWallpaperData(/* isStockWallpaper = */ false, + new Point(2000, 4000)); + + assertThat( + mWallpaperCropper.isWallpaperCompatibleForDisplay(displayId, + wallpaperData)).isTrue(); + } + + private void mockDisplay(int displayId, Point displayResolution) { + final Display mockDisplay = mock(Display.class); + when(mockDisplay.getDisplayInfo(any(DisplayInfo.class))).thenAnswer(invocation -> { + DisplayInfo displayInfo = invocation.getArgument(0); + displayInfo.displayId = displayId; + displayInfo.logicalWidth = displayResolution.x; + displayInfo.logicalHeight = displayResolution.y; + return true; + }); + } + + private WallpaperData createWallpaperData(boolean isStockWallpaper, Point wallpaperSize) + throws Exception { + WallpaperData wallpaperData = new WallpaperData(USER_SYSTEM, FLAG_SYSTEM); + File wallpaperFile = wallpaperData.getWallpaperFile(); + if (!isStockWallpaper) { + wallpaperFile.getParentFile().mkdirs(); + wallpaperFile.createNewFile(); + } + wallpaperData.cropHint.set(0, 0, wallpaperSize.x, wallpaperSize.y); + return wallpaperData; + } + private static Rect centerOf(Rect container, Point point) { checkSubset(container, point); int diffWidth = container.width() - point.x; diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java index bc04fd94c7193..e99c9de108f58 100644 --- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java @@ -123,6 +123,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Map; /** * Tests for the {@link WallpaperManagerService} class. @@ -742,7 +743,9 @@ public class WallpaperManagerServiceTests { wallpaper.connection.mService = mockIWallpaperService; // GIVEN there are two displays: DEFAULT_DISPLAY, 2 final int testDisplayId = 2; - setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + testDisplayId, true)); // WHEN display ID, 2, is ready. WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( @@ -782,7 +785,9 @@ public class WallpaperManagerServiceTests { lockWallpaper.connection.mService = mockIWallpaperService; // GIVEN there are two displays: DEFAULT_DISPLAY, 2 final int testDisplayId = 2; - setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + testDisplayId, true)); // WHEN display ID, 2, is ready. WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( @@ -823,13 +828,15 @@ public class WallpaperManagerServiceTests { throws Exception { final int testUserId = USER_SYSTEM; mService.switchUser(testUserId, null); + mService.mLastWallpaper.connection.mWallpaper.cropHint.set(0, 0, 4000, 2250); IWallpaperService mockIWallpaperService = mock(IWallpaperService.class); mService.mFallbackWallpaper.connection.mService = mockIWallpaperService; // GIVEN there are two displays: DEFAULT_DISPLAY, 2 final int testDisplayId = 2; - setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); - // GIVEN the wallpaper isn't compatible with display ID, 2 - mService.removeWallpaperCompatibleDisplayForTest(testDisplayId); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + // Given the wallpaper is smaller thn the display resolution. + testDisplayId, false)); // WHEN display ID, 2, is ready. WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( @@ -868,7 +875,10 @@ public class WallpaperManagerServiceTests { wallpaper.connection.mService = mockIWallpaperService; // GIVEN there are two displays: DEFAULT_DISPLAY, 2 final int testDisplayId = 2; - setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + mService.mLastWallpaper.connection.mWallpaper.cropHint.set(0, 0, 4000, 2250); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + testDisplayId, true)); // GIVEN wallpaper connections have been established for display ID, 2. WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( WallpaperManagerInternal.class); @@ -906,7 +916,9 @@ public class WallpaperManagerServiceTests { lockWallpaper.connection.mService = mockIWallpaperService; // GIVEN there are two displays: DEFAULT_DISPLAY, 2 final int testDisplayId = 2; - setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + testDisplayId, true)); // GIVEN wallpaper connections have been established for display ID, 2. WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( WallpaperManagerInternal.class); @@ -940,9 +952,9 @@ public class WallpaperManagerServiceTests { mService.mFallbackWallpaper.connection.mService = mockIWallpaperService; // GIVEN there are two displays: DEFAULT_DISPLAY, 2 final int testDisplayId = 2; - setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); - // GIVEN display ID, 2, is incompatible with the wallpaper. - mService.removeWallpaperCompatibleDisplayForTest(testDisplayId); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + testDisplayId, false)); // GIVEN wallpaper connections have been established for display ID, 2. WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( WallpaperManagerInternal.class); @@ -989,7 +1001,9 @@ public class WallpaperManagerServiceTests { wallpaper.connection.mService = mockIWallpaperService; // GIVEN there are two displays: DEFAULT_DISPLAY, 2 final int testDisplayId = 2; - setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + testDisplayId, true)); // GIVEN wallpaper connections have been established for displayID, 2. WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( WallpaperManagerInternal.class); @@ -1023,7 +1037,9 @@ public class WallpaperManagerServiceTests { lockWallpaper.connection.mService = mockIWallpaperService; // GIVEN there are two displays: DEFAULT_DISPLAY, 2 final int testDisplayId = 2; - setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + testDisplayId, true)); // GIVEN wallpaper connections have been established for displayID, 2. WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( WallpaperManagerInternal.class); @@ -1051,12 +1067,14 @@ public class WallpaperManagerServiceTests { @Test @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER) public void deviceBooted_multiDisplays_shouldHaveExpectedConnections() { + final int testUserId = USER_SYSTEM; final int incompatibleDisplayId = 2; final int compatibleDisplayId = 3; - setUpDisplays(List.of(DEFAULT_DISPLAY, incompatibleDisplayId, compatibleDisplayId)); - mService.removeWallpaperCompatibleDisplayForTest(incompatibleDisplayId); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + compatibleDisplayId, true, + incompatibleDisplayId, false)); - final int testUserId = USER_SYSTEM; // After reboot, a switch user triggers the wallpapers initialization. mService.switchUser(testUserId, null); @@ -1087,15 +1105,18 @@ public class WallpaperManagerServiceTests { public void setWallpaperComponent_multiDisplays_displayBecomeCompatible_shouldHaveExpectedConnections() { final int display2 = 2; final int display3 = 3; - setUpDisplays(List.of(DEFAULT_DISPLAY, display2, display3)); - mService.removeWallpaperCompatibleDisplayForTest(display2); final int testUserId = USER_SYSTEM; + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + display2, false, + display3, true)); + mService.switchUser(testUserId, null); + doReturn(true).when(mService.mWallpaperCropper).isWallpaperCompatibleForDisplay( + eq(display2), any()); // Switch to a test wallpaper and then image wallpaper later to simulate a wallpaper change. mService.setWallpaperComponent(TEST_WALLPAPER_COMPONENT, sContext.getOpPackageName(), FLAG_SYSTEM | FLAG_LOCK, testUserId); - mService.addWallpaperCompatibleDisplayForTest(display2); - mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(), FLAG_SYSTEM | FLAG_LOCK, testUserId); @@ -1124,15 +1145,19 @@ public class WallpaperManagerServiceTests { public void setWallpaperComponent_multiDisplays_displayBecomeIncompatible_shouldHaveExpectedConnections() { final int display2 = 2; final int display3 = 3; - setUpDisplays(List.of(DEFAULT_DISPLAY, display2, display3)); - mService.removeWallpaperCompatibleDisplayForTest(display2); final int testUserId = USER_SYSTEM; + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + display2, true, + display3, true)); mService.switchUser(testUserId, null); + doReturn(false).when(mService.mWallpaperCropper).isWallpaperCompatibleForDisplay( + eq(display2), any()); + doReturn(false).when(mService.mWallpaperCropper).isWallpaperCompatibleForDisplay( + eq(display3), any()); // Switch to a test wallpaper and then image wallpaper later to simulate a wallpaper change. mService.setWallpaperComponent(TEST_WALLPAPER_COMPONENT, sContext.getOpPackageName(), FLAG_SYSTEM | FLAG_LOCK, testUserId); - mService.removeWallpaperCompatibleDisplayForTest(display3); - mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(), FLAG_SYSTEM | FLAG_LOCK, testUserId); @@ -1159,14 +1184,15 @@ public class WallpaperManagerServiceTests { public void setWallpaperComponent_systemAndLockWallpapers_multiDisplays_shouldHaveExpectedConnections() { final int incompatibleDisplayId = 2; final int compatibleDisplayId = 3; - setUpDisplays(List.of(DEFAULT_DISPLAY, incompatibleDisplayId, compatibleDisplayId)); + setUpDisplays(Map.of( + DEFAULT_DISPLAY, true, + incompatibleDisplayId, false, + compatibleDisplayId, true)); final int testUserId = USER_SYSTEM; mService.switchUser(testUserId, null); // Switch to a test wallpaper and then image wallpaper later to simulate a wallpaper change. mService.setWallpaperComponent(TEST_WALLPAPER_COMPONENT, sContext.getOpPackageName(), FLAG_SYSTEM | FLAG_LOCK, testUserId); - mService.removeWallpaperCompatibleDisplayForTest(incompatibleDisplayId); - mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(), FLAG_SYSTEM, testUserId); @@ -1258,21 +1284,27 @@ public class WallpaperManagerServiceTests { * to return them. It also sets up the {@link WindowManagerInternal} to indicate that all * displays support home. * - * @param displayIds A list of display IDs to create mock displays for. + * @param displayIdsToWallpaperCompatibility A map of display IDs to wallpaper compatibility. */ - private void setUpDisplays(List displayIds) { + private void setUpDisplays(Map displayIdsToWallpaperCompatibility) { + spyOn(mService.mWallpaperCropper); doReturn(true).when(sWindowManagerInternal).isHomeSupportedOnDisplay(anyInt()); - Display[] mockDisplays = new Display[displayIds.size()]; - for (int i = 0; i < displayIds.size(); i++) { - final int displayId = displayIds.get(i); + Display[] mockDisplays = new Display[displayIdsToWallpaperCompatibility.size()]; + int counter = 0; + for (Map.Entry entry : displayIdsToWallpaperCompatibility.entrySet()) { + final int displayId = entry.getKey(); + final boolean compatibleWithWallpaper = entry.getValue(); final Display mockDisplay = mock(Display.class); - mockDisplays[i] = mockDisplay; + mockDisplays[counter] = mockDisplay; doReturn(DISPLAY_SIZE_DIMENSION).when(mockDisplay).getMaximumSizeDimension(); doReturn(mockDisplay).when(mDisplayManager).getDisplay(eq(displayId)); doReturn(displayId).when(mockDisplay).getDisplayId(); doReturn(true).when(mockDisplay).hasAccess(anyInt()); - mService.addWallpaperCompatibleDisplayForTest(displayId); + doReturn(compatibleWithWallpaper).when( + mService.mWallpaperCropper).isWallpaperCompatibleForDisplay(eq(displayId), + any()); + counter++; } doReturn(mockDisplays).when(mDisplayManager).getDisplays(); @@ -1295,6 +1327,4 @@ public class WallpaperManagerServiceTests { assertEquals(pfdContents, fileContents); } } - - } -- GitLab From 9c43bf5cd675b3c80d5f9000b137ac27f978c11f Mon Sep 17 00:00:00 2001 From: Jon Eckenrode Date: Wed, 19 Feb 2025 23:02:36 +0000 Subject: [PATCH 034/111] Added notes about Android 16 ignoring screen orientation, aspect ratio, and resizability APIs and manifest attributes. Flag: DOCS_ONLY Test: None -- docs won't build NO_BUG: None created Change-Id: I9aa4edfd65454aa7c879edbd9fb134bb1dc99b0a --- core/java/android/app/Activity.java | 26 +++++++----- core/res/res/values/attrs_manifest.xml | 58 ++++++++++++++------------ 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index ee9c64f973820..b4f653354e07f 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -7684,16 +7684,19 @@ public class Activity extends ContextThemeWrapper /** * Change the desired orientation of this activity. If the activity is currently in the * foreground or otherwise impacting the screen orientation, the screen is immediately changed - * (possibly causing the activity to be restarted). Otherwise, the requested orientation is used - * the next time the activity is visible. + * (possibly causing the activity to be restarted). Otherwise, the new orientation is used the + * next time the activity is visible. * *