Merge "Gates RotationResolverService with a config flag" into tm-qpr-dev
diff --git a/packages/SettingsLib/SearchWidget/res/values-ky/strings.xml b/packages/SettingsLib/SearchWidget/res/values-ky/strings.xml
index e61ffdb..88008d6 100644
--- a/packages/SettingsLib/SearchWidget/res/values-ky/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-ky/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="search_menu" msgid="1914043873178389845">"Жөндөөлөрдү издөө"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Параметрлерди издөө"</string>
 </resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
index 90daf11..ec6682e 100644
--- a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="search_menu" msgid="1914043873178389845">"Tìm trong thông tin cài đặt"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Tìm chế độ cài đặt"</string>
 </resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-zu/strings.xml b/packages/SettingsLib/SearchWidget/res/values-zu/strings.xml
index 900f4ba..3d36fa6 100644
--- a/packages/SettingsLib/SearchWidget/res/values-zu/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-zu/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="search_menu" msgid="1914043873178389845">"Sesha izilungiselelo"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Amasethingi okusesha"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ky/strings.xml b/packages/SettingsProvider/res/values-ky/strings.xml
index 7ab6582..830182b 100644
--- a/packages/SettingsProvider/res/values-ky/strings.xml
+++ b/packages/SettingsProvider/res/values-ky/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="4567566098528588863">"Жөндөөлөрдү сактоо"</string>
+    <string name="app_label" msgid="4567566098528588863">"Параметрлерди сактоо"</string>
     <string name="wifi_softap_config_change" msgid="5688373762357941645">"Байланыш түйүнү  параметрлери өзгөрдү"</string>
     <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"Чоо-жайын билүү үчүн басыңыз"</string>
 </resources>
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 83e44b6..f0a8211 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
@@ -18,10 +18,8 @@
 
 import android.graphics.fonts.Font
 import android.graphics.fonts.FontVariationAxis
-import android.util.LruCache
 import android.util.MathUtils
 import android.util.MathUtils.abs
-import androidx.annotation.VisibleForTesting
 import java.lang.Float.max
 import java.lang.Float.min
 
@@ -36,10 +34,6 @@
 private const val FONT_ITALIC_ANIMATION_STEP = 0.1f
 private const val FONT_ITALIC_DEFAULT_VALUE = 0f
 
-// Benchmarked via Perfetto, difference between 10 and 50 entries is about 0.3ms in
-// frame draw time on a Pixel 6.
-@VisibleForTesting const val FONT_CACHE_MAX_ENTRIES = 10
-
 /** Provide interpolation of two fonts by adjusting font variation settings. */
 class FontInterpolator {
 
@@ -87,8 +81,8 @@
     // Font interpolator has two level caches: one for input and one for font with different
     // variation settings. No synchronization is needed since FontInterpolator is not designed to be
     // thread-safe and can be used only on UI thread.
-    private val interpCache = LruCache<InterpKey, Font>(FONT_CACHE_MAX_ENTRIES)
-    private val verFontCache = LruCache<VarFontKey, Font>(FONT_CACHE_MAX_ENTRIES)
+    private val interpCache = hashMapOf<InterpKey, Font>()
+    private val verFontCache = hashMapOf<VarFontKey, Font>()
 
     // Mutable keys for recycling.
     private val tmpInterpKey = InterpKey(null, null, 0f)
@@ -158,7 +152,7 @@
         tmpVarFontKey.set(start, newAxes)
         val axesCachedFont = verFontCache[tmpVarFontKey]
         if (axesCachedFont != null) {
-            interpCache.put(InterpKey(start, end, progress), axesCachedFont)
+            interpCache[InterpKey(start, end, progress)] = axesCachedFont
             return axesCachedFont
         }
 
@@ -166,8 +160,8 @@
         // Font.Builder#build won't throw IOException since creating fonts from existing fonts will
         // not do any IO work.
         val newFont = Font.Builder(start).setFontVariationSettings(newAxes.toTypedArray()).build()
-        interpCache.put(InterpKey(start, end, progress), newFont)
-        verFontCache.put(VarFontKey(start, newAxes), newFont)
+        interpCache[InterpKey(start, end, progress)] = newFont
+        verFontCache[VarFontKey(start, newAxes)] = newFont
         return newFont
     }
 
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 3ee97be..9e9929e 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -24,10 +24,8 @@
 import android.graphics.Typeface
 import android.graphics.fonts.Font
 import android.text.Layout
-import android.util.LruCache
 
 private const val DEFAULT_ANIMATION_DURATION: Long = 300
