Merge "[cts/SettingsProviderPerfTest] use an allowlisted namespace" into main
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 2587969..5f32ba0 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -43,29 +43,14 @@
],
out: [
"ravenwood.jar",
-
- // Following files are created just as FYI.
- "hoststubgen_framework-minus-apex_keep_all.txt",
- "hoststubgen_framework-minus-apex_dump.txt",
-
"hoststubgen_framework-minus-apex.log",
- "hoststubgen_framework-minus-apex_stats.csv",
- "hoststubgen_framework-minus-apex_apis.csv",
],
}
framework_minus_apex_cmd = "$(location hoststubgen) " +
"@$(location :ravenwood-standard-options) " +
-
"--debug-log $(location hoststubgen_framework-minus-apex.log) " +
- "--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " +
- "--supported-api-list-file $(location hoststubgen_framework-minus-apex_apis.csv) " +
-
"--out-impl-jar $(location ravenwood.jar) " +
-
- "--gen-keep-all-file $(location hoststubgen_framework-minus-apex_keep_all.txt) " +
- "--gen-input-dump-file $(location hoststubgen_framework-minus-apex_dump.txt) " +
-
"--in-jar $(location :framework-minus-apex-for-hoststubgen) " +
"--policy-override-file $(location :ravenwood-framework-policies) " +
"--annotation-allowed-classes-file $(location :ravenwood-annotation-allowed-classes) "
@@ -133,13 +118,26 @@
// Build framework-minus-apex.ravenwood-base without sharding.
// We extract the various dump files from this one, rather than the sharded ones, because
// some dumps use the output from other classes (e.g. base classes) which may not be in the
-// same shard.
+// same shard. Also some of the dump files ("apis") may be slow even when sharded, because
+// the output contains the information from all the input classes, rather than the output classes.
// Not using sharding is fine for this module because it's only used for collecting the
// dump / stats files, which don't have to happen regularly.
java_genrule {
name: "framework-minus-apex.ravenwood-base_all",
defaults: ["framework-minus-apex.ravenwood-base_defaults"],
- cmd: framework_minus_apex_cmd,
+ cmd: framework_minus_apex_cmd +
+ "--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " +
+ "--supported-api-list-file $(location hoststubgen_framework-minus-apex_apis.csv) " +
+
+ "--gen-keep-all-file $(location hoststubgen_framework-minus-apex_keep_all.txt) " +
+ "--gen-input-dump-file $(location hoststubgen_framework-minus-apex_dump.txt) ",
+
+ out: [
+ "hoststubgen_framework-minus-apex_keep_all.txt",
+ "hoststubgen_framework-minus-apex_dump.txt",
+ "hoststubgen_framework-minus-apex_stats.csv",
+ "hoststubgen_framework-minus-apex_apis.csv",
+ ],
}
// Marge all the sharded jars
diff --git a/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java b/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java
index c34936f..fbe67a4 100644
--- a/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java
@@ -19,7 +19,6 @@
import android.graphics.Paint;
import android.graphics.RecordingCanvas;
import android.graphics.RenderNode;
-import android.graphics.Typeface;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
@@ -121,34 +120,13 @@
public void testSetFontVariationSettings() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final Paint paint = new Paint(PAINT);
+ final Random random = new Random(0);
while (state.keepRunning()) {
state.pauseTiming();
- paint.setTypeface(null);
- paint.setFontVariationSettings(null);
- Typeface.clearTypefaceCachesForTestingPurpose();
+ int weight = random.nextInt(1000);
state.resumeTiming();
- paint.setFontVariationSettings("'wght' 450");
+ paint.setFontVariationSettings("'wght' " + weight);
}
- Typeface.clearTypefaceCachesForTestingPurpose();
}
-
- @Test
- public void testSetFontVariationSettings_Cached() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final Paint paint = new Paint(PAINT);
- Typeface.clearTypefaceCachesForTestingPurpose();
-
- while (state.keepRunning()) {
- state.pauseTiming();
- paint.setTypeface(null);
- paint.setFontVariationSettings(null);
- state.resumeTiming();
-
- paint.setFontVariationSettings("'wght' 450");
- }
-
- Typeface.clearTypefaceCachesForTestingPurpose();
- }
-
}
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index fd4d8e9..0cc210b 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1836,9 +1836,10 @@
// have shared library asset paths appended if there are any.
if (r.getImpl() != null) {
final ResourcesImpl oldImpl = r.getImpl();
+ final AssetManager oldAssets = oldImpl.getAssets();
// ResourcesImpl constructor will help to append shared library asset paths.
- if (oldImpl.getAssets().isUpToDate()) {
- final ResourcesImpl newImpl = new ResourcesImpl(oldImpl.getAssets(),
+ if (oldAssets != AssetManager.getSystem() && oldAssets.isUpToDate()) {
+ final ResourcesImpl newImpl = new ResourcesImpl(oldAssets,
oldImpl.getMetrics(), oldImpl.getConfiguration(),
oldImpl.getDisplayAdjustments());
r.setImpl(newImpl);
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index 0c55ed5..9bd4860 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -17,8 +17,6 @@
package android.hardware.camera2.params;
-import static com.android.internal.util.Preconditions.*;
-
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -32,8 +30,6 @@
import android.hardware.camera2.CameraDevice.CameraDeviceSetup;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.params.InputConfiguration;
-import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.HashCodeHelpers;
import android.media.ImageReader;
import android.os.Parcel;
@@ -46,6 +42,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -95,8 +92,8 @@
public @interface SessionMode {};
// Camera capture session related parameters.
- private List<OutputConfiguration> mOutputConfigurations;
- private CameraCaptureSession.StateCallback mStateCallback;
+ private final @NonNull List<OutputConfiguration> mOutputConfigurations;
+ private CameraCaptureSession.StateCallback mStateCallback = null;
private int mSessionType;
private Executor mExecutor = null;
private InputConfiguration mInputConfig = null;
@@ -268,7 +265,8 @@
*/
@Override
public int hashCode() {
- return HashCodeHelpers.hashCode(mOutputConfigurations.hashCode(), mInputConfig.hashCode(),
+ return HashCodeHelpers.hashCode(mOutputConfigurations.hashCode(),
+ Objects.hashCode(mInputConfig),
mSessionType);
}
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index 4d176f2..bb3f6c9 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -277,13 +277,3 @@
purpose: PURPOSE_BUGFIX
}
}
-
-flag {
- name: "typeface_cache_for_var_settings"
- namespace: "text"
- description: "Cache Typeface instance for font variation settings."
- bug: "355462362"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
\ No newline at end of file
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index a7641c0..9e4b27d 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -3574,7 +3574,7 @@
checkPreconditions(sc);
if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
- "reparent", this, sc,
+ "setColor", this, sc,
"r=" + color[0] + " g=" + color[1] + " b=" + color[2]);
}
nativeSetColor(mNativeObject, sc.mNativeObject, color);
diff --git a/core/java/com/android/internal/graphics/ColorUtils.java b/core/java/com/android/internal/graphics/ColorUtils.java
index f72a5ca..f210741 100644
--- a/core/java/com/android/internal/graphics/ColorUtils.java
+++ b/core/java/com/android/internal/graphics/ColorUtils.java
@@ -21,7 +21,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.graphics.Color;
-
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import com.android.internal.graphics.cam.Cam;
/**
@@ -29,6 +29,7 @@
*
* A set of color-related utility methods, building upon those available in {@code Color}.
*/
+@RavenwoodKeepWholeClass
public final class ColorUtils {
private static final double XYZ_WHITE_REFERENCE_X = 95.047;
@@ -696,4 +697,4 @@
double calculateContrast(int foreground, int background, int alpha);
}
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/graphics/cam/Cam.java b/core/java/com/android/internal/graphics/cam/Cam.java
index 1df85c3..49fa37b 100644
--- a/core/java/com/android/internal/graphics/cam/Cam.java
+++ b/core/java/com/android/internal/graphics/cam/Cam.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import com.android.internal.graphics.ColorUtils;
@@ -25,6 +26,7 @@
* A color appearance model, based on CAM16, extended to use L* as the lightness dimension, and
* coupled to a gamut mapping algorithm. Creates a color system, enables a digital design system.
*/
+@RavenwoodKeepWholeClass
public class Cam {
// The maximum difference between the requested L* and the L* returned.
private static final float DL_MAX = 0.2f;
diff --git a/core/java/com/android/internal/graphics/cam/CamUtils.java b/core/java/com/android/internal/graphics/cam/CamUtils.java
index f541729..76fabc6 100644
--- a/core/java/com/android/internal/graphics/cam/CamUtils.java
+++ b/core/java/com/android/internal/graphics/cam/CamUtils.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.graphics.Color;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import com.android.internal.graphics.ColorUtils;
@@ -45,6 +46,7 @@
* consistent, and reasonably good. It worked." - Fairchild, Color Models and Systems: Handbook of
* Color Psychology, 2015
*/
+@RavenwoodKeepWholeClass
public final class CamUtils {
private CamUtils() {
}
diff --git a/core/java/com/android/internal/graphics/cam/Frame.java b/core/java/com/android/internal/graphics/cam/Frame.java
index 0ac7cbc..c419fab 100644
--- a/core/java/com/android/internal/graphics/cam/Frame.java
+++ b/core/java/com/android/internal/graphics/cam/Frame.java
@@ -17,6 +17,7 @@
package com.android.internal.graphics.cam;
import android.annotation.NonNull;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.util.MathUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -33,6 +34,7 @@
* number of calculations during the color => CAM conversion process that depend only on the viewing
* conditions. Caching those calculations in a Frame instance saves a significant amount of time.
*/
+@RavenwoodKeepWholeClass
public final class Frame {
// Standard viewing conditions assumed in RGB specification - Stokes, Anderson, Chandrasekar,
// Motta - A Standard Default Color Space for the Internet: sRGB, 1996.
diff --git a/core/java/com/android/internal/graphics/cam/HctSolver.java b/core/java/com/android/internal/graphics/cam/HctSolver.java
index d7a8691..6e558e7 100644
--- a/core/java/com/android/internal/graphics/cam/HctSolver.java
+++ b/core/java/com/android/internal/graphics/cam/HctSolver.java
@@ -16,6 +16,8 @@
package com.android.internal.graphics.cam;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+
/**
* An efficient algorithm for determining the closest sRGB color to a set of HCT coordinates,
* based on geometrical insights for finding intersections in linear RGB, CAM16, and L*a*b*.
@@ -24,6 +26,7 @@
* Copied from //java/com/google/ux/material/libmonet/hct on May 22 2022.
* ColorUtils/MathUtils functions that were required were added to CamUtils.
*/
+@RavenwoodKeepWholeClass
public class HctSolver {
private HctSolver() {}
diff --git a/core/res/res/layout/time_picker_text_input_material.xml b/core/res/res/layout/time_picker_text_input_material.xml
index 4988842..86070b1 100644
--- a/core/res/res/layout/time_picker_text_input_material.xml
+++ b/core/res/res/layout/time_picker_text_input_material.xml
@@ -34,19 +34,29 @@
android:layoutDirection="ltr">
<EditText
android:id="@+id/input_hour"
- android:layout_width="50dp"
+ android:layout_width="50sp"
android:layout_height="wrap_content"
+ android:layout_alignEnd="@id/hour_label_holder"
android:inputType="number"
android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField"
android:imeOptions="actionNext"/>
- <TextView
- android:id="@+id/label_hour"
+ <!-- Ensure the label_hour takes up at least 50sp of space -->
+ <FrameLayout
+ android:id="@+id/hour_label_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@id/input_hour"
- android:layout_alignStart="@id/input_hour"
- android:labelFor="@+id/input_hour"
- android:text="@string/time_picker_hour_label"/>
+ android:layout_below="@id/input_hour">
+ <TextView
+ android:id="@+id/label_hour"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:labelFor="@+id/input_hour"
+ android:text="@string/time_picker_hour_label"/>
+ <Space
+ android:layout_width="50sp"
+ android:layout_height="0dp"/>
+ </FrameLayout>
<TextView
android:id="@+id/input_separator"
@@ -58,21 +68,30 @@
<EditText
android:id="@+id/input_minute"
- android:layout_width="50dp"
+ android:layout_width="50sp"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/input_hour"
android:layout_toEndOf="@id/input_separator"
android:inputType="number"
android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
- <TextView
- android:id="@+id/label_minute"
+ <!-- Ensure the label_minute takes up at least 50sp of space -->
+ <FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/input_minute"
android:layout_alignStart="@id/input_minute"
- android:labelFor="@+id/input_minute"
- android:text="@string/time_picker_minute_label"/>
-
+ >
+ <TextView
+ android:id="@+id/label_minute"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:labelFor="@+id/input_minute"
+ android:text="@string/time_picker_minute_label"/>
+ <Space
+ android:layout_width="50sp"
+ android:layout_height="0dp"/>
+ </FrameLayout>
<TextView
android:visibility="invisible"
android:id="@+id/label_error"
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 5793bbe..2bbaf9c 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -249,6 +249,7 @@
],
srcs: [
"src/android/app/ActivityManagerTest.java",
+ "src/android/colormodel/CamTest.java",
"src/android/content/ContextTest.java",
"src/android/content/pm/PackageManagerTest.java",
"src/android/content/pm/UserInfoTest.java",
diff --git a/core/tests/coretests/src/android/colormodel/CamTest.java b/core/tests/coretests/src/android/colormodel/CamTest.java
index 05fc0e0..cf398db 100644
--- a/core/tests/coretests/src/android/colormodel/CamTest.java
+++ b/core/tests/coretests/src/android/colormodel/CamTest.java
@@ -18,9 +18,12 @@
import static org.junit.Assert.assertEquals;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.LargeTest;
import org.junit.Assert;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -35,6 +38,9 @@
static final int GREEN = 0xff00ff00;
static final int BLUE = 0xff0000ff;
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Test
public void camFromIntToInt() {
Cam cam = Cam.fromInt(RED);
diff --git a/core/tests/coretests/src/android/graphics/PaintFontVariationTest.java b/core/tests/coretests/src/android/graphics/PaintFontVariationTest.java
deleted file mode 100644
index 8a54e5b..0000000
--- a/core/tests/coretests/src/android/graphics/PaintFontVariationTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2015 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 android.graphics;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.test.InstrumentationTestCase;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.text.flags.Flags;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * PaintTest tests {@link Paint}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class PaintFontVariationTest extends InstrumentationTestCase {
- @Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
- @RequiresFlagsEnabled(Flags.FLAG_TYPEFACE_CACHE_FOR_VAR_SETTINGS)
- @Test
- public void testDerivedFromSameTypeface() {
- final Paint p = new Paint();
-
- p.setTypeface(Typeface.SANS_SERIF);
- assertThat(p.setFontVariationSettings("'wght' 450")).isTrue();
- Typeface first = p.getTypeface();
-
- p.setTypeface(Typeface.SANS_SERIF);
- assertThat(p.setFontVariationSettings("'wght' 480")).isTrue();
- Typeface second = p.getTypeface();
-
- assertThat(first.getDerivedFrom()).isSameInstanceAs(second.getDerivedFrom());
- }
-
- @RequiresFlagsEnabled(Flags.FLAG_TYPEFACE_CACHE_FOR_VAR_SETTINGS)
- @Test
- public void testDerivedFromChained() {
- final Paint p = new Paint();
-
- p.setTypeface(Typeface.SANS_SERIF);
- assertThat(p.setFontVariationSettings("'wght' 450")).isTrue();
- Typeface first = p.getTypeface();
-
- assertThat(p.setFontVariationSettings("'wght' 480")).isTrue();
- Typeface second = p.getTypeface();
-
- assertThat(first.getDerivedFrom()).isSameInstanceAs(second.getDerivedFrom());
- }
-}
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index 878ba70..0dec756 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -16,22 +16,13 @@
package android.graphics;
-import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertNotEquals;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.test.InstrumentationTestCase;
import android.text.TextUtils;
import androidx.test.filters.SmallTest;
-import com.android.text.flags.Flags;
-
-import org.junit.Rule;
-
import java.util.Arrays;
import java.util.HashSet;
@@ -39,9 +30,6 @@
* PaintTest tests {@link Paint}.
*/
public class PaintTest extends InstrumentationTestCase {
- @Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
private static final String FONT_PATH = "fonts/HintedAdvanceWidthTest-Regular.ttf";
static void assertEquals(String message, float[] expected, float[] actual) {
@@ -415,33 +403,4 @@
assertEquals(6, getClusterCount(p, rtlStr + ltrStr));
assertEquals(9, getClusterCount(p, ltrStr + rtlStr + ltrStr));
}
-
- @RequiresFlagsEnabled(Flags.FLAG_TYPEFACE_CACHE_FOR_VAR_SETTINGS)
- public void testDerivedFromSameTypeface() {
- final Paint p = new Paint();
-
- p.setTypeface(Typeface.SANS_SERIF);
- assertThat(p.setFontVariationSettings("'wght' 450")).isTrue();
- Typeface first = p.getTypeface();
-
- p.setTypeface(Typeface.SANS_SERIF);
- assertThat(p.setFontVariationSettings("'wght' 480")).isTrue();
- Typeface second = p.getTypeface();
-
- assertThat(first.getDerivedFrom()).isSameInstanceAs(second.getDerivedFrom());
- }
-
- @RequiresFlagsEnabled(Flags.FLAG_TYPEFACE_CACHE_FOR_VAR_SETTINGS)
- public void testDerivedFromChained() {
- final Paint p = new Paint();
-
- p.setTypeface(Typeface.SANS_SERIF);
- assertThat(p.setFontVariationSettings("'wght' 450")).isTrue();
- Typeface first = p.getTypeface();
-
- assertThat(p.setFontVariationSettings("'wght' 480")).isTrue();
- Typeface second = p.getTypeface();
-
- assertThat(first.getDerivedFrom()).isSameInstanceAs(second.getDerivedFrom());
- }
}
diff --git a/core/tests/resourceflaggingtests/Android.bp b/core/tests/resourceflaggingtests/Android.bp
index dd86094..efb8437 100644
--- a/core/tests/resourceflaggingtests/Android.bp
+++ b/core/tests/resourceflaggingtests/Android.bp
@@ -22,54 +22,6 @@
default_team: "trendy_team_android_resources",
}
-genrule {
- name: "resource-flagging-test-app-resources-compile",
- tools: ["aapt2"],
- srcs: [
- "flagged_resources_res/values/bools.xml",
- ],
- out: ["values_bools.arsc.flat"],
- cmd: "$(location aapt2) compile $(in) -o $(genDir) " +
- "--feature-flags test.package.falseFlag:ro=false,test.package.trueFlag:ro=true",
-}
-
-genrule {
- name: "resource-flagging-test-app-resources-compile2",
- tools: ["aapt2"],
- srcs: [
- "flagged_resources_res/values/bools2.xml",
- ],
- out: ["values_bools2.arsc.flat"],
- cmd: "$(location aapt2) compile $(in) -o $(genDir) " +
- "--feature-flags test.package.falseFlag:ro=false,test.package.trueFlag:ro=true",
-}
-
-genrule {
- name: "resource-flagging-test-app-apk",
- tools: ["aapt2"],
- // The first input file in the list must be the manifest
- srcs: [
- "TestAppAndroidManifest.xml",
- ":resource-flagging-test-app-resources-compile",
- ":resource-flagging-test-app-resources-compile2",
- ],
- out: ["resapp.apk"],
- cmd: "$(location aapt2) link -o $(out) --manifest $(in)",
-}
-
-java_genrule {
- name: "resource-flagging-apk-as-resource",
- srcs: [
- ":resource-flagging-test-app-apk",
- ],
- out: ["apks_as_resources.res.zip"],
- tools: ["soong_zip"],
-
- cmd: "mkdir -p $(genDir)/res/raw && " +
- "cp $(in) $(genDir)/res/raw/$$(basename $(in)) && " +
- "$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
-}
-
android_test {
name: "ResourceFlaggingTests",
srcs: [
@@ -82,6 +34,6 @@
"testng",
"compatibility-device-util-axt",
],
- resource_zips: [":resource-flagging-apk-as-resource"],
+ resource_zips: [":resource-flagging-test-app-apk-as-resource"],
test_suites: ["device-tests"],
}
diff --git a/core/tests/resourceflaggingtests/src/com/android/resourceflaggingtests/ResourceFlaggingTest.java b/core/tests/resourceflaggingtests/src/com/android/resourceflaggingtests/ResourceFlaggingTest.java
index ad8542e..c1e3578 100644
--- a/core/tests/resourceflaggingtests/src/com/android/resourceflaggingtests/ResourceFlaggingTest.java
+++ b/core/tests/resourceflaggingtests/src/com/android/resourceflaggingtests/ResourceFlaggingTest.java
@@ -69,11 +69,23 @@
}
private boolean getBoolean(String name) {
- int resId = mResources.getIdentifier(name, "bool", "com.android.intenal.flaggedresources");
+ int resId = mResources.getIdentifier(
+ name,
+ "bool",
+ "com.android.intenal.flaggedresources");
assertThat(resId).isNotEqualTo(0);
return mResources.getBoolean(resId);
}
+ private String getString(String name) {
+ int resId = mResources.getIdentifier(
+ name,
+ "string",
+ "com.android.intenal.flaggedresources");
+ assertThat(resId).isNotEqualTo(0);
+ return mResources.getString(resId);
+ }
+
private String extractApkAndGetPath(int id) throws Exception {
final Resources resources = mContext.getResources();
try (InputStream is = resources.openRawResource(id)) {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 889a7785..fd78816 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -56,7 +56,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
-import com.android.text.flags.Flags;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
@@ -75,7 +74,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -145,23 +143,6 @@
private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16);
private static final Object sDynamicCacheLock = new Object();
- private static final LruCache<Long, LruCache<String, Typeface>> sVariableCache =
- new LruCache<>(16);
- private static final Object sVariableCacheLock = new Object();
-
- /** @hide */
- @VisibleForTesting
- public static void clearTypefaceCachesForTestingPurpose() {
- synchronized (sWeightCacheLock) {
- sWeightTypefaceCache.clear();
- }
- synchronized (sDynamicCacheLock) {
- sDynamicTypefaceCache.evictAll();
- }
- synchronized (sVariableCacheLock) {
- sVariableCache.evictAll();
- }
- }
@GuardedBy("SYSTEM_FONT_MAP_LOCK")
static Typeface sDefaultTypeface;
@@ -214,8 +195,6 @@
@UnsupportedAppUsage
public final long native_instance;
- private final Typeface mDerivedFrom;
-
private final String mSystemFontFamilyName;
private final Runnable mCleaner;
@@ -295,18 +274,6 @@
}
/**
- * Returns the Typeface used for creating this Typeface.
- *
- * Maybe null if this is not derived from other Typeface.
- * TODO(b/357707916): Make this public API.
- * @hide
- */
- @VisibleForTesting
- public final @Nullable Typeface getDerivedFrom() {
- return mDerivedFrom;
- }
-
- /**
* Returns the system font family name if the typeface was created from a system font family,
* otherwise returns null.
*/
@@ -1054,51 +1021,9 @@
return typeface;
}
- private static String axesToVarKey(@NonNull List<FontVariationAxis> axes) {
- // The given list can be mutated because it is allocated in Paint#setFontVariationSettings.
- // Currently, Paint#setFontVariationSettings is the only code path reaches this method.
- axes.sort(Comparator.comparingInt(FontVariationAxis::getOpenTypeTagValue));
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < axes.size(); ++i) {
- final FontVariationAxis fva = axes.get(i);
- sb.append(fva.getTag());
- sb.append(fva.getStyleValue());
- }
- return sb.toString();
- }
-
- /**
- * TODO(b/357707916): Make this public API.
- * @hide
- */
+ /** @hide */
public static Typeface createFromTypefaceWithVariation(@Nullable Typeface family,
@NonNull List<FontVariationAxis> axes) {
- if (Flags.typefaceCacheForVarSettings()) {
- final Typeface target = (family == null) ? Typeface.DEFAULT : family;
- final Typeface base = (target.mDerivedFrom == null) ? target : target.mDerivedFrom;
-
- final String key = axesToVarKey(axes);
-
- synchronized (sVariableCacheLock) {
- LruCache<String, Typeface> innerCache = sVariableCache.get(base.native_instance);
- if (innerCache == null) {
- // Cache up to 16 var instance per root Typeface
- innerCache = new LruCache<>(16);
- sVariableCache.put(base.native_instance, innerCache);
- } else {
- Typeface cached = innerCache.get(key);
- if (cached != null) {
- return cached;
- }
- }
- Typeface typeface = new Typeface(
- nativeCreateFromTypefaceWithVariation(base.native_instance, axes),
- base.getSystemFontFamilyName(), base);
- innerCache.put(key, typeface);
- return typeface;
- }
- }
-
final Typeface base = family == null ? Typeface.DEFAULT : family;
Typeface typeface = new Typeface(
nativeCreateFromTypefaceWithVariation(base.native_instance, axes),
@@ -1259,19 +1184,11 @@
// don't allow clients to call this directly
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Typeface(long ni) {
- this(ni, null, null);
+ this(ni, null);
}
-
// don't allow clients to call this directly
- // This is kept for robolectric.
private Typeface(long ni, @Nullable String systemFontFamilyName) {
- this(ni, systemFontFamilyName, null);
- }
-
- // don't allow clients to call this directly
- private Typeface(long ni, @Nullable String systemFontFamilyName,
- @Nullable Typeface derivedFrom) {
if (ni == 0) {
throw new RuntimeException("native typeface cannot be made");
}
@@ -1281,7 +1198,6 @@
mStyle = nativeGetStyle(ni);
mWeight = nativeGetWeight(ni);
mSystemFontFamilyName = systemFontFamilyName;
- mDerivedFrom = derivedFrom;
}
/**
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 0a8166f..df5f1e4 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -139,6 +139,10 @@
<string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
<!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
<string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
+ <!-- Click action label for bubbles to expand menu. [CHAR LIMIT=30]-->
+ <string name="bubble_accessibility_action_expand_menu">expand menu</string>
+ <!-- Click action label for bubbles to collapse menu. [CHAR LIMIT=30]-->
+ <string name="bubble_accessibility_action_collapse_menu">collapse menu</string>
<!-- Accessibility announcement when the stack of bubbles expands. [CHAR LIMIT=NONE]-->
<string name="bubble_accessibility_announce_expand">expand <xliff:g id="bubble_title" example="Messages">%1$s</xliff:g></string>
<!-- Accessibility announcement when the stack of bubbles collapses. [CHAR LIMIT=NONE]-->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index c374478..b7834db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -32,6 +32,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import com.android.wm.shell.R;
@@ -188,6 +189,17 @@
// Handle view needs to draw on top of task view.
bringChildToFront(mHandleView);
+
+ mHandleView.setAccessibilityDelegate(new AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.addAction(new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK, getResources().getString(
+ R.string.bubble_accessibility_action_expand_menu)));
+ }
+ });
}
mMenuViewController = new BubbleBarMenuViewController(mContext, this);
mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
index 8389c81..0300869 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
@@ -23,7 +23,9 @@
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -71,6 +73,16 @@
mBubbleTitleView = findViewById(R.id.bubble_bar_manage_menu_bubble_title);
mBubbleDismissIconView = findViewById(R.id.bubble_bar_manage_menu_dismiss_icon);
updateThemeColors();
+
+ mBubbleSectionView.setAccessibilityDelegate(new AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.addAction(new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK, getResources().getString(
+ R.string.bubble_accessibility_action_collapse_menu)));
+ }
+ });
}
private void updateThemeColors() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index 7774384..dc21f82 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -31,6 +31,8 @@
import android.os.Bundle;
import android.view.InsetsState;
import android.view.SurfaceControl;
+import android.window.DisplayAreaInfo;
+import android.window.WindowContainerTransaction;
import androidx.annotation.BinderThread;
import androidx.annotation.Nullable;
@@ -40,6 +42,7 @@
import com.android.internal.util.Preconditions;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
@@ -71,7 +74,8 @@
*/
public class PipController implements ConfigurationChangeListener,
PipTransitionState.PipTransitionStateChangedListener,
- DisplayController.OnDisplaysChangedListener, RemoteCallable<PipController> {
+ DisplayController.OnDisplaysChangedListener,
+ DisplayChangeController.OnDisplayChangingListener, RemoteCallable<PipController> {
private static final String TAG = PipController.class.getSimpleName();
private static final String SWIPE_TO_PIP_APP_BOUNDS = "pip_app_bounds";
private static final String SWIPE_TO_PIP_OVERLAY = "swipe_to_pip_overlay";
@@ -197,11 +201,12 @@
mPipDisplayLayoutState.setDisplayLayout(layout);
mDisplayController.addDisplayWindowListener(this);
+ mDisplayController.addDisplayChangingController(this);
mDisplayInsetsController.addInsetsChangedListener(mPipDisplayLayoutState.getDisplayId(),
new DisplayInsetsController.OnInsetsChangedListener() {
@Override
public void insetsChanged(InsetsState insetsState) {
- onDisplayChanged(mDisplayController
+ setDisplayLayout(mDisplayController
.getDisplayLayout(mPipDisplayLayoutState.getDisplayId()));
}
});
@@ -264,11 +269,12 @@
@Override
public void onThemeChanged() {
- onDisplayChanged(new DisplayLayout(mContext, mContext.getDisplay()));
+ setDisplayLayout(new DisplayLayout(mContext, mContext.getDisplay()));
}
//
- // DisplayController.OnDisplaysChangedListener implementations
+ // DisplayController.OnDisplaysChangedListener and
+ // DisplayChangeController.OnDisplayChangingListener implementations
//
@Override
@@ -276,7 +282,7 @@
if (displayId != mPipDisplayLayoutState.getDisplayId()) {
return;
}
- onDisplayChanged(mDisplayController.getDisplayLayout(displayId));
+ setDisplayLayout(mDisplayController.getDisplayLayout(displayId));
}
@Override
@@ -284,10 +290,35 @@
if (displayId != mPipDisplayLayoutState.getDisplayId()) {
return;
}
- onDisplayChanged(mDisplayController.getDisplayLayout(displayId));
+ setDisplayLayout(mDisplayController.getDisplayLayout(displayId));
}
- private void onDisplayChanged(DisplayLayout layout) {
+ /**
+ * A callback for any observed transition that contains a display change in its
+ * {@link android.window.TransitionRequestInfo} with a non-zero rotation delta.
+ */
+ @Override
+ public void onDisplayChange(int displayId, int fromRotation, int toRotation,
+ @Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction t) {
+ if (!mPipTransitionState.isInPip()) {
+ return;
+ }
+
+ // Calculate the snap fraction pre-rotation.
+ float snapFraction = mPipBoundsAlgorithm.getSnapFraction(mPipBoundsState.getBounds());
+
+ // Update the caches to reflect the new display layout and movement bounds.
+ mPipDisplayLayoutState.rotateTo(toRotation);
+ mPipTouchHandler.updateMovementBounds();
+
+ // The policy is to keep PiP width, height and snap fraction invariant.
+ Rect toBounds = mPipBoundsState.getBounds();
+ mPipBoundsAlgorithm.applySnapFraction(toBounds, snapFraction);
+ mPipBoundsState.setBounds(toBounds);
+ t.setBounds(mPipTransitionState.mPipTaskToken, toBounds);
+ }
+
+ private void setDisplayLayout(DisplayLayout layout) {
mPipDisplayLayoutState.setDisplayLayout(layout);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index d7c225b..d75fa00 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -1081,7 +1081,7 @@
* Updates the current movement bounds based on whether the menu is currently visible and
* resized.
*/
- private void updateMovementBounds() {
+ void updateMovementBounds() {
Rect insetBounds = new Rect();
mPipBoundsAlgorithm.getInsetBounds(insetBounds);
mPipBoundsAlgorithm.getMovementBounds(mPipBoundsState.getBounds(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 48d17ec6..c11a112 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -439,9 +439,9 @@
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setResizeTransition: hasPendingResize=%b",
mPendingResize != null);
if (mPendingResize != null) {
+ mPendingResize.cancel(null);
mainDecor.cancelRunningAnimations();
sideDecor.cancelRunningAnimations();
- mPendingResize.cancel(null);
mAnimations.clear();
onFinish(null /* wct */);
}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8751596..a5fd5b9 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -971,8 +971,8 @@
<string name="hearing_devices_presets_error">Couldn\'t update preset</string>
<!-- QuickSettings: Title for hearing aids presets. Preset is a set of hearing aid settings. User can apply different settings in different environments (e.g. Outdoor, Restaurant, Home) [CHAR LIMIT=40]-->
<string name="hearing_devices_preset_label">Preset</string>
- <!-- QuickSettings: Tool name for hearing devices dialog related tools [CHAR LIMIT=40]-->
- <string name="live_caption_title">Live Caption</string>
+ <!-- QuickSettings: Tool name for hearing devices dialog related tools [CHAR LIMIT=40] [BACKUP_MESSAGE_ID=8916875614623730005]-->
+ <string name="quick_settings_hearing_devices_live_caption_title">Live Caption</string>
<!--- Title of dialog triggered if the microphone is disabled but an app tried to access it. [CHAR LIMIT=150] -->
<string name="sensor_privacy_start_use_mic_dialog_title">Unblock device microphone?</string>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index 083f1db..b6fe0df 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -499,7 +499,8 @@
final List<ResolveInfo> resolved = packageManager.queryIntentActivities(LIVE_CAPTION_INTENT,
/* flags= */ 0);
if (!resolved.isEmpty()) {
- return new ToolItem(context.getString(R.string.live_caption_title),
+ return new ToolItem(
+ context.getString(R.string.quick_settings_hearing_devices_live_caption_title),
context.getDrawable(R.drawable.ic_volume_odi_captions),
LIVE_CAPTION_INTENT);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 51d92f0..5dc020f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -300,7 +300,9 @@
swipeToDismissInteractor.dismissFling
.filterNotNull()
.filterRelevantKeyguardState()
- .collect { _ -> startTransitionTo(KeyguardState.GONE) }
+ .collect { _ ->
+ startTransitionTo(KeyguardState.GONE, ownerReason = "dismissFling != null")
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractor.kt
index 86e4115..906d586 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractor.kt
@@ -19,14 +19,15 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.Utils.Companion.sample
-import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import javax.inject.Inject
/**
* Handles logic around the swipe to dismiss gesture, where the user swipes up on the dismissable
@@ -53,12 +54,14 @@
shadeRepository.currentFling
.sample(
transitionInteractor.startedKeyguardState,
- keyguardInteractor.isKeyguardDismissible
+ keyguardInteractor.isKeyguardDismissible,
+ keyguardInteractor.statusBarState,
)
- .filter { (flingInfo, startedState, keyguardDismissable) ->
+ .filter { (flingInfo, startedState, keyguardDismissable, statusBarState) ->
flingInfo != null &&
- !flingInfo.expand &&
- startedState == KeyguardState.LOCKSCREEN &&
+ !flingInfo.expand &&
+ statusBarState != StatusBarState.SHADE_LOCKED &&
+ startedState == KeyguardState.LOCKSCREEN &&
keyguardDismissable
}
.map { (flingInfo, _) -> flingInfo }
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
index 98a61df..863a899 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -24,6 +24,7 @@
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
+import android.util.Log
import com.android.internal.logging.UiEventLogger
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.dagger.qualifiers.LongRunning
@@ -71,6 +72,7 @@
override fun provideRecordingServiceStrings(): RecordingServiceStrings = IrsStrings(resources)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ Log.d(getTag(), "handling action: ${intent?.action}")
when (intent?.action) {
ACTION_START -> {
bgExecutor.execute {
@@ -95,7 +97,7 @@
bgExecutor.execute {
mNotificationManager.cancelAsUser(
null,
- mNotificationId,
+ intent.getIntExtra(EXTRA_NOTIFICATION_ID, mNotificationId),
UserHandle(mUserContextTracker.userContext.userId)
)
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 108564c..700253ba 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -80,6 +80,7 @@
"com.android.systemui.screenrecord.STOP_FROM_NOTIF";
protected static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+ protected static final String EXTRA_NOTIFICATION_ID = "notification_id";
private final RecordingController mController;
protected final KeyguardDismissUtil mKeyguardDismissUtil;
@@ -542,7 +543,8 @@
private Intent getShareIntent(Context context, Uri path) {
return new Intent(context, this.getClass()).setAction(ACTION_SHARE)
- .putExtra(EXTRA_PATH, path);
+ .putExtra(EXTRA_PATH, path)
+ .putExtra(EXTRA_NOTIFICATION_ID, mNotificationId);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index b6d58d6..db8cd57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2985,7 +2985,7 @@
@Override
public void onFalse() {
// Hides quick settings, bouncer, and quick-quick settings.
- mStatusBarKeyguardViewManager.reset(true);
+ mStatusBarKeyguardViewManager.reset(true, /* isFalsingReset= */true);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 2d775b7..f8f9b77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -708,7 +708,7 @@
* Shows the notification keyguard or the bouncer depending on
* {@link #needsFullscreenBouncer()}.
*/
- protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
+ protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing, boolean isFalsingReset) {
boolean isDozing = mDozing;
if (Flags.simPinRaceConditionOnRestart()) {
KeyguardState toState = mKeyguardTransitionInteractor.getTransitionState().getValue()
@@ -734,8 +734,11 @@
mPrimaryBouncerInteractor.show(/* isScrimmed= */ true);
}
}
- } else {
- Log.e(TAG, "Attempted to show the sim bouncer when it is already showing.");
+ } else if (!isFalsingReset) {
+ // Falsing resets can cause this to flicker, so don't reset in this case
+ Log.i(TAG, "Sim bouncer is already showing, issuing a refresh");
+ mPrimaryBouncerInteractor.show(/* isScrimmed= */ true);
+
}
} else {
mCentralSurfaces.showKeyguard();
@@ -957,6 +960,10 @@
@Override
public void reset(boolean hideBouncerWhenShowing) {
+ reset(hideBouncerWhenShowing, /* isFalsingReset= */false);
+ }
+
+ public void reset(boolean hideBouncerWhenShowing, boolean isFalsingReset) {
if (mKeyguardStateController.isShowing() && !bouncerIsAnimatingAway()) {
final boolean isOccluded = mKeyguardStateController.isOccluded();
// Hide quick settings.
@@ -968,7 +975,7 @@
hideBouncer(false /* destroyView */);
}
} else {
- showBouncerOrKeyguard(hideBouncerWhenShowing);
+ showBouncerOrKeyguard(hideBouncerWhenShowing, isFalsingReset);
}
if (hideBouncerWhenShowing) {
hideAlternateBouncer(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index af5e60e..9b61105 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -1068,7 +1068,7 @@
public void testShowBouncerOrKeyguard_needsFullScreen() {
when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
KeyguardSecurityModel.SecurityMode.SimPin);
- mStatusBarKeyguardViewManager.showBouncerOrKeyguard(false);
+ mStatusBarKeyguardViewManager.showBouncerOrKeyguard(false, false);
verify(mCentralSurfaces).hideKeyguard();
verify(mPrimaryBouncerInteractor).show(true);
}
@@ -1084,7 +1084,7 @@
.thenReturn(KeyguardState.LOCKSCREEN);
reset(mCentralSurfaces);
- mStatusBarKeyguardViewManager.showBouncerOrKeyguard(false);
+ mStatusBarKeyguardViewManager.showBouncerOrKeyguard(false, false);
verify(mPrimaryBouncerInteractor).show(true);
verify(mCentralSurfaces).showKeyguard();
}
@@ -1092,11 +1092,26 @@
@Test
@DisableSceneContainer
public void testShowBouncerOrKeyguard_needsFullScreen_bouncerAlreadyShowing() {
+ boolean isFalsingReset = false;
when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
KeyguardSecurityModel.SecurityMode.SimPin);
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
- mStatusBarKeyguardViewManager.showBouncerOrKeyguard(false);
+ mStatusBarKeyguardViewManager.showBouncerOrKeyguard(false, isFalsingReset);
verify(mCentralSurfaces, never()).hideKeyguard();
+ verify(mPrimaryBouncerInteractor).show(true);
+ }
+
+ @Test
+ @DisableSceneContainer
+ public void testShowBouncerOrKeyguard_needsFullScreen_bouncerAlreadyShowing_onFalsing() {
+ boolean isFalsingReset = true;
+ when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
+ KeyguardSecurityModel.SecurityMode.SimPin);
+ when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
+ mStatusBarKeyguardViewManager.showBouncerOrKeyguard(false, isFalsingReset);
+ verify(mCentralSurfaces, never()).hideKeyguard();
+
+ // Do not refresh the full screen bouncer if the call is from falsing
verify(mPrimaryBouncerInteractor, never()).show(true);
}
diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
index 68f185e..cc9b70e 100644
--- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
@@ -281,6 +281,12 @@
com.android.server.LocalServices
+com.android.internal.graphics.cam.Cam
+com.android.internal.graphics.cam.CamUtils
+com.android.internal.graphics.cam.Frame
+com.android.internal.graphics.cam.HctSolver
+com.android.internal.graphics.ColorUtils
+
com.android.internal.util.BitUtils
com.android.internal.util.BitwiseInputStream
com.android.internal.util.BitwiseOutputStream
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index 4dbbfa2..c77b768 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -512,6 +512,9 @@
/**
* Gets the next input method and subtype from the given ones.
*
+ * <p>If the given input method and subtype are not found, this returns the most recent
+ * input method and subtype.</p>
+ *
* @param imi the input method to find the next value from.
* @param subtype the input method subtype to find the next value from, if any.
* @param onlyCurrentIme whether to consider only subtypes of the current input method.
@@ -523,17 +526,20 @@
public ImeSubtypeListItem next(@NonNull InputMethodInfo imi,
@Nullable InputMethodSubtype subtype, boolean onlyCurrentIme,
boolean useRecency, boolean forward) {
- final int size = mItems.size();
- if (size <= 1) {
+ if (mItems.isEmpty()) {
return null;
}
final int index = getIndex(imi, subtype, useRecency);
if (index < 0) {
- return null;
+ Slog.w(TAG, "Trying to switch away from input method: " + imi
+ + " and subtype " + subtype + " which are not in the list,"
+ + " falling back to most recent item in list.");
+ return mItems.get(mRecencyMap[0]);
}
final int incrementSign = (forward ? 1 : -1);
+ final int size = mItems.size();
for (int i = 1; i < size; i++) {
final int nextIndex = (index + i * incrementSign + size) % size;
final int mappedIndex = useRecency ? mRecencyMap[nextIndex] : nextIndex;
@@ -554,7 +560,7 @@
*/
public boolean setMostRecent(@NonNull InputMethodInfo imi,
@Nullable InputMethodSubtype subtype) {
- if (mItems.size() <= 1) {
+ if (mItems.isEmpty()) {
return false;
}
@@ -849,6 +855,9 @@
/**
* Gets the next input method and subtype, starting from the given ones, in the given direction.
*
+ * <p>If the given input method and subtype are not found, this returns the most recent
+ * input method and subtype.</p>
+ *
* @param onlyCurrentIme whether to consider only subtypes of the current input method.
* @param imi the input method to find the next value from.
* @param subtype the input method subtype to find the next value from, if any.
@@ -867,6 +876,9 @@
* Gets the next input method and subtype suitable for hardware keyboards, starting from the
* given ones, in the given direction.
*
+ * <p>If the given input method and subtype are not found, this returns the most recent
+ * input method and subtype.</p>
+ *
* @param onlyCurrentIme whether to consider only subtypes of the current input method.
* @param imi the input method to find the next value from.
* @param subtype the input method subtype to find the next value from, if any.
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 17f6561..a6f4c0e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -530,6 +530,12 @@
*/
private boolean mUseDifferentDelaysForBackgroundChain;
+ /**
+ * Core uids and apps without the internet permission will not have any firewall rules applied
+ * to them.
+ */
+ private boolean mNeverApplyRulesToCoreUids;
+
// See main javadoc for instructions on how to use these locks.
final Object mUidRulesFirstLock = new Object();
final Object mNetworkPoliciesSecondLock = new Object();
@@ -760,7 +766,8 @@
/** List of apps indexed by uid and whether they have the internet permission */
@GuardedBy("mUidRulesFirstLock")
- private final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray();
+ @VisibleForTesting
+ final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray();
/**
* Map of uid -> UidStateCallbackInfo objects holding the data received from
@@ -1038,6 +1045,7 @@
mUseMeteredFirewallChains = Flags.useMeteredFirewallChains();
mUseDifferentDelaysForBackgroundChain = Flags.useDifferentDelaysForBackgroundChain();
+ mNeverApplyRulesToCoreUids = Flags.neverApplyRulesToCoreUids();
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
@@ -4088,6 +4096,8 @@
+ mUseMeteredFirewallChains);
fout.println(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN + ": "
+ mUseDifferentDelaysForBackgroundChain);
+ fout.println(Flags.FLAG_NEVER_APPLY_RULES_TO_CORE_UIDS + ": "
+ + mNeverApplyRulesToCoreUids);
fout.println();
fout.println("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
@@ -4878,6 +4888,12 @@
int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
for (int uid : idleUids) {
if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
+ if (mNeverApplyRulesToCoreUids && !isUidValidForRulesUL(uid)) {
+ // This check is needed to keep mUidFirewallStandbyRules free of any
+ // such uids. Doing this keeps it in sync with the actual rules applied
+ // in the underlying connectivity stack.
+ continue;
+ }
// quick check: if this uid doesn't have INTERNET permission, it
// doesn't have network access anyway, so it is a waste to mess
// with it here.
@@ -5180,6 +5196,11 @@
@GuardedBy("mUidRulesFirstLock")
private boolean isUidValidForAllowlistRulesUL(int uid) {
+ return isUidValidForRulesUL(uid);
+ }
+
+ @GuardedBy("mUidRulesFirstLock")
+ private boolean isUidValidForRulesUL(int uid) {
return UserHandle.isApp(uid) && hasInternetPermissionUL(uid);
}
@@ -6194,41 +6215,33 @@
}
}
- private void addSdkSandboxUidsIfNeeded(SparseIntArray uidRules) {
- final int size = uidRules.size();
- final SparseIntArray sdkSandboxUids = new SparseIntArray();
- for (int index = 0; index < size; index++) {
- final int uid = uidRules.keyAt(index);
- final int rule = uidRules.valueAt(index);
- if (Process.isApplicationUid(uid)) {
- sdkSandboxUids.put(Process.toSdkSandboxUid(uid), rule);
- }
- }
-
- for (int index = 0; index < sdkSandboxUids.size(); index++) {
- final int uid = sdkSandboxUids.keyAt(index);
- final int rule = sdkSandboxUids.valueAt(index);
- uidRules.put(uid, rule);
- }
- }
-
/**
* Set uid rules on a particular firewall chain. This is going to synchronize the rules given
* here to netd. It will clean up dead rules and make sure the target chain only contains rules
* specified here.
*/
+ @GuardedBy("mUidRulesFirstLock")
private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) {
- addSdkSandboxUidsIfNeeded(uidRules);
try {
int size = uidRules.size();
- int[] uids = new int[size];
- int[] rules = new int[size];
+ final IntArray uids = new IntArray(size);
+ final IntArray rules = new IntArray(size);
for(int index = size - 1; index >= 0; --index) {
- uids[index] = uidRules.keyAt(index);
- rules[index] = uidRules.valueAt(index);
+ final int uid = uidRules.keyAt(index);
+ if (mNeverApplyRulesToCoreUids && !isUidValidForRulesUL(uid)) {
+ continue;
+ }
+ uids.add(uid);
+ rules.add(uidRules.valueAt(index));
+ if (Process.isApplicationUid(uid)) {
+ uids.add(Process.toSdkSandboxUid(uid));
+ rules.add(uidRules.valueAt(index));
+ }
}
- mNetworkManager.setFirewallUidRules(chain, uids, rules);
- mLogger.firewallRulesChanged(chain, uids, rules);
+ final int[] uidArray = uids.toArray();
+ final int[] ruleArray = rules.toArray();
+ mNetworkManager.setFirewallUidRules(chain, uidArray, ruleArray);
+ mLogger.firewallRulesChanged(chain, uidArray, ruleArray);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
@@ -6241,6 +6254,9 @@
*/
@GuardedBy("mUidRulesFirstLock")
private void setUidFirewallRuleUL(int chain, int uid, int rule) {
+ if (mNeverApplyRulesToCoreUids && !isUidValidForRulesUL(uid)) {
+ return;
+ }
if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
"setUidFirewallRuleUL: " + chain + "/" + uid + "/" + rule);
@@ -6249,8 +6265,6 @@
if (chain == FIREWALL_CHAIN_STANDBY) {
mUidFirewallStandbyRules.put(uid, rule);
}
- // Note that we do not need keep a separate cache of uid rules for chains that we do
- // not call #setUidFirewallRulesUL for.
try {
mNetworkManager.setFirewallUidRule(chain, uid, rule);
@@ -6295,6 +6309,8 @@
* Resets all firewall rules associated with an UID.
*/
private void resetUidFirewallRules(int uid) {
+ // Resetting rules for uids with isUidValidForRulesUL = false should be OK as no rules
+ // should be previously set and the downstream code will skip no-op changes.
try {
mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid,
FIREWALL_RULE_DEFAULT);
diff --git a/services/core/java/com/android/server/net/flags.aconfig b/services/core/java/com/android/server/net/flags.aconfig
index 586baf0..7f04e66 100644
--- a/services/core/java/com/android/server/net/flags.aconfig
+++ b/services/core/java/com/android/server/net/flags.aconfig
@@ -27,3 +27,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "never_apply_rules_to_core_uids"
+ namespace: "backstage_power"
+ description: "Removes all rule bookkeeping and evaluation logic for core uids and uids without the internet permission"
+ bug: "356956588"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 06e665e..fe5b142 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -761,7 +761,7 @@
if (isMonitorForRemote()) {
mObserver.sendResult(null /* result */);
}
- if (isMonitorAnimationOrTransition()) {
+ if (isMonitorAnimationOrTransition() && canCancelAnimations()) {
clearBackAnimations(true /* cancel */);
}
cancelPendingAnimation();
@@ -2046,11 +2046,22 @@
}
}
+ /** If the open transition is playing, wait for transition to clear the animation */
+ private boolean canCancelAnimations() {
+ if (!Flags.migratePredictiveBackTransition()) {
+ return true;
+ }
+ return mAnimationHandler.mOpenAnimAdaptor == null
+ || mAnimationHandler.mOpenAnimAdaptor.mPreparedOpenTransition == null;
+ }
+
void startAnimation() {
if (!mBackAnimationInProgress) {
// gesture is already finished, do not start animation
if (mPendingAnimation != null) {
- clearBackAnimations(true /* cancel */);
+ if (canCancelAnimations()) {
+ clearBackAnimations(true /* cancel */);
+ }
mPendingAnimation = null;
}
return;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 7a95c2d..2f0ee17 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -129,21 +129,33 @@
@WindowConfiguration.WindowingMode
private int getWindowingModeLocked(@NonNull SettingsProvider.SettingsEntry settings,
@NonNull DisplayContent dc) {
- int windowingMode = settings.mWindowingMode;
+ final int windowingModeFromDisplaySettings = settings.mWindowingMode;
// This display used to be in freeform, but we don't support freeform anymore, so fall
// back to fullscreen.
- if (windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
+ if (windowingModeFromDisplaySettings == WindowConfiguration.WINDOWING_MODE_FREEFORM
&& !mService.mAtmService.mSupportsFreeformWindowManagement) {
return WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
}
- // No record is present so use default windowing mode policy.
- if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- windowingMode = mService.mAtmService.mSupportsFreeformWindowManagement
- && (mService.mIsPc || dc.forceDesktopMode())
- ? WindowConfiguration.WINDOWING_MODE_FREEFORM
- : WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+ if (windowingModeFromDisplaySettings != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
+ return windowingModeFromDisplaySettings;
}
- return windowingMode;
+ // No record is present so use default windowing mode policy.
+ final boolean forceFreeForm = mService.mAtmService.mSupportsFreeformWindowManagement
+ && (mService.mIsPc || dc.forceDesktopMode());
+ if (forceFreeForm) {
+ return WindowConfiguration.WINDOWING_MODE_FREEFORM;
+ }
+ final int currentWindowingMode = dc.getDefaultTaskDisplayArea().getWindowingMode();
+ if (currentWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
+ // No record preset in settings + no mode set via the display area policy.
+ // Move to fullscreen as a fallback.
+ return WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+ }
+ if (currentWindowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) {
+ // Freeform was enabled before but disabled now, the TDA should now move to fullscreen.
+ return WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+ }
+ return currentWindowingMode;
}
@WindowConfiguration.WindowingMode
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index aee7242..a27ad9a 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -913,52 +913,100 @@
final var controller = ControllerImpl.createFrom(null /* currentInstance */, List.of(),
List.of());
- assertNoAction(controller, false /* forHardware */, items);
- assertNoAction(controller, true /* forHardware */, hardwareItems);
+ assertNextItemNoAction(controller, false /* forHardware */, items,
+ null /* expectedNext */);
+ assertNextItemNoAction(controller, true /* forHardware */, hardwareItems,
+ null /* expectedNext */);
}
- /** Verifies that a controller with a single item can't take any actions. */
+ /**
+ * Verifies that a controller with a single item can't update the recency, and cannot switch
+ * away from the item, but allows switching from unknown items to the single item.
+ */
@RequiresFlagsEnabled(Flags.FLAG_IME_SWITCHER_REVAMP)
@Test
public void testSingleItemList() {
final var items = new ArrayList<ImeSubtypeListItem>();
addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
- List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+ null, true /* supportsSwitchingToNextInputMethod */);
+ final var unknownItems = new ArrayList<ImeSubtypeListItem>();
+ addTestImeSubtypeListItems(unknownItems, "UnknownIme", "UnknownIme",
+ List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
final var hardwareItems = new ArrayList<ImeSubtypeListItem>();
addTestImeSubtypeListItems(hardwareItems, "HardwareIme", "HardwareIme",
- List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+ null, true /* supportsSwitchingToNextInputMethod */);
+ final var unknownHardwareItems = new ArrayList<ImeSubtypeListItem>();
+ addTestImeSubtypeListItems(unknownHardwareItems, "HardwareUnknownIme", "HardwareUnknownIme",
+ List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
final var controller = ControllerImpl.createFrom(null /* currentInstance */,
- List.of(items.get(0)), List.of(hardwareItems.get(0)));
+ items, hardwareItems);
- assertNoAction(controller, false /* forHardware */, items);
- assertNoAction(controller, true /* forHardware */, hardwareItems);
+ assertNextItemNoAction(controller, false /* forHardware */, items,
+ null /* expectedNext */);
+ assertNextItemNoAction(controller, false /* forHardware */, unknownItems,
+ items.get(0));
+ assertNextItemNoAction(controller, true /* forHardware */, hardwareItems,
+ null /* expectedNext */);
+ assertNextItemNoAction(controller, true /* forHardware */, unknownHardwareItems,
+ hardwareItems.get(0));
}
- /** Verifies that a controller can't take any actions for unknown items. */
+ /**
+ * Verifies that the recency cannot be updated for unknown items, but switching from unknown
+ * items reaches the most recent known item.
+ */
@RequiresFlagsEnabled(Flags.FLAG_IME_SWITCHER_REVAMP)
@Test
public void testUnknownItems() {
final var items = new ArrayList<ImeSubtypeListItem>();
addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
- List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+ List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
+
+ final var english = items.get(0);
+ final var french = items.get(1);
+ final var italian = items.get(2);
+
final var unknownItems = new ArrayList<ImeSubtypeListItem>();
addTestImeSubtypeListItems(unknownItems, "UnknownIme", "UnknownIme",
- List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+ List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
final var hardwareItems = new ArrayList<ImeSubtypeListItem>();
addTestImeSubtypeListItems(hardwareItems, "HardwareIme", "HardwareIme",
- List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+ List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
final var unknownHardwareItems = new ArrayList<ImeSubtypeListItem>();
addTestImeSubtypeListItems(unknownHardwareItems, "HardwareUnknownIme", "HardwareUnknownIme",
- List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
+ List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
hardwareItems);
- assertNoAction(controller, false /* forHardware */, unknownItems);
- assertNoAction(controller, true /* forHardware */, unknownHardwareItems);
+ assertTrue("Recency updated for french IME", onUserAction(controller, french));
+
+ final var recencyItems = List.of(french, english, italian);
+
+ assertNextItemNoAction(controller, false /* forHardware */, unknownItems,
+ french);
+ assertNextItemNoAction(controller, true /* forHardware */, unknownHardwareItems,
+ hardwareItems.get(0));
+
+ // Known items must not be able to switch to unknown items.
+ assertNextOrder(controller, false /* forHardware */, MODE_STATIC, items,
+ List.of(items));
+ assertNextOrder(controller, false /* forHardware */, MODE_RECENT, recencyItems,
+ List.of(recencyItems));
+ assertNextOrder(controller, false /* forHardware */, MODE_AUTO, true /* forward */,
+ recencyItems, List.of(recencyItems));
+ assertNextOrder(controller, false /* forHardware */, MODE_AUTO, false /* forward */,
+ items.reversed(), List.of(items.reversed()));
+
+ assertNextOrder(controller, true /* forHardware */, MODE_STATIC, hardwareItems,
+ List.of(hardwareItems));
+ assertNextOrder(controller, true /* forHardware */, MODE_RECENT, hardwareItems,
+ List.of(hardwareItems));
+ assertNextOrder(controller, true /* forHardware */, MODE_AUTO, hardwareItems,
+ List.of(hardwareItems));
}
/** Verifies that the IME name does influence the comparison order. */
@@ -1199,25 +1247,26 @@
}
/**
- * Verifies that no next items can be found, and the recency cannot be updated for the
+ * Verifies that the expected next item is returned, and the recency cannot be updated for the
* given items.
*
- * @param controller the controller to verify the items on.
- * @param forHardware whether to try finding the next hardware item, or software item.
- * @param items the list of items to verify.
+ * @param controller the controller to verify the items on.
+ * @param forHardware whether to try finding the next hardware item, or software item.
+ * @param items the list of items to verify.
+ * @param expectedNext the expected next item.
*/
- private void assertNoAction(@NonNull ControllerImpl controller, boolean forHardware,
- @NonNull List<ImeSubtypeListItem> items) {
+ private void assertNextItemNoAction(@NonNull ControllerImpl controller, boolean forHardware,
+ @NonNull List<ImeSubtypeListItem> items, @Nullable ImeSubtypeListItem expectedNext) {
for (var item : items) {
for (int mode = MODE_STATIC; mode <= MODE_AUTO; mode++) {
assertNextItem(controller, forHardware, false /* onlyCurrentIme */, mode,
- false /* forward */, item, null /* expectedNext */);
+ false /* forward */, item, expectedNext);
assertNextItem(controller, forHardware, false /* onlyCurrentIme */, mode,
- true /* forward */, item, null /* expectedNext */);
+ true /* forward */, item, expectedNext);
assertNextItem(controller, forHardware, true /* onlyCurrentIme */, mode,
- false /* forward */, item, null /* expectedNext */);
+ false /* forward */, item, expectedNext);
assertNextItem(controller, forHardware, true /* onlyCurrentIme */, mode,
- true /* forward */, item, null /* expectedNext */);
+ true /* forward */, item, expectedNext);
}
assertFalse("User action shouldn't have updated the recency.",
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 3d68849..dddab65 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -108,6 +108,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
@@ -165,6 +166,7 @@
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SimpleClock;
import android.os.SystemClock;
@@ -197,6 +199,7 @@
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
import com.android.internal.util.test.FsUtil;
@@ -2310,6 +2313,70 @@
assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
}
+ @SuppressWarnings("GuardedBy") // For not holding mUidRulesFirstLock
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_NEVER_APPLY_RULES_TO_CORE_UIDS)
+ public void testRulesNeverAppliedToCoreUids() throws Exception {
+ clearInvocations(mNetworkManager);
+
+ final int coreAppId = Process.FIRST_APPLICATION_UID - 102;
+ final int coreUid = UserHandle.getUid(USER_ID, coreAppId);
+
+ // Enable all restrictions and add this core uid to all allowlists.
+ mService.mDeviceIdleMode = true;
+ mService.mRestrictPower = true;
+ setRestrictBackground(true);
+ expectHasUseRestrictedNetworksPermission(coreUid, true);
+ enableRestrictedMode(true);
+ final NetworkPolicyManagerInternal internal = LocalServices.getService(
+ NetworkPolicyManagerInternal.class);
+ internal.setLowPowerStandbyActive(true);
+ internal.setLowPowerStandbyAllowlist(new int[]{coreUid});
+ internal.onTempPowerSaveWhitelistChange(coreAppId, true, REASON_OTHER, "testing");
+
+ when(mPowerExemptionManager.getAllowListedAppIds(anyBoolean()))
+ .thenReturn(new int[]{coreAppId});
+ mPowerAllowlistReceiver.onReceive(mServiceContext, null);
+
+ // A normal uid would undergo a rule change from denied to allowed on all chains, but we
+ // should not request any rule change for this core uid.
+ verify(mNetworkManager, never()).setFirewallUidRule(anyInt(), eq(coreUid), anyInt());
+ verify(mNetworkManager, never()).setFirewallUidRules(anyInt(),
+ argThat(ar -> ArrayUtils.contains(ar, coreUid)), any(int[].class));
+ }
+
+ @SuppressWarnings("GuardedBy") // For not holding mUidRulesFirstLock
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_NEVER_APPLY_RULES_TO_CORE_UIDS)
+ public void testRulesNeverAppliedToUidsWithoutInternetPermission() throws Exception {
+ clearInvocations(mNetworkManager);
+
+ mService.mInternetPermissionMap.clear();
+ expectHasInternetPermission(UID_A, false);
+
+ // Enable all restrictions and add this uid to all allowlists.
+ mService.mDeviceIdleMode = true;
+ mService.mRestrictPower = true;
+ setRestrictBackground(true);
+ expectHasUseRestrictedNetworksPermission(UID_A, true);
+ enableRestrictedMode(true);
+ final NetworkPolicyManagerInternal internal = LocalServices.getService(
+ NetworkPolicyManagerInternal.class);
+ internal.setLowPowerStandbyActive(true);
+ internal.setLowPowerStandbyAllowlist(new int[]{UID_A});
+ internal.onTempPowerSaveWhitelistChange(APP_ID_A, true, REASON_OTHER, "testing");
+
+ when(mPowerExemptionManager.getAllowListedAppIds(anyBoolean()))
+ .thenReturn(new int[]{APP_ID_A});
+ mPowerAllowlistReceiver.onReceive(mServiceContext, null);
+
+ // A normal uid would undergo a rule change from denied to allowed on all chains, but we
+ // should not request any rule this uid without the INTERNET permission.
+ verify(mNetworkManager, never()).setFirewallUidRule(anyInt(), eq(UID_A), anyInt());
+ verify(mNetworkManager, never()).setFirewallUidRules(anyInt(),
+ argThat(ar -> ArrayUtils.contains(ar, UID_A)), any(int[].class));
+ }
+
private boolean isUidState(int uid, int procState, int procStateSeq, int capability) {
final NetworkPolicyManager.UidState uidState = mService.getUidStateForTest(uid);
if (uidState == null) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index e2524a2..ddadbc4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -115,6 +115,17 @@
}
@Test
+ public void testPrimaryDisplayUnchanged_whenWindowingModeAlreadySet_NoFreeformSupport() {
+ mPrimaryDisplay.getDefaultTaskDisplayArea().setWindowingMode(
+ WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
+
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
+
+ assertEquals(WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW,
+ mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
+ }
+
+ @Test
public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_NoDesktopMode() {
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp
index 827ff4f..ad98e47 100644
--- a/tests/Internal/Android.bp
+++ b/tests/Internal/Android.bp
@@ -24,6 +24,7 @@
"flickerlib-parsers",
"perfetto_trace_java_protos",
"flickerlib-trace_processor_shell",
+ "ravenwood-junit",
],
java_resource_dirs: ["res"],
certificate: "platform",
@@ -39,6 +40,7 @@
"platform-test-annotations",
],
srcs: [
+ "src/com/android/internal/graphics/ColorUtilsTest.java",
"src/com/android/internal/util/ParcellingTests.java",
],
auto_gen_config: true,
diff --git a/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java b/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java
index d0bb8e3..38a22f2 100644
--- a/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java
+++ b/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java
@@ -19,14 +19,19 @@
import static org.junit.Assert.assertTrue;
import android.graphics.Color;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
+import org.junit.Rule;
import org.junit.Test;
@SmallTest
public class ColorUtilsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Test
public void calculateMinimumBackgroundAlpha_satisfiestContrast() {
diff --git a/tests/Internal/src/com/android/internal/util/ParcellingTests.java b/tests/Internal/src/com/android/internal/util/ParcellingTests.java
index 65a3436..fb63422 100644
--- a/tests/Internal/src/com/android/internal/util/ParcellingTests.java
+++ b/tests/Internal/src/com/android/internal/util/ParcellingTests.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.ravenwood.RavenwoodRule;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -26,6 +27,7 @@
import com.android.internal.util.Parcelling.BuiltIn.ForInstant;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -38,6 +40,9 @@
@RunWith(JUnit4.class)
public class ParcellingTests {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private Parcel mParcel = Parcel.obtain();
@Test
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 3f9016b..f43cf52 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -113,6 +113,7 @@
"io/ZipArchive.cpp",
"link/AutoVersioner.cpp",
"link/FeatureFlagsFilter.cpp",
+ "link/FlagDisabledResourceRemover.cpp",
"link/ManifestFixer.cpp",
"link/NoDefaultResourceRemover.cpp",
"link/PrivateAttributeMover.cpp",
@@ -189,6 +190,8 @@
"integration-tests/CommandTests/**/*",
"integration-tests/ConvertTest/**/*",
"integration-tests/DumpTest/**/*",
+ ":resource-flagging-test-app-apk",
+ ":resource-flagging-test-app-r-java",
],
}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 9444dd9..1c85e9f 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -690,9 +690,7 @@
resource_format = item_iter->second.format;
}
- // Don't bother parsing the item if it is behind a disabled flag
- if (out_resource->flag_status != FlagStatus::Disabled &&
- !ParseItem(parser, out_resource, resource_format)) {
+ if (!ParseItem(parser, out_resource, resource_format)) {
return false;
}
return true;
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 2e6ad13..b59b165 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -69,13 +69,8 @@
return TestParse(str, ConfigDescription{});
}
- ::testing::AssertionResult TestParse(StringPiece str, ResourceParserOptions parserOptions) {
- return TestParse(str, ConfigDescription{}, parserOptions);
- }
-
- ::testing::AssertionResult TestParse(
- StringPiece str, const ConfigDescription& config,
- ResourceParserOptions parserOptions = ResourceParserOptions()) {
+ ::testing::AssertionResult TestParse(StringPiece str, const ConfigDescription& config) {
+ ResourceParserOptions parserOptions;
ResourceParser parser(context_->GetDiagnostics(), &table_, android::Source{"test"}, config,
parserOptions);
@@ -247,19 +242,6 @@
EXPECT_FALSE(TestParse(R"(<string name="foo4" translatable="yes">Translate</string>)"));
}
-TEST_F(ResourceParserTest, ParseStringBehindDisabledFlag) {
- FeatureFlagProperties flag_properties(true, false);
- ResourceParserOptions options;
- options.feature_flag_values = {{"falseFlag", flag_properties}};
- ASSERT_TRUE(TestParse(
- R"(<string name="foo" android:featureFlag="falseFlag"
- xmlns:android="http://schemas.android.com/apk/res/android">foo</string>)",
- options));
-
- String* str = test::GetValue<String>(&table_, "string/foo");
- ASSERT_THAT(str, IsNull());
-}
-
TEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) {
std::string input = R"(
<string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 642a561..56f5288 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -57,6 +57,7 @@
#include "java/ManifestClassGenerator.h"
#include "java/ProguardRules.h"
#include "link/FeatureFlagsFilter.h"
+#include "link/FlagDisabledResourceRemover.h"
#include "link/Linkers.h"
#include "link/ManifestFixer.h"
#include "link/NoDefaultResourceRemover.h"
@@ -1840,11 +1841,57 @@
return validate(attr->value);
}
+ class FlagDisabledStringVisitor : public DescendingValueVisitor {
+ public:
+ using DescendingValueVisitor::Visit;
+
+ explicit FlagDisabledStringVisitor(android::StringPool& string_pool)
+ : string_pool_(string_pool) {
+ }
+
+ void Visit(RawString* value) override {
+ value->value = string_pool_.MakeRef("");
+ }
+
+ void Visit(String* value) override {
+ value->value = string_pool_.MakeRef("");
+ }
+
+ void Visit(StyledString* value) override {
+ value->value = string_pool_.MakeRef(android::StyleString{{""}, {}});
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FlagDisabledStringVisitor);
+ android::StringPool& string_pool_;
+ };
+
// Writes the AndroidManifest, ResourceTable, and all XML files referenced by the ResourceTable
// to the IArchiveWriter.
bool WriteApk(IArchiveWriter* writer, proguard::KeepSet* keep_set, xml::XmlResource* manifest,
ResourceTable* table) {
TRACE_CALL();
+
+ FlagDisabledStringVisitor visitor(table->string_pool);
+
+ for (auto& package : table->packages) {
+ for (auto& type : package->types) {
+ for (auto& entry : type->entries) {
+ for (auto& config_value : entry->values) {
+ if (config_value->flag_status == FlagStatus::Disabled) {
+ config_value->value->Accept(&visitor);
+ }
+ }
+ }
+ }
+ }
+
+ if (!FlagDisabledResourceRemover{}.Consume(context_, table)) {
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed removing resources behind disabled flags");
+ return 1;
+ }
+
const bool keep_raw_values = (context_->GetPackageType() == PackageType::kStaticLib)
|| options_.keep_raw_values;
bool result = FlattenXml(context_, *manifest, kAndroidManifestPath, keep_raw_values,
@@ -2331,6 +2378,12 @@
return 1;
};
+ if (options_.generate_java_class_path || options_.generate_text_symbols_path) {
+ if (!GenerateJavaClasses()) {
+ return 1;
+ }
+ }
+
if (!WriteApk(archive_writer.get(), &proguard_keep_set, manifest_xml.get(), &final_table_)) {
return 1;
}
@@ -2339,12 +2392,6 @@
return 1;
}
- if (options_.generate_java_class_path || options_.generate_text_symbols_path) {
- if (!GenerateJavaClasses()) {
- return 1;
- }
- }
-
if (!WriteProguardFile(options_.generate_proguard_rules_path, proguard_keep_set)) {
return 1;
}
diff --git a/tools/aapt2/integration-tests/FlaggedResourcesTest/Android.bp b/tools/aapt2/integration-tests/FlaggedResourcesTest/Android.bp
new file mode 100644
index 0000000..5932271
--- /dev/null
+++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/Android.bp
@@ -0,0 +1,81 @@
+// 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_android_resources",
+}
+
+genrule {
+ name: "resource-flagging-test-app-compile",
+ tools: ["aapt2"],
+ srcs: [
+ "res/values/bools.xml",
+ "res/values/bools2.xml",
+ "res/values/strings.xml",
+ ],
+ out: [
+ "values_bools.arsc.flat",
+ "values_bools2.arsc.flat",
+ "values_strings.arsc.flat",
+ ],
+ cmd: "$(location aapt2) compile $(in) -o $(genDir) " +
+ "--feature-flags test.package.falseFlag:ro=false,test.package.trueFlag:ro=true",
+}
+
+genrule {
+ name: "resource-flagging-test-app-apk",
+ tools: ["aapt2"],
+ // The first input file in the list must be the manifest
+ srcs: [
+ "AndroidManifest.xml",
+ ":resource-flagging-test-app-compile",
+ ],
+ out: [
+ "resapp.apk",
+ ],
+ cmd: "$(location aapt2) link -o $(out) --manifest $(in)",
+}
+
+genrule {
+ name: "resource-flagging-test-app-r-java",
+ tools: ["aapt2"],
+ // The first input file in the list must be the manifest
+ srcs: [
+ "AndroidManifest.xml",
+ ":resource-flagging-test-app-compile",
+ ],
+ out: [
+ "resource-flagging-java/com/android/intenal/flaggedresources/R.java",
+ ],
+ cmd: "$(location aapt2) link -o $(genDir)/resapp.apk --java $(genDir)/resource-flagging-java --manifest $(in)",
+}
+
+java_genrule {
+ name: "resource-flagging-test-app-apk-as-resource",
+ srcs: [
+ ":resource-flagging-test-app-apk",
+ ],
+ out: ["apks_as_resources.res.zip"],
+ tools: ["soong_zip"],
+
+ cmd: "mkdir -p $(genDir)/res/raw && " +
+ "cp $(in) $(genDir)/res/raw/$$(basename $(in)) && " +
+ "$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
+}
diff --git a/core/tests/resourceflaggingtests/TestAppAndroidManifest.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/AndroidManifest.xml
similarity index 100%
rename from core/tests/resourceflaggingtests/TestAppAndroidManifest.xml
rename to tools/aapt2/integration-tests/FlaggedResourcesTest/AndroidManifest.xml
diff --git a/core/tests/resourceflaggingtests/flagged_resources_res/values/bools.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools.xml
similarity index 82%
rename from core/tests/resourceflaggingtests/flagged_resources_res/values/bools.xml
rename to tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools.xml
index 8d01465..3e094fb 100644
--- a/core/tests/resourceflaggingtests/flagged_resources_res/values/bools.xml
+++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools.xml
@@ -7,4 +7,6 @@
<bool name="res2" android:featureFlag="test.package.trueFlag">true</bool>
<bool name="res3">false</bool>
+
+ <bool name="res4" android:featureFlag="test.package.falseFlag">true</bool>
</resources>
\ No newline at end of file
diff --git a/core/tests/resourceflaggingtests/flagged_resources_res/values/bools2.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools2.xml
similarity index 100%
rename from core/tests/resourceflaggingtests/flagged_resources_res/values/bools2.xml
rename to tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools2.xml
diff --git a/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/strings.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/strings.xml
new file mode 100644
index 0000000..5c0fca1
--- /dev/null
+++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <string name="str">plain string</string>
+
+ <string name="str1" android:featureFlag="test.package.falseFlag">DONTFIND</string>
+</resources>
\ No newline at end of file
diff --git a/tools/aapt2/link/FlagDisabledResourceRemover.cpp b/tools/aapt2/link/FlagDisabledResourceRemover.cpp
new file mode 100644
index 0000000..e3289e2
--- /dev/null
+++ b/tools/aapt2/link/FlagDisabledResourceRemover.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include "link/FlagDisabledResourceRemover.h"
+
+#include <algorithm>
+
+#include "ResourceTable.h"
+
+using android::ConfigDescription;
+
+namespace aapt {
+
+static bool KeepResourceEntry(const std::unique_ptr<ResourceEntry>& entry) {
+ if (entry->values.empty()) {
+ return true;
+ }
+ const auto end_iter = entry->values.end();
+ const auto remove_iter =
+ std::stable_partition(entry->values.begin(), end_iter,
+ [](const std::unique_ptr<ResourceConfigValue>& value) -> bool {
+ return value->flag_status != FlagStatus::Disabled;
+ });
+
+ bool keep = remove_iter != entry->values.begin();
+
+ entry->values.erase(remove_iter, end_iter);
+ return keep;
+}
+
+bool FlagDisabledResourceRemover::Consume(IAaptContext* context, ResourceTable* table) {
+ for (auto& pkg : table->packages) {
+ for (auto& type : pkg->types) {
+ const auto end_iter = type->entries.end();
+ const auto remove_iter = std::stable_partition(
+ type->entries.begin(), end_iter, [](const std::unique_ptr<ResourceEntry>& entry) -> bool {
+ return KeepResourceEntry(entry);
+ });
+
+ type->entries.erase(remove_iter, end_iter);
+ }
+ }
+ return true;
+}
+
+} // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/link/FlagDisabledResourceRemover.h b/tools/aapt2/link/FlagDisabledResourceRemover.h
new file mode 100644
index 0000000..2db2cb4
--- /dev/null
+++ b/tools/aapt2/link/FlagDisabledResourceRemover.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "android-base/macros.h"
+#include "process/IResourceTableConsumer.h"
+
+namespace aapt {
+
+// Removes any resource that are behind disabled flags.
+class FlagDisabledResourceRemover : public IResourceTableConsumer {
+ public:
+ FlagDisabledResourceRemover() = default;
+
+ bool Consume(IAaptContext* context, ResourceTable* table) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FlagDisabledResourceRemover);
+};
+
+} // namespace aapt
diff --git a/tools/aapt2/link/FlaggedResources_test.cpp b/tools/aapt2/link/FlaggedResources_test.cpp
new file mode 100644
index 0000000..c901b58
--- /dev/null
+++ b/tools/aapt2/link/FlaggedResources_test.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "LoadedApk.h"
+#include "cmd/Dump.h"
+#include "io/StringStream.h"
+#include "test/Test.h"
+#include "text/Printer.h"
+
+using ::aapt::io::StringOutputStream;
+using ::aapt::text::Printer;
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+using FlaggedResourcesTest = CommandTestFixture;
+
+static android::NoOpDiagnostics noop_diag;
+
+void DumpStringPoolToString(LoadedApk* loaded_apk, std::string* output) {
+ StringOutputStream output_stream(output);
+ Printer printer(&output_stream);
+
+ DumpStringsCommand command(&printer, &noop_diag);
+ ASSERT_EQ(command.Dump(loaded_apk), 0);
+ output_stream.Flush();
+}
+
+void DumpResourceTableToString(LoadedApk* loaded_apk, std::string* output) {
+ StringOutputStream output_stream(output);
+ Printer printer(&output_stream);
+
+ DumpTableCommand command(&printer, &noop_diag);
+ ASSERT_EQ(command.Dump(loaded_apk), 0);
+ output_stream.Flush();
+}
+
+void DumpChunksToString(LoadedApk* loaded_apk, std::string* output) {
+ StringOutputStream output_stream(output);
+ Printer printer(&output_stream);
+
+ DumpChunks command(&printer, &noop_diag);
+ ASSERT_EQ(command.Dump(loaded_apk), 0);
+ output_stream.Flush();
+}
+
+TEST_F(FlaggedResourcesTest, DisabledStringRemovedFromPool) {
+ auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "resapp.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpStringPoolToString(loaded_apk.get(), &output);
+
+ std::string excluded = "DONTFIND";
+ ASSERT_EQ(output.find(excluded), std::string::npos);
+}
+
+TEST_F(FlaggedResourcesTest, DisabledResourcesRemovedFromTable) {
+ auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "resapp.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpResourceTableToString(loaded_apk.get(), &output);
+}
+
+TEST_F(FlaggedResourcesTest, DisabledResourcesRemovedFromTableChunks) {
+ auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "resapp.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpChunksToString(loaded_apk.get(), &output);
+
+ ASSERT_EQ(output.find("res4"), std::string::npos);
+ ASSERT_EQ(output.find("str1"), std::string::npos);
+}
+
+TEST_F(FlaggedResourcesTest, DisabledResourcesInRJava) {
+ auto r_path = file::BuildPath({android::base::GetExecutableDirectory(), "resource-flagging-java",
+ "com", "android", "intenal", "flaggedresources", "R.java"});
+ std::string r_contents;
+ ::android::base::ReadFileToString(r_path, &r_contents);
+
+ ASSERT_NE(r_contents.find("public static final int res4"), std::string::npos);
+ ASSERT_NE(r_contents.find("public static final int str1"), std::string::npos);
+}
+
+} // namespace aapt
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 5dde265..36bfbef 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -58,17 +58,19 @@
// Dump the classes, if specified.
options.inputJarDumpFile.ifSet {
- PrintWriter(it).use { pw -> allClasses.dump(pw) }
- log.i("Dump file created at $it")
+ log.iTime("Dump file created at $it") {
+ PrintWriter(it).use { pw -> allClasses.dump(pw) }
+ }
}
options.inputJarAsKeepAllFile.ifSet {
- PrintWriter(it).use {
- pw -> allClasses.forEach {
- classNode -> printAsTextPolicy(pw, classNode)
+ log.iTime("Dump file created at $it") {
+ PrintWriter(it).use { pw ->
+ allClasses.forEach { classNode ->
+ printAsTextPolicy(pw, classNode)
+ }
}
}
- log.i("Dump file created at $it")
}
// Build the filters.
@@ -91,16 +93,18 @@
// Dump statistics, if specified.
options.statsFile.ifSet {
- PrintWriter(it).use { pw -> stats.dumpOverview(pw) }
- log.i("Dump file created at $it")
+ log.iTime("Dump file created at $it") {
+ PrintWriter(it).use { pw -> stats.dumpOverview(pw) }
+ }
}
options.apiListFile.ifSet {
- PrintWriter(it).use { pw ->
- // TODO, when dumping a jar that's not framework-minus-apex.jar, we need to feed
- // framework-minus-apex.jar so that we can dump inherited methods from it.
- ApiDumper(pw, allClasses, null, filter).dump()
+ log.iTime("API list file created at $it") {
+ PrintWriter(it).use { pw ->
+ // TODO, when dumping a jar that's not framework-minus-apex.jar, we need to feed
+ // framework-minus-apex.jar so that we can dump inherited methods from it.
+ ApiDumper(pw, allClasses, null, filter).dump()
+ }
}
- log.i("API list file created at $it")
}
}
@@ -221,47 +225,48 @@
log.i("Converting %s into [stub: %s, impl: %s] ...", inJar, outStubJar, outImplJar)
log.i("ASM CheckClassAdapter is %s", if (enableChecker) "enabled" else "disabled")
- val start = System.currentTimeMillis()
+ log.iTime("Transforming jar") {
+ val packageRedirector = PackageRedirectRemapper(options.packageRedirects)
- val packageRedirector = PackageRedirectRemapper(options.packageRedirects)
+ var itemIndex = 0
+ var numItemsProcessed = 0
+ var numItems = -1 // == Unknown
- var itemIndex = 0
- var numItemsProcessed = 0
- var numItems = -1 // == Unknown
+ log.withIndent {
+ // Open the input jar file and process each entry.
+ ZipFile(inJar).use { inZip ->
- log.withIndent {
- // Open the input jar file and process each entry.
- ZipFile(inJar).use { inZip ->
+ numItems = inZip.size()
+ val shardStart = numItems * shard / numShards
+ val shardNextStart = numItems * (shard + 1) / numShards
- numItems = inZip.size()
- val shardStart = numItems * shard / numShards
- val shardNextStart = numItems * (shard + 1) / numShards
-
- maybeWithZipOutputStream(outStubJar) { stubOutStream ->
- maybeWithZipOutputStream(outImplJar) { implOutStream ->
- val inEntries = inZip.entries()
- while (inEntries.hasMoreElements()) {
- val entry = inEntries.nextElement()
- val inShard = (shardStart <= itemIndex) && (itemIndex < shardNextStart)
- itemIndex++
- if (!inShard) {
- continue
- }
- convertSingleEntry(inZip, entry, stubOutStream, implOutStream,
+ maybeWithZipOutputStream(outStubJar) { stubOutStream ->
+ maybeWithZipOutputStream(outImplJar) { implOutStream ->
+ val inEntries = inZip.entries()
+ while (inEntries.hasMoreElements()) {
+ val entry = inEntries.nextElement()
+ val inShard = (shardStart <= itemIndex)
+ && (itemIndex < shardNextStart)
+ itemIndex++
+ if (!inShard) {
+ continue
+ }
+ convertSingleEntry(
+ inZip, entry, stubOutStream, implOutStream,
filter, packageRedirector, remapper,
- enableChecker, classes, errors, stats)
- numItemsProcessed++
+ enableChecker, classes, errors, stats
+ )
+ numItemsProcessed++
+ }
+ log.i("Converted all entries.")
}
- log.i("Converted all entries.")
}
+ outStubJar?.let { log.i("Created stub: $it") }
+ outImplJar?.let { log.i("Created impl: $it") }
}
- outStubJar?.let { log.i("Created stub: $it") }
- outImplJar?.let { log.i("Created impl: $it") }
}
+ log.i("%d / %d item(s) processed.", numItemsProcessed, numItems)
}
- val end = System.currentTimeMillis()
- log.i("Done transforming the jar in %.1f second(s). %d / %d item(s) processed.",
- (end - start) / 1000.0, numItemsProcessed, numItems)
}
private fun <T> maybeWithZipOutputStream(filename: String?, block: (ZipOutputStream?) -> T): T {
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
index 18065ba..ee4a06f 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
@@ -185,6 +185,16 @@
println(LogLevel.Debug, format, *args)
}
+ inline fun <T> iTime(message: String, block: () -> T): T {
+ val start = System.currentTimeMillis()
+ val ret = block()
+ val end = System.currentTimeMillis()
+
+ log.i("%s: took %.1f second(s).", message, (end - start) / 1000.0)
+
+ return ret
+ }
+
inline fun forVerbose(block: () -> Unit) {
if (isEnabled(LogLevel.Verbose)) {
block()
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
index 92906a7..2607df6 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
@@ -184,49 +184,50 @@
* Load all the classes, without code.
*/
fun loadClassStructures(inJar: String): ClassNodes {
- log.i("Reading class structure from $inJar ...")
- val start = System.currentTimeMillis()
+ log.iTime("Reading class structure from $inJar") {
+ val allClasses = ClassNodes()
- val allClasses = ClassNodes()
+ log.withIndent {
+ ZipFile(inJar).use { inZip ->
+ val inEntries = inZip.entries()
- log.withIndent {
- ZipFile(inJar).use { inZip ->
- val inEntries = inZip.entries()
+ while (inEntries.hasMoreElements()) {
+ val entry = inEntries.nextElement()
- while (inEntries.hasMoreElements()) {
- val entry = inEntries.nextElement()
-
- BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
- if (entry.name.endsWith(".class")) {
- val cr = ClassReader(bis)
- val cn = ClassNode()
- cr.accept(cn, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG
- or ClassReader.SKIP_FRAMES)
- if (!allClasses.addClass(cn)) {
- log.w("Duplicate class found: ${cn.name}")
- }
- } else if (entry.name.endsWith(".dex")) {
- // Seems like it's an ART jar file. We can't process it.
- // It's a fatal error.
- throw InvalidJarFileException(
- "$inJar is not a desktop jar file. It contains a *.dex file.")
- } else {
- // Unknown file type. Skip.
- while (bis.available() > 0) {
- bis.skip((1024 * 1024).toLong())
+ BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+ if (entry.name.endsWith(".class")) {
+ val cr = ClassReader(bis)
+ val cn = ClassNode()
+ cr.accept(
+ cn, ClassReader.SKIP_CODE
+ or ClassReader.SKIP_DEBUG
+ or ClassReader.SKIP_FRAMES
+ )
+ if (!allClasses.addClass(cn)) {
+ log.w("Duplicate class found: ${cn.name}")
+ }
+ } else if (entry.name.endsWith(".dex")) {
+ // Seems like it's an ART jar file. We can't process it.
+ // It's a fatal error.
+ throw InvalidJarFileException(
+ "$inJar is not a desktop jar file."
+ + " It contains a *.dex file."
+ )
+ } else {
+ // Unknown file type. Skip.
+ while (bis.available() > 0) {
+ bis.skip((1024 * 1024).toLong())
+ }
}
}
}
}
}
+ if (allClasses.size == 0) {
+ log.w("$inJar contains no *.class files.")
+ }
+ return allClasses
}
- if (allClasses.size == 0) {
- log.w("$inJar contains no *.class files.")
- }
-
- val end = System.currentTimeMillis()
- log.i("Done reading class structure in %.1f second(s).", (end - start) / 1000.0)
- return allClasses
}
}
}
\ No newline at end of file