-private const val TYPEFACE_CACHE_MAX_ENTRIES = 5
 
 typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
 /**
@@ -116,7 +114,7 @@
 
     private val fontVariationUtils = FontVariationUtils()
 
-    private val typefaceCache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES)
+    private val typefaceCache = HashMap<String, Typeface?>()
 
     fun updateLayout(layout: Layout) {
         textInterpolator.layout = layout
@@ -220,12 +218,12 @@
         }
 
         if (!fvar.isNullOrBlank()) {
-            textInterpolator.targetPaint.typeface = typefaceCache.get(fvar) ?: run {
-                textInterpolator.targetPaint.fontVariationSettings = fvar
-                textInterpolator.targetPaint.typeface?.also {
+            textInterpolator.targetPaint.typeface =
+                typefaceCache.getOrElse(fvar) {
+                    textInterpolator.targetPaint.fontVariationSettings = fvar
                     typefaceCache.put(fvar, textInterpolator.targetPaint.typeface)
+                    textInterpolator.targetPaint.typeface
                 }
-            }
         }
 
         if (color != null) {
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3faacf2..adc4c55 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -396,7 +396,7 @@
     <dimen name="navigation_key_width">70dp</dimen>
 
     <!-- The width/height of the icon of a navigation button -->
-    <dimen name="navigation_icon_size">32dp</dimen>
+    <dimen name="navigation_icon_size">24dp</dimen>
 
     <!-- The padding on the side of the navigation bar. Must be greater than or equal to
          navigation_extra_key_width -->
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index b575f9a..a2872e3 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -197,7 +197,8 @@
                     if (mShouldShowComplications) {
                         return (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
                     }
-                    return (requiredTypes & mSupportedTypes) == requiredTypes;
+                    final int typesToAlwaysShow = mSupportedTypes & getAvailableComplicationTypes();
+                    return (requiredTypes & typesToAlwaysShow) == requiredTypes;
                 })
                 .collect(Collectors.toCollection(HashSet::new))
                 : mComplications);
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 57a355f..8a5c5b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
@@ -106,29 +106,4 @@
         val reversedFont = interp.lerp(endFont, startFont, 0.5f)
         assertThat(resultFont).isSameInstanceAs(reversedFont)
     }
-
-    @Test
-    fun testCacheMaxSize() {
-        val interp = FontInterpolator()
-
-        val startFont = Font.Builder(sFont)
-                .setFontVariationSettings("'wght' 100")
-                .build()
-        val endFont = Font.Builder(sFont)
-                .setFontVariationSettings("'wght' 1")
-                .build()
-        val resultFont = interp.lerp(startFont, endFont, 0.5f)
-        for (i in 0..FONT_CACHE_MAX_ENTRIES + 1) {
-            val f1 = Font.Builder(sFont)
-                    .setFontVariationSettings("'wght' ${i * 100}")
-                    .build()
-            val f2 = Font.Builder(sFont)
-                    .setFontVariationSettings("'wght' $i")
-                    .build()
-            interp.lerp(f1, f2, 0.5f)
-        }
-
-        val cachedFont = interp.lerp(startFont, endFont, 0.5f)
-        assertThat(resultFont).isNotSameInstanceAs(cachedFont)
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index 55f0a8c..d0c1c4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -353,6 +353,34 @@
         }
     }
 
+    @Test
+    public void testHomeControlsDoNotShowIfNotAvailable_featureEnabled() {
+        when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(true);
+
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+        stateController.setShouldShowComplications(true);
+
+        final Complication homeControlsComplication = Mockito.mock(Complication.class);
+        when(homeControlsComplication.getRequiredTypeAvailability())
+                .thenReturn(Complication.COMPLICATION_TYPE_HOME_CONTROLS);
+
+        stateController.addComplication(homeControlsComplication);
+
+        final DreamOverlayStateController.Callback callback =
+                Mockito.mock(DreamOverlayStateController.Callback.class);
+
+        stateController.addCallback(callback);
+        mExecutor.runAllReady();
+
+        // No home controls since it is not available.
+        assertThat(stateController.getComplications()).doesNotContain(homeControlsComplication);
+
+        stateController.setAvailableComplicationTypes(Complication.COMPLICATION_TYPE_HOME_CONTROLS
+                | Complication.COMPLICATION_TYPE_WEATHER);
+        mExecutor.runAllReady();
+        assertThat(stateController.getComplications()).contains(homeControlsComplication);
+    }
+
     private DreamOverlayStateController getDreamOverlayStateController(boolean overlayEnabled) {
         return new DreamOverlayStateController(mExecutor, overlayEnabled, mFeatureFlags);
     }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 2cff354..6107aa7 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -916,6 +916,16 @@
     }
 
     void freezeRotation(int rotation) {
+        if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()) {
+            // Flipping 270 and 90 has the same effect as changing the direction which rotation is
+            // applied.
+            if (rotation == Surface.ROTATION_90) {
+                rotation = Surface.ROTATION_270;
+            } else if (rotation == Surface.ROTATION_270) {
+                rotation = Surface.ROTATION_90;
+            }
+        }
+
         rotation = (rotation == -1) ? mRotation : rotation;
         setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 950e9e4..a831b27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -537,6 +537,24 @@
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_180));
     }
 
+    @Test
+    public void testFreezeRotation_reverseRotationDirectionAroundZAxis_yes() throws Exception {
+        mBuilder.build();
+        when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()).thenReturn(true);
+
+        freezeRotation(Surface.ROTATION_90);
+        assertEquals(Surface.ROTATION_270, mTarget.getUserRotation());
+    }
+
+    @Test
+    public void testFreezeRotation_reverseRotationDirectionAroundZAxis_no() throws Exception {
+        mBuilder.build();
+        when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()).thenReturn(false);
+
+        freezeRotation(Surface.ROTATION_90);
+        assertEquals(Surface.ROTATION_90, mTarget.getUserRotation());
+    }
+
     private boolean waitForUiHandler() {
         final CountDownLatch latch = new CountDownLatch(1);
         UiThread.getHandler().post(latch::countDown);