Merge "Make the Connected Display flag read-only" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 6bd6c93..09225a5 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -31,6 +31,7 @@
":android.companion.virtual.flags-aconfig-java{.generated_srcjars}",
":android.view.inputmethod.flags-aconfig-java{.generated_srcjars}",
":android.widget.flags-aconfig-java{.generated_srcjars}",
+ ":com.android.media.flags.bettertogether-aconfig-java{.generated_srcjars}",
],
// Add aconfig-annotations-lib as a dependency for the optimization
libs: ["aconfig-annotations-lib"],
@@ -214,3 +215,15 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// Media BetterTogether
+aconfig_declarations {
+ name: "com.android.media.flags.bettertogether-aconfig",
+ package: "com.android.media.flags",
+ srcs: ["media/java/android/media/flags/media_better_together.aconfig"],
+}
+
+java_aconfig_library {
+ name: "com.android.media.flags.bettertogether-aconfig-java",
+ aconfig_declarations: "com.android.media.flags.bettertogether-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/OWNERS b/OWNERS
index 6c25324..4e5c7d8 100644
--- a/OWNERS
+++ b/OWNERS
@@ -28,7 +28,7 @@
# Support bulk translation updates
per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
-per-file **.bp,**.mk = hansson@google.com, joeo@google.com
+per-file **.bp,**.mk = hansson@google.com, joeo@google.com, lamontjones@google.com
per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS
per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
index dcc324d..5c60562 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -75,7 +75,7 @@
private static final String ALARM_TAG_AFFORDABILITY_CHECK = "*tare.affordability_check*";
private final Object mLock;
- private final Handler mHandler;
+ private final AgentHandler mHandler;
private final Analyst mAnalyst;
private final InternalResourceService mIrs;
private final Scribe mScribe;
@@ -992,6 +992,7 @@
void tearDownLocked() {
mCurrentOngoingEvents.clear();
mBalanceThresholdAlarmQueue.removeAllAlarms();
+ mHandler.removeAllMessages();
}
@VisibleForTesting
@@ -1290,6 +1291,11 @@
break;
}
}
+
+ void removeAllMessages() {
+ removeMessages(MSG_CHECK_ALL_AFFORDABILITY);
+ removeMessages(MSG_CHECK_INDIVIDUAL_AFFORDABILITY);
+ }
}
@GuardedBy("mLock")
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index e481fe9..2f84df7 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -33,7 +33,7 @@
"android-non-updatable-stubs-defaults",
"module-classpath-stubs-defaults",
],
- args: metalava_framework_docs_args,
+ args: metalava_framework_docs_args + "--error UnflaggedApi ",
check_api: {
current: {
api_file: ":non-updatable-current.txt",
@@ -47,6 +47,7 @@
api_lint: {
enabled: true,
new_since: ":android.api.public.latest",
+ baseline_file: ":non-updatable-lint-baseline.txt",
},
},
dists: [
@@ -73,7 +74,8 @@
"client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
"\\)"
-test = " --show-annotation android.annotation.TestApi"
+test = " --show-annotation android.annotation.TestApi" +
+ " --hide UnflaggedApi" // TODO(b/297362755): TestApi lint doesn't ignore existing APIs.
module_libs = " --show-annotation android.annotation.SystemApi\\(" +
"client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
diff --git a/core/api/Android.bp b/core/api/Android.bp
index 71a2ca2..907916a 100644
--- a/core/api/Android.bp
+++ b/core/api/Android.bp
@@ -38,6 +38,11 @@
}
filegroup {
+ name: "non-updatable-lint-baseline.txt",
+ srcs: ["lint-baseline.txt"],
+}
+
+filegroup {
name: "non-updatable-system-current.txt",
srcs: ["system-current.txt"],
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 8de8ab8..078c46f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -15096,7 +15096,7 @@
method public int getByteCount();
method @NonNull public android.graphics.Color getColor(int, int);
method @Nullable public android.graphics.ColorSpace getColorSpace();
- method @NonNull public android.graphics.Bitmap.Config getConfig();
+ method @Nullable public android.graphics.Bitmap.Config getConfig();
method public int getDensity();
method @Nullable public android.graphics.Gainmap getGainmap();
method public int getGenerationId();
@@ -23946,10 +23946,12 @@
method @Nullable public android.media.MediaRouter2.RoutingController getController(@NonNull String);
method @NonNull public java.util.List<android.media.MediaRouter2.RoutingController> getControllers();
method @NonNull public static android.media.MediaRouter2 getInstance(@NonNull android.content.Context);
+ method @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2) @Nullable public android.media.RouteListingPreference getRouteListingPreference();
method @NonNull public java.util.List<android.media.MediaRoute2Info> getRoutes();
method @NonNull public android.media.MediaRouter2.RoutingController getSystemController();
method public void registerControllerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.ControllerCallback);
method public void registerRouteCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.RouteCallback, @NonNull android.media.RouteDiscoveryPreference);
+ method @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2) public void registerRouteListingPreferenceCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.RouteListingPreferenceCallback);
method public void registerTransferCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.TransferCallback);
method public void setOnGetControllerHintsListener(@Nullable android.media.MediaRouter2.OnGetControllerHintsListener);
method public void setRouteListingPreference(@Nullable android.media.RouteListingPreference);
@@ -23958,6 +23960,7 @@
method public void transferTo(@NonNull android.media.MediaRoute2Info);
method public void unregisterControllerCallback(@NonNull android.media.MediaRouter2.ControllerCallback);
method public void unregisterRouteCallback(@NonNull android.media.MediaRouter2.RouteCallback);
+ method @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2) public void unregisterRouteListingPreferenceCallback(@NonNull android.media.MediaRouter2.RouteListingPreferenceCallback);
method public void unregisterTransferCallback(@NonNull android.media.MediaRouter2.TransferCallback);
}
@@ -23978,6 +23981,11 @@
method public void onRoutesUpdated(@NonNull java.util.List<android.media.MediaRoute2Info>);
}
+ @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2) public abstract static class MediaRouter2.RouteListingPreferenceCallback {
+ ctor @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2) public MediaRouter2.RouteListingPreferenceCallback();
+ method @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2) public void onRouteListingPreferenceChanged(@Nullable android.media.RouteListingPreference);
+ }
+
public class MediaRouter2.RoutingController {
method public void deselectRoute(@NonNull android.media.MediaRoute2Info);
method @Nullable public android.os.Bundle getControlHints();
@@ -38645,7 +38653,7 @@
public final class FileIntegrityManager {
method @FlaggedApi(Flags.FLAG_FSVERITY_API) @Nullable public byte[] getFsVerityDigest(@NonNull java.io.File) throws java.io.IOException;
method public boolean isApkVeritySupported();
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public boolean isAppSourceCertificateTrusted(@NonNull java.security.cert.X509Certificate) throws java.security.cert.CertificateEncodingException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public boolean isAppSourceCertificateTrusted(@NonNull java.security.cert.X509Certificate) throws java.security.cert.CertificateEncodingException;
method @FlaggedApi(Flags.FLAG_FSVERITY_API) public void setupFsVerity(@NonNull java.io.File) throws java.io.IOException;
}
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
new file mode 100644
index 0000000..6b7910a
--- /dev/null
+++ b/core/api/lint-baseline.txt
@@ -0,0 +1,521 @@
+// Baseline format: 1.0
+UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INTERNAL_ERROR:
+ New API must be flagged with @FlaggedApi: field android.accessibilityservice.AccessibilityService.OVERLAY_RESULT_INTERNAL_ERROR
+UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INVALID:
+ New API must be flagged with @FlaggedApi: field android.accessibilityservice.AccessibilityService.OVERLAY_RESULT_INVALID
+UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_SUCCESS:
+ New API must be flagged with @FlaggedApi: field android.accessibilityservice.AccessibilityService.OVERLAY_RESULT_SUCCESS
+UnflaggedApi: android.accessibilityservice.AccessibilityService#attachAccessibilityOverlayToDisplay(int, android.view.SurfaceControl, java.util.concurrent.Executor, java.util.function.IntConsumer):
+ New API must be flagged with @FlaggedApi: method android.accessibilityservice.AccessibilityService.attachAccessibilityOverlayToDisplay(int,android.view.SurfaceControl,java.util.concurrent.Executor,java.util.function.IntConsumer)
+UnflaggedApi: android.accessibilityservice.AccessibilityService#attachAccessibilityOverlayToWindow(int, android.view.SurfaceControl, java.util.concurrent.Executor, java.util.function.IntConsumer):
+ New API must be flagged with @FlaggedApi: method android.accessibilityservice.AccessibilityService.attachAccessibilityOverlayToWindow(int,android.view.SurfaceControl,java.util.concurrent.Executor,java.util.function.IntConsumer)
+UnflaggedApi: android.app.Activity#onRequestPermissionsResult(int, String[], int[], int):
+ New API must be flagged with @FlaggedApi: method android.app.Activity.onRequestPermissionsResult(int,String[],int[],int)
+UnflaggedApi: android.app.Activity#requestPermissions(String[], int, int):
+ New API must be flagged with @FlaggedApi: method android.app.Activity.requestPermissions(String[],int,int)
+UnflaggedApi: android.app.Activity#setAllowCrossUidActivitySwitchFromBelow(boolean):
+ New API must be flagged with @FlaggedApi: method android.app.Activity.setAllowCrossUidActivitySwitchFromBelow(boolean)
+UnflaggedApi: android.app.Activity#shouldShowRequestPermissionRationale(String, int):
+ New API must be flagged with @FlaggedApi: method android.app.Activity.shouldShowRequestPermissionRationale(String,int)
+UnflaggedApi: android.app.ActivityManager#addStartInfoTimestamp(int, long):
+ New API must be flagged with @FlaggedApi: method android.app.ActivityManager.addStartInfoTimestamp(int,long)
+UnflaggedApi: android.app.ActivityManager#clearApplicationStartInfoCompletionListener():
+ New API must be flagged with @FlaggedApi: method android.app.ActivityManager.clearApplicationStartInfoCompletionListener()
+UnflaggedApi: android.app.ActivityManager#getHistoricalProcessStartReasons(int):
+ New API must be flagged with @FlaggedApi: method android.app.ActivityManager.getHistoricalProcessStartReasons(int)
+UnflaggedApi: android.app.ActivityManager#setApplicationStartInfoCompletionListener(java.util.concurrent.Executor, java.util.function.Consumer<android.app.ApplicationStartInfo>):
+ New API must be flagged with @FlaggedApi: method android.app.ActivityManager.setApplicationStartInfoCompletionListener(java.util.concurrent.Executor,java.util.function.Consumer<android.app.ApplicationStartInfo>)
+UnflaggedApi: android.app.ApplicationStartInfo:
+ New API must be flagged with @FlaggedApi: class android.app.ApplicationStartInfo
+UnflaggedApi: android.app.ApplicationStartInfo#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.CREATOR
+UnflaggedApi: android.app.ApplicationStartInfo#LAUNCH_MODE_SINGLE_INSTANCE:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.LAUNCH_MODE_SINGLE_INSTANCE
+UnflaggedApi: android.app.ApplicationStartInfo#LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK
+UnflaggedApi: android.app.ApplicationStartInfo#LAUNCH_MODE_SINGLE_TASK:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.LAUNCH_MODE_SINGLE_TASK
+UnflaggedApi: android.app.ApplicationStartInfo#LAUNCH_MODE_SINGLE_TOP:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.LAUNCH_MODE_SINGLE_TOP
+UnflaggedApi: android.app.ApplicationStartInfo#LAUNCH_MODE_STANDARD:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.LAUNCH_MODE_STANDARD
+UnflaggedApi: android.app.ApplicationStartInfo#STARTUP_STATE_ERROR:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.STARTUP_STATE_ERROR
+UnflaggedApi: android.app.ApplicationStartInfo#STARTUP_STATE_FIRST_FRAME_DRAWN:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN
+UnflaggedApi: android.app.ApplicationStartInfo#STARTUP_STATE_STARTED:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.STARTUP_STATE_STARTED
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_ALARM:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_ALARM
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_BACKUP:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_BACKUP
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_BOOT_COMPLETE:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_BOOT_COMPLETE
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_BROADCAST:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_BROADCAST
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_CONTENT_PROVIDER:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_CONTENT_PROVIDER
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_JOB:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_JOB
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_LAUNCHER:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_LAUNCHER
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_LAUNCHER_RECENTS:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_LAUNCHER_RECENTS
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_OTHER:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_OTHER
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_PUSH:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_PUSH
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_SERVICE
+UnflaggedApi: android.app.ApplicationStartInfo#START_REASON_START_ACTIVITY:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_REASON_START_ACTIVITY
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_APPLICATION_ONCREATE:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_APPLICATION_ONCREATE
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_BIND_APPLICATION:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_BIND_APPLICATION
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_FIRST_FRAME:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_FORK:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_FORK
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_FULLY_DRAWN:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_LAUNCH:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_LAUNCH
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_RESERVED_RANGE_DEVELOPER:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_RESERVED_RANGE_SYSTEM:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_SYSTEM
+UnflaggedApi: android.app.ApplicationStartInfo#START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE
+UnflaggedApi: android.app.ApplicationStartInfo#START_TYPE_COLD:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TYPE_COLD
+UnflaggedApi: android.app.ApplicationStartInfo#START_TYPE_HOT:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TYPE_HOT
+UnflaggedApi: android.app.ApplicationStartInfo#START_TYPE_WARM:
+ New API must be flagged with @FlaggedApi: field android.app.ApplicationStartInfo.START_TYPE_WARM
+UnflaggedApi: android.app.ApplicationStartInfo#describeContents():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.describeContents()
+UnflaggedApi: android.app.ApplicationStartInfo#getDefiningUid():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getDefiningUid()
+UnflaggedApi: android.app.ApplicationStartInfo#getIntent():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getIntent()
+UnflaggedApi: android.app.ApplicationStartInfo#getLaunchMode():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getLaunchMode()
+UnflaggedApi: android.app.ApplicationStartInfo#getPackageUid():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getPackageUid()
+UnflaggedApi: android.app.ApplicationStartInfo#getPid():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getPid()
+UnflaggedApi: android.app.ApplicationStartInfo#getProcessName():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getProcessName()
+UnflaggedApi: android.app.ApplicationStartInfo#getRealUid():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getRealUid()
+UnflaggedApi: android.app.ApplicationStartInfo#getReason():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getReason()
+UnflaggedApi: android.app.ApplicationStartInfo#getStartType():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getStartType()
+UnflaggedApi: android.app.ApplicationStartInfo#getStartupState():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getStartupState()
+UnflaggedApi: android.app.ApplicationStartInfo#getStartupTimestamps():
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.getStartupTimestamps()
+UnflaggedApi: android.app.ApplicationStartInfo#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.app.ApplicationStartInfo.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.app.Notification.TvExtender:
+ New API must be flagged with @FlaggedApi: class android.app.Notification.TvExtender
+UnflaggedApi: android.app.Notification.TvExtender#TvExtender():
+ New API must be flagged with @FlaggedApi: constructor android.app.Notification.TvExtender()
+UnflaggedApi: android.app.Notification.TvExtender#TvExtender(android.app.Notification):
+ New API must be flagged with @FlaggedApi: constructor android.app.Notification.TvExtender(android.app.Notification)
+UnflaggedApi: android.app.Notification.TvExtender#extend(android.app.Notification.Builder):
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.extend(android.app.Notification.Builder)
+UnflaggedApi: android.app.Notification.TvExtender#getChannelId():
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.getChannelId()
+UnflaggedApi: android.app.Notification.TvExtender#getContentIntent():
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.getContentIntent()
+UnflaggedApi: android.app.Notification.TvExtender#getDeleteIntent():
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.getDeleteIntent()
+UnflaggedApi: android.app.Notification.TvExtender#isAvailableOnTv():
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.isAvailableOnTv()
+UnflaggedApi: android.app.Notification.TvExtender#isSuppressShowOverApps():
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.isSuppressShowOverApps()
+UnflaggedApi: android.app.Notification.TvExtender#setChannelId(String):
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.setChannelId(String)
+UnflaggedApi: android.app.Notification.TvExtender#setContentIntent(android.app.PendingIntent):
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.setContentIntent(android.app.PendingIntent)
+UnflaggedApi: android.app.Notification.TvExtender#setDeleteIntent(android.app.PendingIntent):
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.setDeleteIntent(android.app.PendingIntent)
+UnflaggedApi: android.app.Notification.TvExtender#setSuppressShowOverApps(boolean):
+ New API must be flagged with @FlaggedApi: method android.app.Notification.TvExtender.setSuppressShowOverApps(boolean)
+UnflaggedApi: android.companion.AssociationInfo#getTag():
+ New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.getTag()
+UnflaggedApi: android.companion.CompanionDeviceManager#clearAssociationTag(int):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.clearAssociationTag(int)
+UnflaggedApi: android.companion.CompanionDeviceManager#setAssociationTag(int, String):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.setAssociationTag(int,String)
+UnflaggedApi: android.companion.CompanionDeviceService#DEVICE_EVENT_BLE_APPEARED:
+ New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceService.DEVICE_EVENT_BLE_APPEARED
+UnflaggedApi: android.companion.CompanionDeviceService#DEVICE_EVENT_BLE_DISAPPEARED:
+ New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceService.DEVICE_EVENT_BLE_DISAPPEARED
+UnflaggedApi: android.companion.CompanionDeviceService#DEVICE_EVENT_BT_CONNECTED:
+ New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceService.DEVICE_EVENT_BT_CONNECTED
+UnflaggedApi: android.companion.CompanionDeviceService#DEVICE_EVENT_BT_DISCONNECTED:
+ New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceService.DEVICE_EVENT_BT_DISCONNECTED
+UnflaggedApi: android.companion.CompanionDeviceService#DEVICE_EVENT_SELF_MANAGED_APPEARED:
+ New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceService.DEVICE_EVENT_SELF_MANAGED_APPEARED
+UnflaggedApi: android.companion.CompanionDeviceService#DEVICE_EVENT_SELF_MANAGED_DISAPPEARED:
+ New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceService.DEVICE_EVENT_SELF_MANAGED_DISAPPEARED
+UnflaggedApi: android.companion.CompanionDeviceService#onDeviceEvent(android.companion.AssociationInfo, int):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceService.onDeviceEvent(android.companion.AssociationInfo,int)
+UnflaggedApi: android.companion.virtual.VirtualDevice#getPersistentDeviceId():
+ New API must be flagged with @FlaggedApi: method android.companion.virtual.VirtualDevice.getPersistentDeviceId()
+UnflaggedApi: android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener#onVirtualDeviceClosed(int):
+ New API must be flagged with @FlaggedApi: method android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener.onVirtualDeviceClosed(int)
+UnflaggedApi: android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener#onVirtualDeviceCreated(int):
+ New API must be flagged with @FlaggedApi: method android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener.onVirtualDeviceCreated(int)
+UnflaggedApi: android.content.AttributionSource#getDeviceId():
+ New API must be flagged with @FlaggedApi: method android.content.AttributionSource.getDeviceId()
+UnflaggedApi: android.content.AttributionSource.Builder#setDeviceId(int):
+ New API must be flagged with @FlaggedApi: method android.content.AttributionSource.Builder.setDeviceId(int)
+UnflaggedApi: android.content.AttributionSource.Builder#setNextAttributionSource(android.content.AttributionSource):
+ New API must be flagged with @FlaggedApi: method android.content.AttributionSource.Builder.setNextAttributionSource(android.content.AttributionSource)
+UnflaggedApi: android.content.ContextParams#shouldRegisterAttributionSource():
+ New API must be flagged with @FlaggedApi: method android.content.ContextParams.shouldRegisterAttributionSource()
+UnflaggedApi: android.content.ContextParams.Builder#setShouldRegisterAttributionSource(boolean):
+ New API must be flagged with @FlaggedApi: method android.content.ContextParams.Builder.setShouldRegisterAttributionSource(boolean)
+UnflaggedApi: android.content.Intent#EXTRA_ARCHIVAL:
+ New API must be flagged with @FlaggedApi: field android.content.Intent.EXTRA_ARCHIVAL
+UnflaggedApi: android.content.om.FabricatedOverlay#setResourceValue(String, android.content.res.AssetFileDescriptor, String):
+ New API must be flagged with @FlaggedApi: method android.content.om.FabricatedOverlay.setResourceValue(String,android.content.res.AssetFileDescriptor,String)
+UnflaggedApi: android.content.pm.PackageManager#FEATURE_THREAD_NETWORK:
+ New API must be flagged with @FlaggedApi: field android.content.pm.PackageManager.FEATURE_THREAD_NETWORK
+UnflaggedApi: android.database.sqlite.SQLiteDatabase#beginTransactionReadOnly():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteDatabase.beginTransactionReadOnly()
+UnflaggedApi: android.database.sqlite.SQLiteDatabase#beginTransactionWithListenerReadOnly(android.database.sqlite.SQLiteTransactionListener):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteDatabase.beginTransactionWithListenerReadOnly(android.database.sqlite.SQLiteTransactionListener)
+UnflaggedApi: android.database.sqlite.SQLiteDatabase#createRawStatement(String):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteDatabase.createRawStatement(String)
+UnflaggedApi: android.database.sqlite.SQLiteDatabase#getLastChangedRowCount():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteDatabase.getLastChangedRowCount()
+UnflaggedApi: android.database.sqlite.SQLiteDatabase#getLastInsertRowId():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteDatabase.getLastInsertRowId()
+UnflaggedApi: android.database.sqlite.SQLiteDatabase#getTotalChangedRowCount():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteDatabase.getTotalChangedRowCount()
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement:
+ New API must be flagged with @FlaggedApi: class android.database.sqlite.SQLiteRawStatement
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#SQLITE_DATA_TYPE_BLOB:
+ New API must be flagged with @FlaggedApi: field android.database.sqlite.SQLiteRawStatement.SQLITE_DATA_TYPE_BLOB
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#SQLITE_DATA_TYPE_FLOAT:
+ New API must be flagged with @FlaggedApi: field android.database.sqlite.SQLiteRawStatement.SQLITE_DATA_TYPE_FLOAT
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#SQLITE_DATA_TYPE_INTEGER:
+ New API must be flagged with @FlaggedApi: field android.database.sqlite.SQLiteRawStatement.SQLITE_DATA_TYPE_INTEGER
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#SQLITE_DATA_TYPE_NULL:
+ New API must be flagged with @FlaggedApi: field android.database.sqlite.SQLiteRawStatement.SQLITE_DATA_TYPE_NULL
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#SQLITE_DATA_TYPE_TEXT:
+ New API must be flagged with @FlaggedApi: field android.database.sqlite.SQLiteRawStatement.SQLITE_DATA_TYPE_TEXT
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#bindBlob(int, byte[]):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.bindBlob(int,byte[])
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#bindBlob(int, byte[], int, int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.bindBlob(int,byte[],int,int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#bindDouble(int, double):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.bindDouble(int,double)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#bindInt(int, int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.bindInt(int,int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#bindLong(int, long):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.bindLong(int,long)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#bindNull(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.bindNull(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#bindText(int, String):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.bindText(int,String)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#clearBindings():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.clearBindings()
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#close():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.close()
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getColumnBlob(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getColumnBlob(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getColumnDouble(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getColumnDouble(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getColumnInt(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getColumnInt(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getColumnLength(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getColumnLength(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getColumnLong(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getColumnLong(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getColumnName(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getColumnName(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getColumnText(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getColumnText(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getColumnType(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getColumnType(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getParameterCount():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getParameterCount()
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getParameterIndex(String):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getParameterIndex(String)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getParameterName(int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getParameterName(int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#getResultColumnCount():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.getResultColumnCount()
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#isOpen():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.isOpen()
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#readColumnBlob(int, byte[], int, int, int):
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.readColumnBlob(int,byte[],int,int,int)
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#reset():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.reset()
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#step():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.step()
+UnflaggedApi: android.database.sqlite.SQLiteRawStatement#toString():
+ New API must be flagged with @FlaggedApi: method android.database.sqlite.SQLiteRawStatement.toString()
+UnflaggedApi: android.graphics.Gainmap#Gainmap(android.graphics.Gainmap, android.graphics.Bitmap):
+ New API must be flagged with @FlaggedApi: constructor android.graphics.Gainmap(android.graphics.Gainmap,android.graphics.Bitmap)
+UnflaggedApi: android.graphics.Path#computeBounds(android.graphics.RectF):
+ New API must be flagged with @FlaggedApi: method android.graphics.Path.computeBounds(android.graphics.RectF)
+UnflaggedApi: android.graphics.fonts.FontFamily.Builder#buildVariableFamily():
+ New API must be flagged with @FlaggedApi: method android.graphics.fonts.FontFamily.Builder.buildVariableFamily()
+UnflaggedApi: android.graphics.text.LineBreakConfig#LINE_BREAK_STYLE_UNSPECIFIED:
+ New API must be flagged with @FlaggedApi: field android.graphics.text.LineBreakConfig.LINE_BREAK_STYLE_UNSPECIFIED
+UnflaggedApi: android.graphics.text.LineBreakConfig#LINE_BREAK_WORD_STYLE_UNSPECIFIED:
+ New API must be flagged with @FlaggedApi: field android.graphics.text.LineBreakConfig.LINE_BREAK_WORD_STYLE_UNSPECIFIED
+UnflaggedApi: android.graphics.text.LineBreakConfig#merge(android.graphics.text.LineBreakConfig):
+ New API must be flagged with @FlaggedApi: method android.graphics.text.LineBreakConfig.merge(android.graphics.text.LineBreakConfig)
+UnflaggedApi: android.graphics.text.LineBreakConfig.Builder#merge(android.graphics.text.LineBreakConfig):
+ New API must be flagged with @FlaggedApi: method android.graphics.text.LineBreakConfig.Builder.merge(android.graphics.text.LineBreakConfig)
+UnflaggedApi: android.graphics.text.LineBreaker.Builder#setUseBoundsForWidth(boolean):
+ New API must be flagged with @FlaggedApi: method android.graphics.text.LineBreaker.Builder.setUseBoundsForWidth(boolean)
+UnflaggedApi: android.graphics.text.PositionedGlyphs#NO_OVERRIDE:
+ New API must be flagged with @FlaggedApi: field android.graphics.text.PositionedGlyphs.NO_OVERRIDE
+UnflaggedApi: android.graphics.text.PositionedGlyphs#getFakeBold(int):
+ New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getFakeBold(int)
+UnflaggedApi: android.graphics.text.PositionedGlyphs#getFakeItalic(int):
+ New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getFakeItalic(int)
+UnflaggedApi: android.graphics.text.PositionedGlyphs#getItalicOverride(int):
+ New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getItalicOverride(int)
+UnflaggedApi: android.graphics.text.PositionedGlyphs#getWeightOverride(int):
+ New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getWeightOverride(int)
+UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_CAR:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_CAR
+UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_COMPUTER:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_COMPUTER
+UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_GAME_CONSOLE:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_GAME_CONSOLE
+UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_SMARTPHONE:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_SMARTPHONE
+UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_SMARTWATCH:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_SMARTWATCH
+UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_TABLET:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_TABLET
+UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_TABLET_DOCKED:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_TABLET_DOCKED
+UnflaggedApi: android.media.midi.MidiUmpDeviceService:
+ New API must be flagged with @FlaggedApi: class android.media.midi.MidiUmpDeviceService
+UnflaggedApi: android.media.midi.MidiUmpDeviceService#MidiUmpDeviceService():
+ New API must be flagged with @FlaggedApi: constructor android.media.midi.MidiUmpDeviceService()
+UnflaggedApi: android.media.midi.MidiUmpDeviceService#SERVICE_INTERFACE:
+ New API must be flagged with @FlaggedApi: field android.media.midi.MidiUmpDeviceService.SERVICE_INTERFACE
+UnflaggedApi: android.media.midi.MidiUmpDeviceService#getDeviceInfo():
+ New API must be flagged with @FlaggedApi: method android.media.midi.MidiUmpDeviceService.getDeviceInfo()
+UnflaggedApi: android.media.midi.MidiUmpDeviceService#getOutputPortReceivers():
+ New API must be flagged with @FlaggedApi: method android.media.midi.MidiUmpDeviceService.getOutputPortReceivers()
+UnflaggedApi: android.media.midi.MidiUmpDeviceService#onBind(android.content.Intent):
+ New API must be flagged with @FlaggedApi: method android.media.midi.MidiUmpDeviceService.onBind(android.content.Intent)
+UnflaggedApi: android.media.midi.MidiUmpDeviceService#onClose():
+ New API must be flagged with @FlaggedApi: method android.media.midi.MidiUmpDeviceService.onClose()
+UnflaggedApi: android.media.midi.MidiUmpDeviceService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.media.midi.MidiUmpDeviceService.onCreate()
+UnflaggedApi: android.media.midi.MidiUmpDeviceService#onDeviceStatusChanged(android.media.midi.MidiDeviceStatus):
+ New API must be flagged with @FlaggedApi: method android.media.midi.MidiUmpDeviceService.onDeviceStatusChanged(android.media.midi.MidiDeviceStatus)
+UnflaggedApi: android.media.midi.MidiUmpDeviceService#onGetInputPortReceivers():
+ New API must be flagged with @FlaggedApi: method android.media.midi.MidiUmpDeviceService.onGetInputPortReceivers()
+UnflaggedApi: android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM:
+ New API must be flagged with @FlaggedApi: field android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM
+UnflaggedApi: android.os.PerformanceHintManager.Session#setPreferPowerEfficiency(boolean):
+ New API must be flagged with @FlaggedApi: method android.os.PerformanceHintManager.Session.setPreferPowerEfficiency(boolean)
+UnflaggedApi: android.os.UserManager#DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO:
+ New API must be flagged with @FlaggedApi: field android.os.UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO
+UnflaggedApi: android.provider.Settings#ACTION_CREDENTIAL_PROVIDER:
+ New API must be flagged with @FlaggedApi: field android.provider.Settings.ACTION_CREDENTIAL_PROVIDER
+UnflaggedApi: android.telecom.Call.Details#PROPERTY_IS_TRANSACTIONAL:
+ New API must be flagged with @FlaggedApi: field android.telecom.Call.Details.PROPERTY_IS_TRANSACTIONAL
+UnflaggedApi: android.telecom.Call.Details#getId():
+ New API must be flagged with @FlaggedApi: method android.telecom.Call.Details.getId()
+UnflaggedApi: android.telephony.CarrierConfigManager#KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE:
+ New API must be flagged with @FlaggedApi: field android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE
+UnflaggedApi: android.telephony.DisconnectCause#SATELLITE_ENABLED:
+ New API must be flagged with @FlaggedApi: field android.telephony.DisconnectCause.SATELLITE_ENABLED
+UnflaggedApi: android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_MMS:
+ New API must be flagged with @FlaggedApi: field android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_MMS
+UnflaggedApi: android.telephony.NetworkRegistrationInfo#isNonTerrestrialNetwork():
+ New API must be flagged with @FlaggedApi: method android.telephony.NetworkRegistrationInfo.isNonTerrestrialNetwork()
+UnflaggedApi: android.telephony.PhoneNumberUtils#isWpsCallNumber(String):
+ New API must be flagged with @FlaggedApi: method android.telephony.PhoneNumberUtils.isWpsCallNumber(String)
+UnflaggedApi: android.telephony.ServiceState#isUsingNonTerrestrialNetwork():
+ New API must be flagged with @FlaggedApi: method android.telephony.ServiceState.isUsingNonTerrestrialNetwork()
+UnflaggedApi: android.telephony.TelephonyManager#EVENT_DISPLAY_SOS_MESSAGE:
+ New API must be flagged with @FlaggedApi: field android.telephony.TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE
+UnflaggedApi: android.telephony.TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED:
+ New API must be flagged with @FlaggedApi: field android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED
+UnflaggedApi: android.text.BoringLayout#computeDrawingBoundingBox():
+ New API must be flagged with @FlaggedApi: method android.text.BoringLayout.computeDrawingBoundingBox()
+UnflaggedApi: android.text.BoringLayout.Metrics#getDrawingBoundingBox():
+ New API must be flagged with @FlaggedApi: method android.text.BoringLayout.Metrics.getDrawingBoundingBox()
+UnflaggedApi: android.text.DynamicLayout#getLineBreakConfig():
+ New API must be flagged with @FlaggedApi: method android.text.DynamicLayout.getLineBreakConfig()
+UnflaggedApi: android.text.DynamicLayout.Builder#setLineBreakConfig(android.graphics.text.LineBreakConfig):
+ New API must be flagged with @FlaggedApi: method android.text.DynamicLayout.Builder.setLineBreakConfig(android.graphics.text.LineBreakConfig)
+UnflaggedApi: android.text.DynamicLayout.Builder#setUseBoundsForWidth(boolean):
+ New API must be flagged with @FlaggedApi: method android.text.DynamicLayout.Builder.setUseBoundsForWidth(boolean)
+UnflaggedApi: android.text.Layout#computeDrawingBoundingBox():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.computeDrawingBoundingBox()
+UnflaggedApi: android.text.Layout#getBreakStrategy():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getBreakStrategy()
+UnflaggedApi: android.text.Layout#getEllipsize():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getEllipsize()
+UnflaggedApi: android.text.Layout#getHyphenationFrequency():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getHyphenationFrequency()
+UnflaggedApi: android.text.Layout#getJustificationMode():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getJustificationMode()
+UnflaggedApi: android.text.Layout#getLeftIndents():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getLeftIndents()
+UnflaggedApi: android.text.Layout#getLineBreakConfig():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getLineBreakConfig()
+UnflaggedApi: android.text.Layout#getLineSpacingAmount():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getLineSpacingAmount()
+UnflaggedApi: android.text.Layout#getLineSpacingMultiplier():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getLineSpacingMultiplier()
+UnflaggedApi: android.text.Layout#getMaxLines():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getMaxLines()
+UnflaggedApi: android.text.Layout#getRightIndents():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getRightIndents()
+UnflaggedApi: android.text.Layout#getTextDirectionHeuristic():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getTextDirectionHeuristic()
+UnflaggedApi: android.text.Layout#getUseBoundsForWidth():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.getUseBoundsForWidth()
+UnflaggedApi: android.text.Layout#isFontPaddingIncluded():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.isFontPaddingIncluded()
+UnflaggedApi: android.text.Layout.Builder:
+ New API must be flagged with @FlaggedApi: class android.text.Layout.Builder
+UnflaggedApi: android.text.Layout.Builder#Builder(CharSequence, int, int, android.text.TextPaint, int):
+ New API must be flagged with @FlaggedApi: constructor android.text.Layout.Builder(CharSequence,int,int,android.text.TextPaint,int)
+UnflaggedApi: android.text.Layout.Builder#build():
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.build()
+UnflaggedApi: android.text.Layout.Builder#setAlignment(android.text.Layout.Alignment):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setAlignment(android.text.Layout.Alignment)
+UnflaggedApi: android.text.Layout.Builder#setBreakStrategy(int):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setBreakStrategy(int)
+UnflaggedApi: android.text.Layout.Builder#setEllipsize(android.text.TextUtils.TruncateAt):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setEllipsize(android.text.TextUtils.TruncateAt)
+UnflaggedApi: android.text.Layout.Builder#setEllipsizedWidth(int):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setEllipsizedWidth(int)
+UnflaggedApi: android.text.Layout.Builder#setFallbackLineSpacingEnabled(boolean):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setFallbackLineSpacingEnabled(boolean)
+UnflaggedApi: android.text.Layout.Builder#setFontPaddingIncluded(boolean):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setFontPaddingIncluded(boolean)
+UnflaggedApi: android.text.Layout.Builder#setHyphenationFrequency(int):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setHyphenationFrequency(int)
+UnflaggedApi: android.text.Layout.Builder#setJustificationMode(int):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setJustificationMode(int)
+UnflaggedApi: android.text.Layout.Builder#setLeftIndents(int[]):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setLeftIndents(int[])
+UnflaggedApi: android.text.Layout.Builder#setLineBreakConfig(android.graphics.text.LineBreakConfig):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setLineBreakConfig(android.graphics.text.LineBreakConfig)
+UnflaggedApi: android.text.Layout.Builder#setLineSpacingAmount(float):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setLineSpacingAmount(float)
+UnflaggedApi: android.text.Layout.Builder#setLineSpacingMultiplier(float):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setLineSpacingMultiplier(float)
+UnflaggedApi: android.text.Layout.Builder#setMaxLines(int):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setMaxLines(int)
+UnflaggedApi: android.text.Layout.Builder#setRightIndents(int[]):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setRightIndents(int[])
+UnflaggedApi: android.text.Layout.Builder#setTextDirectionHeuristic(android.text.TextDirectionHeuristic):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setTextDirectionHeuristic(android.text.TextDirectionHeuristic)
+UnflaggedApi: android.text.Layout.Builder#setUseBoundsForWidth(boolean):
+ New API must be flagged with @FlaggedApi: method android.text.Layout.Builder.setUseBoundsForWidth(boolean)
+UnflaggedApi: android.text.StaticLayout#computeDrawingBoundingBox():
+ New API must be flagged with @FlaggedApi: method android.text.StaticLayout.computeDrawingBoundingBox()
+UnflaggedApi: android.text.StaticLayout.Builder#setUseBoundsForWidth(boolean):
+ New API must be flagged with @FlaggedApi: method android.text.StaticLayout.Builder.setUseBoundsForWidth(boolean)
+UnflaggedApi: android.text.style.LineBreakConfigSpan:
+ New API must be flagged with @FlaggedApi: class android.text.style.LineBreakConfigSpan
+UnflaggedApi: android.text.style.LineBreakConfigSpan#LineBreakConfigSpan(android.graphics.text.LineBreakConfig):
+ New API must be flagged with @FlaggedApi: constructor android.text.style.LineBreakConfigSpan(android.graphics.text.LineBreakConfig)
+UnflaggedApi: android.text.style.LineBreakConfigSpan#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.text.style.LineBreakConfigSpan.equals(Object)
+UnflaggedApi: android.text.style.LineBreakConfigSpan#getLineBreakConfig():
+ New API must be flagged with @FlaggedApi: method android.text.style.LineBreakConfigSpan.getLineBreakConfig()
+UnflaggedApi: android.text.style.LineBreakConfigSpan#hashCode():
+ New API must be flagged with @FlaggedApi: method android.text.style.LineBreakConfigSpan.hashCode()
+UnflaggedApi: android.text.style.LineBreakConfigSpan#toString():
+ New API must be flagged with @FlaggedApi: method android.text.style.LineBreakConfigSpan.toString()
+UnflaggedApi: android.view.HapticScrollFeedbackProvider#HapticScrollFeedbackProvider(android.view.View):
+ New API must be flagged with @FlaggedApi: constructor android.view.HapticScrollFeedbackProvider(android.view.View)
+UnflaggedApi: android.view.HapticScrollFeedbackProvider#onScrollLimit(int, int, int, boolean):
+ New API must be flagged with @FlaggedApi: method android.view.HapticScrollFeedbackProvider.onScrollLimit(int,int,int,boolean)
+UnflaggedApi: android.view.HapticScrollFeedbackProvider#onScrollProgress(int, int, int, int):
+ New API must be flagged with @FlaggedApi: method android.view.HapticScrollFeedbackProvider.onScrollProgress(int,int,int,int)
+UnflaggedApi: android.view.HapticScrollFeedbackProvider#onSnapToItem(int, int, int):
+ New API must be flagged with @FlaggedApi: method android.view.HapticScrollFeedbackProvider.onSnapToItem(int,int,int)
+UnflaggedApi: android.view.ScrollFeedbackProvider#onScrollLimit(android.view.MotionEvent, int, boolean):
+ New API must be flagged with @FlaggedApi: method android.view.ScrollFeedbackProvider.onScrollLimit(android.view.MotionEvent,int,boolean)
+UnflaggedApi: android.view.ScrollFeedbackProvider#onScrollLimit(int, int, int, boolean):
+ New API must be flagged with @FlaggedApi: method android.view.ScrollFeedbackProvider.onScrollLimit(int,int,int,boolean)
+UnflaggedApi: android.view.ScrollFeedbackProvider#onScrollProgress(android.view.MotionEvent, int, int):
+ New API must be flagged with @FlaggedApi: method android.view.ScrollFeedbackProvider.onScrollProgress(android.view.MotionEvent,int,int)
+UnflaggedApi: android.view.ScrollFeedbackProvider#onScrollProgress(int, int, int, int):
+ New API must be flagged with @FlaggedApi: method android.view.ScrollFeedbackProvider.onScrollProgress(int,int,int,int)
+UnflaggedApi: android.view.ScrollFeedbackProvider#onSnapToItem(android.view.MotionEvent, int):
+ New API must be flagged with @FlaggedApi: method android.view.ScrollFeedbackProvider.onSnapToItem(android.view.MotionEvent,int)
+UnflaggedApi: android.view.ScrollFeedbackProvider#onSnapToItem(int, int, int):
+ New API must be flagged with @FlaggedApi: method android.view.ScrollFeedbackProvider.onSnapToItem(int,int,int)
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT:
+ New API must be flagged with @FlaggedApi: field android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo#isGranularScrollingSupported():
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.isGranularScrollingSupported()
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo#setGranularScrollingSupported(boolean):
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.setGranularScrollingSupported(boolean)
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int, boolean, int, int, int):
+ New API must be flagged with @FlaggedApi: constructor android.view.accessibility.AccessibilityNodeInfo.CollectionInfo(int,int,boolean,int,int,int)
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo#UNDEFINED:
+ New API must be flagged with @FlaggedApi: field android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.UNDEFINED
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo#getImportantForAccessibilityItemCount():
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.getImportantForAccessibilityItemCount()
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo#getItemCount():
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.getItemCount()
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder:
+ New API must be flagged with @FlaggedApi: class android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder#Builder():
+ New API must be flagged with @FlaggedApi: constructor android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder()
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder#build():
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder.build()
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder#setColumnCount(int):
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder.setColumnCount(int)
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder#setHierarchical(boolean):
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder.setHierarchical(boolean)
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder#setImportantForAccessibilityItemCount(int):
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder.setImportantForAccessibilityItemCount(int)
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder#setItemCount(int):
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder.setItemCount(int)
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder#setRowCount(int):
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder.setRowCount(int)
+UnflaggedApi: android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder#setSelectionMode(int):
+ New API must be flagged with @FlaggedApi: method android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder.setSelectionMode(int)
+UnflaggedApi: android.view.animation.AnimationUtils#getExpectedPresentationTimeMillis():
+ New API must be flagged with @FlaggedApi: method android.view.animation.AnimationUtils.getExpectedPresentationTimeMillis()
+UnflaggedApi: android.view.animation.AnimationUtils#getExpectedPresentationTimeNanos():
+ New API must be flagged with @FlaggedApi: method android.view.animation.AnimationUtils.getExpectedPresentationTimeNanos()
+UnflaggedApi: android.view.autofill.AutofillManager#clearAutofillRequestCallback():
+ New API must be flagged with @FlaggedApi: method android.view.autofill.AutofillManager.clearAutofillRequestCallback()
+UnflaggedApi: android.view.autofill.AutofillManager#setAutofillRequestCallback(java.util.concurrent.Executor, android.view.autofill.AutofillRequestCallback):
+ New API must be flagged with @FlaggedApi: method android.view.autofill.AutofillManager.setAutofillRequestCallback(java.util.concurrent.Executor,android.view.autofill.AutofillRequestCallback)
+UnflaggedApi: android.view.autofill.AutofillRequestCallback:
+ New API must be flagged with @FlaggedApi: class android.view.autofill.AutofillRequestCallback
+UnflaggedApi: android.view.autofill.AutofillRequestCallback#onFillRequest(android.view.inputmethod.InlineSuggestionsRequest, android.os.CancellationSignal, android.service.autofill.FillCallback):
+ New API must be flagged with @FlaggedApi: method android.view.autofill.AutofillRequestCallback.onFillRequest(android.view.inputmethod.InlineSuggestionsRequest,android.os.CancellationSignal,android.service.autofill.FillCallback)
+UnflaggedApi: android.view.inputmethod.InlineSuggestionsRequest.Builder#setClientSupported(boolean):
+ New API must be flagged with @FlaggedApi: method android.view.inputmethod.InlineSuggestionsRequest.Builder.setClientSupported(boolean)
+UnflaggedApi: android.view.inputmethod.InlineSuggestionsRequest.Builder#setServiceSupported(boolean):
+ New API must be flagged with @FlaggedApi: method android.view.inputmethod.InlineSuggestionsRequest.Builder.setServiceSupported(boolean)
+UnflaggedApi: android.widget.TextView#getUseBoundsForWidth():
+ New API must be flagged with @FlaggedApi: method android.widget.TextView.getUseBoundsForWidth()
+UnflaggedApi: android.widget.TextView#setUseBoundsForWidth(boolean):
+ New API must be flagged with @FlaggedApi: method android.widget.TextView.setUseBoundsForWidth(boolean)
diff --git a/core/api/module-lib-lint-baseline.txt b/core/api/module-lib-lint-baseline.txt
index 471745a..a0d3858 100644
--- a/core/api/module-lib-lint-baseline.txt
+++ b/core/api/module-lib-lint-baseline.txt
@@ -45,3 +45,57 @@
SAM-compatible parameters (such as parameter 1, "recipient", in android.os.IBinder.linkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.IBinder#unlinkToDeath(android.os.IBinder.DeathRecipient, int):
SAM-compatible parameters (such as parameter 1, "recipient", in android.os.IBinder.unlinkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+
+
+UnflaggedApi: android.Manifest.permission#BLUETOOTH_STACK:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BLUETOOTH_STACK
+UnflaggedApi: android.Manifest.permission#CONTROL_AUTOMOTIVE_GNSS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONTROL_AUTOMOTIVE_GNSS
+UnflaggedApi: android.Manifest.permission#GET_INTENT_SENDER_INTENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.GET_INTENT_SENDER_INTENT
+UnflaggedApi: android.Manifest.permission#MAKE_UID_VISIBLE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MAKE_UID_VISIBLE
+UnflaggedApi: android.Manifest.permission#MANAGE_REMOTE_AUTH:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_REMOTE_AUTH
+UnflaggedApi: android.Manifest.permission#USE_COMPANION_TRANSPORTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.USE_COMPANION_TRANSPORTS
+UnflaggedApi: android.Manifest.permission#USE_REMOTE_AUTH:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.USE_REMOTE_AUTH
+UnflaggedApi: android.app.Activity#isResumed():
+ New API must be flagged with @FlaggedApi: method android.app.Activity.isResumed()
+UnflaggedApi: android.companion.CompanionDeviceManager#MESSAGE_REQUEST_CONTEXT_SYNC:
+ New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceManager.MESSAGE_REQUEST_CONTEXT_SYNC
+UnflaggedApi: android.companion.CompanionDeviceManager#MESSAGE_REQUEST_PERMISSION_RESTORE:
+ New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceManager.MESSAGE_REQUEST_PERMISSION_RESTORE
+UnflaggedApi: android.companion.CompanionDeviceManager#MESSAGE_REQUEST_REMOTE_AUTHENTICATION:
+ New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceManager.MESSAGE_REQUEST_REMOTE_AUTHENTICATION
+UnflaggedApi: android.companion.CompanionDeviceManager#addOnMessageReceivedListener(java.util.concurrent.Executor, int, android.companion.CompanionDeviceManager.OnMessageReceivedListener):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.addOnMessageReceivedListener(java.util.concurrent.Executor,int,android.companion.CompanionDeviceManager.OnMessageReceivedListener)
+UnflaggedApi: android.companion.CompanionDeviceManager#addOnTransportsChangedListener(java.util.concurrent.Executor, android.companion.CompanionDeviceManager.OnTransportsChangedListener):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.addOnTransportsChangedListener(java.util.concurrent.Executor,android.companion.CompanionDeviceManager.OnTransportsChangedListener)
+UnflaggedApi: android.companion.CompanionDeviceManager#removeOnMessageReceivedListener(int, android.companion.CompanionDeviceManager.OnMessageReceivedListener):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.removeOnMessageReceivedListener(int,android.companion.CompanionDeviceManager.OnMessageReceivedListener)
+UnflaggedApi: android.companion.CompanionDeviceManager#removeOnTransportsChangedListener(android.companion.CompanionDeviceManager.OnTransportsChangedListener):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.removeOnTransportsChangedListener(android.companion.CompanionDeviceManager.OnTransportsChangedListener)
+UnflaggedApi: android.companion.CompanionDeviceManager#sendMessage(int, byte[], int[]):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.sendMessage(int,byte[],int[])
+UnflaggedApi: android.companion.CompanionDeviceManager.OnMessageReceivedListener:
+ New API must be flagged with @FlaggedApi: class android.companion.CompanionDeviceManager.OnMessageReceivedListener
+UnflaggedApi: android.companion.CompanionDeviceManager.OnMessageReceivedListener#onMessageReceived(int, byte[]):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.OnMessageReceivedListener.onMessageReceived(int,byte[])
+UnflaggedApi: android.companion.CompanionDeviceManager.OnTransportsChangedListener:
+ New API must be flagged with @FlaggedApi: class android.companion.CompanionDeviceManager.OnTransportsChangedListener
+UnflaggedApi: android.companion.CompanionDeviceManager.OnTransportsChangedListener#onTransportsChanged(java.util.List<android.companion.AssociationInfo>):
+ New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.OnTransportsChangedListener.onTransportsChanged(java.util.List<android.companion.AssociationInfo>)
+UnflaggedApi: android.content.Context#REMOTE_AUTH_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.content.Context.REMOTE_AUTH_SERVICE
+UnflaggedApi: android.content.ContextWrapper#createContextForSdkInSandbox(android.content.pm.ApplicationInfo, int):
+ New API must be flagged with @FlaggedApi: method android.content.ContextWrapper.createContextForSdkInSandbox(android.content.pm.ApplicationInfo,int)
+UnflaggedApi: android.media.session.MediaController.PlaybackInfo#PlaybackInfo(int, int, int, int, android.media.AudioAttributes, String):
+ New API must be flagged with @FlaggedApi: constructor android.media.session.MediaController.PlaybackInfo(int,int,int,int,android.media.AudioAttributes,String)
+UnflaggedApi: android.os.IpcDataCache#MODULE_TELEPHONY:
+ New API must be flagged with @FlaggedApi: field android.os.IpcDataCache.MODULE_TELEPHONY
+UnflaggedApi: android.provider.ContactsContract.RawContactsEntity#queryRawContactEntity(android.content.ContentResolver, long):
+ New API must be flagged with @FlaggedApi: method android.provider.ContactsContract.RawContactsEntity.queryRawContactEntity(android.content.ContentResolver,long)
+UnflaggedApi: android.provider.Settings.Config#getAllStrings():
+ New API must be flagged with @FlaggedApi: method android.provider.Settings.Config.getAllStrings()
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ff44a1b..eba1fbe 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3192,6 +3192,7 @@
public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
method public void addActivityListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
+ method @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY) @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void addActivityPolicyExemption(@NonNull android.content.ComponentName);
method public void addSoundEffectListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener);
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
method @NonNull public android.content.Context createContext();
@@ -3212,6 +3213,7 @@
method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
+ method @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY) @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void removeActivityPolicyExemption(@NonNull android.content.ComponentName);
method public void removeSoundEffectListener(@NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener);
method @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY) @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setDevicePolicy(int, int);
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean);
@@ -3243,6 +3245,7 @@
field public static final int LOCK_STATE_DEFAULT = 0; // 0x0
field public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; // 0x0
field public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
+ field @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY) public static final int POLICY_TYPE_ACTIVITY = 3; // 0x3
field public static final int POLICY_TYPE_AUDIO = 1; // 0x1
field public static final int POLICY_TYPE_RECENTS = 2; // 0x2
field public static final int POLICY_TYPE_SENSORS = 0; // 0x0
@@ -12654,7 +12657,7 @@
method @NonNull public android.service.voice.HotwordTrainingAudio build();
method @NonNull public android.service.voice.HotwordTrainingAudio.Builder setAudioFormat(@NonNull android.media.AudioFormat);
method @NonNull public android.service.voice.HotwordTrainingAudio.Builder setAudioType(@NonNull int);
- method @NonNull public android.service.voice.HotwordTrainingAudio.Builder setHotwordAudio(@NonNull byte...);
+ method @NonNull public android.service.voice.HotwordTrainingAudio.Builder setHotwordAudio(@NonNull byte[]);
method @NonNull public android.service.voice.HotwordTrainingAudio.Builder setHotwordOffsetMillis(int);
}
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index e7c0a91..d62bea8 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -223,3 +223,3143 @@
SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addTouchExplorationStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams):
SAM-compatible parameters (such as parameter 2, "filePathCallback", in android.webkit.WebChromeClient.onShowFileChooser) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+
+
+UnflaggedApi: android.Manifest.permission#ACCESS_AMBIENT_CONTEXT_EVENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT
+UnflaggedApi: android.Manifest.permission#ACCESS_AMBIENT_LIGHT_STATS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS
+UnflaggedApi: android.Manifest.permission#ACCESS_BROADCAST_RADIO:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_BROADCAST_RADIO
+UnflaggedApi: android.Manifest.permission#ACCESS_BROADCAST_RESPONSE_STATS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS
+UnflaggedApi: android.Manifest.permission#ACCESS_CACHE_FILESYSTEM:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_CACHE_FILESYSTEM
+UnflaggedApi: android.Manifest.permission#ACCESS_CONTEXT_HUB:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_CONTEXT_HUB
+UnflaggedApi: android.Manifest.permission#ACCESS_DRM_CERTIFICATES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_DRM_CERTIFICATES
+UnflaggedApi: android.Manifest.permission#ACCESS_FPS_COUNTER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_FPS_COUNTER
+UnflaggedApi: android.Manifest.permission#ACCESS_INSTANT_APPS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_INSTANT_APPS
+UnflaggedApi: android.Manifest.permission#ACCESS_LOCUS_ID_USAGE_STATS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_LOCUS_ID_USAGE_STATS
+UnflaggedApi: android.Manifest.permission#ACCESS_MOCK_LOCATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_MOCK_LOCATION
+UnflaggedApi: android.Manifest.permission#ACCESS_MTP:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_MTP
+UnflaggedApi: android.Manifest.permission#ACCESS_NETWORK_CONDITIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_NETWORK_CONDITIONS
+UnflaggedApi: android.Manifest.permission#ACCESS_NOTIFICATIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_NOTIFICATIONS
+UnflaggedApi: android.Manifest.permission#ACCESS_PDB_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_PDB_STATE
+UnflaggedApi: android.Manifest.permission#ACCESS_RCS_USER_CAPABILITY_EXCHANGE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE
+UnflaggedApi: android.Manifest.permission#ACCESS_SHARED_LIBRARIES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_SHARED_LIBRARIES
+UnflaggedApi: android.Manifest.permission#ACCESS_SHORTCUTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_SHORTCUTS
+UnflaggedApi: android.Manifest.permission#ACCESS_SMARTSPACE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_SMARTSPACE
+UnflaggedApi: android.Manifest.permission#ACCESS_SURFACE_FLINGER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_SURFACE_FLINGER
+UnflaggedApi: android.Manifest.permission#ACCESS_TUNED_INFO:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_TUNED_INFO
+UnflaggedApi: android.Manifest.permission#ACCESS_TV_DESCRAMBLER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_TV_DESCRAMBLER
+UnflaggedApi: android.Manifest.permission#ACCESS_TV_SHARED_FILTER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_TV_SHARED_FILTER
+UnflaggedApi: android.Manifest.permission#ACCESS_TV_TUNER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_TV_TUNER
+UnflaggedApi: android.Manifest.permission#ACCESS_ULTRASOUND:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_ULTRASOUND
+UnflaggedApi: android.Manifest.permission#ACCESS_VIBRATOR_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_VIBRATOR_STATE
+UnflaggedApi: android.Manifest.permission#ACTIVITY_EMBEDDING:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACTIVITY_EMBEDDING
+UnflaggedApi: android.Manifest.permission#ADD_ALWAYS_UNLOCKED_DISPLAY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY
+UnflaggedApi: android.Manifest.permission#ADD_TRUSTED_DISPLAY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ADD_TRUSTED_DISPLAY
+UnflaggedApi: android.Manifest.permission#ADJUST_RUNTIME_PERMISSIONS_POLICY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY
+UnflaggedApi: android.Manifest.permission#ALLOCATE_AGGRESSIVE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ALLOCATE_AGGRESSIVE
+UnflaggedApi: android.Manifest.permission#ALLOW_ANY_CODEC_FOR_PLAYBACK:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK
+UnflaggedApi: android.Manifest.permission#ALLOW_PLACE_IN_MULTI_PANE_SETTINGS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS
+UnflaggedApi: android.Manifest.permission#ALLOW_SLIPPERY_TOUCHES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES
+UnflaggedApi: android.Manifest.permission#ALWAYS_UPDATE_WALLPAPER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ALWAYS_UPDATE_WALLPAPER
+UnflaggedApi: android.Manifest.permission#AMBIENT_WALLPAPER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.AMBIENT_WALLPAPER
+UnflaggedApi: android.Manifest.permission#APPROVE_INCIDENT_REPORTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.APPROVE_INCIDENT_REPORTS
+UnflaggedApi: android.Manifest.permission#ASSOCIATE_COMPANION_DEVICES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES
+UnflaggedApi: android.Manifest.permission#BACKGROUND_CAMERA:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BACKGROUND_CAMERA
+UnflaggedApi: android.Manifest.permission#BACKUP:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BACKUP
+UnflaggedApi: android.Manifest.permission#BATTERY_PREDICTION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BATTERY_PREDICTION
+UnflaggedApi: android.Manifest.permission#BIND_AMBIENT_CONTEXT_DETECTION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_AMBIENT_CONTEXT_DETECTION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_ATTENTION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_ATTENTION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_AUGMENTED_AUTOFILL_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_AUGMENTED_AUTOFILL_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_CALL_DIAGNOSTIC_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_CALL_DIAGNOSTIC_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_CALL_STREAMING_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_CALL_STREAMING_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_CELL_BROADCAST_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_CELL_BROADCAST_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_CONTENT_CAPTURE_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_CONTENT_SUGGESTIONS_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_CONTENT_SUGGESTIONS_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_DIRECTORY_SEARCH:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_DIRECTORY_SEARCH
+UnflaggedApi: android.Manifest.permission#BIND_DISPLAY_HASHING_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_DISPLAY_HASHING_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_DOMAIN_VERIFICATION_AGENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_DOMAIN_VERIFICATION_AGENT
+UnflaggedApi: android.Manifest.permission#BIND_EUICC_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_EUICC_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_EXTERNAL_STORAGE_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_FIELD_CLASSIFICATION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_FIELD_CLASSIFICATION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_GBA_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_GBA_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_HOTWORD_DETECTION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_IMS_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_IMS_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_KEYGUARD_APPWIDGET:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_KEYGUARD_APPWIDGET
+UnflaggedApi: android.Manifest.permission#BIND_MUSIC_RECOGNITION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_MUSIC_RECOGNITION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_NETWORK_RECOMMENDATION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_NETWORK_RECOMMENDATION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_NOTIFICATION_ASSISTANT_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_PRINT_RECOMMENDATION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_PRINT_RECOMMENDATION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_REMOTE_LOCKSCREEN_VALIDATION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_REMOTE_LOCKSCREEN_VALIDATION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_RESOLVER_RANKER_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_RESOLVER_RANKER_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_RESUME_ON_REBOOT_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_ROTATION_RESOLVER_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_ROTATION_RESOLVER_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_SATELLITE_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_SATELLITE_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_SETTINGS_SUGGESTIONS_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_SOUND_TRIGGER_DETECTION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_TELEPHONY_DATA_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_TELEPHONY_DATA_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_TELEPHONY_NETWORK_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_TELEPHONY_NETWORK_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_TEXTCLASSIFIER_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_TEXTCLASSIFIER_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_TIME_ZONE_PROVIDER_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_TIME_ZONE_PROVIDER_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_TRACE_REPORT_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_TRACE_REPORT_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_TRANSLATION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_TRANSLATION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_TRUST_AGENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_TRUST_AGENT
+UnflaggedApi: android.Manifest.permission#BIND_TV_REMOTE_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_TV_REMOTE_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_VISUAL_QUERY_DETECTION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE
+UnflaggedApi: android.Manifest.permission#BIND_WEARABLE_SENSING_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BIND_WEARABLE_SENSING_SERVICE
+UnflaggedApi: android.Manifest.permission#BLUETOOTH_MAP:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BLUETOOTH_MAP
+UnflaggedApi: android.Manifest.permission#BRICK:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BRICK
+UnflaggedApi: android.Manifest.permission#BRIGHTNESS_SLIDER_USAGE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BRIGHTNESS_SLIDER_USAGE
+UnflaggedApi: android.Manifest.permission#BROADCAST_CLOSE_SYSTEM_DIALOGS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS
+UnflaggedApi: android.Manifest.permission#BYPASS_ROLE_QUALIFICATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.BYPASS_ROLE_QUALIFICATION
+UnflaggedApi: android.Manifest.permission#CALL_AUDIO_INTERCEPTION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CALL_AUDIO_INTERCEPTION
+UnflaggedApi: android.Manifest.permission#CAMERA_DISABLE_TRANSMIT_LED:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAMERA_DISABLE_TRANSMIT_LED
+UnflaggedApi: android.Manifest.permission#CAMERA_OPEN_CLOSE_LISTENER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAMERA_OPEN_CLOSE_LISTENER
+UnflaggedApi: android.Manifest.permission#CAPTURE_AUDIO_HOTWORD:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAPTURE_AUDIO_HOTWORD
+UnflaggedApi: android.Manifest.permission#CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD
+UnflaggedApi: android.Manifest.permission#CAPTURE_MEDIA_OUTPUT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAPTURE_MEDIA_OUTPUT
+UnflaggedApi: android.Manifest.permission#CAPTURE_TUNER_AUDIO_INPUT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAPTURE_TUNER_AUDIO_INPUT
+UnflaggedApi: android.Manifest.permission#CAPTURE_TV_INPUT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAPTURE_TV_INPUT
+UnflaggedApi: android.Manifest.permission#CAPTURE_VOICE_COMMUNICATION_OUTPUT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT
+UnflaggedApi: android.Manifest.permission#CHANGE_APP_IDLE_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CHANGE_APP_IDLE_STATE
+UnflaggedApi: android.Manifest.permission#CHANGE_APP_LAUNCH_TIME_ESTIMATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE
+UnflaggedApi: android.Manifest.permission#CHANGE_DEVICE_IDLE_TEMP_WHITELIST:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST
+UnflaggedApi: android.Manifest.permission#CHECK_REMOTE_LOCKSCREEN:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CHECK_REMOTE_LOCKSCREEN
+UnflaggedApi: android.Manifest.permission#CLEAR_APP_USER_DATA:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CLEAR_APP_USER_DATA
+UnflaggedApi: android.Manifest.permission#COMPANION_APPROVE_WIFI_CONNECTIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.COMPANION_APPROVE_WIFI_CONNECTIONS
+UnflaggedApi: android.Manifest.permission#CONFIGURE_DISPLAY_BRIGHTNESS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS
+UnflaggedApi: android.Manifest.permission#CONFIGURE_INTERACT_ACROSS_PROFILES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES
+UnflaggedApi: android.Manifest.permission#CONNECTIVITY_USE_RESTRICTED_NETWORKS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS
+UnflaggedApi: android.Manifest.permission#CONTROL_DEVICE_LIGHTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONTROL_DEVICE_LIGHTS
+UnflaggedApi: android.Manifest.permission#CONTROL_DISPLAY_COLOR_TRANSFORMS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS
+UnflaggedApi: android.Manifest.permission#CONTROL_DISPLAY_SATURATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONTROL_DISPLAY_SATURATION
+UnflaggedApi: android.Manifest.permission#CONTROL_INCALL_EXPERIENCE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONTROL_INCALL_EXPERIENCE
+UnflaggedApi: android.Manifest.permission#CONTROL_KEYGUARD_SECURE_NOTIFICATIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS
+UnflaggedApi: android.Manifest.permission#CONTROL_OEM_PAID_NETWORK_PREFERENCE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE
+UnflaggedApi: android.Manifest.permission#CONTROL_VPN:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CONTROL_VPN
+UnflaggedApi: android.Manifest.permission#CREATE_USERS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CREATE_USERS
+UnflaggedApi: android.Manifest.permission#CREATE_VIRTUAL_DEVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CREATE_VIRTUAL_DEVICE
+UnflaggedApi: android.Manifest.permission#CRYPT_KEEPER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.CRYPT_KEEPER
+UnflaggedApi: android.Manifest.permission#DEVICE_POWER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.DEVICE_POWER
+UnflaggedApi: android.Manifest.permission#DISABLE_SYSTEM_SOUND_EFFECTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS
+UnflaggedApi: android.Manifest.permission#DISPATCH_PROVISIONING_MESSAGE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.DISPATCH_PROVISIONING_MESSAGE
+UnflaggedApi: android.Manifest.permission#DOMAIN_VERIFICATION_AGENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.DOMAIN_VERIFICATION_AGENT
+UnflaggedApi: android.Manifest.permission#ENTER_CAR_MODE_PRIORITIZED:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED
+UnflaggedApi: android.Manifest.permission#EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS
+UnflaggedApi: android.Manifest.permission#FORCE_BACK:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.FORCE_BACK
+UnflaggedApi: android.Manifest.permission#FORCE_STOP_PACKAGES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.FORCE_STOP_PACKAGES
+UnflaggedApi: android.Manifest.permission#GET_APP_METADATA:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.GET_APP_METADATA
+UnflaggedApi: android.Manifest.permission#GET_APP_OPS_STATS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.GET_APP_OPS_STATS
+UnflaggedApi: android.Manifest.permission#GET_HISTORICAL_APP_OPS_STATS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.GET_HISTORICAL_APP_OPS_STATS
+UnflaggedApi: android.Manifest.permission#GET_PROCESS_STATE_AND_OOM_SCORE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.GET_PROCESS_STATE_AND_OOM_SCORE
+UnflaggedApi: android.Manifest.permission#GET_RUNTIME_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.GET_RUNTIME_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#GET_TOP_ACTIVITY_INFO:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.GET_TOP_ACTIVITY_INFO
+UnflaggedApi: android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS
+UnflaggedApi: android.Manifest.permission#HANDLE_CAR_MODE_CHANGES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.HANDLE_CAR_MODE_CHANGES
+UnflaggedApi: android.Manifest.permission#HARDWARE_TEST:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.HARDWARE_TEST
+UnflaggedApi: android.Manifest.permission#HDMI_CEC:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.HDMI_CEC
+UnflaggedApi: android.Manifest.permission#INJECT_EVENTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INJECT_EVENTS
+UnflaggedApi: android.Manifest.permission#INSTALL_DPC_PACKAGES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INSTALL_DPC_PACKAGES
+UnflaggedApi: android.Manifest.permission#INSTALL_DYNAMIC_SYSTEM:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM
+UnflaggedApi: android.Manifest.permission#INSTALL_EXISTING_PACKAGES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INSTALL_EXISTING_PACKAGES
+UnflaggedApi: android.Manifest.permission#INSTALL_GRANT_RUNTIME_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE
+UnflaggedApi: android.Manifest.permission#INSTALL_PACKAGE_UPDATES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INSTALL_PACKAGE_UPDATES
+UnflaggedApi: android.Manifest.permission#INSTALL_SELF_UPDATES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INSTALL_SELF_UPDATES
+UnflaggedApi: android.Manifest.permission#INTENT_FILTER_VERIFICATION_AGENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT
+UnflaggedApi: android.Manifest.permission#INTERACT_ACROSS_USERS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INTERACT_ACROSS_USERS
+UnflaggedApi: android.Manifest.permission#INTERACT_ACROSS_USERS_FULL:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INTERACT_ACROSS_USERS_FULL
+UnflaggedApi: android.Manifest.permission#INTERNAL_SYSTEM_WINDOW:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INTERNAL_SYSTEM_WINDOW
+UnflaggedApi: android.Manifest.permission#INVOKE_CARRIER_SETUP:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.INVOKE_CARRIER_SETUP
+UnflaggedApi: android.Manifest.permission#KILL_ALL_BACKGROUND_PROCESSES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.KILL_ALL_BACKGROUND_PROCESSES
+UnflaggedApi: android.Manifest.permission#KILL_UID:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.KILL_UID
+UnflaggedApi: android.Manifest.permission#LAUNCH_DEVICE_MANAGER_SETUP:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP
+UnflaggedApi: android.Manifest.permission#LAUNCH_PERMISSION_SETTINGS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.LAUNCH_PERMISSION_SETTINGS
+UnflaggedApi: android.Manifest.permission#LOCAL_MAC_ADDRESS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.LOCAL_MAC_ADDRESS
+UnflaggedApi: android.Manifest.permission#LOCATION_BYPASS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.LOCATION_BYPASS
+UnflaggedApi: android.Manifest.permission#LOCK_DEVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.LOCK_DEVICE
+UnflaggedApi: android.Manifest.permission#LOG_FOREGROUND_RESOURCE_USE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.LOG_FOREGROUND_RESOURCE_USE
+UnflaggedApi: android.Manifest.permission#LOOP_RADIO:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.LOOP_RADIO
+UnflaggedApi: android.Manifest.permission#MANAGE_ACCESSIBILITY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_ACCESSIBILITY
+UnflaggedApi: android.Manifest.permission#MANAGE_ACTIVITY_TASKS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_ACTIVITY_TASKS
+UnflaggedApi: android.Manifest.permission#MANAGE_APP_HIBERNATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_APP_HIBERNATION
+UnflaggedApi: android.Manifest.permission#MANAGE_APP_OPS_RESTRICTIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS
+UnflaggedApi: android.Manifest.permission#MANAGE_APP_PREDICTIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_APP_PREDICTIONS
+UnflaggedApi: android.Manifest.permission#MANAGE_APP_TOKENS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_APP_TOKENS
+UnflaggedApi: android.Manifest.permission#MANAGE_AUTO_FILL:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_AUTO_FILL
+UnflaggedApi: android.Manifest.permission#MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED
+UnflaggedApi: android.Manifest.permission#MANAGE_CARRIER_OEM_UNLOCK_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE
+UnflaggedApi: android.Manifest.permission#MANAGE_CA_CERTIFICATES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_CA_CERTIFICATES
+UnflaggedApi: android.Manifest.permission#MANAGE_CLIPBOARD_ACCESS_NOTIFICATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_CLIPBOARD_ACCESS_NOTIFICATION
+UnflaggedApi: android.Manifest.permission#MANAGE_CLOUDSEARCH:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_CLOUDSEARCH
+UnflaggedApi: android.Manifest.permission#MANAGE_CONTENT_CAPTURE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_CONTENT_CAPTURE
+UnflaggedApi: android.Manifest.permission#MANAGE_CONTENT_SUGGESTIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS
+UnflaggedApi: android.Manifest.permission#MANAGE_DEBUGGING:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_DEBUGGING
+UnflaggedApi: android.Manifest.permission#MANAGE_DEFAULT_APPLICATIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_DEFAULT_APPLICATIONS
+UnflaggedApi: android.Manifest.permission#MANAGE_DEVICE_ADMINS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_DEVICE_ADMINS
+UnflaggedApi: android.Manifest.permission#MANAGE_DEVICE_POLICY_APP_EXEMPTIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS
+UnflaggedApi: android.Manifest.permission#MANAGE_ETHERNET_NETWORKS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_ETHERNET_NETWORKS
+UnflaggedApi: android.Manifest.permission#MANAGE_FACTORY_RESET_PROTECTION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION
+UnflaggedApi: android.Manifest.permission#MANAGE_GAME_ACTIVITY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_GAME_ACTIVITY
+UnflaggedApi: android.Manifest.permission#MANAGE_GAME_MODE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_GAME_MODE
+UnflaggedApi: android.Manifest.permission#MANAGE_HOTWORD_DETECTION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_HOTWORD_DETECTION
+UnflaggedApi: android.Manifest.permission#MANAGE_IPSEC_TUNNELS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_IPSEC_TUNNELS
+UnflaggedApi: android.Manifest.permission#MANAGE_LOW_POWER_STANDBY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_LOW_POWER_STANDBY
+UnflaggedApi: android.Manifest.permission#MANAGE_MUSIC_RECOGNITION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_MUSIC_RECOGNITION
+UnflaggedApi: android.Manifest.permission#MANAGE_NOTIFICATION_LISTENERS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS
+UnflaggedApi: android.Manifest.permission#MANAGE_ONE_TIME_PERMISSION_SESSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
+UnflaggedApi: android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
+UnflaggedApi: android.Manifest.permission#MANAGE_ROLE_HOLDERS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_ROLE_HOLDERS
+UnflaggedApi: android.Manifest.permission#MANAGE_ROLLBACKS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_ROLLBACKS
+UnflaggedApi: android.Manifest.permission#MANAGE_ROTATION_RESOLVER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_ROTATION_RESOLVER
+UnflaggedApi: android.Manifest.permission#MANAGE_SAFETY_CENTER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_SAFETY_CENTER
+UnflaggedApi: android.Manifest.permission#MANAGE_SEARCH_UI:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_SEARCH_UI
+UnflaggedApi: android.Manifest.permission#MANAGE_SENSOR_PRIVACY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_SENSOR_PRIVACY
+UnflaggedApi: android.Manifest.permission#MANAGE_SMARTSPACE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_SMARTSPACE
+UnflaggedApi: android.Manifest.permission#MANAGE_SOUND_TRIGGER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_SOUND_TRIGGER
+UnflaggedApi: android.Manifest.permission#MANAGE_SPEECH_RECOGNITION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_SPEECH_RECOGNITION
+UnflaggedApi: android.Manifest.permission#MANAGE_SUBSCRIPTION_PLANS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS
+UnflaggedApi: android.Manifest.permission#MANAGE_SUBSCRIPTION_USER_ASSOCIATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION
+UnflaggedApi: android.Manifest.permission#MANAGE_TEST_NETWORKS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_TEST_NETWORKS
+UnflaggedApi: android.Manifest.permission#MANAGE_TIME_AND_ZONE_DETECTION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION
+UnflaggedApi: android.Manifest.permission#MANAGE_UI_TRANSLATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_UI_TRANSLATION
+UnflaggedApi: android.Manifest.permission#MANAGE_USB:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_USB
+UnflaggedApi: android.Manifest.permission#MANAGE_USERS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_USERS
+UnflaggedApi: android.Manifest.permission#MANAGE_USER_OEM_UNLOCK_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE
+UnflaggedApi: android.Manifest.permission#MANAGE_WALLPAPER_EFFECTS_GENERATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION
+UnflaggedApi: android.Manifest.permission#MANAGE_WEAK_ESCROW_TOKEN:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN
+UnflaggedApi: android.Manifest.permission#MANAGE_WEARABLE_SENSING_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE
+UnflaggedApi: android.Manifest.permission#MANAGE_WIFI_COUNTRY_CODE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE
+UnflaggedApi: android.Manifest.permission#MARK_DEVICE_ORGANIZATION_OWNED:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED
+UnflaggedApi: android.Manifest.permission#MEDIA_RESOURCE_OVERRIDE_PID:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MEDIA_RESOURCE_OVERRIDE_PID
+UnflaggedApi: android.Manifest.permission#MIGRATE_HEALTH_CONNECT_DATA:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA
+UnflaggedApi: android.Manifest.permission#MODIFY_APPWIDGET_BIND_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#MODIFY_AUDIO_ROUTING:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MODIFY_AUDIO_ROUTING
+UnflaggedApi: android.Manifest.permission#MODIFY_AUDIO_SETTINGS_PRIVILEGED:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+UnflaggedApi: android.Manifest.permission#MODIFY_CELL_BROADCASTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MODIFY_CELL_BROADCASTS
+UnflaggedApi: android.Manifest.permission#MODIFY_DAY_NIGHT_MODE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MODIFY_DAY_NIGHT_MODE
+UnflaggedApi: android.Manifest.permission#MODIFY_PARENTAL_CONTROLS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MODIFY_PARENTAL_CONTROLS
+UnflaggedApi: android.Manifest.permission#MODIFY_QUIET_MODE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MODIFY_QUIET_MODE
+UnflaggedApi: android.Manifest.permission#MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE
+UnflaggedApi: android.Manifest.permission#MONITOR_DEVICE_CONFIG_ACCESS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS
+UnflaggedApi: android.Manifest.permission#MOVE_PACKAGE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MOVE_PACKAGE
+UnflaggedApi: android.Manifest.permission#NETWORK_AIRPLANE_MODE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_AIRPLANE_MODE
+UnflaggedApi: android.Manifest.permission#NETWORK_CARRIER_PROVISIONING:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
+UnflaggedApi: android.Manifest.permission#NETWORK_FACTORY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_FACTORY
+UnflaggedApi: android.Manifest.permission#NETWORK_MANAGED_PROVISIONING:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_MANAGED_PROVISIONING
+UnflaggedApi: android.Manifest.permission#NETWORK_SCAN:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_SCAN
+UnflaggedApi: android.Manifest.permission#NETWORK_SETTINGS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_SETTINGS
+UnflaggedApi: android.Manifest.permission#NETWORK_SETUP_WIZARD:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_SETUP_WIZARD
+UnflaggedApi: android.Manifest.permission#NETWORK_SIGNAL_STRENGTH_WAKEUP:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP
+UnflaggedApi: android.Manifest.permission#NETWORK_STACK:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_STACK
+UnflaggedApi: android.Manifest.permission#NETWORK_STATS_PROVIDER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NETWORK_STATS_PROVIDER
+UnflaggedApi: android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON
+UnflaggedApi: android.Manifest.permission#NOTIFICATION_DURING_SETUP:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NOTIFICATION_DURING_SETUP
+UnflaggedApi: android.Manifest.permission#NOTIFY_TV_INPUTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.NOTIFY_TV_INPUTS
+UnflaggedApi: android.Manifest.permission#OBSERVE_APP_USAGE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.OBSERVE_APP_USAGE
+UnflaggedApi: android.Manifest.permission#OBSERVE_NETWORK_POLICY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.OBSERVE_NETWORK_POLICY
+UnflaggedApi: android.Manifest.permission#OBSERVE_ROLE_HOLDERS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.OBSERVE_ROLE_HOLDERS
+UnflaggedApi: android.Manifest.permission#OBSERVE_SENSOR_PRIVACY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.OBSERVE_SENSOR_PRIVACY
+UnflaggedApi: android.Manifest.permission#OPEN_ACCESSIBILITY_DETAILS_SETTINGS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS
+UnflaggedApi: android.Manifest.permission#OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD
+UnflaggedApi: android.Manifest.permission#PACKAGE_VERIFICATION_AGENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PACKAGE_VERIFICATION_AGENT
+UnflaggedApi: android.Manifest.permission#PACKET_KEEPALIVE_OFFLOAD:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
+UnflaggedApi: android.Manifest.permission#PEERS_MAC_ADDRESS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PEERS_MAC_ADDRESS
+UnflaggedApi: android.Manifest.permission#PERFORM_CDMA_PROVISIONING:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PERFORM_CDMA_PROVISIONING
+UnflaggedApi: android.Manifest.permission#PERFORM_IMS_SINGLE_REGISTRATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION
+UnflaggedApi: android.Manifest.permission#PERFORM_SIM_ACTIVATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PERFORM_SIM_ACTIVATION
+UnflaggedApi: android.Manifest.permission#POWER_SAVER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.POWER_SAVER
+UnflaggedApi: android.Manifest.permission#PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE
+UnflaggedApi: android.Manifest.permission#PROVIDE_RESOLVER_RANKER_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PROVIDE_RESOLVER_RANKER_SERVICE
+UnflaggedApi: android.Manifest.permission#PROVIDE_TRUST_AGENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PROVIDE_TRUST_AGENT
+UnflaggedApi: android.Manifest.permission#PROVISION_DEMO_DEVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.PROVISION_DEMO_DEVICE
+UnflaggedApi: android.Manifest.permission#QUERY_ADMIN_POLICY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.QUERY_ADMIN_POLICY
+UnflaggedApi: android.Manifest.permission#QUERY_CLONED_APPS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.QUERY_CLONED_APPS
+UnflaggedApi: android.Manifest.permission#QUERY_USERS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.QUERY_USERS
+UnflaggedApi: android.Manifest.permission#RADIO_SCAN_WITHOUT_LOCATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RADIO_SCAN_WITHOUT_LOCATION
+UnflaggedApi: android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION
+UnflaggedApi: android.Manifest.permission#READ_APP_SPECIFIC_LOCALES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_APP_SPECIFIC_LOCALES
+UnflaggedApi: android.Manifest.permission#READ_CARRIER_APP_INFO:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_CARRIER_APP_INFO
+UnflaggedApi: android.Manifest.permission#READ_CELL_BROADCASTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_CELL_BROADCASTS
+UnflaggedApi: android.Manifest.permission#READ_CLIPBOARD_IN_BACKGROUND:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_CLIPBOARD_IN_BACKGROUND
+UnflaggedApi: android.Manifest.permission#READ_CONTENT_RATING_SYSTEMS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS
+UnflaggedApi: android.Manifest.permission#READ_DEVICE_CONFIG:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_DEVICE_CONFIG
+UnflaggedApi: android.Manifest.permission#READ_DREAM_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_DREAM_STATE
+UnflaggedApi: android.Manifest.permission#READ_GLOBAL_APP_SEARCH_DATA:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_GLOBAL_APP_SEARCH_DATA
+UnflaggedApi: android.Manifest.permission#READ_INSTALLED_SESSION_PATHS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_INSTALLED_SESSION_PATHS
+UnflaggedApi: android.Manifest.permission#READ_INSTALL_SESSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_INSTALL_SESSIONS
+UnflaggedApi: android.Manifest.permission#READ_NETWORK_USAGE_HISTORY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_NETWORK_USAGE_HISTORY
+UnflaggedApi: android.Manifest.permission#READ_OEM_UNLOCK_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_OEM_UNLOCK_STATE
+UnflaggedApi: android.Manifest.permission#READ_PEOPLE_DATA:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_PEOPLE_DATA
+UnflaggedApi: android.Manifest.permission#READ_PRINT_SERVICES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_PRINT_SERVICES
+UnflaggedApi: android.Manifest.permission#READ_PRINT_SERVICE_RECOMMENDATIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS
+UnflaggedApi: android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
+UnflaggedApi: android.Manifest.permission#READ_PROJECTION_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_PROJECTION_STATE
+UnflaggedApi: android.Manifest.permission#READ_RESTRICTED_STATS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_RESTRICTED_STATS
+UnflaggedApi: android.Manifest.permission#READ_RUNTIME_PROFILES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_RUNTIME_PROFILES
+UnflaggedApi: android.Manifest.permission#READ_SAFETY_CENTER_STATUS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_SAFETY_CENTER_STATUS
+UnflaggedApi: android.Manifest.permission#READ_SEARCH_INDEXABLES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_SEARCH_INDEXABLES
+UnflaggedApi: android.Manifest.permission#READ_SYSTEM_UPDATE_INFO:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_SYSTEM_UPDATE_INFO
+UnflaggedApi: android.Manifest.permission#READ_WALLPAPER_INTERNAL:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_WALLPAPER_INTERNAL
+UnflaggedApi: android.Manifest.permission#READ_WIFI_CREDENTIAL:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_WIFI_CREDENTIAL
+UnflaggedApi: android.Manifest.permission#READ_WRITE_SYNC_DISABLED_MODE_CONFIG:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG
+UnflaggedApi: android.Manifest.permission#REAL_GET_TASKS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REAL_GET_TASKS
+UnflaggedApi: android.Manifest.permission#RECEIVE_BLUETOOTH_MAP:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RECEIVE_BLUETOOTH_MAP
+UnflaggedApi: android.Manifest.permission#RECEIVE_DATA_ACTIVITY_CHANGE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE
+UnflaggedApi: android.Manifest.permission#RECEIVE_DEVICE_CUSTOMIZATION_READY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY
+UnflaggedApi: android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST
+UnflaggedApi: android.Manifest.permission#RECEIVE_WIFI_CREDENTIAL_CHANGE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE
+UnflaggedApi: android.Manifest.permission#RECORD_BACKGROUND_AUDIO:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RECORD_BACKGROUND_AUDIO
+UnflaggedApi: android.Manifest.permission#RECOVERY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RECOVERY
+UnflaggedApi: android.Manifest.permission#RECOVER_KEYSTORE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RECOVER_KEYSTORE
+UnflaggedApi: android.Manifest.permission#REGISTER_CALL_PROVIDER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REGISTER_CALL_PROVIDER
+UnflaggedApi: android.Manifest.permission#REGISTER_CONNECTION_MANAGER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REGISTER_CONNECTION_MANAGER
+UnflaggedApi: android.Manifest.permission#REGISTER_NSD_OFFLOAD_ENGINE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REGISTER_NSD_OFFLOAD_ENGINE
+UnflaggedApi: android.Manifest.permission#REGISTER_SIM_SUBSCRIPTION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION
+UnflaggedApi: android.Manifest.permission#REGISTER_STATS_PULL_ATOM:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REGISTER_STATS_PULL_ATOM
+UnflaggedApi: android.Manifest.permission#REMOTE_DISPLAY_PROVIDER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REMOTE_DISPLAY_PROVIDER
+UnflaggedApi: android.Manifest.permission#REMOVE_DRM_CERTIFICATES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REMOVE_DRM_CERTIFICATES
+UnflaggedApi: android.Manifest.permission#REMOVE_TASKS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REMOVE_TASKS
+UnflaggedApi: android.Manifest.permission#RENOUNCE_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RENOUNCE_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#REPORT_USAGE_STATS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REPORT_USAGE_STATS
+UnflaggedApi: android.Manifest.permission#REQUEST_NOTIFICATION_ASSISTANT_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE
+UnflaggedApi: android.Manifest.permission#RESET_PASSWORD:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RESET_PASSWORD
+UnflaggedApi: android.Manifest.permission#RESTART_WIFI_SUBSYSTEM:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RESTART_WIFI_SUBSYSTEM
+UnflaggedApi: android.Manifest.permission#RESTORE_RUNTIME_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#RESTRICTED_VR_ACCESS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RESTRICTED_VR_ACCESS
+UnflaggedApi: android.Manifest.permission#RETRIEVE_WINDOW_CONTENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RETRIEVE_WINDOW_CONTENT
+UnflaggedApi: android.Manifest.permission#REVIEW_ACCESSIBILITY_SERVICES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REVIEW_ACCESSIBILITY_SERVICES
+UnflaggedApi: android.Manifest.permission#REVOKE_RUNTIME_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#ROTATE_SURFACE_FLINGER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.ROTATE_SURFACE_FLINGER
+UnflaggedApi: android.Manifest.permission#SATELLITE_COMMUNICATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SATELLITE_COMMUNICATION
+UnflaggedApi: android.Manifest.permission#SCHEDULE_PRIORITIZED_ALARM:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SCHEDULE_PRIORITIZED_ALARM
+UnflaggedApi: android.Manifest.permission#SECURE_ELEMENT_PRIVILEGED_OPERATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION
+UnflaggedApi: android.Manifest.permission#SEND_CATEGORY_CAR_NOTIFICATIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SEND_CATEGORY_CAR_NOTIFICATIONS
+UnflaggedApi: android.Manifest.permission#SEND_DEVICE_CUSTOMIZATION_READY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SEND_DEVICE_CUSTOMIZATION_READY
+UnflaggedApi: android.Manifest.permission#SEND_SAFETY_CENTER_UPDATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
+UnflaggedApi: android.Manifest.permission#SEND_SHOW_SUSPENDED_APP_DETAILS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS
+UnflaggedApi: android.Manifest.permission#SEND_SMS_NO_CONFIRMATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SEND_SMS_NO_CONFIRMATION
+UnflaggedApi: android.Manifest.permission#SERIAL_PORT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SERIAL_PORT
+UnflaggedApi: android.Manifest.permission#SET_ACTIVITY_WATCHER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_ACTIVITY_WATCHER
+UnflaggedApi: android.Manifest.permission#SET_CLIP_SOURCE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_CLIP_SOURCE
+UnflaggedApi: android.Manifest.permission#SET_DEFAULT_ACCOUNT_FOR_CONTACTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS
+UnflaggedApi: android.Manifest.permission#SET_HARMFUL_APP_WARNINGS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_HARMFUL_APP_WARNINGS
+UnflaggedApi: android.Manifest.permission#SET_LOW_POWER_STANDBY_PORTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS
+UnflaggedApi: android.Manifest.permission#SET_MEDIA_KEY_LISTENER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_MEDIA_KEY_LISTENER
+UnflaggedApi: android.Manifest.permission#SET_ORIENTATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_ORIENTATION
+UnflaggedApi: android.Manifest.permission#SET_POINTER_SPEED:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_POINTER_SPEED
+UnflaggedApi: android.Manifest.permission#SET_SCREEN_COMPATIBILITY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_SCREEN_COMPATIBILITY
+UnflaggedApi: android.Manifest.permission#SET_SYSTEM_AUDIO_CAPTION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION
+UnflaggedApi: android.Manifest.permission#SET_UNRESTRICTED_KEEP_CLEAR_AREAS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS
+UnflaggedApi: android.Manifest.permission#SET_VOLUME_KEY_LONG_PRESS_LISTENER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER
+UnflaggedApi: android.Manifest.permission#SET_WALLPAPER_COMPONENT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_WALLPAPER_COMPONENT
+UnflaggedApi: android.Manifest.permission#SET_WALLPAPER_DIM_AMOUNT:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT
+UnflaggedApi: android.Manifest.permission#SHOW_KEYGUARD_MESSAGE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SHOW_KEYGUARD_MESSAGE
+UnflaggedApi: android.Manifest.permission#SHUTDOWN:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SHUTDOWN
+UnflaggedApi: android.Manifest.permission#SIGNAL_REBOOT_READINESS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SIGNAL_REBOOT_READINESS
+UnflaggedApi: android.Manifest.permission#SOUND_TRIGGER_RUN_IN_BATTERY_SAVER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER
+UnflaggedApi: android.Manifest.permission#STAGE_HEALTH_CONNECT_REMOTE_DATA:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.STAGE_HEALTH_CONNECT_REMOTE_DATA
+UnflaggedApi: android.Manifest.permission#START_ACTIVITIES_FROM_BACKGROUND:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND
+UnflaggedApi: android.Manifest.permission#START_CROSS_PROFILE_ACTIVITIES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES
+UnflaggedApi: android.Manifest.permission#START_REVIEW_PERMISSION_DECISIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.START_REVIEW_PERMISSION_DECISIONS
+UnflaggedApi: android.Manifest.permission#START_TASKS_FROM_RECENTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.START_TASKS_FROM_RECENTS
+UnflaggedApi: android.Manifest.permission#STATUS_BAR_SERVICE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.STATUS_BAR_SERVICE
+UnflaggedApi: android.Manifest.permission#STOP_APP_SWITCHES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.STOP_APP_SWITCHES
+UnflaggedApi: android.Manifest.permission#SUBSTITUTE_NOTIFICATION_APP_NAME:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME
+UnflaggedApi: android.Manifest.permission#SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON
+UnflaggedApi: android.Manifest.permission#SUGGEST_EXTERNAL_TIME:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SUGGEST_EXTERNAL_TIME
+UnflaggedApi: android.Manifest.permission#SUSPEND_APPS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SUSPEND_APPS
+UnflaggedApi: android.Manifest.permission#SYSTEM_APPLICATION_OVERLAY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY
+UnflaggedApi: android.Manifest.permission#SYSTEM_CAMERA:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.SYSTEM_CAMERA
+UnflaggedApi: android.Manifest.permission#TETHER_PRIVILEGED:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.TETHER_PRIVILEGED
+UnflaggedApi: android.Manifest.permission#TIS_EXTENSION_INTERFACE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.TIS_EXTENSION_INTERFACE
+UnflaggedApi: android.Manifest.permission#TOGGLE_AUTOMOTIVE_PROJECTION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION
+UnflaggedApi: android.Manifest.permission#TRIGGER_LOST_MODE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.TRIGGER_LOST_MODE
+UnflaggedApi: android.Manifest.permission#TV_INPUT_HARDWARE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.TV_INPUT_HARDWARE
+UnflaggedApi: android.Manifest.permission#TV_VIRTUAL_REMOTE_CONTROLLER:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER
+UnflaggedApi: android.Manifest.permission#UNLIMITED_SHORTCUTS_API_CALLS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.UNLIMITED_SHORTCUTS_API_CALLS
+UnflaggedApi: android.Manifest.permission#UPDATE_APP_OPS_STATS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.UPDATE_APP_OPS_STATS
+UnflaggedApi: android.Manifest.permission#UPDATE_DEVICE_MANAGEMENT_RESOURCES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES
+UnflaggedApi: android.Manifest.permission#UPDATE_DOMAIN_VERIFICATION_USER_SELECTION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
+UnflaggedApi: android.Manifest.permission#UPDATE_FONTS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.UPDATE_FONTS
+UnflaggedApi: android.Manifest.permission#UPDATE_LOCK:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.UPDATE_LOCK
+UnflaggedApi: android.Manifest.permission#UPGRADE_RUNTIME_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#USER_ACTIVITY:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.USER_ACTIVITY
+UnflaggedApi: android.Manifest.permission#USE_COLORIZED_NOTIFICATIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS
+UnflaggedApi: android.Manifest.permission#USE_RESERVED_DISK:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.USE_RESERVED_DISK
+UnflaggedApi: android.Manifest.permission#UWB_PRIVILEGED:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.UWB_PRIVILEGED
+UnflaggedApi: android.Manifest.permission#WHITELIST_AUTO_REVOKE_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#WHITELIST_RESTRICTED_PERMISSIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS
+UnflaggedApi: android.Manifest.permission#WIFI_ACCESS_COEX_UNSAFE_CHANNELS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS
+UnflaggedApi: android.Manifest.permission#WIFI_SET_DEVICE_MOBILITY_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE
+UnflaggedApi: android.Manifest.permission#WIFI_UPDATE_COEX_UNSAFE_CHANNELS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS
+UnflaggedApi: android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE
+UnflaggedApi: android.Manifest.permission#WRITE_ALLOWLISTED_DEVICE_CONFIG:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG
+UnflaggedApi: android.Manifest.permission#WRITE_DEVICE_CONFIG:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WRITE_DEVICE_CONFIG
+UnflaggedApi: android.Manifest.permission#WRITE_DREAM_STATE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WRITE_DREAM_STATE
+UnflaggedApi: android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS
+UnflaggedApi: android.Manifest.permission#WRITE_OBB:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WRITE_OBB
+UnflaggedApi: android.Manifest.permission#WRITE_SECURITY_LOG:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WRITE_SECURITY_LOG
+UnflaggedApi: android.Manifest.permission#WRITE_SMS:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.WRITE_SMS
+UnflaggedApi: android.Manifest.permission_group#UNDEFINED:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission_group.UNDEFINED
+UnflaggedApi: android.R.array#config_keySystemUuidMapping:
+ New API must be flagged with @FlaggedApi: field android.R.array.config_keySystemUuidMapping
+UnflaggedApi: android.R.array#config_optionalIpSecAlgorithms:
+ New API must be flagged with @FlaggedApi: field android.R.array.config_optionalIpSecAlgorithms
+UnflaggedApi: android.R.attr#allowClearUserDataOnFailedRestore:
+ New API must be flagged with @FlaggedApi: field android.R.attr.allowClearUserDataOnFailedRestore
+UnflaggedApi: android.R.attr#gameSessionService:
+ New API must be flagged with @FlaggedApi: field android.R.attr.gameSessionService
+UnflaggedApi: android.R.attr#hotwordDetectionService:
+ New API must be flagged with @FlaggedApi: field android.R.attr.hotwordDetectionService
+UnflaggedApi: android.R.attr#isVrOnly:
+ New API must be flagged with @FlaggedApi: field android.R.attr.isVrOnly
+UnflaggedApi: android.R.attr#minExtensionVersion:
+ New API must be flagged with @FlaggedApi: field android.R.attr.minExtensionVersion
+UnflaggedApi: android.R.attr#playHomeTransitionSound:
+ New API must be flagged with @FlaggedApi: field android.R.attr.playHomeTransitionSound
+UnflaggedApi: android.R.attr#requiredSystemPropertyName:
+ New API must be flagged with @FlaggedApi: field android.R.attr.requiredSystemPropertyName
+UnflaggedApi: android.R.attr#requiredSystemPropertyValue:
+ New API must be flagged with @FlaggedApi: field android.R.attr.requiredSystemPropertyValue
+UnflaggedApi: android.R.attr#sdkVersion:
+ New API must be flagged with @FlaggedApi: field android.R.attr.sdkVersion
+UnflaggedApi: android.R.attr#supportsAmbientMode:
+ New API must be flagged with @FlaggedApi: field android.R.attr.supportsAmbientMode
+UnflaggedApi: android.R.attr#userRestriction:
+ New API must be flagged with @FlaggedApi: field android.R.attr.userRestriction
+UnflaggedApi: android.R.attr#visualQueryDetectionService:
+ New API must be flagged with @FlaggedApi: field android.R.attr.visualQueryDetectionService
+UnflaggedApi: android.R.bool#config_enableDefaultNotes:
+ New API must be flagged with @FlaggedApi: field android.R.bool.config_enableDefaultNotes
+UnflaggedApi: android.R.bool#config_enableDefaultNotesForWorkProfile:
+ New API must be flagged with @FlaggedApi: field android.R.bool.config_enableDefaultNotesForWorkProfile
+UnflaggedApi: android.R.bool#config_enableQrCodeScannerOnLockScreen:
+ New API must be flagged with @FlaggedApi: field android.R.bool.config_enableQrCodeScannerOnLockScreen
+UnflaggedApi: android.R.bool#config_safetyProtectionEnabled:
+ New API must be flagged with @FlaggedApi: field android.R.bool.config_safetyProtectionEnabled
+UnflaggedApi: android.R.bool#config_sendPackageName:
+ New API must be flagged with @FlaggedApi: field android.R.bool.config_sendPackageName
+UnflaggedApi: android.R.bool#config_showDefaultAssistant:
+ New API must be flagged with @FlaggedApi: field android.R.bool.config_showDefaultAssistant
+UnflaggedApi: android.R.bool#config_showDefaultEmergency:
+ New API must be flagged with @FlaggedApi: field android.R.bool.config_showDefaultEmergency
+UnflaggedApi: android.R.bool#config_showDefaultHome:
+ New API must be flagged with @FlaggedApi: field android.R.bool.config_showDefaultHome
+UnflaggedApi: android.R.color#system_notification_accent_color:
+ New API must be flagged with @FlaggedApi: field android.R.color.system_notification_accent_color
+UnflaggedApi: android.R.dimen#config_restrictedIconSize:
+ New API must be flagged with @FlaggedApi: field android.R.dimen.config_restrictedIconSize
+UnflaggedApi: android.R.dimen#config_viewConfigurationHandwritingGestureLineMargin:
+ New API must be flagged with @FlaggedApi: field android.R.dimen.config_viewConfigurationHandwritingGestureLineMargin
+UnflaggedApi: android.R.drawable#ic_info:
+ New API must be flagged with @FlaggedApi: field android.R.drawable.ic_info
+UnflaggedApi: android.R.drawable#ic_safety_protection:
+ New API must be flagged with @FlaggedApi: field android.R.drawable.ic_safety_protection
+UnflaggedApi: android.R.raw#loaderror:
+ New API must be flagged with @FlaggedApi: field android.R.raw.loaderror
+UnflaggedApi: android.R.raw#nodomain:
+ New API must be flagged with @FlaggedApi: field android.R.raw.nodomain
+UnflaggedApi: android.R.string#config_customMediaKeyDispatcher:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_customMediaKeyDispatcher
+UnflaggedApi: android.R.string#config_customMediaSessionPolicyProvider:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_customMediaSessionPolicyProvider
+UnflaggedApi: android.R.string#config_defaultAssistant:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_defaultAssistant
+UnflaggedApi: android.R.string#config_defaultAutomotiveNavigation:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_defaultAutomotiveNavigation
+UnflaggedApi: android.R.string#config_defaultBrowser:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_defaultBrowser
+UnflaggedApi: android.R.string#config_defaultCallRedirection:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_defaultCallRedirection
+UnflaggedApi: android.R.string#config_defaultCallScreening:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_defaultCallScreening
+UnflaggedApi: android.R.string#config_defaultDialer:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_defaultDialer
+UnflaggedApi: android.R.string#config_defaultNotes:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_defaultNotes
+UnflaggedApi: android.R.string#config_defaultRetailDemo:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_defaultRetailDemo
+UnflaggedApi: android.R.string#config_defaultSms:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_defaultSms
+UnflaggedApi: android.R.string#config_devicePolicyManagement:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_devicePolicyManagement
+UnflaggedApi: android.R.string#config_feedbackIntentExtraKey:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_feedbackIntentExtraKey
+UnflaggedApi: android.R.string#config_feedbackIntentNameKey:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_feedbackIntentNameKey
+UnflaggedApi: android.R.string#config_helpIntentExtraKey:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_helpIntentExtraKey
+UnflaggedApi: android.R.string#config_helpIntentNameKey:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_helpIntentNameKey
+UnflaggedApi: android.R.string#config_helpPackageNameKey:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_helpPackageNameKey
+UnflaggedApi: android.R.string#config_helpPackageNameValue:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_helpPackageNameValue
+UnflaggedApi: android.R.string#config_systemActivityRecognizer:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemActivityRecognizer
+UnflaggedApi: android.R.string#config_systemAmbientAudioIntelligence:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemAmbientAudioIntelligence
+UnflaggedApi: android.R.string#config_systemAppProtectionService:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemAppProtectionService
+UnflaggedApi: android.R.string#config_systemAudioIntelligence:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemAudioIntelligence
+UnflaggedApi: android.R.string#config_systemAutomotiveCalendarSyncManager:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemAutomotiveCalendarSyncManager
+UnflaggedApi: android.R.string#config_systemAutomotiveCluster:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemAutomotiveCluster
+UnflaggedApi: android.R.string#config_systemAutomotiveProjection:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemAutomotiveProjection
+UnflaggedApi: android.R.string#config_systemCallStreaming:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemCallStreaming
+UnflaggedApi: android.R.string#config_systemCompanionDeviceProvider:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemCompanionDeviceProvider
+UnflaggedApi: android.R.string#config_systemContacts:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemContacts
+UnflaggedApi: android.R.string#config_systemFinancedDeviceController:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemFinancedDeviceController
+UnflaggedApi: android.R.string#config_systemGallery:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemGallery
+UnflaggedApi: android.R.string#config_systemNotificationIntelligence:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemNotificationIntelligence
+UnflaggedApi: android.R.string#config_systemSettingsIntelligence:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemSettingsIntelligence
+UnflaggedApi: android.R.string#config_systemShell:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemShell
+UnflaggedApi: android.R.string#config_systemSpeechRecognizer:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemSpeechRecognizer
+UnflaggedApi: android.R.string#config_systemSupervision:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemSupervision
+UnflaggedApi: android.R.string#config_systemTelevisionNotificationHandler:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemTelevisionNotificationHandler
+UnflaggedApi: android.R.string#config_systemTextIntelligence:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemTextIntelligence
+UnflaggedApi: android.R.string#config_systemUi:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemUi
+UnflaggedApi: android.R.string#config_systemUiIntelligence:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemUiIntelligence
+UnflaggedApi: android.R.string#config_systemVisualIntelligence:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemVisualIntelligence
+UnflaggedApi: android.R.string#config_systemWearHealthService:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemWearHealthService
+UnflaggedApi: android.R.string#config_systemWellbeing:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemWellbeing
+UnflaggedApi: android.R.string#config_systemWifiCoexManager:
+ New API must be flagged with @FlaggedApi: field android.R.string.config_systemWifiCoexManager
+UnflaggedApi: android.R.string#safety_protection_display_text:
+ New API must be flagged with @FlaggedApi: field android.R.string.safety_protection_display_text
+UnflaggedApi: android.R.style#Theme_DeviceDefault_DocumentsUI:
+ New API must be flagged with @FlaggedApi: field android.R.style.Theme_DeviceDefault_DocumentsUI
+UnflaggedApi: android.R.style#Theme_Leanback_FormWizard:
+ New API must be flagged with @FlaggedApi: field android.R.style.Theme_Leanback_FormWizard
+UnflaggedApi: android.app.ActivityManager#getExternalHistoricalProcessStartReasons(String, int):
+ New API must be flagged with @FlaggedApi: method android.app.ActivityManager.getExternalHistoricalProcessStartReasons(String,int)
+UnflaggedApi: android.app.AppOpsManager#OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO:
+ New API must be flagged with @FlaggedApi: field android.app.AppOpsManager.OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO
+UnflaggedApi: android.app.AppOpsManager.AttributedHistoricalOps#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.AttributedHistoricalOps.equals(Object)
+UnflaggedApi: android.app.AppOpsManager.AttributedHistoricalOps#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.AttributedHistoricalOps.hashCode()
+UnflaggedApi: android.app.AppOpsManager.HistoricalOp#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.HistoricalOp.equals(Object)
+UnflaggedApi: android.app.AppOpsManager.HistoricalOp#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.HistoricalOp.hashCode()
+UnflaggedApi: android.app.AppOpsManager.HistoricalOps#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.HistoricalOps.equals(Object)
+UnflaggedApi: android.app.AppOpsManager.HistoricalOps#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.HistoricalOps.hashCode()
+UnflaggedApi: android.app.AppOpsManager.HistoricalOps#toString():
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.HistoricalOps.toString()
+UnflaggedApi: android.app.AppOpsManager.HistoricalPackageOps#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.HistoricalPackageOps.equals(Object)
+UnflaggedApi: android.app.AppOpsManager.HistoricalPackageOps#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.HistoricalPackageOps.hashCode()
+UnflaggedApi: android.app.AppOpsManager.HistoricalUidOps#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.HistoricalUidOps.equals(Object)
+UnflaggedApi: android.app.AppOpsManager.HistoricalUidOps#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.AppOpsManager.HistoricalUidOps.hashCode()
+UnflaggedApi: android.app.GameModeConfiguration#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.GameModeConfiguration.equals(Object)
+UnflaggedApi: android.app.GameModeConfiguration#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.GameModeConfiguration.hashCode()
+UnflaggedApi: android.app.StatusBarManager.DisableInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.app.StatusBarManager.DisableInfo.toString()
+UnflaggedApi: android.app.Vr2dDisplayProperties#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.Vr2dDisplayProperties.equals(Object)
+UnflaggedApi: android.app.Vr2dDisplayProperties#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.Vr2dDisplayProperties.hashCode()
+UnflaggedApi: android.app.Vr2dDisplayProperties#toString():
+ New API must be flagged with @FlaggedApi: method android.app.Vr2dDisplayProperties.toString()
+UnflaggedApi: android.app.admin.AccountTypePolicyKey#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.AccountTypePolicyKey.equals(Object)
+UnflaggedApi: android.app.admin.AccountTypePolicyKey#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.AccountTypePolicyKey.hashCode()
+UnflaggedApi: android.app.admin.AccountTypePolicyKey#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.AccountTypePolicyKey.toString()
+UnflaggedApi: android.app.admin.Authority#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.Authority.equals(Object)
+UnflaggedApi: android.app.admin.Authority#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.Authority.hashCode()
+UnflaggedApi: android.app.admin.DeviceAdminAuthority#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.DeviceAdminAuthority.equals(Object)
+UnflaggedApi: android.app.admin.DeviceAdminAuthority#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.DeviceAdminAuthority.hashCode()
+UnflaggedApi: android.app.admin.DeviceAdminAuthority#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.DeviceAdminAuthority.toString()
+UnflaggedApi: android.app.admin.DevicePolicyDrawableResource#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.DevicePolicyDrawableResource.equals(Object)
+UnflaggedApi: android.app.admin.DevicePolicyDrawableResource#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.DevicePolicyDrawableResource.hashCode()
+UnflaggedApi: android.app.admin.DevicePolicyKeyguardService#onDestroy():
+ New API must be flagged with @FlaggedApi: method android.app.admin.DevicePolicyKeyguardService.onDestroy()
+UnflaggedApi: android.app.admin.DevicePolicyResources.Strings:
+ New API must be flagged with @FlaggedApi: class android.app.admin.DevicePolicyResources.Strings
+UnflaggedApi: android.app.admin.DevicePolicyResources.Strings.DefaultAppSettings:
+ New API must be flagged with @FlaggedApi: class android.app.admin.DevicePolicyResources.Strings.DefaultAppSettings
+UnflaggedApi: android.app.admin.DevicePolicyResources.Strings.DefaultAppSettings#HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE:
+ New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyResources.Strings.DefaultAppSettings.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE
+UnflaggedApi: android.app.admin.DevicePolicyResources.Strings.DefaultAppSettings#WORK_PROFILE_DEFAULT_APPS_TITLE:
+ New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyResources.Strings.DefaultAppSettings.WORK_PROFILE_DEFAULT_APPS_TITLE
+UnflaggedApi: android.app.admin.DevicePolicyResources.Strings.PermissionSettings:
+ New API must be flagged with @FlaggedApi: class android.app.admin.DevicePolicyResources.Strings.PermissionSettings
+UnflaggedApi: android.app.admin.DevicePolicyResources.Strings.PermissionSettings#BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE:
+ New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyResources.Strings.PermissionSettings.BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE
+UnflaggedApi: android.app.admin.DevicePolicyResources.Strings.PermissionSettings#BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE:
+ New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyResources.Strings.PermissionSettings.BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE
+UnflaggedApi: android.app.admin.DevicePolicyResources.Strings.PermissionSettings#FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE:
+ New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyResources.Strings.PermissionSettings.FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE
+UnflaggedApi: android.app.admin.DevicePolicyResources.Strings.PermissionSettings#LOCATION_AUTO_GRANTED_MESSAGE:
+ New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyResources.Strings.PermissionSettings.LOCATION_AUTO_GRANTED_MESSAGE
+UnflaggedApi: android.app.admin.DevicePolicyState#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.DevicePolicyState.toString()
+UnflaggedApi: android.app.admin.DevicePolicyStringResource#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.DevicePolicyStringResource.equals(Object)
+UnflaggedApi: android.app.admin.DevicePolicyStringResource#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.DevicePolicyStringResource.hashCode()
+UnflaggedApi: android.app.admin.DpcAuthority#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.DpcAuthority.equals(Object)
+UnflaggedApi: android.app.admin.DpcAuthority#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.DpcAuthority.hashCode()
+UnflaggedApi: android.app.admin.DpcAuthority#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.DpcAuthority.toString()
+UnflaggedApi: android.app.admin.EnforcingAdmin#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.EnforcingAdmin.equals(Object)
+UnflaggedApi: android.app.admin.EnforcingAdmin#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.EnforcingAdmin.hashCode()
+UnflaggedApi: android.app.admin.EnforcingAdmin#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.EnforcingAdmin.toString()
+UnflaggedApi: android.app.admin.IntentFilterPolicyKey#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.IntentFilterPolicyKey.equals(Object)
+UnflaggedApi: android.app.admin.IntentFilterPolicyKey#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.IntentFilterPolicyKey.hashCode()
+UnflaggedApi: android.app.admin.IntentFilterPolicyKey#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.IntentFilterPolicyKey.toString()
+UnflaggedApi: android.app.admin.LockTaskPolicy#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.LockTaskPolicy.equals(Object)
+UnflaggedApi: android.app.admin.LockTaskPolicy#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.LockTaskPolicy.hashCode()
+UnflaggedApi: android.app.admin.LockTaskPolicy#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.LockTaskPolicy.toString()
+UnflaggedApi: android.app.admin.NoArgsPolicyKey#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.NoArgsPolicyKey.toString()
+UnflaggedApi: android.app.admin.PackagePermissionPolicyKey#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.PackagePermissionPolicyKey.equals(Object)
+UnflaggedApi: android.app.admin.PackagePermissionPolicyKey#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.PackagePermissionPolicyKey.hashCode()
+UnflaggedApi: android.app.admin.PackagePermissionPolicyKey#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.PackagePermissionPolicyKey.toString()
+UnflaggedApi: android.app.admin.PackagePolicyKey#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.PackagePolicyKey.equals(Object)
+UnflaggedApi: android.app.admin.PackagePolicyKey#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.PackagePolicyKey.hashCode()
+UnflaggedApi: android.app.admin.PackagePolicyKey#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.PackagePolicyKey.toString()
+UnflaggedApi: android.app.admin.PolicyKey#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.PolicyKey.equals(Object)
+UnflaggedApi: android.app.admin.PolicyKey#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.PolicyKey.hashCode()
+UnflaggedApi: android.app.admin.PolicyState#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.PolicyState.toString()
+UnflaggedApi: android.app.admin.RoleAuthority#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.RoleAuthority.equals(Object)
+UnflaggedApi: android.app.admin.RoleAuthority#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.RoleAuthority.hashCode()
+UnflaggedApi: android.app.admin.RoleAuthority#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.RoleAuthority.toString()
+UnflaggedApi: android.app.admin.UnknownAuthority#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.admin.UnknownAuthority.equals(Object)
+UnflaggedApi: android.app.admin.UnknownAuthority#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.admin.UnknownAuthority.hashCode()
+UnflaggedApi: android.app.admin.UnknownAuthority#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.UnknownAuthority.toString()
+UnflaggedApi: android.app.admin.UserRestrictionPolicyKey#toString():
+ New API must be flagged with @FlaggedApi: method android.app.admin.UserRestrictionPolicyKey.toString()
+UnflaggedApi: android.app.ambientcontext.AmbientContextEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.app.ambientcontext.AmbientContextEvent.toString()
+UnflaggedApi: android.app.ambientcontext.AmbientContextEventRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.app.ambientcontext.AmbientContextEventRequest.toString()
+UnflaggedApi: android.app.assist.ActivityId#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.assist.ActivityId.equals(Object)
+UnflaggedApi: android.app.assist.ActivityId#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.assist.ActivityId.hashCode()
+UnflaggedApi: android.app.assist.ActivityId#toString():
+ New API must be flagged with @FlaggedApi: method android.app.assist.ActivityId.toString()
+UnflaggedApi: android.app.assist.AssistStructure.ViewNode#ViewNode():
+ New API must be flagged with @FlaggedApi: constructor android.app.assist.AssistStructure.ViewNode()
+UnflaggedApi: android.app.backup.RestoreDescription#toString():
+ New API must be flagged with @FlaggedApi: method android.app.backup.RestoreDescription.toString()
+UnflaggedApi: android.app.cloudsearch.SearchRequest#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.cloudsearch.SearchRequest.equals(Object)
+UnflaggedApi: android.app.cloudsearch.SearchRequest#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.cloudsearch.SearchRequest.hashCode()
+UnflaggedApi: android.app.cloudsearch.SearchRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.app.cloudsearch.SearchRequest.toString()
+UnflaggedApi: android.app.cloudsearch.SearchResponse#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.cloudsearch.SearchResponse.equals(Object)
+UnflaggedApi: android.app.cloudsearch.SearchResponse#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.cloudsearch.SearchResponse.hashCode()
+UnflaggedApi: android.app.cloudsearch.SearchResult#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.cloudsearch.SearchResult.equals(Object)
+UnflaggedApi: android.app.cloudsearch.SearchResult#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.cloudsearch.SearchResult.hashCode()
+UnflaggedApi: android.app.prediction.AppPredictionContext#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.prediction.AppPredictionContext.equals(Object)
+UnflaggedApi: android.app.prediction.AppPredictionSessionId#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.prediction.AppPredictionSessionId.equals(Object)
+UnflaggedApi: android.app.prediction.AppPredictionSessionId#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.prediction.AppPredictionSessionId.hashCode()
+UnflaggedApi: android.app.prediction.AppPredictionSessionId#toString():
+ New API must be flagged with @FlaggedApi: method android.app.prediction.AppPredictionSessionId.toString()
+UnflaggedApi: android.app.prediction.AppPredictor#finalize():
+ New API must be flagged with @FlaggedApi: method android.app.prediction.AppPredictor.finalize()
+UnflaggedApi: android.app.prediction.AppTarget#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.prediction.AppTarget.equals(Object)
+UnflaggedApi: android.app.prediction.AppTargetEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.prediction.AppTargetEvent.equals(Object)
+UnflaggedApi: android.app.prediction.AppTargetId#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.prediction.AppTargetId.equals(Object)
+UnflaggedApi: android.app.prediction.AppTargetId#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.prediction.AppTargetId.hashCode()
+UnflaggedApi: android.app.search.SearchAction#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.search.SearchAction.equals(Object)
+UnflaggedApi: android.app.search.SearchAction#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.search.SearchAction.hashCode()
+UnflaggedApi: android.app.search.SearchAction#toString():
+ New API must be flagged with @FlaggedApi: method android.app.search.SearchAction.toString()
+UnflaggedApi: android.app.search.SearchSessionId#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.search.SearchSessionId.equals(Object)
+UnflaggedApi: android.app.search.SearchSessionId#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.search.SearchSessionId.hashCode()
+UnflaggedApi: android.app.search.SearchSessionId#toString():
+ New API must be flagged with @FlaggedApi: method android.app.search.SearchSessionId.toString()
+UnflaggedApi: android.app.search.SearchTargetEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.search.SearchTargetEvent.equals(Object)
+UnflaggedApi: android.app.search.SearchTargetEvent#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.search.SearchTargetEvent.hashCode()
+UnflaggedApi: android.app.smartspace.SmartspaceAction#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceAction.equals(Object)
+UnflaggedApi: android.app.smartspace.SmartspaceAction#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceAction.hashCode()
+UnflaggedApi: android.app.smartspace.SmartspaceAction#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceAction.toString()
+UnflaggedApi: android.app.smartspace.SmartspaceConfig#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceConfig.equals(Object)
+UnflaggedApi: android.app.smartspace.SmartspaceConfig#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceConfig.hashCode()
+UnflaggedApi: android.app.smartspace.SmartspaceSessionId#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceSessionId.equals(Object)
+UnflaggedApi: android.app.smartspace.SmartspaceSessionId#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceSessionId.hashCode()
+UnflaggedApi: android.app.smartspace.SmartspaceSessionId#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceSessionId.toString()
+UnflaggedApi: android.app.smartspace.SmartspaceTarget#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceTarget.equals(Object)
+UnflaggedApi: android.app.smartspace.SmartspaceTarget#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceTarget.hashCode()
+UnflaggedApi: android.app.smartspace.SmartspaceTarget#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceTarget.toString()
+UnflaggedApi: android.app.smartspace.SmartspaceTargetEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.SmartspaceTargetEvent.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.BaseTemplateData#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.BaseTemplateData.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.BaseTemplateData#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.BaseTemplateData.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.BaseTemplateData#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.BaseTemplateData.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.CarouselTemplateData#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.CarouselTemplateData.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.CarouselTemplateData#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.CarouselTemplateData.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.CarouselTemplateData#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.CarouselTemplateData.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.CombinedCardsTemplateData#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.CombinedCardsTemplateData.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.CombinedCardsTemplateData#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.CombinedCardsTemplateData.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.CombinedCardsTemplateData#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.CombinedCardsTemplateData.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.HeadToHeadTemplateData#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.HeadToHeadTemplateData.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.HeadToHeadTemplateData#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.HeadToHeadTemplateData.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.HeadToHeadTemplateData#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.HeadToHeadTemplateData.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.Icon#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.Icon.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.Icon#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.Icon.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.Icon#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.Icon.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.SubCardTemplateData#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.SubCardTemplateData.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.SubCardTemplateData#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.SubCardTemplateData.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.SubCardTemplateData#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.SubCardTemplateData.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.SubImageTemplateData#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.SubImageTemplateData.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.SubImageTemplateData#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.SubImageTemplateData.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.SubImageTemplateData#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.SubImageTemplateData.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.SubListTemplateData#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.SubListTemplateData.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.SubListTemplateData#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.SubListTemplateData.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.SubListTemplateData#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.SubListTemplateData.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.TapAction#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.TapAction.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.TapAction#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.TapAction.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.TapAction#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.TapAction.toString()
+UnflaggedApi: android.app.smartspace.uitemplatedata.Text#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.Text.equals(Object)
+UnflaggedApi: android.app.smartspace.uitemplatedata.Text#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.Text.hashCode()
+UnflaggedApi: android.app.smartspace.uitemplatedata.Text#toString():
+ New API must be flagged with @FlaggedApi: method android.app.smartspace.uitemplatedata.Text.toString()
+UnflaggedApi: android.app.time.ExternalTimeSuggestion#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.ExternalTimeSuggestion.equals(Object)
+UnflaggedApi: android.app.time.ExternalTimeSuggestion#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.ExternalTimeSuggestion.hashCode()
+UnflaggedApi: android.app.time.ExternalTimeSuggestion#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.ExternalTimeSuggestion.toString()
+UnflaggedApi: android.app.time.TimeCapabilities#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeCapabilities.equals(Object)
+UnflaggedApi: android.app.time.TimeCapabilities#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeCapabilities.hashCode()
+UnflaggedApi: android.app.time.TimeCapabilities#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeCapabilities.toString()
+UnflaggedApi: android.app.time.TimeCapabilitiesAndConfig#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeCapabilitiesAndConfig.equals(Object)
+UnflaggedApi: android.app.time.TimeCapabilitiesAndConfig#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeCapabilitiesAndConfig.hashCode()
+UnflaggedApi: android.app.time.TimeCapabilitiesAndConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeCapabilitiesAndConfig.toString()
+UnflaggedApi: android.app.time.TimeConfiguration#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeConfiguration.equals(Object)
+UnflaggedApi: android.app.time.TimeConfiguration#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeConfiguration.hashCode()
+UnflaggedApi: android.app.time.TimeConfiguration#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeConfiguration.toString()
+UnflaggedApi: android.app.time.TimeState#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeState.equals(Object)
+UnflaggedApi: android.app.time.TimeState#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeState.hashCode()
+UnflaggedApi: android.app.time.TimeState#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeState.toString()
+UnflaggedApi: android.app.time.TimeZoneCapabilities#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneCapabilities.equals(Object)
+UnflaggedApi: android.app.time.TimeZoneCapabilities#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneCapabilities.hashCode()
+UnflaggedApi: android.app.time.TimeZoneCapabilities#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneCapabilities.toString()
+UnflaggedApi: android.app.time.TimeZoneCapabilitiesAndConfig#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneCapabilitiesAndConfig.equals(Object)
+UnflaggedApi: android.app.time.TimeZoneCapabilitiesAndConfig#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneCapabilitiesAndConfig.hashCode()
+UnflaggedApi: android.app.time.TimeZoneCapabilitiesAndConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneCapabilitiesAndConfig.toString()
+UnflaggedApi: android.app.time.TimeZoneConfiguration#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneConfiguration.equals(Object)
+UnflaggedApi: android.app.time.TimeZoneConfiguration#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneConfiguration.hashCode()
+UnflaggedApi: android.app.time.TimeZoneConfiguration#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneConfiguration.toString()
+UnflaggedApi: android.app.time.TimeZoneState#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneState.equals(Object)
+UnflaggedApi: android.app.time.TimeZoneState#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneState.hashCode()
+UnflaggedApi: android.app.time.TimeZoneState#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.TimeZoneState.toString()
+UnflaggedApi: android.app.time.UnixEpochTime#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.time.UnixEpochTime.equals(Object)
+UnflaggedApi: android.app.time.UnixEpochTime#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.time.UnixEpochTime.hashCode()
+UnflaggedApi: android.app.time.UnixEpochTime#toString():
+ New API must be flagged with @FlaggedApi: method android.app.time.UnixEpochTime.toString()
+UnflaggedApi: android.app.usage.BroadcastResponseStats#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.usage.BroadcastResponseStats.equals(Object)
+UnflaggedApi: android.app.usage.BroadcastResponseStats#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.usage.BroadcastResponseStats.hashCode()
+UnflaggedApi: android.app.usage.BroadcastResponseStats#toString():
+ New API must be flagged with @FlaggedApi: method android.app.usage.BroadcastResponseStats.toString()
+UnflaggedApi: android.app.usage.CacheQuotaHint#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.usage.CacheQuotaHint.equals(Object)
+UnflaggedApi: android.app.usage.CacheQuotaHint#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.usage.CacheQuotaHint.hashCode()
+UnflaggedApi: android.app.usage.CacheQuotaService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.app.usage.CacheQuotaService.onCreate()
+UnflaggedApi: android.app.usage.UsageEvents.Event#NOTIFICATION_INTERRUPTION:
+ New API must be flagged with @FlaggedApi: field android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION
+UnflaggedApi: android.app.usage.UsageEvents.Event#NOTIFICATION_SEEN:
+ New API must be flagged with @FlaggedApi: field android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN
+UnflaggedApi: android.app.usage.UsageEvents.Event#SLICE_PINNED:
+ New API must be flagged with @FlaggedApi: field android.app.usage.UsageEvents.Event.SLICE_PINNED
+UnflaggedApi: android.app.usage.UsageEvents.Event#SLICE_PINNED_PRIV:
+ New API must be flagged with @FlaggedApi: field android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV
+UnflaggedApi: android.app.usage.UsageEvents.Event#SYSTEM_INTERACTION:
+ New API must be flagged with @FlaggedApi: field android.app.usage.UsageEvents.Event.SYSTEM_INTERACTION
+UnflaggedApi: android.app.usage.UsageEvents.Event#getInstanceId():
+ New API must be flagged with @FlaggedApi: method android.app.usage.UsageEvents.Event.getInstanceId()
+UnflaggedApi: android.app.usage.UsageEvents.Event#getNotificationChannelId():
+ New API must be flagged with @FlaggedApi: method android.app.usage.UsageEvents.Event.getNotificationChannelId()
+UnflaggedApi: android.app.usage.UsageEvents.Event#getTaskRootClassName():
+ New API must be flagged with @FlaggedApi: method android.app.usage.UsageEvents.Event.getTaskRootClassName()
+UnflaggedApi: android.app.usage.UsageEvents.Event#getTaskRootPackageName():
+ New API must be flagged with @FlaggedApi: method android.app.usage.UsageEvents.Event.getTaskRootPackageName()
+UnflaggedApi: android.app.usage.UsageEvents.Event#isInstantApp():
+ New API must be flagged with @FlaggedApi: method android.app.usage.UsageEvents.Event.isInstantApp()
+UnflaggedApi: android.app.wallpapereffectsgeneration.CinematicEffectRequest#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.wallpapereffectsgeneration.CinematicEffectRequest.equals(Object)
+UnflaggedApi: android.app.wallpapereffectsgeneration.CinematicEffectRequest#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.wallpapereffectsgeneration.CinematicEffectRequest.hashCode()
+UnflaggedApi: android.app.wallpapereffectsgeneration.CinematicEffectResponse#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.app.wallpapereffectsgeneration.CinematicEffectResponse.equals(Object)
+UnflaggedApi: android.app.wallpapereffectsgeneration.CinematicEffectResponse#hashCode():
+ New API must be flagged with @FlaggedApi: method android.app.wallpapereffectsgeneration.CinematicEffectResponse.hashCode()
+UnflaggedApi: android.companion.virtual.VirtualDeviceManager.VirtualDevice#getPersistentDeviceId():
+ New API must be flagged with @FlaggedApi: method android.companion.virtual.VirtualDeviceManager.VirtualDevice.getPersistentDeviceId()
+UnflaggedApi: android.companion.virtual.VirtualDeviceParams#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.companion.virtual.VirtualDeviceParams.equals(Object)
+UnflaggedApi: android.companion.virtual.VirtualDeviceParams#hashCode():
+ New API must be flagged with @FlaggedApi: method android.companion.virtual.VirtualDeviceParams.hashCode()
+UnflaggedApi: android.companion.virtual.VirtualDeviceParams#toString():
+ New API must be flagged with @FlaggedApi: method android.companion.virtual.VirtualDeviceParams.toString()
+UnflaggedApi: android.companion.virtual.sensor.VirtualSensorConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.companion.virtual.sensor.VirtualSensorConfig.toString()
+UnflaggedApi: android.content.Intent#ACTION_UNARCHIVE_PACKAGE:
+ New API must be flagged with @FlaggedApi: field android.content.Intent.ACTION_UNARCHIVE_PACKAGE
+UnflaggedApi: android.content.integrity.Rule#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.content.integrity.Rule.equals(Object)
+UnflaggedApi: android.content.integrity.Rule#hashCode():
+ New API must be flagged with @FlaggedApi: method android.content.integrity.Rule.hashCode()
+UnflaggedApi: android.content.integrity.Rule#toString():
+ New API must be flagged with @FlaggedApi: method android.content.integrity.Rule.toString()
+UnflaggedApi: android.content.pm.PackageArchiver:
+ New API must be flagged with @FlaggedApi: class android.content.pm.PackageArchiver
+UnflaggedApi: android.content.pm.PackageArchiver#EXTRA_UNARCHIVE_ALL_USERS:
+ New API must be flagged with @FlaggedApi: field android.content.pm.PackageArchiver.EXTRA_UNARCHIVE_ALL_USERS
+UnflaggedApi: android.content.pm.PackageArchiver#EXTRA_UNARCHIVE_PACKAGE_NAME:
+ New API must be flagged with @FlaggedApi: field android.content.pm.PackageArchiver.EXTRA_UNARCHIVE_PACKAGE_NAME
+UnflaggedApi: android.content.pm.PackageArchiver#requestArchive(String, android.content.IntentSender):
+ New API must be flagged with @FlaggedApi: method android.content.pm.PackageArchiver.requestArchive(String,android.content.IntentSender)
+UnflaggedApi: android.content.pm.PackageArchiver#requestUnarchive(String):
+ New API must be flagged with @FlaggedApi: method android.content.pm.PackageArchiver.requestUnarchive(String)
+UnflaggedApi: android.content.pm.PackageInfo#isArchived:
+ New API must be flagged with @FlaggedApi: field android.content.pm.PackageInfo.isArchived
+UnflaggedApi: android.content.pm.PackageInstaller#readInstallInfo(android.os.ParcelFileDescriptor, String, int):
+ New API must be flagged with @FlaggedApi: method android.content.pm.PackageInstaller.readInstallInfo(android.os.ParcelFileDescriptor,String,int)
+UnflaggedApi: android.content.pm.PackageInstaller.InstallInfo#calculateInstalledSize(android.content.pm.PackageInstaller.SessionParams, android.os.ParcelFileDescriptor):
+ New API must be flagged with @FlaggedApi: method android.content.pm.PackageInstaller.InstallInfo.calculateInstalledSize(android.content.pm.PackageInstaller.SessionParams,android.os.ParcelFileDescriptor)
+UnflaggedApi: android.content.pm.PackageInstaller.SessionInfo#getResolvedBaseApkPath():
+ New API must be flagged with @FlaggedApi: method android.content.pm.PackageInstaller.SessionInfo.getResolvedBaseApkPath()
+UnflaggedApi: android.content.pm.PackageManager#EXTRA_REQUEST_PERMISSIONS_DEVICE_ID:
+ New API must be flagged with @FlaggedApi: field android.content.pm.PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID
+UnflaggedApi: android.content.pm.PackageManager#MATCH_ARCHIVED_PACKAGES:
+ New API must be flagged with @FlaggedApi: field android.content.pm.PackageManager.MATCH_ARCHIVED_PACKAGES
+UnflaggedApi: android.content.pm.PackageManager#getPackageArchiver():
+ New API must be flagged with @FlaggedApi: method android.content.pm.PackageManager.getPackageArchiver()
+UnflaggedApi: android.content.pm.SuspendDialogInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.content.pm.SuspendDialogInfo.equals(Object)
+UnflaggedApi: android.content.pm.SuspendDialogInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.content.pm.SuspendDialogInfo.hashCode()
+UnflaggedApi: android.content.pm.SuspendDialogInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.content.pm.SuspendDialogInfo.toString()
+UnflaggedApi: android.content.pm.UserProperties#toString():
+ New API must be flagged with @FlaggedApi: method android.content.pm.UserProperties.toString()
+UnflaggedApi: android.content.pm.verify.domain.DomainOwner#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.content.pm.verify.domain.DomainOwner.equals(Object)
+UnflaggedApi: android.content.pm.verify.domain.DomainOwner#hashCode():
+ New API must be flagged with @FlaggedApi: method android.content.pm.verify.domain.DomainOwner.hashCode()
+UnflaggedApi: android.content.pm.verify.domain.DomainOwner#toString():
+ New API must be flagged with @FlaggedApi: method android.content.pm.verify.domain.DomainOwner.toString()
+UnflaggedApi: android.content.pm.verify.domain.DomainVerificationInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.content.pm.verify.domain.DomainVerificationInfo.equals(Object)
+UnflaggedApi: android.content.pm.verify.domain.DomainVerificationInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.content.pm.verify.domain.DomainVerificationInfo.hashCode()
+UnflaggedApi: android.content.pm.verify.domain.DomainVerificationInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.content.pm.verify.domain.DomainVerificationInfo.toString()
+UnflaggedApi: android.content.pm.verify.domain.DomainVerificationRequest#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.content.pm.verify.domain.DomainVerificationRequest.equals(Object)
+UnflaggedApi: android.content.pm.verify.domain.DomainVerificationRequest#hashCode():
+ New API must be flagged with @FlaggedApi: method android.content.pm.verify.domain.DomainVerificationRequest.hashCode()
+UnflaggedApi: android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_CONVENIENCE:
+ New API must be flagged with @FlaggedApi: field android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE
+UnflaggedApi: android.hardware.biometrics.BiometricManager.Authenticators#EMPTY_SET:
+ New API must be flagged with @FlaggedApi: field android.hardware.biometrics.BiometricManager.Authenticators.EMPTY_SET
+UnflaggedApi: android.hardware.display.AmbientBrightnessDayStats#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.display.AmbientBrightnessDayStats.equals(Object)
+UnflaggedApi: android.hardware.display.AmbientBrightnessDayStats#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.display.AmbientBrightnessDayStats.hashCode()
+UnflaggedApi: android.hardware.display.AmbientBrightnessDayStats#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.display.AmbientBrightnessDayStats.toString()
+UnflaggedApi: android.hardware.display.BrightnessChangeEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.display.BrightnessChangeEvent.toString()
+UnflaggedApi: android.hardware.display.BrightnessConfiguration#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.display.BrightnessConfiguration.equals(Object)
+UnflaggedApi: android.hardware.display.BrightnessConfiguration#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.display.BrightnessConfiguration.hashCode()
+UnflaggedApi: android.hardware.display.BrightnessConfiguration#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.display.BrightnessConfiguration.toString()
+UnflaggedApi: android.hardware.display.BrightnessCorrection#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.display.BrightnessCorrection.equals(Object)
+UnflaggedApi: android.hardware.display.BrightnessCorrection#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.display.BrightnessCorrection.hashCode()
+UnflaggedApi: android.hardware.display.BrightnessCorrection#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.display.BrightnessCorrection.toString()
+UnflaggedApi: android.hardware.hdmi.HdmiDeviceInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.hdmi.HdmiDeviceInfo.equals(Object)
+UnflaggedApi: android.hardware.hdmi.HdmiDeviceInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.hdmi.HdmiDeviceInfo.hashCode()
+UnflaggedApi: android.hardware.hdmi.HdmiDeviceInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.hdmi.HdmiDeviceInfo.toString()
+UnflaggedApi: android.hardware.hdmi.HdmiPortInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.hdmi.HdmiPortInfo.equals(Object)
+UnflaggedApi: android.hardware.hdmi.HdmiPortInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.hdmi.HdmiPortInfo.hashCode()
+UnflaggedApi: android.hardware.hdmi.HdmiPortInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.hdmi.HdmiPortInfo.toString()
+UnflaggedApi: android.hardware.location.ContextHubClient#finalize():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.ContextHubClient.finalize()
+UnflaggedApi: android.hardware.location.ContextHubInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.location.ContextHubInfo.equals(Object)
+UnflaggedApi: android.hardware.location.ContextHubInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.ContextHubInfo.toString()
+UnflaggedApi: android.hardware.location.ContextHubIntentEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.location.ContextHubIntentEvent.equals(Object)
+UnflaggedApi: android.hardware.location.ContextHubIntentEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.ContextHubIntentEvent.toString()
+UnflaggedApi: android.hardware.location.ContextHubMessage#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.ContextHubMessage.toString()
+UnflaggedApi: android.hardware.location.GeofenceHardwareMonitorEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.GeofenceHardwareMonitorEvent.toString()
+UnflaggedApi: android.hardware.location.MemoryRegion#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.location.MemoryRegion.equals(Object)
+UnflaggedApi: android.hardware.location.MemoryRegion#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.MemoryRegion.toString()
+UnflaggedApi: android.hardware.location.NanoApp#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.NanoApp.toString()
+UnflaggedApi: android.hardware.location.NanoAppFilter#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.NanoAppFilter.toString()
+UnflaggedApi: android.hardware.location.NanoAppInstanceInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.NanoAppInstanceInfo.toString()
+UnflaggedApi: android.hardware.location.NanoAppMessage#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.location.NanoAppMessage.equals(Object)
+UnflaggedApi: android.hardware.location.NanoAppMessage#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.NanoAppMessage.toString()
+UnflaggedApi: android.hardware.location.NanoAppRpcService#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.location.NanoAppRpcService.equals(Object)
+UnflaggedApi: android.hardware.location.NanoAppRpcService#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.NanoAppRpcService.hashCode()
+UnflaggedApi: android.hardware.location.NanoAppRpcService#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.location.NanoAppRpcService.toString()
+UnflaggedApi: android.hardware.radio.ProgramList.Filter#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.ProgramList.Filter.equals(Object)
+UnflaggedApi: android.hardware.radio.ProgramList.Filter#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.ProgramList.Filter.hashCode()
+UnflaggedApi: android.hardware.radio.ProgramList.Filter#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.ProgramList.Filter.toString()
+UnflaggedApi: android.hardware.radio.ProgramSelector#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.ProgramSelector.equals(Object)
+UnflaggedApi: android.hardware.radio.ProgramSelector#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.ProgramSelector.hashCode()
+UnflaggedApi: android.hardware.radio.ProgramSelector#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.ProgramSelector.toString()
+UnflaggedApi: android.hardware.radio.ProgramSelector.Identifier#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.ProgramSelector.Identifier.equals(Object)
+UnflaggedApi: android.hardware.radio.ProgramSelector.Identifier#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.ProgramSelector.Identifier.hashCode()
+UnflaggedApi: android.hardware.radio.ProgramSelector.Identifier#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.ProgramSelector.Identifier.toString()
+UnflaggedApi: android.hardware.radio.RadioManager.AmBandConfig#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.AmBandConfig.equals(Object)
+UnflaggedApi: android.hardware.radio.RadioManager.AmBandConfig#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.AmBandConfig.hashCode()
+UnflaggedApi: android.hardware.radio.RadioManager.AmBandConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.AmBandConfig.toString()
+UnflaggedApi: android.hardware.radio.RadioManager.AmBandDescriptor#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.AmBandDescriptor.equals(Object)
+UnflaggedApi: android.hardware.radio.RadioManager.AmBandDescriptor#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.AmBandDescriptor.hashCode()
+UnflaggedApi: android.hardware.radio.RadioManager.AmBandDescriptor#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.AmBandDescriptor.toString()
+UnflaggedApi: android.hardware.radio.RadioManager.BandConfig#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.BandConfig.equals(Object)
+UnflaggedApi: android.hardware.radio.RadioManager.BandConfig#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.BandConfig.hashCode()
+UnflaggedApi: android.hardware.radio.RadioManager.BandConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.BandConfig.toString()
+UnflaggedApi: android.hardware.radio.RadioManager.BandDescriptor#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.BandDescriptor.equals(Object)
+UnflaggedApi: android.hardware.radio.RadioManager.BandDescriptor#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.BandDescriptor.hashCode()
+UnflaggedApi: android.hardware.radio.RadioManager.BandDescriptor#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.BandDescriptor.toString()
+UnflaggedApi: android.hardware.radio.RadioManager.FmBandConfig#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.FmBandConfig.equals(Object)
+UnflaggedApi: android.hardware.radio.RadioManager.FmBandConfig#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.FmBandConfig.hashCode()
+UnflaggedApi: android.hardware.radio.RadioManager.FmBandConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.FmBandConfig.toString()
+UnflaggedApi: android.hardware.radio.RadioManager.FmBandDescriptor#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.FmBandDescriptor.equals(Object)
+UnflaggedApi: android.hardware.radio.RadioManager.FmBandDescriptor#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.FmBandDescriptor.hashCode()
+UnflaggedApi: android.hardware.radio.RadioManager.FmBandDescriptor#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.FmBandDescriptor.toString()
+UnflaggedApi: android.hardware.radio.RadioManager.ModuleProperties#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.ModuleProperties.equals(Object)
+UnflaggedApi: android.hardware.radio.RadioManager.ModuleProperties#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.ModuleProperties.hashCode()
+UnflaggedApi: android.hardware.radio.RadioManager.ModuleProperties#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.ModuleProperties.toString()
+UnflaggedApi: android.hardware.radio.RadioManager.ProgramInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.ProgramInfo.equals(Object)
+UnflaggedApi: android.hardware.radio.RadioManager.ProgramInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.ProgramInfo.hashCode()
+UnflaggedApi: android.hardware.radio.RadioManager.ProgramInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioManager.ProgramInfo.toString()
+UnflaggedApi: android.hardware.radio.RadioMetadata#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioMetadata.equals(Object)
+UnflaggedApi: android.hardware.radio.RadioMetadata#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioMetadata.hashCode()
+UnflaggedApi: android.hardware.radio.RadioMetadata#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.radio.RadioMetadata.toString()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.Keyphrase#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.Keyphrase.equals(Object)
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.Keyphrase#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.Keyphrase.hashCode()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.Keyphrase#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.Keyphrase.toString()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra.equals(Object)
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra.hashCode()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra.toString()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel.equals(Object)
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel.hashCode()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel.toString()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.ModelParamRange#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.ModelParamRange.equals(Object)
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.ModelParamRange#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.ModelParamRange.toString()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.ModuleProperties#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.ModuleProperties.equals(Object)
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.ModuleProperties#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.ModuleProperties.hashCode()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.ModuleProperties#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.ModuleProperties.toString()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.RecognitionEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.RecognitionEvent.equals(Object)
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.RecognitionEvent#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.RecognitionEvent.hashCode()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.RecognitionEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.RecognitionEvent.toString()
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.SoundModel#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.SoundModel.equals(Object)
+UnflaggedApi: android.hardware.soundtrigger.SoundTrigger.SoundModel#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.soundtrigger.SoundTrigger.SoundModel.hashCode()
+UnflaggedApi: android.hardware.usb.DisplayPortAltModeInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.hardware.usb.DisplayPortAltModeInfo.equals(Object)
+UnflaggedApi: android.hardware.usb.DisplayPortAltModeInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.hardware.usb.DisplayPortAltModeInfo.hashCode()
+UnflaggedApi: android.hardware.usb.DisplayPortAltModeInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.usb.DisplayPortAltModeInfo.toString()
+UnflaggedApi: android.hardware.usb.UsbPort#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.usb.UsbPort.toString()
+UnflaggedApi: android.hardware.usb.UsbPortStatus#toString():
+ New API must be flagged with @FlaggedApi: method android.hardware.usb.UsbPortStatus.toString()
+UnflaggedApi: android.location.CorrelationVector#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.location.CorrelationVector.equals(Object)
+UnflaggedApi: android.location.CorrelationVector#hashCode():
+ New API must be flagged with @FlaggedApi: method android.location.CorrelationVector.hashCode()
+UnflaggedApi: android.location.CorrelationVector#toString():
+ New API must be flagged with @FlaggedApi: method android.location.CorrelationVector.toString()
+UnflaggedApi: android.location.Country#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.location.Country.equals(Object)
+UnflaggedApi: android.location.Country#hashCode():
+ New API must be flagged with @FlaggedApi: method android.location.Country.hashCode()
+UnflaggedApi: android.location.Country#toString():
+ New API must be flagged with @FlaggedApi: method android.location.Country.toString()
+UnflaggedApi: android.location.GnssExcessPathInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.location.GnssExcessPathInfo.equals(Object)
+UnflaggedApi: android.location.GnssExcessPathInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.location.GnssExcessPathInfo.hashCode()
+UnflaggedApi: android.location.GnssExcessPathInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GnssExcessPathInfo.toString()
+UnflaggedApi: android.location.GnssMeasurementCorrections#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GnssMeasurementCorrections.toString()
+UnflaggedApi: android.location.GnssMeasurementRequest#getWorkSource():
+ New API must be flagged with @FlaggedApi: method android.location.GnssMeasurementRequest.getWorkSource()
+UnflaggedApi: android.location.GnssMeasurementRequest.Builder#setWorkSource(android.os.WorkSource):
+ New API must be flagged with @FlaggedApi: method android.location.GnssMeasurementRequest.Builder.setWorkSource(android.os.WorkSource)
+UnflaggedApi: android.location.GnssReflectingPlane#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.location.GnssReflectingPlane.equals(Object)
+UnflaggedApi: android.location.GnssReflectingPlane#hashCode():
+ New API must be flagged with @FlaggedApi: method android.location.GnssReflectingPlane.hashCode()
+UnflaggedApi: android.location.GnssReflectingPlane#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GnssReflectingPlane.toString()
+UnflaggedApi: android.location.GnssRequest#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.location.GnssRequest.equals(Object)
+UnflaggedApi: android.location.GnssRequest#hashCode():
+ New API must be flagged with @FlaggedApi: method android.location.GnssRequest.hashCode()
+UnflaggedApi: android.location.GnssRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GnssRequest.toString()
+UnflaggedApi: android.location.GnssSingleSatCorrection#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.location.GnssSingleSatCorrection.equals(Object)
+UnflaggedApi: android.location.GnssSingleSatCorrection#hashCode():
+ New API must be flagged with @FlaggedApi: method android.location.GnssSingleSatCorrection.hashCode()
+UnflaggedApi: android.location.GnssSingleSatCorrection#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GnssSingleSatCorrection.toString()
+UnflaggedApi: android.location.GpsClock#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GpsClock.toString()
+UnflaggedApi: android.location.GpsMeasurement#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GpsMeasurement.toString()
+UnflaggedApi: android.location.GpsMeasurementsEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GpsMeasurementsEvent.toString()
+UnflaggedApi: android.location.GpsNavigationMessage#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GpsNavigationMessage.toString()
+UnflaggedApi: android.location.GpsNavigationMessageEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.location.GpsNavigationMessageEvent.toString()
+UnflaggedApi: android.location.LastLocationRequest#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.location.LastLocationRequest.equals(Object)
+UnflaggedApi: android.location.LastLocationRequest#hashCode():
+ New API must be flagged with @FlaggedApi: method android.location.LastLocationRequest.hashCode()
+UnflaggedApi: android.location.LastLocationRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.location.LastLocationRequest.toString()
+UnflaggedApi: android.location.SatellitePvt#toString():
+ New API must be flagged with @FlaggedApi: method android.location.SatellitePvt.toString()
+UnflaggedApi: android.location.SatellitePvt.ClockInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.location.SatellitePvt.ClockInfo.toString()
+UnflaggedApi: android.location.SatellitePvt.PositionEcef#toString():
+ New API must be flagged with @FlaggedApi: method android.location.SatellitePvt.PositionEcef.toString()
+UnflaggedApi: android.location.SatellitePvt.VelocityEcef#toString():
+ New API must be flagged with @FlaggedApi: method android.location.SatellitePvt.VelocityEcef.toString()
+UnflaggedApi: android.location.provider.ProviderRequest#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.location.provider.ProviderRequest.equals(Object)
+UnflaggedApi: android.location.provider.ProviderRequest#hashCode():
+ New API must be flagged with @FlaggedApi: method android.location.provider.ProviderRequest.hashCode()
+UnflaggedApi: android.location.provider.ProviderRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.location.provider.ProviderRequest.toString()
+UnflaggedApi: android.media.AudioDeviceAttributes#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.media.AudioDeviceAttributes.equals(Object)
+UnflaggedApi: android.media.AudioDeviceAttributes#hashCode():
+ New API must be flagged with @FlaggedApi: method android.media.AudioDeviceAttributes.hashCode()
+UnflaggedApi: android.media.AudioDeviceAttributes#toString():
+ New API must be flagged with @FlaggedApi: method android.media.AudioDeviceAttributes.toString()
+UnflaggedApi: android.media.AudioFocusInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.media.AudioFocusInfo.equals(Object)
+UnflaggedApi: android.media.AudioFocusInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.media.AudioFocusInfo.hashCode()
+UnflaggedApi: android.media.MediaRecorder.AudioSource#ECHO_REFERENCE:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRecorder.AudioSource.ECHO_REFERENCE
+UnflaggedApi: android.media.MediaRecorder.AudioSource#HOTWORD:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRecorder.AudioSource.HOTWORD
+UnflaggedApi: android.media.MediaRecorder.AudioSource#RADIO_TUNER:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRecorder.AudioSource.RADIO_TUNER
+UnflaggedApi: android.media.MediaRecorder.AudioSource#ULTRASOUND:
+ New API must be flagged with @FlaggedApi: field android.media.MediaRecorder.AudioSource.ULTRASOUND
+UnflaggedApi: android.media.NearbyDevice#toString():
+ New API must be flagged with @FlaggedApi: method android.media.NearbyDevice.toString()
+UnflaggedApi: android.media.VolumeInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.media.VolumeInfo.equals(Object)
+UnflaggedApi: android.media.VolumeInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.media.VolumeInfo.hashCode()
+UnflaggedApi: android.media.VolumeInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.media.VolumeInfo.toString()
+UnflaggedApi: android.media.audiopolicy.AudioMix#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.media.audiopolicy.AudioMix.CREATOR
+UnflaggedApi: android.media.audiopolicy.AudioMix#describeContents():
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioMix.describeContents()
+UnflaggedApi: android.media.audiopolicy.AudioMix#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioMix.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.media.audiopolicy.AudioMixingRule#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.media.audiopolicy.AudioMixingRule.CREATOR
+UnflaggedApi: android.media.audiopolicy.AudioMixingRule#describeContents():
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioMixingRule.describeContents()
+UnflaggedApi: android.media.audiopolicy.AudioMixingRule#hashCode():
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioMixingRule.hashCode()
+UnflaggedApi: android.media.audiopolicy.AudioMixingRule#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioMixingRule.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.media.audiopolicy.AudioPolicy#updateMixingRules(java.util.List<android.util.Pair<android.media.audiopolicy.AudioMix,android.media.audiopolicy.AudioMixingRule>>):
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioPolicy.updateMixingRules(java.util.List<android.util.Pair<android.media.audiopolicy.AudioMix,android.media.audiopolicy.AudioMixingRule>>)
+UnflaggedApi: android.media.audiopolicy.AudioProductStrategy#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioProductStrategy.equals(Object)
+UnflaggedApi: android.media.audiopolicy.AudioProductStrategy#hashCode():
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioProductStrategy.hashCode()
+UnflaggedApi: android.media.audiopolicy.AudioProductStrategy#toString():
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioProductStrategy.toString()
+UnflaggedApi: android.media.audiopolicy.AudioVolumeGroup#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioVolumeGroup.equals(Object)
+UnflaggedApi: android.media.audiopolicy.AudioVolumeGroup#toString():
+ New API must be flagged with @FlaggedApi: method android.media.audiopolicy.AudioVolumeGroup.toString()
+UnflaggedApi: android.media.musicrecognition.MusicRecognitionService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.media.musicrecognition.MusicRecognitionService.onCreate()
+UnflaggedApi: android.media.soundtrigger.SoundTriggerDetectionService#onUnbind(android.content.Intent):
+ New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerDetectionService.onUnbind(android.content.Intent)
+UnflaggedApi: android.media.tv.TunedInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.media.tv.TunedInfo.equals(Object)
+UnflaggedApi: android.media.tv.TunedInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.media.tv.TunedInfo.hashCode()
+UnflaggedApi: android.media.tv.TunedInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.media.tv.TunedInfo.toString()
+UnflaggedApi: android.media.tv.TvInputHardwareInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.media.tv.TvInputHardwareInfo.toString()
+UnflaggedApi: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle):
+ New API must be flagged with @FlaggedApi: method android.media.tv.TvRecordingClient.RecordingCallback.onEvent(String,String,android.os.Bundle)
+UnflaggedApi: android.media.tv.TvStreamConfig#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.media.tv.TvStreamConfig.equals(Object)
+UnflaggedApi: android.media.tv.TvStreamConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.media.tv.TvStreamConfig.toString()
+UnflaggedApi: android.net.MatchAllNetworkSpecifier#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.MatchAllNetworkSpecifier.equals(Object)
+UnflaggedApi: android.net.MatchAllNetworkSpecifier#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.MatchAllNetworkSpecifier.hashCode()
+UnflaggedApi: android.net.NetworkKey#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.NetworkKey.equals(Object)
+UnflaggedApi: android.net.NetworkKey#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.NetworkKey.hashCode()
+UnflaggedApi: android.net.NetworkKey#toString():
+ New API must be flagged with @FlaggedApi: method android.net.NetworkKey.toString()
+UnflaggedApi: android.net.RssiCurve#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.RssiCurve.equals(Object)
+UnflaggedApi: android.net.RssiCurve#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.RssiCurve.hashCode()
+UnflaggedApi: android.net.RssiCurve#toString():
+ New API must be flagged with @FlaggedApi: method android.net.RssiCurve.toString()
+UnflaggedApi: android.net.ScoredNetwork#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.ScoredNetwork.equals(Object)
+UnflaggedApi: android.net.ScoredNetwork#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.ScoredNetwork.hashCode()
+UnflaggedApi: android.net.ScoredNetwork#toString():
+ New API must be flagged with @FlaggedApi: method android.net.ScoredNetwork.toString()
+UnflaggedApi: android.net.WebAddress#toString():
+ New API must be flagged with @FlaggedApi: method android.net.WebAddress.toString()
+UnflaggedApi: android.net.WifiKey#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.WifiKey.equals(Object)
+UnflaggedApi: android.net.WifiKey#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.WifiKey.hashCode()
+UnflaggedApi: android.net.WifiKey#toString():
+ New API must be flagged with @FlaggedApi: method android.net.WifiKey.toString()
+UnflaggedApi: android.net.metrics.ApfProgramEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.metrics.ApfProgramEvent.equals(Object)
+UnflaggedApi: android.net.metrics.ApfProgramEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.net.metrics.ApfProgramEvent.toString()
+UnflaggedApi: android.net.metrics.ApfStats#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.metrics.ApfStats.equals(Object)
+UnflaggedApi: android.net.metrics.ApfStats#toString():
+ New API must be flagged with @FlaggedApi: method android.net.metrics.ApfStats.toString()
+UnflaggedApi: android.net.metrics.DhcpClientEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.metrics.DhcpClientEvent.equals(Object)
+UnflaggedApi: android.net.metrics.DhcpClientEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.net.metrics.DhcpClientEvent.toString()
+UnflaggedApi: android.net.metrics.DhcpErrorEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.net.metrics.DhcpErrorEvent.toString()
+UnflaggedApi: android.net.metrics.IpManagerEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.metrics.IpManagerEvent.equals(Object)
+UnflaggedApi: android.net.metrics.IpManagerEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.net.metrics.IpManagerEvent.toString()
+UnflaggedApi: android.net.metrics.IpReachabilityEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.metrics.IpReachabilityEvent.equals(Object)
+UnflaggedApi: android.net.metrics.IpReachabilityEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.net.metrics.IpReachabilityEvent.toString()
+UnflaggedApi: android.net.metrics.NetworkEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.metrics.NetworkEvent.equals(Object)
+UnflaggedApi: android.net.metrics.NetworkEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.net.metrics.NetworkEvent.toString()
+UnflaggedApi: android.net.metrics.RaEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.metrics.RaEvent.equals(Object)
+UnflaggedApi: android.net.metrics.RaEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.net.metrics.RaEvent.toString()
+UnflaggedApi: android.net.metrics.ValidationProbeEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.metrics.ValidationProbeEvent.equals(Object)
+UnflaggedApi: android.net.metrics.ValidationProbeEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.net.metrics.ValidationProbeEvent.toString()
+UnflaggedApi: android.net.vcn.VcnNetworkPolicyResult#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.vcn.VcnNetworkPolicyResult.equals(Object)
+UnflaggedApi: android.net.vcn.VcnNetworkPolicyResult#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.vcn.VcnNetworkPolicyResult.hashCode()
+UnflaggedApi: android.net.vcn.VcnNetworkPolicyResult#toString():
+ New API must be flagged with @FlaggedApi: method android.net.vcn.VcnNetworkPolicyResult.toString()
+UnflaggedApi: android.net.wifi.nl80211.DeviceWiphyCapabilities#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.DeviceWiphyCapabilities.equals(Object)
+UnflaggedApi: android.net.wifi.nl80211.DeviceWiphyCapabilities#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.DeviceWiphyCapabilities.hashCode()
+UnflaggedApi: android.net.wifi.nl80211.DeviceWiphyCapabilities#toString():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.DeviceWiphyCapabilities.toString()
+UnflaggedApi: android.net.wifi.nl80211.NativeWifiClient#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.NativeWifiClient.equals(Object)
+UnflaggedApi: android.net.wifi.nl80211.NativeWifiClient#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.NativeWifiClient.hashCode()
+UnflaggedApi: android.net.wifi.nl80211.PnoNetwork#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.PnoNetwork.equals(Object)
+UnflaggedApi: android.net.wifi.nl80211.PnoNetwork#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.PnoNetwork.hashCode()
+UnflaggedApi: android.net.wifi.nl80211.PnoSettings#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.PnoSettings.equals(Object)
+UnflaggedApi: android.net.wifi.nl80211.PnoSettings#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.PnoSettings.hashCode()
+UnflaggedApi: android.net.wifi.nl80211.RadioChainInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.RadioChainInfo.equals(Object)
+UnflaggedApi: android.net.wifi.nl80211.RadioChainInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.nl80211.RadioChainInfo.hashCode()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.HotspotNetwork#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.HotspotNetwork.equals(Object)
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.HotspotNetwork#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.HotspotNetwork.hashCode()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.HotspotNetwork#toString():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.HotspotNetwork.toString()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.equals(Object)
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.hashCode()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus#toString():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.toString()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.KnownNetwork#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.KnownNetwork.equals(Object)
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.KnownNetwork#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.KnownNetwork.hashCode()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.KnownNetwork#toString():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.KnownNetwork.toString()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.equals(Object)
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.hashCode()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus#toString():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.toString()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.NetworkProviderInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.equals(Object)
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.NetworkProviderInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.hashCode()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.NetworkProviderInfo#isBatteryCharging():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.isBatteryCharging()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.NetworkProviderInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.toString()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder#setBatteryCharging(boolean):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder.setBatteryCharging(boolean)
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState.equals(Object)
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState#hashCode():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState.hashCode()
+UnflaggedApi: android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState#toString():
+ New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState.toString()
+UnflaggedApi: android.os.BatterySaverPolicyConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.os.BatterySaverPolicyConfig.toString()
+UnflaggedApi: android.os.BugreportParams#BUGREPORT_MODE_ONBOARDING:
+ New API must be flagged with @FlaggedApi: field android.os.BugreportParams.BUGREPORT_MODE_ONBOARDING
+UnflaggedApi: android.os.Build.VERSION#KNOWN_CODENAMES:
+ New API must be flagged with @FlaggedApi: field android.os.Build.VERSION.KNOWN_CODENAMES
+UnflaggedApi: android.os.Build.VERSION#PREVIEW_SDK_FINGERPRINT:
+ New API must be flagged with @FlaggedApi: field android.os.Build.VERSION.PREVIEW_SDK_FINGERPRINT
+UnflaggedApi: android.os.IncidentManager.PendingReport#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.os.IncidentManager.PendingReport.equals(Object)
+UnflaggedApi: android.os.IncidentManager.PendingReport#toString():
+ New API must be flagged with @FlaggedApi: method android.os.IncidentManager.PendingReport.toString()
+UnflaggedApi: android.os.IncidentReportArgs#toString():
+ New API must be flagged with @FlaggedApi: method android.os.IncidentReportArgs.toString()
+UnflaggedApi: android.os.NewUserRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.os.NewUserRequest.toString()
+UnflaggedApi: android.os.NewUserResponse#toString():
+ New API must be flagged with @FlaggedApi: method android.os.NewUserResponse.toString()
+UnflaggedApi: android.os.PowerManager.LowPowerStandbyPolicy#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.os.PowerManager.LowPowerStandbyPolicy.equals(Object)
+UnflaggedApi: android.os.PowerManager.LowPowerStandbyPolicy#hashCode():
+ New API must be flagged with @FlaggedApi: method android.os.PowerManager.LowPowerStandbyPolicy.hashCode()
+UnflaggedApi: android.os.PowerManager.LowPowerStandbyPolicy#toString():
+ New API must be flagged with @FlaggedApi: method android.os.PowerManager.LowPowerStandbyPolicy.toString()
+UnflaggedApi: android.os.PowerManager.LowPowerStandbyPortDescription#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.os.PowerManager.LowPowerStandbyPortDescription.equals(Object)
+UnflaggedApi: android.os.PowerManager.LowPowerStandbyPortDescription#hashCode():
+ New API must be flagged with @FlaggedApi: method android.os.PowerManager.LowPowerStandbyPortDescription.hashCode()
+UnflaggedApi: android.os.PowerManager.LowPowerStandbyPortDescription#toString():
+ New API must be flagged with @FlaggedApi: method android.os.PowerManager.LowPowerStandbyPortDescription.toString()
+UnflaggedApi: android.os.ServiceSpecificException#toString():
+ New API must be flagged with @FlaggedApi: method android.os.ServiceSpecificException.toString()
+UnflaggedApi: android.os.WorkSource.WorkChain#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.os.WorkSource.WorkChain.equals(Object)
+UnflaggedApi: android.os.WorkSource.WorkChain#hashCode():
+ New API must be flagged with @FlaggedApi: method android.os.WorkSource.WorkChain.hashCode()
+UnflaggedApi: android.os.WorkSource.WorkChain#toString():
+ New API must be flagged with @FlaggedApi: method android.os.WorkSource.WorkChain.toString()
+UnflaggedApi: android.os.connectivity.CellularBatteryStats#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.os.connectivity.CellularBatteryStats.equals(Object)
+UnflaggedApi: android.os.connectivity.CellularBatteryStats#hashCode():
+ New API must be flagged with @FlaggedApi: method android.os.connectivity.CellularBatteryStats.hashCode()
+UnflaggedApi: android.os.connectivity.WifiActivityEnergyInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.os.connectivity.WifiActivityEnergyInfo.toString()
+UnflaggedApi: android.os.connectivity.WifiBatteryStats#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.os.connectivity.WifiBatteryStats.equals(Object)
+UnflaggedApi: android.os.connectivity.WifiBatteryStats#hashCode():
+ New API must be flagged with @FlaggedApi: method android.os.connectivity.WifiBatteryStats.hashCode()
+UnflaggedApi: android.permission.AdminPermissionControlParams#toString():
+ New API must be flagged with @FlaggedApi: method android.permission.AdminPermissionControlParams.toString()
+UnflaggedApi: android.permission.PermissionGroupUsage#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.permission.PermissionGroupUsage.equals(Object)
+UnflaggedApi: android.permission.PermissionGroupUsage#hashCode():
+ New API must be flagged with @FlaggedApi: method android.permission.PermissionGroupUsage.hashCode()
+UnflaggedApi: android.permission.PermissionGroupUsage#toString():
+ New API must be flagged with @FlaggedApi: method android.permission.PermissionGroupUsage.toString()
+UnflaggedApi: android.permission.PermissionManager.SplitPermissionInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.permission.PermissionManager.SplitPermissionInfo.equals(Object)
+UnflaggedApi: android.permission.PermissionManager.SplitPermissionInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.permission.PermissionManager.SplitPermissionInfo.hashCode()
+UnflaggedApi: android.printservice.PrintServiceInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.printservice.PrintServiceInfo.equals(Object)
+UnflaggedApi: android.printservice.PrintServiceInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.printservice.PrintServiceInfo.hashCode()
+UnflaggedApi: android.printservice.PrintServiceInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.printservice.PrintServiceInfo.toString()
+UnflaggedApi: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context):
+ New API must be flagged with @FlaggedApi: method android.printservice.recommendation.RecommendationService.attachBaseContext(android.content.Context)
+UnflaggedApi: android.provider.CallLog.CallComposerLoggingException#toString():
+ New API must be flagged with @FlaggedApi: method android.provider.CallLog.CallComposerLoggingException.toString()
+UnflaggedApi: android.provider.ContactsContract.MetadataSync#CONTENT_ITEM_TYPE:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSync.CONTENT_ITEM_TYPE
+UnflaggedApi: android.provider.ContactsContract.MetadataSync#CONTENT_TYPE:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSync.CONTENT_TYPE
+UnflaggedApi: android.provider.ContactsContract.MetadataSync#CONTENT_URI:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSync.CONTENT_URI
+UnflaggedApi: android.provider.ContactsContract.MetadataSync#METADATA_AUTHORITY:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSync.METADATA_AUTHORITY
+UnflaggedApi: android.provider.ContactsContract.MetadataSync#METADATA_AUTHORITY_URI:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSync.METADATA_AUTHORITY_URI
+UnflaggedApi: android.provider.ContactsContract.MetadataSync#_COUNT:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSync._COUNT
+UnflaggedApi: android.provider.ContactsContract.MetadataSync#_ID:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSync._ID
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncColumns#ACCOUNT_NAME:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncColumns.ACCOUNT_NAME
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncColumns#ACCOUNT_TYPE:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncColumns.ACCOUNT_TYPE
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncColumns#DATA:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncColumns.DATA
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncColumns#DATA_SET:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncColumns.DATA_SET
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncColumns#DELETED:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncColumns.DELETED
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncColumns#RAW_CONTACT_BACKUP_ID:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncColumns.RAW_CONTACT_BACKUP_ID
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncState#CONTENT_ITEM_TYPE:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncState.CONTENT_ITEM_TYPE
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncState#CONTENT_TYPE:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncState.CONTENT_TYPE
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncState#CONTENT_URI:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncState.CONTENT_URI
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncState#_COUNT:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncState._COUNT
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncState#_ID:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncState._ID
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncStateColumns#ACCOUNT_NAME:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncStateColumns.ACCOUNT_NAME
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncStateColumns#ACCOUNT_TYPE:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncStateColumns.ACCOUNT_TYPE
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncStateColumns#DATA_SET:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncStateColumns.DATA_SET
+UnflaggedApi: android.provider.ContactsContract.MetadataSyncStateColumns#STATE:
+ New API must be flagged with @FlaggedApi: field android.provider.ContactsContract.MetadataSyncStateColumns.STATE
+UnflaggedApi: android.provider.ContactsContract.Settings#setDefaultAccount(android.content.ContentResolver, android.accounts.Account):
+ New API must be flagged with @FlaggedApi: method android.provider.ContactsContract.Settings.setDefaultAccount(android.content.ContentResolver,android.accounts.Account)
+UnflaggedApi: android.provider.ContactsContract.SimContacts#addSimAccount(android.content.ContentResolver, String, String, int, int):
+ New API must be flagged with @FlaggedApi: method android.provider.ContactsContract.SimContacts.addSimAccount(android.content.ContentResolver,String,String,int,int)
+UnflaggedApi: android.provider.ContactsContract.SimContacts#removeSimAccounts(android.content.ContentResolver, int):
+ New API must be flagged with @FlaggedApi: method android.provider.ContactsContract.SimContacts.removeSimAccounts(android.content.ContentResolver,int)
+UnflaggedApi: android.provider.SearchIndexableData#toString():
+ New API must be flagged with @FlaggedApi: method android.provider.SearchIndexableData.toString()
+UnflaggedApi: android.provider.SearchIndexableResource#toString():
+ New API must be flagged with @FlaggedApi: method android.provider.SearchIndexableResource.toString()
+UnflaggedApi: android.provider.SearchIndexablesProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo):
+ New API must be flagged with @FlaggedApi: method android.provider.SearchIndexablesProvider.attachInfo(android.content.Context,android.content.pm.ProviderInfo)
+UnflaggedApi: android.provider.Settings#ACTION_APP_PERMISSIONS_SETTINGS:
+ New API must be flagged with @FlaggedApi: field android.provider.Settings.ACTION_APP_PERMISSIONS_SETTINGS
+UnflaggedApi: android.provider.Settings.System#putString(android.content.ContentResolver, String, String, boolean, boolean):
+ New API must be flagged with @FlaggedApi: method android.provider.Settings.System.putString(android.content.ContentResolver,String,String,boolean,boolean)
+UnflaggedApi: android.provider.Settings.System#resetToDefaults(android.content.ContentResolver, String):
+ New API must be flagged with @FlaggedApi: method android.provider.Settings.System.resetToDefaults(android.content.ContentResolver,String)
+UnflaggedApi: android.provider.SimPhonebookContract.SimRecords#QUERY_ARG_PIN2:
+ New API must be flagged with @FlaggedApi: field android.provider.SimPhonebookContract.SimRecords.QUERY_ARG_PIN2
+UnflaggedApi: android.provider.Telephony.Carriers#APN_SET_ID:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.APN_SET_ID
+UnflaggedApi: android.provider.Telephony.Carriers#CARRIER_EDITED:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.CARRIER_EDITED
+UnflaggedApi: android.provider.Telephony.Carriers#EDITED_STATUS:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.EDITED_STATUS
+UnflaggedApi: android.provider.Telephony.Carriers#MATCH_ALL_APN_SET_ID:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.MATCH_ALL_APN_SET_ID
+UnflaggedApi: android.provider.Telephony.Carriers#MAX_CONNECTIONS:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.MAX_CONNECTIONS
+UnflaggedApi: android.provider.Telephony.Carriers#MODEM_PERSIST:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.MODEM_PERSIST
+UnflaggedApi: android.provider.Telephony.Carriers#MTU_V4:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.MTU_V4
+UnflaggedApi: android.provider.Telephony.Carriers#MTU_V6:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.MTU_V6
+UnflaggedApi: android.provider.Telephony.Carriers#NO_APN_SET_ID:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.NO_APN_SET_ID
+UnflaggedApi: android.provider.Telephony.Carriers#TIME_LIMIT_FOR_MAX_CONNECTIONS:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS
+UnflaggedApi: android.provider.Telephony.Carriers#UNEDITED:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.UNEDITED
+UnflaggedApi: android.provider.Telephony.Carriers#USER_DELETED:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.USER_DELETED
+UnflaggedApi: android.provider.Telephony.Carriers#USER_EDITABLE:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.USER_EDITABLE
+UnflaggedApi: android.provider.Telephony.Carriers#USER_EDITED:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.USER_EDITED
+UnflaggedApi: android.provider.Telephony.Carriers#USER_VISIBLE:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.USER_VISIBLE
+UnflaggedApi: android.provider.Telephony.Carriers#WAIT_TIME_RETRY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Carriers.WAIT_TIME_RETRY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts:
+ New API must be flagged with @FlaggedApi: class android.provider.Telephony.CellBroadcasts
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#AUTHORITY_LEGACY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.AUTHORITY_LEGACY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#AUTHORITY_LEGACY_URI:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.AUTHORITY_LEGACY_URI
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#CALL_METHOD_GET_PREFERENCE:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.CALL_METHOD_GET_PREFERENCE
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#CID:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.CID
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#CMAS_CATEGORY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.CMAS_CATEGORY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#CMAS_CERTAINTY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.CMAS_CERTAINTY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#CMAS_MESSAGE_CLASS:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.CMAS_MESSAGE_CLASS
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#CMAS_RESPONSE_TYPE:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.CMAS_RESPONSE_TYPE
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#CMAS_SEVERITY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.CMAS_SEVERITY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#CMAS_URGENCY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.CMAS_URGENCY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#CONTENT_URI:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.CONTENT_URI
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#DATA_CODING_SCHEME:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.DATA_CODING_SCHEME
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#DEFAULT_SORT_ORDER:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.DEFAULT_SORT_ORDER
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#DELIVERY_TIME:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.DELIVERY_TIME
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#ETWS_IS_PRIMARY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.ETWS_IS_PRIMARY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#ETWS_WARNING_TYPE:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.ETWS_WARNING_TYPE
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#GEOGRAPHICAL_SCOPE:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.GEOGRAPHICAL_SCOPE
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#GEOMETRIES:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.GEOMETRIES
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#LAC:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.LAC
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#LANGUAGE_CODE:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.LANGUAGE_CODE
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#LOCATION_CHECK_TIME:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.LOCATION_CHECK_TIME
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#MAXIMUM_WAIT_TIME:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.MAXIMUM_WAIT_TIME
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#MESSAGE_BODY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.MESSAGE_BODY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#MESSAGE_BROADCASTED:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.MESSAGE_BROADCASTED
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#MESSAGE_DISPLAYED:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.MESSAGE_DISPLAYED
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#MESSAGE_FORMAT:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.MESSAGE_FORMAT
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#MESSAGE_HISTORY_URI:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.MESSAGE_HISTORY_URI
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#MESSAGE_PRIORITY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.MESSAGE_PRIORITY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#MESSAGE_READ:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.MESSAGE_READ
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#PLMN:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.PLMN
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#RECEIVED_TIME:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.RECEIVED_TIME
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#SERIAL_NUMBER:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.SERIAL_NUMBER
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#SERVICE_CATEGORY:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.SERVICE_CATEGORY
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#SLOT_INDEX:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.SLOT_INDEX
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#SUBSCRIPTION_ID:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.SUBSCRIPTION_ID
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#_COUNT:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts._COUNT
+UnflaggedApi: android.provider.Telephony.CellBroadcasts#_ID:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts._ID
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference:
+ New API must be flagged with @FlaggedApi: class android.provider.Telephony.CellBroadcasts.Preference
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_ALERT_VIBRATION_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_ALERT_VIBRATION_PREF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_AREA_UPDATE_INFO_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_AREA_UPDATE_INFO_PREF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_CMAS_AMBER_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_CMAS_AMBER_PREF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_CMAS_EXTREME_THREAT_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_CMAS_EXTREME_THREAT_PREF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_CMAS_IN_SECOND_LANGUAGE_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_CMAS_IN_SECOND_LANGUAGE_PREF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_CMAS_PRESIDENTIAL_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_CMAS_PRESIDENTIAL_PREF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_CMAS_SEVERE_THREAT_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_CMAS_SEVERE_THREAT_PREF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_EMERGENCY_PERF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_EMERGENCY_PERF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_PUBLIC_SAFETY_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_PUBLIC_SAFETY_PREF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_STATE_LOCAL_TEST_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_STATE_LOCAL_TEST_PREF
+UnflaggedApi: android.provider.Telephony.CellBroadcasts.Preference#ENABLE_TEST_ALERT_PREF:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.CellBroadcasts.Preference.ENABLE_TEST_ALERT_PREF
+UnflaggedApi: android.provider.Telephony.Sms.Intents#ACTION_SMS_EMERGENCY_CB_RECEIVED:
+ New API must be flagged with @FlaggedApi: field android.provider.Telephony.Sms.Intents.ACTION_SMS_EMERGENCY_CB_RECEIVED
+UnflaggedApi: android.service.ambientcontext.AmbientContextDetectionResult#toString():
+ New API must be flagged with @FlaggedApi: method android.service.ambientcontext.AmbientContextDetectionResult.toString()
+UnflaggedApi: android.service.ambientcontext.AmbientContextDetectionServiceStatus#toString():
+ New API must be flagged with @FlaggedApi: method android.service.ambientcontext.AmbientContextDetectionServiceStatus.toString()
+UnflaggedApi: android.service.appprediction.AppPredictionService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.appprediction.AppPredictionService.onCreate()
+UnflaggedApi: android.service.assist.classification.FieldClassificationRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.service.assist.classification.FieldClassificationRequest.toString()
+UnflaggedApi: android.service.assist.classification.FieldClassificationResponse#toString():
+ New API must be flagged with @FlaggedApi: method android.service.assist.classification.FieldClassificationResponse.toString()
+UnflaggedApi: android.service.assist.classification.FieldClassificationService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.assist.classification.FieldClassificationService.onCreate()
+UnflaggedApi: android.service.autofill.AutofillFieldClassificationService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.autofill.AutofillFieldClassificationService.onCreate()
+UnflaggedApi: android.service.autofill.Dataset.Builder#setContent(android.view.autofill.AutofillId, android.content.ClipData):
+ New API must be flagged with @FlaggedApi: method android.service.autofill.Dataset.Builder.setContent(android.view.autofill.AutofillId,android.content.ClipData)
+UnflaggedApi: android.service.autofill.augmented.AugmentedAutofillService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.autofill.augmented.AugmentedAutofillService.onCreate()
+UnflaggedApi: android.service.autofill.augmented.AugmentedAutofillService#onUnbind(android.content.Intent):
+ New API must be flagged with @FlaggedApi: method android.service.autofill.augmented.AugmentedAutofillService.onUnbind(android.content.Intent)
+UnflaggedApi: android.service.autofill.augmented.FillRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.service.autofill.augmented.FillRequest.toString()
+UnflaggedApi: android.service.autofill.augmented.FillWindow#finalize():
+ New API must be flagged with @FlaggedApi: method android.service.autofill.augmented.FillWindow.finalize()
+UnflaggedApi: android.service.autofill.augmented.PresentationParams.Area#toString():
+ New API must be flagged with @FlaggedApi: method android.service.autofill.augmented.PresentationParams.Area.toString()
+UnflaggedApi: android.service.cloudsearch.CloudSearchService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.cloudsearch.CloudSearchService.onCreate()
+UnflaggedApi: android.service.contentcapture.ActivityEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.service.contentcapture.ActivityEvent.toString()
+UnflaggedApi: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+ New API must be flagged with @FlaggedApi: method android.service.contentcapture.ContentCaptureService.dump(java.io.FileDescriptor,java.io.PrintWriter,String[])
+UnflaggedApi: android.service.contentcapture.ContentCaptureService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.contentcapture.ContentCaptureService.onCreate()
+UnflaggedApi: android.service.contentsuggestions.ContentSuggestionsService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.contentsuggestions.ContentSuggestionsService.onCreate()
+UnflaggedApi: android.service.displayhash.DisplayHashParams#toString():
+ New API must be flagged with @FlaggedApi: method android.service.displayhash.DisplayHashParams.toString()
+UnflaggedApi: android.service.displayhash.DisplayHashingService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.displayhash.DisplayHashingService.onCreate()
+UnflaggedApi: android.service.euicc.EuiccProfileInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.euicc.EuiccProfileInfo.equals(Object)
+UnflaggedApi: android.service.euicc.EuiccProfileInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.euicc.EuiccProfileInfo.hashCode()
+UnflaggedApi: android.service.euicc.EuiccProfileInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.service.euicc.EuiccProfileInfo.toString()
+UnflaggedApi: android.service.euicc.EuiccService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.euicc.EuiccService.onCreate()
+UnflaggedApi: android.service.euicc.EuiccService#onDestroy():
+ New API must be flagged with @FlaggedApi: method android.service.euicc.EuiccService.onDestroy()
+UnflaggedApi: android.service.games.CreateGameSessionRequest#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.games.CreateGameSessionRequest.equals(Object)
+UnflaggedApi: android.service.games.CreateGameSessionRequest#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.games.CreateGameSessionRequest.hashCode()
+UnflaggedApi: android.service.games.CreateGameSessionRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.service.games.CreateGameSessionRequest.toString()
+UnflaggedApi: android.service.games.GameSessionService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.games.GameSessionService.onCreate()
+UnflaggedApi: android.service.games.GameStartedEvent#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.games.GameStartedEvent.equals(Object)
+UnflaggedApi: android.service.games.GameStartedEvent#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.games.GameStartedEvent.hashCode()
+UnflaggedApi: android.service.games.GameStartedEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.service.games.GameStartedEvent.toString()
+UnflaggedApi: android.service.notification.Adjustment#toString():
+ New API must be flagged with @FlaggedApi: method android.service.notification.Adjustment.toString()
+UnflaggedApi: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
+ New API must be flagged with @FlaggedApi: method android.service.notification.NotificationAssistantService.attachBaseContext(android.content.Context)
+UnflaggedApi: android.service.notification.NotificationStats#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.notification.NotificationStats.equals(Object)
+UnflaggedApi: android.service.notification.NotificationStats#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.notification.NotificationStats.hashCode()
+UnflaggedApi: android.service.notification.NotificationStats#toString():
+ New API must be flagged with @FlaggedApi: method android.service.notification.NotificationStats.toString()
+UnflaggedApi: android.service.notification.SnoozeCriterion#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.notification.SnoozeCriterion.equals(Object)
+UnflaggedApi: android.service.notification.SnoozeCriterion#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.notification.SnoozeCriterion.hashCode()
+UnflaggedApi: android.service.resolver.ResolverRankerService#onDestroy():
+ New API must be flagged with @FlaggedApi: method android.service.resolver.ResolverRankerService.onDestroy()
+UnflaggedApi: android.service.resolver.ResolverTarget#toString():
+ New API must be flagged with @FlaggedApi: method android.service.resolver.ResolverTarget.toString()
+UnflaggedApi: android.service.rotationresolver.RotationResolutionRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.service.rotationresolver.RotationResolutionRequest.toString()
+UnflaggedApi: android.service.search.SearchUiService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.search.SearchUiService.onCreate()
+UnflaggedApi: android.service.smartspace.SmartspaceService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.smartspace.SmartspaceService.onCreate()
+UnflaggedApi: android.service.textclassifier.TextClassifierService#onUnbind(android.content.Intent):
+ New API must be flagged with @FlaggedApi: method android.service.textclassifier.TextClassifierService.onUnbind(android.content.Intent)
+UnflaggedApi: android.service.timezone.TimeZoneProviderStatus#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.timezone.TimeZoneProviderStatus.equals(Object)
+UnflaggedApi: android.service.timezone.TimeZoneProviderStatus#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.timezone.TimeZoneProviderStatus.hashCode()
+UnflaggedApi: android.service.timezone.TimeZoneProviderStatus#toString():
+ New API must be flagged with @FlaggedApi: method android.service.timezone.TimeZoneProviderStatus.toString()
+UnflaggedApi: android.service.timezone.TimeZoneProviderSuggestion#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.timezone.TimeZoneProviderSuggestion.equals(Object)
+UnflaggedApi: android.service.timezone.TimeZoneProviderSuggestion#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.timezone.TimeZoneProviderSuggestion.hashCode()
+UnflaggedApi: android.service.timezone.TimeZoneProviderSuggestion#toString():
+ New API must be flagged with @FlaggedApi: method android.service.timezone.TimeZoneProviderSuggestion.toString()
+UnflaggedApi: android.service.translation.TranslationService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.translation.TranslationService.onCreate()
+UnflaggedApi: android.service.trust.TrustAgentService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.trust.TrustAgentService.onCreate()
+UnflaggedApi: android.service.voice.AlwaysOnHotwordDetector#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.voice.AlwaysOnHotwordDetector.equals(Object)
+UnflaggedApi: android.service.voice.AlwaysOnHotwordDetector#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.voice.AlwaysOnHotwordDetector.hashCode()
+UnflaggedApi: android.service.voice.AlwaysOnHotwordDetector.ModelParamRange#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.voice.AlwaysOnHotwordDetector.ModelParamRange.equals(Object)
+UnflaggedApi: android.service.voice.AlwaysOnHotwordDetector.ModelParamRange#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.voice.AlwaysOnHotwordDetector.ModelParamRange.hashCode()
+UnflaggedApi: android.service.voice.AlwaysOnHotwordDetector.ModelParamRange#toString():
+ New API must be flagged with @FlaggedApi: method android.service.voice.AlwaysOnHotwordDetector.ModelParamRange.toString()
+UnflaggedApi: android.service.voice.HotwordAudioStream#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordAudioStream.equals(Object)
+UnflaggedApi: android.service.voice.HotwordAudioStream#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordAudioStream.hashCode()
+UnflaggedApi: android.service.voice.HotwordAudioStream#toString():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordAudioStream.toString()
+UnflaggedApi: android.service.voice.HotwordDetectedResult#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordDetectedResult.equals(Object)
+UnflaggedApi: android.service.voice.HotwordDetectedResult#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordDetectedResult.hashCode()
+UnflaggedApi: android.service.voice.HotwordDetectedResult#toString():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordDetectedResult.toString()
+UnflaggedApi: android.service.voice.HotwordDetectionService#getSystemService(String):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordDetectionService.getSystemService(String)
+UnflaggedApi: android.service.voice.HotwordDetectionServiceFailure#toString():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordDetectionServiceFailure.toString()
+UnflaggedApi: android.service.voice.HotwordRejectedResult#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordRejectedResult.equals(Object)
+UnflaggedApi: android.service.voice.HotwordRejectedResult#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordRejectedResult.hashCode()
+UnflaggedApi: android.service.voice.HotwordRejectedResult#toString():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordRejectedResult.toString()
+UnflaggedApi: android.service.voice.HotwordTrainingAudio:
+ New API must be flagged with @FlaggedApi: class android.service.voice.HotwordTrainingAudio
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingAudio.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingAudio.CREATOR
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#HOTWORD_OFFSET_UNSET:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingAudio.HOTWORD_OFFSET_UNSET
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingAudio.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#describeContents():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.describeContents()
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.equals(Object)
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#getAudioFormat():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.getAudioFormat()
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#getAudioType():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.getAudioType()
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#getHotwordAudio():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.getHotwordAudio()
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#getHotwordOffsetMillis():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.getHotwordOffsetMillis()
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.hashCode()
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#toString():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.toString()
+UnflaggedApi: android.service.voice.HotwordTrainingAudio#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.service.voice.HotwordTrainingAudio.Builder:
+ New API must be flagged with @FlaggedApi: class android.service.voice.HotwordTrainingAudio.Builder
+UnflaggedApi: android.service.voice.HotwordTrainingAudio.Builder#Builder(byte[], android.media.AudioFormat):
+ New API must be flagged with @FlaggedApi: constructor android.service.voice.HotwordTrainingAudio.Builder(byte[],android.media.AudioFormat)
+UnflaggedApi: android.service.voice.HotwordTrainingAudio.Builder#build():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.Builder.build()
+UnflaggedApi: android.service.voice.HotwordTrainingAudio.Builder#setAudioFormat(android.media.AudioFormat):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.Builder.setAudioFormat(android.media.AudioFormat)
+UnflaggedApi: android.service.voice.HotwordTrainingAudio.Builder#setAudioType(int):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.Builder.setAudioType(int)
+UnflaggedApi: android.service.voice.HotwordTrainingAudio.Builder#setHotwordAudio(byte...):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.Builder.setHotwordAudio(byte...)
+UnflaggedApi: android.service.voice.HotwordTrainingAudio.Builder#setHotwordOffsetMillis(int):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingAudio.Builder.setHotwordOffsetMillis(int)
+UnflaggedApi: android.service.voice.HotwordTrainingData:
+ New API must be flagged with @FlaggedApi: class android.service.voice.HotwordTrainingData
+UnflaggedApi: android.service.voice.HotwordTrainingData#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingData.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.service.voice.HotwordTrainingData#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingData.CREATOR
+UnflaggedApi: android.service.voice.HotwordTrainingData#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingData.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.service.voice.HotwordTrainingData#TIMEOUT_STAGE_EARLY:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingData.TIMEOUT_STAGE_EARLY
+UnflaggedApi: android.service.voice.HotwordTrainingData#TIMEOUT_STAGE_LATE:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingData.TIMEOUT_STAGE_LATE
+UnflaggedApi: android.service.voice.HotwordTrainingData#TIMEOUT_STAGE_MIDDLE:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingData.TIMEOUT_STAGE_MIDDLE
+UnflaggedApi: android.service.voice.HotwordTrainingData#TIMEOUT_STAGE_UNKNOWN:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingData.TIMEOUT_STAGE_UNKNOWN
+UnflaggedApi: android.service.voice.HotwordTrainingData#TIMEOUT_STAGE_VERY_EARLY:
+ New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingData.TIMEOUT_STAGE_VERY_EARLY
+UnflaggedApi: android.service.voice.HotwordTrainingData#describeContents():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.describeContents()
+UnflaggedApi: android.service.voice.HotwordTrainingData#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.equals(Object)
+UnflaggedApi: android.service.voice.HotwordTrainingData#getMaxTrainingDataSize():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.getMaxTrainingDataSize()
+UnflaggedApi: android.service.voice.HotwordTrainingData#getTimeoutStage():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.getTimeoutStage()
+UnflaggedApi: android.service.voice.HotwordTrainingData#getTrainingAudios():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.getTrainingAudios()
+UnflaggedApi: android.service.voice.HotwordTrainingData#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.hashCode()
+UnflaggedApi: android.service.voice.HotwordTrainingData#toString():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.toString()
+UnflaggedApi: android.service.voice.HotwordTrainingData#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.service.voice.HotwordTrainingData.Builder:
+ New API must be flagged with @FlaggedApi: class android.service.voice.HotwordTrainingData.Builder
+UnflaggedApi: android.service.voice.HotwordTrainingData.Builder#Builder():
+ New API must be flagged with @FlaggedApi: constructor android.service.voice.HotwordTrainingData.Builder()
+UnflaggedApi: android.service.voice.HotwordTrainingData.Builder#addTrainingAudio(android.service.voice.HotwordTrainingAudio):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.Builder.addTrainingAudio(android.service.voice.HotwordTrainingAudio)
+UnflaggedApi: android.service.voice.HotwordTrainingData.Builder#build():
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.Builder.build()
+UnflaggedApi: android.service.voice.HotwordTrainingData.Builder#setTimeoutStage(int):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.Builder.setTimeoutStage(int)
+UnflaggedApi: android.service.voice.HotwordTrainingData.Builder#setTrainingAudios(java.util.List<android.service.voice.HotwordTrainingAudio>):
+ New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.Builder.setTrainingAudios(java.util.List<android.service.voice.HotwordTrainingAudio>)
+UnflaggedApi: android.service.voice.SoundTriggerFailure#toString():
+ New API must be flagged with @FlaggedApi: method android.service.voice.SoundTriggerFailure.toString()
+UnflaggedApi: android.service.voice.VisualQueryDetectionService#getSystemService(String):
+ New API must be flagged with @FlaggedApi: method android.service.voice.VisualQueryDetectionService.getSystemService(String)
+UnflaggedApi: android.service.voice.VisualQueryDetectionService#openFileInput(String):
+ New API must be flagged with @FlaggedApi: method android.service.voice.VisualQueryDetectionService.openFileInput(String)
+UnflaggedApi: android.service.voice.VisualQueryDetectionServiceFailure#toString():
+ New API must be flagged with @FlaggedApi: method android.service.voice.VisualQueryDetectionServiceFailure.toString()
+UnflaggedApi: android.service.wallpaper.WallpaperService.Engine#isInAmbientMode():
+ New API must be flagged with @FlaggedApi: method android.service.wallpaper.WallpaperService.Engine.isInAmbientMode()
+UnflaggedApi: android.service.wallpaper.WallpaperService.Engine#onAmbientModeChanged(boolean, long):
+ New API must be flagged with @FlaggedApi: method android.service.wallpaper.WallpaperService.Engine.onAmbientModeChanged(boolean,long)
+UnflaggedApi: android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService#onCreate():
+ New API must be flagged with @FlaggedApi: method android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService.onCreate()
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.PackageConfig.equals(Object)
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#hashCode():
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.PackageConfig.hashCode()
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.PackageConfig.toString()
+UnflaggedApi: android.telecom.AudioState#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telecom.AudioState.equals(Object)
+UnflaggedApi: android.telecom.AudioState#toString():
+ New API must be flagged with @FlaggedApi: method android.telecom.AudioState.toString()
+UnflaggedApi: android.telecom.BluetoothCallQualityReport#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telecom.BluetoothCallQualityReport.equals(Object)
+UnflaggedApi: android.telecom.BluetoothCallQualityReport#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telecom.BluetoothCallQualityReport.hashCode()
+UnflaggedApi: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallViaAudioProcessing(boolean):
+ New API must be flagged with @FlaggedApi: method android.telecom.CallScreeningService.CallResponse.Builder.setShouldScreenCallViaAudioProcessing(boolean)
+UnflaggedApi: android.telecom.Connection.CallFilteringCompletionInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telecom.Connection.CallFilteringCompletionInfo.toString()
+UnflaggedApi: android.telecom.StreamingCall#EXTRA_CALL_ID:
+ New API must be flagged with @FlaggedApi: field android.telecom.StreamingCall.EXTRA_CALL_ID
+UnflaggedApi: android.telephony.CallAttributes#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.CallAttributes.equals(Object)
+UnflaggedApi: android.telephony.CallAttributes#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.CallAttributes.hashCode()
+UnflaggedApi: android.telephony.CallAttributes#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.CallAttributes.toString()
+UnflaggedApi: android.telephony.CallQuality#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.CallQuality.equals(Object)
+UnflaggedApi: android.telephony.CallQuality#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.CallQuality.hashCode()
+UnflaggedApi: android.telephony.CallQuality#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.CallQuality.toString()
+UnflaggedApi: android.telephony.CallState#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.CallState.equals(Object)
+UnflaggedApi: android.telephony.CallState#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.CallState.hashCode()
+UnflaggedApi: android.telephony.CallState#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.CallState.toString()
+UnflaggedApi: android.telephony.CarrierRestrictionRules#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.CarrierRestrictionRules.toString()
+UnflaggedApi: android.telephony.CbGeoUtils.Circle#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.CbGeoUtils.Circle.toString()
+UnflaggedApi: android.telephony.CbGeoUtils.LatLng#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.CbGeoUtils.LatLng.toString()
+UnflaggedApi: android.telephony.CbGeoUtils.Polygon#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.CbGeoUtils.Polygon.toString()
+UnflaggedApi: android.telephony.CellBroadcastIdRange#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.CellBroadcastIdRange.equals(Object)
+UnflaggedApi: android.telephony.CellBroadcastIdRange#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.CellBroadcastIdRange.hashCode()
+UnflaggedApi: android.telephony.CellBroadcastIdRange#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.CellBroadcastIdRange.toString()
+UnflaggedApi: android.telephony.DataSpecificRegistrationInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.DataSpecificRegistrationInfo.equals(Object)
+UnflaggedApi: android.telephony.DataSpecificRegistrationInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.DataSpecificRegistrationInfo.hashCode()
+UnflaggedApi: android.telephony.DataSpecificRegistrationInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.DataSpecificRegistrationInfo.toString()
+UnflaggedApi: android.telephony.DataThrottlingRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.DataThrottlingRequest.toString()
+UnflaggedApi: android.telephony.ImsiEncryptionInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ImsiEncryptionInfo.toString()
+UnflaggedApi: android.telephony.LinkCapacityEstimate#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.LinkCapacityEstimate.equals(Object)
+UnflaggedApi: android.telephony.LinkCapacityEstimate#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.LinkCapacityEstimate.hashCode()
+UnflaggedApi: android.telephony.LinkCapacityEstimate#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.LinkCapacityEstimate.toString()
+UnflaggedApi: android.telephony.LteVopsSupportInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.LteVopsSupportInfo.toString()
+UnflaggedApi: android.telephony.ModemActivityInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ModemActivityInfo.equals(Object)
+UnflaggedApi: android.telephony.ModemActivityInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ModemActivityInfo.hashCode()
+UnflaggedApi: android.telephony.ModemActivityInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ModemActivityInfo.toString()
+UnflaggedApi: android.telephony.NetworkRegistrationInfo.Builder#setIsNonTerrestrialNetwork(boolean):
+ New API must be flagged with @FlaggedApi: method android.telephony.NetworkRegistrationInfo.Builder.setIsNonTerrestrialNetwork(boolean)
+UnflaggedApi: android.telephony.NetworkService#onUnbind(android.content.Intent):
+ New API must be flagged with @FlaggedApi: method android.telephony.NetworkService.onUnbind(android.content.Intent)
+UnflaggedApi: android.telephony.NrVopsSupportInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.NrVopsSupportInfo.toString()
+UnflaggedApi: android.telephony.PhoneCapability#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.PhoneCapability.equals(Object)
+UnflaggedApi: android.telephony.PhoneCapability#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.PhoneCapability.hashCode()
+UnflaggedApi: android.telephony.PhoneCapability#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.PhoneCapability.toString()
+UnflaggedApi: android.telephony.PhoneNumberRange#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.PhoneNumberRange.equals(Object)
+UnflaggedApi: android.telephony.PhoneNumberRange#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.PhoneNumberRange.hashCode()
+UnflaggedApi: android.telephony.PhoneNumberRange#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.PhoneNumberRange.toString()
+UnflaggedApi: android.telephony.PinResult#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.PinResult.equals(Object)
+UnflaggedApi: android.telephony.PinResult#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.PinResult.hashCode()
+UnflaggedApi: android.telephony.PinResult#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.PinResult.toString()
+UnflaggedApi: android.telephony.PreciseCallState#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.PreciseCallState.equals(Object)
+UnflaggedApi: android.telephony.PreciseCallState#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.PreciseCallState.hashCode()
+UnflaggedApi: android.telephony.PreciseCallState#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.PreciseCallState.toString()
+UnflaggedApi: android.telephony.SmsCbCmasInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.SmsCbCmasInfo.toString()
+UnflaggedApi: android.telephony.SmsCbEtwsInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.SmsCbEtwsInfo.toString()
+UnflaggedApi: android.telephony.SmsCbLocation#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.SmsCbLocation.equals(Object)
+UnflaggedApi: android.telephony.SmsCbLocation#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.SmsCbLocation.hashCode()
+UnflaggedApi: android.telephony.SmsCbLocation#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.SmsCbLocation.toString()
+UnflaggedApi: android.telephony.SmsCbMessage#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.SmsCbMessage.toString()
+UnflaggedApi: android.telephony.TelephonyHistogram#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.TelephonyHistogram.toString()
+UnflaggedApi: android.telephony.TelephonyManager.ModemActivityInfoException#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.TelephonyManager.ModemActivityInfoException.toString()
+UnflaggedApi: android.telephony.ThermalMitigationRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ThermalMitigationRequest.toString()
+UnflaggedApi: android.telephony.UiccAccessRule#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.UiccAccessRule.equals(Object)
+UnflaggedApi: android.telephony.UiccAccessRule#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.UiccAccessRule.hashCode()
+UnflaggedApi: android.telephony.UiccAccessRule#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.UiccAccessRule.toString()
+UnflaggedApi: android.telephony.UiccSlotInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.UiccSlotInfo.equals(Object)
+UnflaggedApi: android.telephony.UiccSlotInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.UiccSlotInfo.hashCode()
+UnflaggedApi: android.telephony.UiccSlotInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.UiccSlotInfo.toString()
+UnflaggedApi: android.telephony.UiccSlotMapping#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.UiccSlotMapping.equals(Object)
+UnflaggedApi: android.telephony.UiccSlotMapping#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.UiccSlotMapping.hashCode()
+UnflaggedApi: android.telephony.UiccSlotMapping#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.UiccSlotMapping.toString()
+UnflaggedApi: android.telephony.VopsSupportInfo#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.telephony.VopsSupportInfo.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.telephony.cdma.CdmaSmsCbProgramData#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.cdma.CdmaSmsCbProgramData.toString()
+UnflaggedApi: android.telephony.data.DataCallResponse#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.data.DataCallResponse.equals(Object)
+UnflaggedApi: android.telephony.data.DataCallResponse#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.data.DataCallResponse.hashCode()
+UnflaggedApi: android.telephony.data.DataCallResponse#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.data.DataCallResponse.toString()
+UnflaggedApi: android.telephony.data.DataProfile#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.data.DataProfile.equals(Object)
+UnflaggedApi: android.telephony.data.DataProfile#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.data.DataProfile.hashCode()
+UnflaggedApi: android.telephony.data.DataProfile#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.data.DataProfile.toString()
+UnflaggedApi: android.telephony.data.DataService#onDestroy():
+ New API must be flagged with @FlaggedApi: method android.telephony.data.DataService.onDestroy()
+UnflaggedApi: android.telephony.data.DataService#onUnbind(android.content.Intent):
+ New API must be flagged with @FlaggedApi: method android.telephony.data.DataService.onUnbind(android.content.Intent)
+UnflaggedApi: android.telephony.data.EpsBearerQosSessionAttributes#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.data.EpsBearerQosSessionAttributes.equals(Object)
+UnflaggedApi: android.telephony.data.EpsBearerQosSessionAttributes#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.data.EpsBearerQosSessionAttributes.hashCode()
+UnflaggedApi: android.telephony.data.NrQosSessionAttributes#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.data.NrQosSessionAttributes.equals(Object)
+UnflaggedApi: android.telephony.data.NrQosSessionAttributes#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.data.NrQosSessionAttributes.hashCode()
+UnflaggedApi: android.telephony.data.ThrottleStatus#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.data.ThrottleStatus.equals(Object)
+UnflaggedApi: android.telephony.data.ThrottleStatus#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.data.ThrottleStatus.hashCode()
+UnflaggedApi: android.telephony.data.ThrottleStatus#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.data.ThrottleStatus.toString()
+UnflaggedApi: android.telephony.euicc.EuiccNotification#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.euicc.EuiccNotification.equals(Object)
+UnflaggedApi: android.telephony.euicc.EuiccNotification#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.euicc.EuiccNotification.hashCode()
+UnflaggedApi: android.telephony.euicc.EuiccNotification#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.euicc.EuiccNotification.toString()
+UnflaggedApi: android.telephony.euicc.EuiccRulesAuthTable#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.euicc.EuiccRulesAuthTable.equals(Object)
+UnflaggedApi: android.telephony.gba.UaSecurityProtocolIdentifier#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.gba.UaSecurityProtocolIdentifier.equals(Object)
+UnflaggedApi: android.telephony.gba.UaSecurityProtocolIdentifier#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.gba.UaSecurityProtocolIdentifier.hashCode()
+UnflaggedApi: android.telephony.gba.UaSecurityProtocolIdentifier#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.gba.UaSecurityProtocolIdentifier.toString()
+UnflaggedApi: android.telephony.ims.AudioCodecAttributes#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.AudioCodecAttributes.toString()
+UnflaggedApi: android.telephony.ims.DelegateRegistrationState#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.DelegateRegistrationState.equals(Object)
+UnflaggedApi: android.telephony.ims.DelegateRegistrationState#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.DelegateRegistrationState.hashCode()
+UnflaggedApi: android.telephony.ims.DelegateRegistrationState#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.DelegateRegistrationState.toString()
+UnflaggedApi: android.telephony.ims.DelegateRequest#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.DelegateRequest.equals(Object)
+UnflaggedApi: android.telephony.ims.DelegateRequest#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.DelegateRequest.hashCode()
+UnflaggedApi: android.telephony.ims.DelegateRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.DelegateRequest.toString()
+UnflaggedApi: android.telephony.ims.FeatureTagState#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.FeatureTagState.equals(Object)
+UnflaggedApi: android.telephony.ims.FeatureTagState#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.FeatureTagState.hashCode()
+UnflaggedApi: android.telephony.ims.FeatureTagState#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.FeatureTagState.toString()
+UnflaggedApi: android.telephony.ims.ImsCallForwardInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsCallForwardInfo.toString()
+UnflaggedApi: android.telephony.ims.ImsCallProfile#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsCallProfile.toString()
+UnflaggedApi: android.telephony.ims.ImsConferenceState#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsConferenceState.toString()
+UnflaggedApi: android.telephony.ims.ImsExternalCallState#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsExternalCallState.toString()
+UnflaggedApi: android.telephony.ims.ImsMmTelManager.RegistrationCallback#onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsMmTelManager.RegistrationCallback.onTechnologyChangeFailed(int,android.telephony.ims.ImsReasonInfo)
+UnflaggedApi: android.telephony.ims.ImsMmTelManager.RegistrationCallback#onUnregistered(android.telephony.ims.ImsReasonInfo):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsMmTelManager.RegistrationCallback.onUnregistered(android.telephony.ims.ImsReasonInfo)
+UnflaggedApi: android.telephony.ims.ImsSsData#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsSsData.toString()
+UnflaggedApi: android.telephony.ims.ImsSsInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsSsInfo.toString()
+UnflaggedApi: android.telephony.ims.ImsStreamMediaProfile#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsStreamMediaProfile.toString()
+UnflaggedApi: android.telephony.ims.ImsSuppServiceNotification#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.ImsSuppServiceNotification.toString()
+UnflaggedApi: android.telephony.ims.MediaQualityStatus#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.MediaQualityStatus.equals(Object)
+UnflaggedApi: android.telephony.ims.MediaQualityStatus#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.MediaQualityStatus.hashCode()
+UnflaggedApi: android.telephony.ims.MediaQualityStatus#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.MediaQualityStatus.toString()
+UnflaggedApi: android.telephony.ims.MediaThreshold#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.MediaThreshold.equals(Object)
+UnflaggedApi: android.telephony.ims.MediaThreshold#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.MediaThreshold.hashCode()
+UnflaggedApi: android.telephony.ims.MediaThreshold#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.MediaThreshold.toString()
+UnflaggedApi: android.telephony.ims.PublishAttributes#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.PublishAttributes.equals(Object)
+UnflaggedApi: android.telephony.ims.PublishAttributes#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.PublishAttributes.hashCode()
+UnflaggedApi: android.telephony.ims.PublishAttributes#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.PublishAttributes.toString()
+UnflaggedApi: android.telephony.ims.RcsClientConfiguration#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RcsClientConfiguration.equals(Object)
+UnflaggedApi: android.telephony.ims.RcsClientConfiguration#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RcsClientConfiguration.hashCode()
+UnflaggedApi: android.telephony.ims.RcsContactPresenceTuple#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RcsContactPresenceTuple.toString()
+UnflaggedApi: android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.toString()
+UnflaggedApi: android.telephony.ims.RcsContactUceCapability#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RcsContactUceCapability.toString()
+UnflaggedApi: android.telephony.ims.RtpHeaderExtension#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RtpHeaderExtension.equals(Object)
+UnflaggedApi: android.telephony.ims.RtpHeaderExtension#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RtpHeaderExtension.hashCode()
+UnflaggedApi: android.telephony.ims.RtpHeaderExtension#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RtpHeaderExtension.toString()
+UnflaggedApi: android.telephony.ims.RtpHeaderExtensionType#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RtpHeaderExtensionType.equals(Object)
+UnflaggedApi: android.telephony.ims.RtpHeaderExtensionType#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RtpHeaderExtensionType.hashCode()
+UnflaggedApi: android.telephony.ims.RtpHeaderExtensionType#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.RtpHeaderExtensionType.toString()
+UnflaggedApi: android.telephony.ims.SipDelegateConfiguration#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipDelegateConfiguration.equals(Object)
+UnflaggedApi: android.telephony.ims.SipDelegateConfiguration#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipDelegateConfiguration.hashCode()
+UnflaggedApi: android.telephony.ims.SipDelegateConfiguration#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipDelegateConfiguration.toString()
+UnflaggedApi: android.telephony.ims.SipDelegateConfiguration.IpSecConfiguration#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipDelegateConfiguration.IpSecConfiguration.equals(Object)
+UnflaggedApi: android.telephony.ims.SipDelegateConfiguration.IpSecConfiguration#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipDelegateConfiguration.IpSecConfiguration.hashCode()
+UnflaggedApi: android.telephony.ims.SipDelegateConfiguration.IpSecConfiguration#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipDelegateConfiguration.IpSecConfiguration.toString()
+UnflaggedApi: android.telephony.ims.SipDialogState#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipDialogState.equals(Object)
+UnflaggedApi: android.telephony.ims.SipDialogState#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipDialogState.hashCode()
+UnflaggedApi: android.telephony.ims.SipMessage#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipMessage.equals(Object)
+UnflaggedApi: android.telephony.ims.SipMessage#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipMessage.hashCode()
+UnflaggedApi: android.telephony.ims.SipMessage#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SipMessage.toString()
+UnflaggedApi: android.telephony.ims.SrvccCall#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SrvccCall.equals(Object)
+UnflaggedApi: android.telephony.ims.SrvccCall#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SrvccCall.hashCode()
+UnflaggedApi: android.telephony.ims.SrvccCall#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.SrvccCall.toString()
+UnflaggedApi: android.telephony.ims.feature.CapabilityChangeRequest#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.feature.CapabilityChangeRequest.toString()
+UnflaggedApi: android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair.toString()
+UnflaggedApi: android.telephony.ims.stub.ImsFeatureConfiguration.FeatureSlotPair#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.stub.ImsFeatureConfiguration.FeatureSlotPair.equals(Object)
+UnflaggedApi: android.telephony.ims.stub.ImsFeatureConfiguration.FeatureSlotPair#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.stub.ImsFeatureConfiguration.FeatureSlotPair.hashCode()
+UnflaggedApi: android.telephony.ims.stub.ImsFeatureConfiguration.FeatureSlotPair#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.ims.stub.ImsFeatureConfiguration.FeatureSlotPair.toString()
+UnflaggedApi: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
+ New API must be flagged with @FlaggedApi: method android.telephony.mbms.DownloadRequest.Builder.setServiceId(String)
+UnflaggedApi: android.telephony.mbms.vendor.MbmsDownloadServiceBase#DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.mbms.vendor.MbmsDownloadServiceBase.DESCRIPTOR
+UnflaggedApi: android.telephony.mbms.vendor.MbmsStreamingServiceBase#DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.mbms.vendor.MbmsStreamingServiceBase.DESCRIPTOR
+UnflaggedApi: android.telephony.satellite.AntennaDirection:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.AntennaDirection
+UnflaggedApi: android.telephony.satellite.AntennaDirection#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.AntennaDirection.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.telephony.satellite.AntennaDirection#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.AntennaDirection.CREATOR
+UnflaggedApi: android.telephony.satellite.AntennaDirection#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.AntennaDirection.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.telephony.satellite.AntennaDirection#describeContents():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaDirection.describeContents()
+UnflaggedApi: android.telephony.satellite.AntennaDirection#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaDirection.equals(Object)
+UnflaggedApi: android.telephony.satellite.AntennaDirection#getX():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaDirection.getX()
+UnflaggedApi: android.telephony.satellite.AntennaDirection#getY():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaDirection.getY()
+UnflaggedApi: android.telephony.satellite.AntennaDirection#getZ():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaDirection.getZ()
+UnflaggedApi: android.telephony.satellite.AntennaDirection#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaDirection.hashCode()
+UnflaggedApi: android.telephony.satellite.AntennaDirection#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaDirection.toString()
+UnflaggedApi: android.telephony.satellite.AntennaDirection#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaDirection.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.telephony.satellite.AntennaPosition:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.AntennaPosition
+UnflaggedApi: android.telephony.satellite.AntennaPosition#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.AntennaPosition.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.telephony.satellite.AntennaPosition#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.AntennaPosition.CREATOR
+UnflaggedApi: android.telephony.satellite.AntennaPosition#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.AntennaPosition.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.telephony.satellite.AntennaPosition#describeContents():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaPosition.describeContents()
+UnflaggedApi: android.telephony.satellite.AntennaPosition#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaPosition.equals(Object)
+UnflaggedApi: android.telephony.satellite.AntennaPosition#getAntennaDirection():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaPosition.getAntennaDirection()
+UnflaggedApi: android.telephony.satellite.AntennaPosition#getSuggestedHoldPosition():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaPosition.getSuggestedHoldPosition()
+UnflaggedApi: android.telephony.satellite.AntennaPosition#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaPosition.hashCode()
+UnflaggedApi: android.telephony.satellite.AntennaPosition#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaPosition.toString()
+UnflaggedApi: android.telephony.satellite.AntennaPosition#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.AntennaPosition.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.telephony.satellite.PointingInfo:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.PointingInfo
+UnflaggedApi: android.telephony.satellite.PointingInfo#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.PointingInfo.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.telephony.satellite.PointingInfo#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.PointingInfo.CREATOR
+UnflaggedApi: android.telephony.satellite.PointingInfo#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.PointingInfo.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.telephony.satellite.PointingInfo#describeContents():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.PointingInfo.describeContents()
+UnflaggedApi: android.telephony.satellite.PointingInfo#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.PointingInfo.equals(Object)
+UnflaggedApi: android.telephony.satellite.PointingInfo#getSatelliteAzimuthDegrees():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.PointingInfo.getSatelliteAzimuthDegrees()
+UnflaggedApi: android.telephony.satellite.PointingInfo#getSatelliteElevationDegrees():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.PointingInfo.getSatelliteElevationDegrees()
+UnflaggedApi: android.telephony.satellite.PointingInfo#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.PointingInfo.hashCode()
+UnflaggedApi: android.telephony.satellite.PointingInfo#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.PointingInfo.toString()
+UnflaggedApi: android.telephony.satellite.PointingInfo#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.PointingInfo.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteCapabilities
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteCapabilities.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteCapabilities.CREATOR
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteCapabilities.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#describeContents():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteCapabilities.describeContents()
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteCapabilities.equals(Object)
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#getAntennaPositionMap():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteCapabilities.getAntennaPositionMap()
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#getMaxBytesPerOutgoingDatagram():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteCapabilities.getMaxBytesPerOutgoingDatagram()
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#getSupportedRadioTechnologies():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteCapabilities.getSupportedRadioTechnologies()
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#hashCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteCapabilities.hashCode()
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#isPointingRequired():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteCapabilities.isPointingRequired()
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#toString():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteCapabilities.toString()
+UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteCapabilities.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.telephony.satellite.SatelliteDatagram:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteDatagram
+UnflaggedApi: android.telephony.satellite.SatelliteDatagram#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteDatagram.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.telephony.satellite.SatelliteDatagram#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteDatagram.CREATOR
+UnflaggedApi: android.telephony.satellite.SatelliteDatagram#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteDatagram.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.telephony.satellite.SatelliteDatagram#describeContents():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteDatagram.describeContents()
+UnflaggedApi: android.telephony.satellite.SatelliteDatagram#getSatelliteDatagram():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteDatagram.getSatelliteDatagram()
+UnflaggedApi: android.telephony.satellite.SatelliteDatagram#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteDatagram.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.telephony.satellite.SatelliteDatagramCallback:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteDatagramCallback
+UnflaggedApi: android.telephony.satellite.SatelliteDatagramCallback#onSatelliteDatagramReceived(long, android.telephony.satellite.SatelliteDatagram, int, java.util.function.Consumer<java.lang.Void>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteDatagramCallback.onSatelliteDatagramReceived(long,android.telephony.satellite.SatelliteDatagram,int,java.util.function.Consumer<java.lang.Void>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteManager
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DATAGRAM_TYPE_LOCATION_SHARING:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DATAGRAM_TYPE_SOS_MESSAGE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DATAGRAM_TYPE_UNKNOWN:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DEVICE_HOLD_POSITION_LANDSCAPE_LEFT:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DEVICE_HOLD_POSITION_LANDSCAPE_LEFT
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DEVICE_HOLD_POSITION_PORTRAIT:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DEVICE_HOLD_POSITION_PORTRAIT
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DEVICE_HOLD_POSITION_UNKNOWN:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DEVICE_HOLD_POSITION_UNKNOWN
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DISPLAY_MODE_CLOSED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DISPLAY_MODE_CLOSED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DISPLAY_MODE_FIXED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DISPLAY_MODE_FIXED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DISPLAY_MODE_OPENED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DISPLAY_MODE_OPENED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#DISPLAY_MODE_UNKNOWN:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.DISPLAY_MODE_UNKNOWN
+UnflaggedApi: android.telephony.satellite.SatelliteManager#NT_RADIO_TECHNOLOGY_EMTC_NTN:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_EMTC_NTN
+UnflaggedApi: android.telephony.satellite.SatelliteManager#NT_RADIO_TECHNOLOGY_NB_IOT_NTN:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN
+UnflaggedApi: android.telephony.satellite.SatelliteManager#NT_RADIO_TECHNOLOGY_NR_NTN:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_NR_NTN
+UnflaggedApi: android.telephony.satellite.SatelliteManager#NT_RADIO_TECHNOLOGY_PROPRIETARY:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_PROPRIETARY
+UnflaggedApi: android.telephony.satellite.SatelliteManager#NT_RADIO_TECHNOLOGY_UNKNOWN:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_ACCESS_BARRED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_ACCESS_BARRED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_ERROR_NONE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_ERROR_NONE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_INVALID_ARGUMENTS:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_ARGUMENTS
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_INVALID_MODEM_STATE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_MODEM_STATE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_INVALID_TELEPHONY_STATE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_BUSY:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_BUSY
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_STATE_DATAGRAM_RETRYING:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_STATE_IDLE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_IDLE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_STATE_LISTENING:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_LISTENING
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_STATE_OFF:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_STATE_UNAVAILABLE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_STATE_UNKNOWN:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_NETWORK_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_NETWORK_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_NETWORK_TIMEOUT:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_NETWORK_TIMEOUT
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_NOT_AUTHORIZED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_NOT_AUTHORIZED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_NOT_REACHABLE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_NOT_REACHABLE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_NOT_SUPPORTED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_NOT_SUPPORTED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_NO_RESOURCES:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_NO_RESOURCES
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RADIO_NOT_AVAILABLE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_REQUEST_ABORTED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_REQUEST_ABORTED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_REQUEST_FAILED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_REQUEST_FAILED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_REQUEST_IN_PROGRESS:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_REQUEST_IN_PROGRESS
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_REQUEST_NOT_SUPPORTED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_ACCESS_BARRED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ACCESS_BARRED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_INVALID_ARGUMENTS:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_INVALID_MODEM_STATE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_INVALID_TELEPHONY_STATE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_MODEM_BUSY:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_BUSY
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_MODEM_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_NETWORK_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NETWORK_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_NETWORK_TIMEOUT:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NETWORK_TIMEOUT
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_NOT_AUTHORIZED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_AUTHORIZED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_NOT_REACHABLE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_NOT_SUPPORTED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_NO_RESOURCES:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NO_RESOURCES
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_RADIO_NOT_AVAILABLE:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_REQUEST_ABORTED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_REQUEST_FAILED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_FAILED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_REQUEST_IN_PROGRESS:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_REQUEST_NOT_SUPPORTED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_SERVER_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SERVER_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_SERVICE_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_SERVICE_NOT_PROVISIONED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_SUCCESS:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_SERVER_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_SERVER_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_SERVICE_ERROR:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_SERVICE_ERROR
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_SERVICE_NOT_PROVISIONED:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED
+UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_SERVICE_PROVISION_IN_PROGRESS:
+ New API must be flagged with @FlaggedApi: field android.telephony.satellite.SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS
+UnflaggedApi: android.telephony.satellite.SatelliteManager#deprovisionSatelliteService(String, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.deprovisionSatelliteService(String,java.util.concurrent.Executor,java.util.function.Consumer<java.lang.Integer>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#pollPendingSatelliteDatagrams(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.pollPendingSatelliteDatagrams(java.util.concurrent.Executor,java.util.function.Consumer<java.lang.Integer>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#provisionSatelliteService(String, byte[], android.os.CancellationSignal, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.provisionSatelliteService(String,byte[],android.os.CancellationSignal,java.util.concurrent.Executor,java.util.function.Consumer<java.lang.Integer>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#registerForSatelliteDatagram(java.util.concurrent.Executor, android.telephony.satellite.SatelliteDatagramCallback):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.registerForSatelliteDatagram(java.util.concurrent.Executor,android.telephony.satellite.SatelliteDatagramCallback)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#registerForSatelliteModemStateChanged(java.util.concurrent.Executor, android.telephony.satellite.SatelliteStateCallback):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.registerForSatelliteModemStateChanged(java.util.concurrent.Executor,android.telephony.satellite.SatelliteStateCallback)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#registerForSatelliteProvisionStateChanged(java.util.concurrent.Executor, android.telephony.satellite.SatelliteProvisionStateCallback):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.registerForSatelliteProvisionStateChanged(java.util.concurrent.Executor,android.telephony.satellite.SatelliteProvisionStateCallback)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#requestIsDemoModeEnabled(java.util.concurrent.Executor, android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.requestIsDemoModeEnabled(java.util.concurrent.Executor,android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#requestIsSatelliteCommunicationAllowedForCurrentLocation(java.util.concurrent.Executor, android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.requestIsSatelliteCommunicationAllowedForCurrentLocation(java.util.concurrent.Executor,android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#requestIsSatelliteEnabled(java.util.concurrent.Executor, android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.requestIsSatelliteEnabled(java.util.concurrent.Executor,android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#requestIsSatelliteProvisioned(java.util.concurrent.Executor, android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.requestIsSatelliteProvisioned(java.util.concurrent.Executor,android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#requestIsSatelliteSupported(java.util.concurrent.Executor, android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.requestIsSatelliteSupported(java.util.concurrent.Executor,android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#requestSatelliteCapabilities(java.util.concurrent.Executor, android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.requestSatelliteCapabilities(java.util.concurrent.Executor,android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#requestSatelliteEnabled(boolean, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.requestSatelliteEnabled(boolean,boolean,java.util.concurrent.Executor,java.util.function.Consumer<java.lang.Integer>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#requestTimeForNextSatelliteVisibility(java.util.concurrent.Executor, android.os.OutcomeReceiver<java.time.Duration,android.telephony.satellite.SatelliteManager.SatelliteException>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.requestTimeForNextSatelliteVisibility(java.util.concurrent.Executor,android.os.OutcomeReceiver<java.time.Duration,android.telephony.satellite.SatelliteManager.SatelliteException>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#sendSatelliteDatagram(int, android.telephony.satellite.SatelliteDatagram, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.sendSatelliteDatagram(int,android.telephony.satellite.SatelliteDatagram,boolean,java.util.concurrent.Executor,java.util.function.Consumer<java.lang.Integer>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#setDeviceAlignedWithSatellite(boolean):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.setDeviceAlignedWithSatellite(boolean)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#startSatelliteTransmissionUpdates(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>, android.telephony.satellite.SatelliteTransmissionUpdateCallback):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.startSatelliteTransmissionUpdates(java.util.concurrent.Executor,java.util.function.Consumer<java.lang.Integer>,android.telephony.satellite.SatelliteTransmissionUpdateCallback)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#stopSatelliteTransmissionUpdates(android.telephony.satellite.SatelliteTransmissionUpdateCallback, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.stopSatelliteTransmissionUpdates(android.telephony.satellite.SatelliteTransmissionUpdateCallback,java.util.concurrent.Executor,java.util.function.Consumer<java.lang.Integer>)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#unregisterForSatelliteDatagram(android.telephony.satellite.SatelliteDatagramCallback):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.unregisterForSatelliteDatagram(android.telephony.satellite.SatelliteDatagramCallback)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#unregisterForSatelliteModemStateChanged(android.telephony.satellite.SatelliteStateCallback):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.unregisterForSatelliteModemStateChanged(android.telephony.satellite.SatelliteStateCallback)
+UnflaggedApi: android.telephony.satellite.SatelliteManager#unregisterForSatelliteProvisionStateChanged(android.telephony.satellite.SatelliteProvisionStateCallback):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.unregisterForSatelliteProvisionStateChanged(android.telephony.satellite.SatelliteProvisionStateCallback)
+UnflaggedApi: android.telephony.satellite.SatelliteManager.SatelliteException:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteManager.SatelliteException
+UnflaggedApi: android.telephony.satellite.SatelliteManager.SatelliteException#SatelliteException(int):
+ New API must be flagged with @FlaggedApi: constructor android.telephony.satellite.SatelliteManager.SatelliteException(int)
+UnflaggedApi: android.telephony.satellite.SatelliteManager.SatelliteException#getErrorCode():
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.SatelliteException.getErrorCode()
+UnflaggedApi: android.telephony.satellite.SatelliteProvisionStateCallback:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteProvisionStateCallback
+UnflaggedApi: android.telephony.satellite.SatelliteProvisionStateCallback#onSatelliteProvisionStateChanged(boolean):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteProvisionStateCallback.onSatelliteProvisionStateChanged(boolean)
+UnflaggedApi: android.telephony.satellite.SatelliteStateCallback:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteStateCallback
+UnflaggedApi: android.telephony.satellite.SatelliteStateCallback#onSatelliteModemStateChanged(int):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteStateCallback.onSatelliteModemStateChanged(int)
+UnflaggedApi: android.telephony.satellite.SatelliteTransmissionUpdateCallback:
+ New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteTransmissionUpdateCallback
+UnflaggedApi: android.telephony.satellite.SatelliteTransmissionUpdateCallback#onReceiveDatagramStateChanged(int, int, int):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteTransmissionUpdateCallback.onReceiveDatagramStateChanged(int,int,int)
+UnflaggedApi: android.telephony.satellite.SatelliteTransmissionUpdateCallback#onSatellitePositionChanged(android.telephony.satellite.PointingInfo):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteTransmissionUpdateCallback.onSatellitePositionChanged(android.telephony.satellite.PointingInfo)
+UnflaggedApi: android.telephony.satellite.SatelliteTransmissionUpdateCallback#onSendDatagramStateChanged(int, int, int):
+ New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteTransmissionUpdateCallback.onSendDatagramStateChanged(int,int,int)
+UnflaggedApi: android.text.FontConfig#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.equals(Object)
+UnflaggedApi: android.text.FontConfig#hashCode():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.hashCode()
+UnflaggedApi: android.text.FontConfig#toString():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.toString()
+UnflaggedApi: android.text.FontConfig.Alias#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.Alias.equals(Object)
+UnflaggedApi: android.text.FontConfig.Alias#hashCode():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.Alias.hashCode()
+UnflaggedApi: android.text.FontConfig.Alias#toString():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.Alias.toString()
+UnflaggedApi: android.text.FontConfig.Font#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.Font.equals(Object)
+UnflaggedApi: android.text.FontConfig.Font#hashCode():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.Font.hashCode()
+UnflaggedApi: android.text.FontConfig.Font#toString():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.Font.toString()
+UnflaggedApi: android.text.FontConfig.FontFamily#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.FontFamily.equals(Object)
+UnflaggedApi: android.text.FontConfig.FontFamily#hashCode():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.FontFamily.hashCode()
+UnflaggedApi: android.text.FontConfig.FontFamily#toString():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.FontFamily.toString()
+UnflaggedApi: android.text.FontConfig.NamedFamilyList#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.NamedFamilyList.equals(Object)
+UnflaggedApi: android.text.FontConfig.NamedFamilyList#hashCode():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.NamedFamilyList.hashCode()
+UnflaggedApi: android.text.FontConfig.NamedFamilyList#toString():
+ New API must be flagged with @FlaggedApi: method android.text.FontConfig.NamedFamilyList.toString()
+UnflaggedApi: android.view.contentcapture.ContentCaptureEvent#toString():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ContentCaptureEvent.toString()
+UnflaggedApi: android.view.contentcapture.ViewNode#getAutofillHints():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getAutofillHints()
+UnflaggedApi: android.view.contentcapture.ViewNode#getAutofillId():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getAutofillId()
+UnflaggedApi: android.view.contentcapture.ViewNode#getAutofillOptions():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getAutofillOptions()
+UnflaggedApi: android.view.contentcapture.ViewNode#getAutofillType():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getAutofillType()
+UnflaggedApi: android.view.contentcapture.ViewNode#getAutofillValue():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getAutofillValue()
+UnflaggedApi: android.view.contentcapture.ViewNode#getClassName():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getClassName()
+UnflaggedApi: android.view.contentcapture.ViewNode#getContentDescription():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getContentDescription()
+UnflaggedApi: android.view.contentcapture.ViewNode#getExtras():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getExtras()
+UnflaggedApi: android.view.contentcapture.ViewNode#getHeight():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getHeight()
+UnflaggedApi: android.view.contentcapture.ViewNode#getHint():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getHint()
+UnflaggedApi: android.view.contentcapture.ViewNode#getHintIdEntry():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getHintIdEntry()
+UnflaggedApi: android.view.contentcapture.ViewNode#getId():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getId()
+UnflaggedApi: android.view.contentcapture.ViewNode#getIdEntry():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getIdEntry()
+UnflaggedApi: android.view.contentcapture.ViewNode#getIdPackage():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getIdPackage()
+UnflaggedApi: android.view.contentcapture.ViewNode#getIdType():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getIdType()
+UnflaggedApi: android.view.contentcapture.ViewNode#getInputType():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getInputType()
+UnflaggedApi: android.view.contentcapture.ViewNode#getLeft():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getLeft()
+UnflaggedApi: android.view.contentcapture.ViewNode#getLocaleList():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getLocaleList()
+UnflaggedApi: android.view.contentcapture.ViewNode#getMaxTextEms():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getMaxTextEms()
+UnflaggedApi: android.view.contentcapture.ViewNode#getMaxTextLength():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getMaxTextLength()
+UnflaggedApi: android.view.contentcapture.ViewNode#getMinTextEms():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getMinTextEms()
+UnflaggedApi: android.view.contentcapture.ViewNode#getReceiveContentMimeTypes():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getReceiveContentMimeTypes()
+UnflaggedApi: android.view.contentcapture.ViewNode#getScrollX():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getScrollX()
+UnflaggedApi: android.view.contentcapture.ViewNode#getScrollY():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getScrollY()
+UnflaggedApi: android.view.contentcapture.ViewNode#getText():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getText()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTextBackgroundColor():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTextBackgroundColor()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTextColor():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTextColor()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTextIdEntry():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTextIdEntry()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTextLineBaselines():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTextLineBaselines()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTextLineCharOffsets():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTextLineCharOffsets()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTextSelectionEnd():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTextSelectionEnd()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTextSelectionStart():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTextSelectionStart()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTextSize():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTextSize()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTextStyle():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTextStyle()
+UnflaggedApi: android.view.contentcapture.ViewNode#getTop():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getTop()
+UnflaggedApi: android.view.contentcapture.ViewNode#getVisibility():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getVisibility()
+UnflaggedApi: android.view.contentcapture.ViewNode#getWidth():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.getWidth()
+UnflaggedApi: android.view.contentcapture.ViewNode#isAccessibilityFocused():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isAccessibilityFocused()
+UnflaggedApi: android.view.contentcapture.ViewNode#isActivated():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isActivated()
+UnflaggedApi: android.view.contentcapture.ViewNode#isAssistBlocked():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isAssistBlocked()
+UnflaggedApi: android.view.contentcapture.ViewNode#isCheckable():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isCheckable()
+UnflaggedApi: android.view.contentcapture.ViewNode#isChecked():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isChecked()
+UnflaggedApi: android.view.contentcapture.ViewNode#isClickable():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isClickable()
+UnflaggedApi: android.view.contentcapture.ViewNode#isContextClickable():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isContextClickable()
+UnflaggedApi: android.view.contentcapture.ViewNode#isEnabled():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isEnabled()
+UnflaggedApi: android.view.contentcapture.ViewNode#isFocusable():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isFocusable()
+UnflaggedApi: android.view.contentcapture.ViewNode#isFocused():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isFocused()
+UnflaggedApi: android.view.contentcapture.ViewNode#isLongClickable():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isLongClickable()
+UnflaggedApi: android.view.contentcapture.ViewNode#isOpaque():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isOpaque()
+UnflaggedApi: android.view.contentcapture.ViewNode#isSelected():
+ New API must be flagged with @FlaggedApi: method android.view.contentcapture.ViewNode.isSelected()
+UnflaggedApi: android.view.translation.UiTranslationSpec#equals(Object):
+ New API must be flagged with @FlaggedApi: method android.view.translation.UiTranslationSpec.equals(Object)
+UnflaggedApi: android.view.translation.UiTranslationSpec#hashCode():
+ New API must be flagged with @FlaggedApi: method android.view.translation.UiTranslationSpec.hashCode()
+UnflaggedApi: android.view.translation.UiTranslationSpec#toString():
+ New API must be flagged with @FlaggedApi: method android.view.translation.UiTranslationSpec.toString()
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 39589fa..f28b4b4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -36,7 +36,6 @@
import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
import static android.window.ConfigurationHelper.isDifferentDisplay;
import static android.window.ConfigurationHelper.shouldUpdateResources;
-
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL;
@@ -1286,8 +1285,13 @@
}
private void updateCompatOverrideScale(CompatibilityInfo info) {
- CompatibilityInfo.setOverrideInvertedScale(
- info.hasOverrideScaling() ? info.applicationInvertedScale : 1f);
+ if (info.hasOverrideScaling()) {
+ CompatibilityInfo.setOverrideInvertedScale(info.applicationInvertedScale,
+ info.applicationDensityInvertedScale);
+ } else {
+ CompatibilityInfo.setOverrideInvertedScale(/* invertScale */ 1f,
+ /* densityInvertScale */1f);
+ }
}
public final void runIsolatedEntryPoint(String entryPoint, String[] entryPointArgs) {
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index c58561d..bf00a5a 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -23,6 +23,7 @@
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
+import android.content.ComponentName;
import android.content.IntentFilter;
import android.graphics.Point;
import android.graphics.PointF;
@@ -86,6 +87,18 @@
void setDevicePolicy(int policyType, int devicePolicy);
/**
+ * Adds an exemption to the default activity launch policy.
+ */
+ @EnforcePermission("CREATE_VIRTUAL_DEVICE")
+ void addActivityPolicyExemption(in ComponentName exemption);
+
+ /**
+ * Removes an exemption to the default activity launch policy.
+ */
+ @EnforcePermission("CREATE_VIRTUAL_DEVICE")
+ void removeActivityPolicyExemption(in ComponentName exemption);
+
+ /**
* Notifies that an audio session being started.
*/
@EnforcePermission("CREATE_VIRTUAL_DEVICE")
diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java
index 2e5c0f7..7bf2e91 100644
--- a/core/java/android/companion/virtual/VirtualDeviceInternal.java
+++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java
@@ -247,6 +247,22 @@
}
}
+ void addActivityPolicyExemption(@NonNull ComponentName componentName) {
+ try {
+ mVirtualDevice.addActivityPolicyExemption(componentName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void removeActivityPolicyExemption(@NonNull ComponentName componentName) {
+ try {
+ mVirtualDevice.removeActivityPolicyExemption(componentName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@NonNull
VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) {
try {
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 7b81031..d338d17 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -62,7 +62,6 @@
import android.view.Surface;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.AnnotationValidations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -624,19 +623,62 @@
* @param devicePolicy the value of the policy, i.e. how to interpret the device behavior.
*
* @see VirtualDeviceParams#POLICY_TYPE_RECENTS
+ * @see VirtualDeviceParams#POLICY_TYPE_ACTIVITY
*/
@FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
@VirtualDeviceParams.DevicePolicy int devicePolicy) {
- AnnotationValidations.validate(
- VirtualDeviceParams.DynamicPolicyType.class, null, policyType);
- AnnotationValidations.validate(
- VirtualDeviceParams.DevicePolicy.class, null, devicePolicy);
mVirtualDeviceInternal.setDevicePolicy(policyType, devicePolicy);
}
/**
+ * Specifies a component name to be exempt from the current activity launch policy.
+ *
+ * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVIY} allows activity
+ * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT},
+ * then the specified component will be blocked from launching.
+ * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity
+ * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}, then
+ * the specified component will be allowed to launch.</p>
+ *
+ * <p>Note that changing the activity launch policy will not affect current set of exempt
+ * components and it needs to be updated separately.</p>
+ *
+ * @see #removeActivityPolicyExemption
+ * @see #setDevicePolicy
+ */
+ @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
+ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+ public void addActivityPolicyExemption(@NonNull ComponentName componentName) {
+ mVirtualDeviceInternal.addActivityPolicyExemption(
+ Objects.requireNonNull(componentName));
+ }
+
+ /**
+ * Makes the specified component name to adhere to the default activity launch policy.
+ *
+ * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVIY} allows activity
+ * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT},
+ * then the specified component will be allowed to launch.
+ * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity
+ * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}, then
+ * the specified component will be blocked from launching.</p>
+ *
+ * <p>Note that changing the activity launch policy will not affect current set of exempt
+ * components and it needs to be updated separately.</p>
+ *
+ * @see #addActivityPolicyExemption
+ * @see #setDevicePolicy
+ */
+ @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
+ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+ public void removeActivityPolicyExemption(@NonNull ComponentName componentName) {
+ mVirtualDeviceInternal.removeActivityPolicyExemption(
+ Objects.requireNonNull(componentName));
+ }
+
+ /**
* Creates a virtual dpad.
*
* @param config the configurations of the virtual dpad.
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 51df257..b4c740ec 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -22,12 +22,14 @@
import static java.util.concurrent.TimeUnit.MICROSECONDS;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.companion.virtual.flags.Flags;
import android.companion.virtual.sensor.IVirtualSensorCallback;
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorCallback;
@@ -144,7 +146,7 @@
* @hide
*/
@IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO,
- POLICY_TYPE_RECENTS})
+ POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public @interface PolicyType {}
@@ -155,7 +157,7 @@
* @see VirtualDeviceManager.VirtualDevice#setDevicePolicy
* @hide
*/
- @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_RECENTS})
+ @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public @interface DynamicPolicyType {}
@@ -195,19 +197,35 @@
* <li>{@link #DEVICE_POLICY_DEFAULT}: Activities launched on VirtualDisplays owned by this
* device will appear in the host device recents.
* <li>{@link #DEVICE_POLICY_CUSTOM}: Activities launched on VirtualDisplays owned by this
- * * device will not appear in recents.
+ * device will not appear in recents.
* </ul>
*/
public static final int POLICY_TYPE_RECENTS = 2;
+ /**
+ * Tells the activity manager what the default launch behavior for activities on this device is.
+ *
+ * <ul>
+ * <li>{@link #DEVICE_POLICY_DEFAULT}: Activities are allowed to be launched on displays
+ * owned by this device, unless explicitly blocked by the device.
+ * <li>{@link #DEVICE_POLICY_CUSTOM}: Activities are blocked from launching on displays
+ * owned by this device, unless explicitly allowed by the device.
+ * </ul>
+ *
+ * @see VirtualDeviceManager.VirtualDevice#addActivityPolicyExemption
+ * @see VirtualDeviceManager.VirtualDevice#removeActivityPolicyExemption
+ */
+ @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
+ public static final int POLICY_TYPE_ACTIVITY = 3;
+
private final int mLockState;
@NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
@NavigationPolicy
private final int mDefaultNavigationPolicy;
- @NonNull private final ArraySet<ComponentName> mCrossTaskNavigationExceptions;
+ @NonNull private final ArraySet<ComponentName> mCrossTaskNavigationExemptions;
@ActivityPolicy
private final int mDefaultActivityPolicy;
- @NonNull private final ArraySet<ComponentName> mActivityPolicyExceptions;
+ @NonNull private final ArraySet<ComponentName> mActivityPolicyExemptions;
@Nullable private final String mName;
// Mapping of @PolicyType to @DevicePolicy
@NonNull private final SparseIntArray mDevicePolicies;
@@ -220,9 +238,9 @@
@LockState int lockState,
@NonNull Set<UserHandle> usersWithMatchingAccounts,
@NavigationPolicy int defaultNavigationPolicy,
- @NonNull Set<ComponentName> crossTaskNavigationExceptions,
+ @NonNull Set<ComponentName> crossTaskNavigationExemptions,
@ActivityPolicy int defaultActivityPolicy,
- @NonNull Set<ComponentName> activityPolicyExceptions,
+ @NonNull Set<ComponentName> activityPolicyExemptions,
@Nullable String name,
@NonNull SparseIntArray devicePolicies,
@NonNull List<VirtualSensorConfig> virtualSensorConfigs,
@@ -233,11 +251,11 @@
mUsersWithMatchingAccounts =
new ArraySet<>(Objects.requireNonNull(usersWithMatchingAccounts));
mDefaultNavigationPolicy = defaultNavigationPolicy;
- mCrossTaskNavigationExceptions =
- new ArraySet<>(Objects.requireNonNull(crossTaskNavigationExceptions));
+ mCrossTaskNavigationExemptions =
+ new ArraySet<>(Objects.requireNonNull(crossTaskNavigationExemptions));
mDefaultActivityPolicy = defaultActivityPolicy;
- mActivityPolicyExceptions =
- new ArraySet<>(Objects.requireNonNull(activityPolicyExceptions));
+ mActivityPolicyExemptions =
+ new ArraySet<>(Objects.requireNonNull(activityPolicyExemptions));
mName = name;
mDevicePolicies = Objects.requireNonNull(devicePolicies);
mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
@@ -251,9 +269,9 @@
mLockState = parcel.readInt();
mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null);
mDefaultNavigationPolicy = parcel.readInt();
- mCrossTaskNavigationExceptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
+ mCrossTaskNavigationExemptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
mDefaultActivityPolicy = parcel.readInt();
- mActivityPolicyExceptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
+ mActivityPolicyExemptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
mName = parcel.readString8();
mDevicePolicies = parcel.readSparseIntArray();
mVirtualSensorConfigs = new ArrayList<>();
@@ -295,7 +313,7 @@
public Set<ComponentName> getAllowedCrossTaskNavigations() {
return mDefaultNavigationPolicy == NAVIGATION_POLICY_DEFAULT_ALLOWED
? Collections.emptySet()
- : Collections.unmodifiableSet(mCrossTaskNavigationExceptions);
+ : Collections.unmodifiableSet(mCrossTaskNavigationExemptions);
}
/**
@@ -310,7 +328,7 @@
public Set<ComponentName> getBlockedCrossTaskNavigations() {
return mDefaultNavigationPolicy == NAVIGATION_POLICY_DEFAULT_BLOCKED
? Collections.emptySet()
- : Collections.unmodifiableSet(mCrossTaskNavigationExceptions);
+ : Collections.unmodifiableSet(mCrossTaskNavigationExemptions);
}
/**
@@ -336,7 +354,7 @@
public Set<ComponentName> getAllowedActivities() {
return mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_ALLOWED
? Collections.emptySet()
- : Collections.unmodifiableSet(mActivityPolicyExceptions);
+ : Collections.unmodifiableSet(mActivityPolicyExemptions);
}
/**
@@ -349,7 +367,7 @@
public Set<ComponentName> getBlockedActivities() {
return mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED
? Collections.emptySet()
- : Collections.unmodifiableSet(mActivityPolicyExceptions);
+ : Collections.unmodifiableSet(mActivityPolicyExemptions);
}
/**
@@ -440,9 +458,9 @@
dest.writeInt(mLockState);
dest.writeArraySet(mUsersWithMatchingAccounts);
dest.writeInt(mDefaultNavigationPolicy);
- dest.writeArraySet(mCrossTaskNavigationExceptions);
+ dest.writeArraySet(mCrossTaskNavigationExemptions);
dest.writeInt(mDefaultActivityPolicy);
- dest.writeArraySet(mActivityPolicyExceptions);
+ dest.writeArraySet(mActivityPolicyExemptions);
dest.writeString8(mName);
dest.writeSparseIntArray(mDevicePolicies);
dest.writeTypedList(mVirtualSensorConfigs);
@@ -476,9 +494,9 @@
return mLockState == that.mLockState
&& mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts)
&& Objects.equals(
- mCrossTaskNavigationExceptions, that.mCrossTaskNavigationExceptions)
+ mCrossTaskNavigationExemptions, that.mCrossTaskNavigationExemptions)
&& mDefaultNavigationPolicy == that.mDefaultNavigationPolicy
- && Objects.equals(mActivityPolicyExceptions, that.mActivityPolicyExceptions)
+ && Objects.equals(mActivityPolicyExemptions, that.mActivityPolicyExemptions)
&& mDefaultActivityPolicy == that.mDefaultActivityPolicy
&& Objects.equals(mName, that.mName)
&& mAudioPlaybackSessionId == that.mAudioPlaybackSessionId
@@ -488,8 +506,8 @@
@Override
public int hashCode() {
int hashCode = Objects.hash(
- mLockState, mUsersWithMatchingAccounts, mCrossTaskNavigationExceptions,
- mDefaultNavigationPolicy, mActivityPolicyExceptions, mDefaultActivityPolicy, mName,
+ mLockState, mUsersWithMatchingAccounts, mCrossTaskNavigationExemptions,
+ mDefaultNavigationPolicy, mActivityPolicyExemptions, mDefaultActivityPolicy, mName,
mDevicePolicies, mAudioPlaybackSessionId, mAudioRecordingSessionId);
for (int i = 0; i < mDevicePolicies.size(); i++) {
hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
@@ -505,9 +523,9 @@
+ " mLockState=" + mLockState
+ " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts
+ " mDefaultNavigationPolicy=" + mDefaultNavigationPolicy
- + " mCrossTaskNavigationExceptions=" + mCrossTaskNavigationExceptions
+ + " mCrossTaskNavigationExemptions=" + mCrossTaskNavigationExemptions
+ " mDefaultActivityPolicy=" + mDefaultActivityPolicy
- + " mActivityPolicyExceptions=" + mActivityPolicyExceptions
+ + " mActivityPolicyExemptions=" + mActivityPolicyExemptions
+ " mName=" + mName
+ " mDevicePolicies=" + mDevicePolicies
+ " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId
@@ -524,9 +542,9 @@
pw.println(prefix + "mLockState=" + mLockState);
pw.println(prefix + "mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts);
pw.println(prefix + "mDefaultNavigationPolicy=" + mDefaultNavigationPolicy);
- pw.println(prefix + "mCrossTaskNavigationExceptions=" + mCrossTaskNavigationExceptions);
+ pw.println(prefix + "mCrossTaskNavigationExemptions=" + mCrossTaskNavigationExemptions);
pw.println(prefix + "mDefaultActivityPolicy=" + mDefaultActivityPolicy);
- pw.println(prefix + "mActivityPolicyExceptions=" + mActivityPolicyExceptions);
+ pw.println(prefix + "mActivityPolicyExemptions=" + mActivityPolicyExemptions);
pw.println(prefix + "mDevicePolicies=" + mDevicePolicies);
pw.println(prefix + "mVirtualSensorConfigs=" + mVirtualSensorConfigs);
pw.println(prefix + "mAudioPlaybackSessionId=" + mAudioPlaybackSessionId);
@@ -552,11 +570,11 @@
private @LockState int mLockState = LOCK_STATE_DEFAULT;
@NonNull private Set<UserHandle> mUsersWithMatchingAccounts = Collections.emptySet();
- @NonNull private Set<ComponentName> mCrossTaskNavigationExceptions = Collections.emptySet();
+ @NonNull private Set<ComponentName> mCrossTaskNavigationExemptions = Collections.emptySet();
@NavigationPolicy
private int mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
private boolean mDefaultNavigationPolicyConfigured = false;
- @NonNull private Set<ComponentName> mActivityPolicyExceptions = Collections.emptySet();
+ @NonNull private Set<ComponentName> mActivityPolicyExemptions = Collections.emptySet();
@ActivityPolicy
private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
private boolean mDefaultActivityPolicyConfigured = false;
@@ -700,7 +718,7 @@
}
mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_BLOCKED;
mDefaultNavigationPolicyConfigured = true;
- mCrossTaskNavigationExceptions = Objects.requireNonNull(allowedCrossTaskNavigations);
+ mCrossTaskNavigationExemptions = Objects.requireNonNull(allowedCrossTaskNavigations);
return this;
}
@@ -731,7 +749,7 @@
}
mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
mDefaultNavigationPolicyConfigured = true;
- mCrossTaskNavigationExceptions = Objects.requireNonNull(blockedCrossTaskNavigations);
+ mCrossTaskNavigationExemptions = Objects.requireNonNull(blockedCrossTaskNavigations);
return this;
}
@@ -757,7 +775,7 @@
}
mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_BLOCKED;
mDefaultActivityPolicyConfigured = true;
- mActivityPolicyExceptions = Objects.requireNonNull(allowedActivities);
+ mActivityPolicyExemptions = Objects.requireNonNull(allowedActivities);
return this;
}
@@ -783,7 +801,7 @@
}
mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
mDefaultActivityPolicyConfigured = true;
- mActivityPolicyExceptions = Objects.requireNonNull(blockedActivities);
+ mActivityPolicyExemptions = Objects.requireNonNull(blockedActivities);
return this;
}
@@ -956,6 +974,35 @@
mVirtualSensorDirectChannelCallback);
}
+ if (Flags.dynamicPolicy()) {
+ switch (mDevicePolicies.get(POLICY_TYPE_ACTIVITY, -1)) {
+ case DEVICE_POLICY_DEFAULT:
+ if (mDefaultActivityPolicyConfigured
+ && mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED) {
+ throw new IllegalArgumentException(
+ "DEVICE_POLICY_DEFAULT is explicitly configured for "
+ + "POLICY_TYPE_ACTIVITY, which is exclusive with "
+ + "setAllowedActivities.");
+ }
+ break;
+ case DEVICE_POLICY_CUSTOM:
+ if (mDefaultActivityPolicyConfigured
+ && mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_ALLOWED) {
+ throw new IllegalArgumentException(
+ "DEVICE_POLICY_CUSTOM is explicitly configured for "
+ + "POLICY_TYPE_ACTIVITY, which is exclusive with "
+ + "setBlockedActivities.");
+ }
+ break;
+ default:
+ if (mDefaultActivityPolicyConfigured
+ && mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED) {
+ mDevicePolicies.put(POLICY_TYPE_ACTIVITY, DEVICE_POLICY_CUSTOM);
+ }
+ break;
+ }
+ }
+
if ((mAudioPlaybackSessionId != AUDIO_SESSION_ID_GENERATE
|| mAudioRecordingSessionId != AUDIO_SESSION_ID_GENERATE)
&& mDevicePolicies.get(POLICY_TYPE_AUDIO, DEVICE_POLICY_DEFAULT)
@@ -964,7 +1011,7 @@
+ "required for configuration of device-specific audio session ids.");
}
- SparseArray<Set<String>> sensorNameByType = new SparseArray();
+ SparseArray<Set<String>> sensorNameByType = new SparseArray<>();
for (int i = 0; i < mVirtualSensorConfigs.size(); ++i) {
VirtualSensorConfig config = mVirtualSensorConfigs.get(i);
Set<String> sensorNames = sensorNameByType.get(config.getType(), new ArraySet<>());
@@ -979,9 +1026,9 @@
mLockState,
mUsersWithMatchingAccounts,
mDefaultNavigationPolicy,
- mCrossTaskNavigationExceptions,
+ mCrossTaskNavigationExemptions,
mDefaultActivityPolicy,
- mActivityPolicyExceptions,
+ mActivityPolicyExemptions,
mName,
mDevicePolicies,
mVirtualSensorConfigs,
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 3a3ab24..ee36f18 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -27,4 +27,3 @@
description: "Enable Virtual Camera"
bug: "270352264"
}
-
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 08ba5b6..f929c1f 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -100,7 +100,7 @@
* The effective screen density we have selected for this application.
*/
public final int applicationDensity;
-
+
/**
* Application's scale.
*/
@@ -112,9 +112,27 @@
*/
public final float applicationInvertedScale;
+ /**
+ * Application's density scale.
+ *
+ * <p>In most cases this is equal to {@link #applicationScale}, but in some cases e.g.
+ * Automotive the requirement is to just scale the density and keep the resolution the same.
+ * This is used for artificially making apps look zoomed in to compensate for the user distance
+ * from the screen.
+ */
+ public final float applicationDensityScale;
+
+ /**
+ * Application's density inverted scale.
+ */
+ public final float applicationDensityInvertedScale;
+
/** The process level override inverted scale. See {@link #HAS_OVERRIDE_SCALING}. */
private static float sOverrideInvertedScale = 1f;
+ /** The process level override inverted density scale. See {@link #HAS_OVERRIDE_SCALING}. */
+ private static float sOverrideDensityInvertScale = 1f;
+
@UnsupportedAppUsage
@Deprecated
public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw,
@@ -123,17 +141,24 @@
}
public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw,
- boolean forceCompat, float overrideScale) {
+ boolean forceCompat, float scaleFactor) {
+ this(appInfo, screenLayout, sw, forceCompat, scaleFactor, scaleFactor);
+ }
+
+ public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw,
+ boolean forceCompat, float scaleFactor, float densityScaleFactor) {
int compatFlags = 0;
if (appInfo.targetSdkVersion < VERSION_CODES.O) {
compatFlags |= NEEDS_COMPAT_RES;
}
- if (overrideScale != 1.0f) {
- applicationScale = overrideScale;
- applicationInvertedScale = 1.0f / overrideScale;
+ if (scaleFactor != 1f || densityScaleFactor != 1f) {
+ applicationScale = scaleFactor;
+ applicationInvertedScale = 1f / scaleFactor;
+ applicationDensityScale = densityScaleFactor;
+ applicationDensityInvertedScale = 1f / densityScaleFactor;
applicationDensity = (int) ((DisplayMetrics.DENSITY_DEVICE_STABLE
- * applicationInvertedScale) + .5f);
+ * applicationDensityInvertedScale) + .5f);
mCompatibilityFlags = NEVER_NEEDS_COMPAT | HAS_OVERRIDE_SCALING;
// Override scale has the highest priority. So ignore other compatibility attributes.
return;
@@ -181,7 +206,8 @@
applicationDensity = DisplayMetrics.DENSITY_DEVICE;
applicationScale = 1.0f;
applicationInvertedScale = 1.0f;
-
+ applicationDensityScale = 1.0f;
+ applicationDensityInvertedScale = 1.0f;
} else {
/**
* Has the application said that its UI is expandable? Based on the
@@ -271,11 +297,16 @@
applicationDensity = DisplayMetrics.DENSITY_DEVICE;
applicationScale = 1.0f;
applicationInvertedScale = 1.0f;
+ applicationDensityScale = 1.0f;
+ applicationDensityInvertedScale = 1.0f;
} else {
applicationDensity = DisplayMetrics.DENSITY_DEFAULT;
applicationScale = DisplayMetrics.DENSITY_DEVICE
/ (float) DisplayMetrics.DENSITY_DEFAULT;
applicationInvertedScale = 1.0f / applicationScale;
+ applicationDensityScale = DisplayMetrics.DENSITY_DEVICE
+ / (float) DisplayMetrics.DENSITY_DEFAULT;
+ applicationDensityInvertedScale = 1f / applicationDensityScale;
compatFlags |= SCALING_REQUIRED;
}
}
@@ -289,6 +320,8 @@
applicationDensity = dens;
applicationScale = scale;
applicationInvertedScale = invertedScale;
+ applicationDensityScale = (float) DisplayMetrics.DENSITY_DEVICE_STABLE / dens;
+ applicationDensityInvertedScale = 1f / applicationDensityScale;
}
@UnsupportedAppUsage
@@ -528,7 +561,8 @@
/** Applies the compatibility adjustment to the display metrics. */
public void applyDisplayMetricsIfNeeded(DisplayMetrics inoutDm, boolean applyToSize) {
if (hasOverrideScale()) {
- scaleDisplayMetrics(sOverrideInvertedScale, inoutDm, applyToSize);
+ scaleDisplayMetrics(sOverrideInvertedScale, sOverrideDensityInvertScale, inoutDm,
+ applyToSize);
return;
}
if (!equals(DEFAULT_COMPATIBILITY_INFO)) {
@@ -548,15 +582,17 @@
}
if (isScalingRequired()) {
- scaleDisplayMetrics(applicationInvertedScale, inoutDm, true /* applyToSize */);
+ scaleDisplayMetrics(applicationInvertedScale, applicationDensityInvertedScale, inoutDm,
+ true /* applyToSize */);
}
}
/** Scales the density of the given display metrics. */
- private static void scaleDisplayMetrics(float invertedRatio, DisplayMetrics inoutDm,
- boolean applyToSize) {
- inoutDm.density = inoutDm.noncompatDensity * invertedRatio;
- inoutDm.densityDpi = (int) ((inoutDm.noncompatDensityDpi * invertedRatio) + .5f);
+ private static void scaleDisplayMetrics(float invertScale, float densityInvertScale,
+ DisplayMetrics inoutDm, boolean applyToSize) {
+ inoutDm.density = inoutDm.noncompatDensity * densityInvertScale;
+ inoutDm.densityDpi = (int) ((inoutDm.noncompatDensityDpi
+ * densityInvertScale) + .5f);
// Note: since this is changing the scaledDensity, you might think we also need to change
// inoutDm.fontScaleConverter to accurately calculate non-linear font scaling. But we're not
// going to do that, for a couple of reasons (see b/265695259 for details):
@@ -570,12 +606,12 @@
// b. Sometime later by WindowManager in onResume or other windowing events. In this case
// the DisplayMetrics object is never used by the app/resources, so it's ok if
// fontScaleConverter is null because it's not being used to scale fonts anyway.
- inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * invertedRatio;
- inoutDm.xdpi = inoutDm.noncompatXdpi * invertedRatio;
- inoutDm.ydpi = inoutDm.noncompatYdpi * invertedRatio;
+ inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * densityInvertScale;
+ inoutDm.xdpi = inoutDm.noncompatXdpi * densityInvertScale;
+ inoutDm.ydpi = inoutDm.noncompatYdpi * densityInvertScale;
if (applyToSize) {
- inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f);
- inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f);
+ inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertScale + 0.5f);
+ inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertScale + 0.5f);
}
}
@@ -594,38 +630,55 @@
}
inoutConfig.densityDpi = displayDensity;
if (isScalingRequired()) {
- scaleConfiguration(applicationInvertedScale, inoutConfig);
+ scaleConfiguration(applicationInvertedScale, applicationDensityInvertedScale,
+ inoutConfig);
}
}
/** Scales the density and bounds of the given configuration. */
- public static void scaleConfiguration(float invertedRatio, Configuration inoutConfig) {
- inoutConfig.densityDpi = (int) ((inoutConfig.densityDpi * invertedRatio) + .5f);
- inoutConfig.windowConfiguration.scale(invertedRatio);
+ public static void scaleConfiguration(float invertScale, Configuration inoutConfig) {
+ scaleConfiguration(invertScale, invertScale, inoutConfig);
+ }
+
+ /** Scales the density and bounds of the given configuration. */
+ public static void scaleConfiguration(float invertScale, float densityInvertScale,
+ Configuration inoutConfig) {
+ inoutConfig.densityDpi = (int) ((inoutConfig.densityDpi
+ * densityInvertScale) + .5f);
+ inoutConfig.windowConfiguration.scale(invertScale);
}
/** @see #sOverrideInvertedScale */
public static void applyOverrideScaleIfNeeded(Configuration config) {
if (!hasOverrideScale()) return;
- scaleConfiguration(sOverrideInvertedScale, config);
+ scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, config);
}
/** @see #sOverrideInvertedScale */
public static void applyOverrideScaleIfNeeded(MergedConfiguration mergedConfig) {
if (!hasOverrideScale()) return;
- scaleConfiguration(sOverrideInvertedScale, mergedConfig.getGlobalConfiguration());
- scaleConfiguration(sOverrideInvertedScale, mergedConfig.getOverrideConfiguration());
- scaleConfiguration(sOverrideInvertedScale, mergedConfig.getMergedConfiguration());
+ scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale,
+ mergedConfig.getGlobalConfiguration());
+ scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale,
+ mergedConfig.getOverrideConfiguration());
+ scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale,
+ mergedConfig.getMergedConfiguration());
}
/** Returns {@code true} if this process is in a environment with override scale. */
private static boolean hasOverrideScale() {
- return sOverrideInvertedScale != 1f;
+ return sOverrideInvertedScale != 1f || sOverrideDensityInvertScale != 1f;
}
/** @see #sOverrideInvertedScale */
- public static void setOverrideInvertedScale(float invertedRatio) {
- sOverrideInvertedScale = invertedRatio;
+ public static void setOverrideInvertedScale(float invertScale) {
+ setOverrideInvertedScale(invertScale, invertScale);
+ }
+
+ /** @see #sOverrideInvertedScale */
+ public static void setOverrideInvertedScale(float invertScale, float densityInvertScale) {
+ sOverrideInvertedScale = invertScale;
+ sOverrideDensityInvertScale = densityInvertScale;
}
/** @see #sOverrideInvertedScale */
@@ -633,6 +686,11 @@
return sOverrideInvertedScale;
}
+ /** @see #sOverrideDensityInvertScale */
+ public static float getOverrideDensityInvertedScale() {
+ return sOverrideDensityInvertScale;
+ }
+
/**
* Compute the frame Rect for applications runs under compatibility mode.
*
@@ -693,6 +751,8 @@
if (applicationDensity != oc.applicationDensity) return false;
if (applicationScale != oc.applicationScale) return false;
if (applicationInvertedScale != oc.applicationInvertedScale) return false;
+ if (applicationDensityScale != oc.applicationDensityScale) return false;
+ if (applicationDensityInvertedScale != oc.applicationDensityInvertedScale) return false;
return true;
} catch (ClassCastException e) {
return false;
@@ -713,6 +773,8 @@
if (hasOverrideScaling()) {
sb.append(" overrideInvScale=");
sb.append(applicationInvertedScale);
+ sb.append(" overrideDensityInvScale=");
+ sb.append(applicationDensityInvertedScale);
}
if (!supportsScreen()) {
sb.append(" resizing");
@@ -734,6 +796,8 @@
result = 31 * result + applicationDensity;
result = 31 * result + Float.floatToIntBits(applicationScale);
result = 31 * result + Float.floatToIntBits(applicationInvertedScale);
+ result = 31 * result + Float.floatToIntBits(applicationDensityScale);
+ result = 31 * result + Float.floatToIntBits(applicationDensityInvertedScale);
return result;
}
@@ -748,6 +812,8 @@
dest.writeInt(applicationDensity);
dest.writeFloat(applicationScale);
dest.writeFloat(applicationInvertedScale);
+ dest.writeFloat(applicationDensityScale);
+ dest.writeFloat(applicationDensityInvertedScale);
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -769,5 +835,61 @@
applicationDensity = source.readInt();
applicationScale = source.readFloat();
applicationInvertedScale = source.readFloat();
+ applicationDensityScale = source.readFloat();
+ applicationDensityInvertedScale = source.readFloat();
+ }
+
+ /**
+ * A data class for holding scale factor for width, height, and density.
+ */
+ public static final class CompatScale {
+
+ public final float mScaleFactor;
+ public final float mDensityScaleFactor;
+
+ public CompatScale(float scaleFactor) {
+ this(scaleFactor, scaleFactor);
+ }
+
+ public CompatScale(float scaleFactor, float densityScaleFactor) {
+ mScaleFactor = scaleFactor;
+ mDensityScaleFactor = densityScaleFactor;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof CompatScale)) {
+ return false;
+ }
+ try {
+ CompatScale oc = (CompatScale) o;
+ if (mScaleFactor != oc.mScaleFactor) return false;
+ if (mDensityScaleFactor != oc.mDensityScaleFactor) return false;
+ return true;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("mScaleFactor= ");
+ sb.append(mScaleFactor);
+ sb.append(" mDensityScaleFactor= ");
+ sb.append(mDensityScaleFactor);
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + Float.floatToIntBits(mScaleFactor);
+ result = 31 * result + Float.floatToIntBits(mDensityScaleFactor);
+ return result;
+ }
}
}
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index b2dfd85..4f07acf 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -23,6 +23,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
+import android.util.ArraySet;
import com.android.internal.annotations.GuardedBy;
@@ -34,7 +35,6 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
-import java.util.stream.Collectors;
/**
* @hide
@@ -45,8 +45,8 @@
private final Object mLock = new Object();
@GuardedBy("mLock")
- private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mPrograms =
- new ArrayMap<>();
+ private final Map<ProgramSelector.Identifier, Map<UniqueProgramIdentifier,
+ RadioManager.ProgramInfo>> mPrograms = new ArrayMap<>();
@GuardedBy("mLock")
private final List<ListCallback> mListCallbacks = new ArrayList<>();
@@ -193,7 +193,7 @@
void apply(Chunk chunk) {
List<ProgramSelector.Identifier> removedList = new ArrayList<>();
- List<ProgramSelector.Identifier> changedList = new ArrayList<>();
+ Set<ProgramSelector.Identifier> changedSet = new ArraySet<>();
List<ProgramList.ListCallback> listCallbacksCopied;
List<OnCompleteListener> onCompleteListenersCopied = new ArrayList<>();
synchronized (mLock) {
@@ -203,19 +203,27 @@
listCallbacksCopied = new ArrayList<>(mListCallbacks);
if (chunk.isPurge()) {
- Iterator<Map.Entry<ProgramSelector.Identifier, RadioManager.ProgramInfo>>
- programsIterator = mPrograms.entrySet().iterator();
+ Iterator<Map.Entry<ProgramSelector.Identifier, Map<UniqueProgramIdentifier,
+ RadioManager.ProgramInfo>>> programsIterator =
+ mPrograms.entrySet().iterator();
while (programsIterator.hasNext()) {
- RadioManager.ProgramInfo removed = programsIterator.next().getValue();
- if (removed != null) {
- removedList.add(removed.getSelector().getPrimaryId());
+ Map.Entry<ProgramSelector.Identifier, Map<UniqueProgramIdentifier,
+ RadioManager.ProgramInfo>> removed = programsIterator.next();
+ if (removed.getValue() != null) {
+ removedList.add(removed.getKey());
}
programsIterator.remove();
}
}
- chunk.getRemoved().stream().forEach(id -> removeLocked(id, removedList));
- chunk.getModified().stream().forEach(info -> putLocked(info, changedList));
+ Iterator<UniqueProgramIdentifier> removedIterator = chunk.getRemoved().iterator();
+ while (removedIterator.hasNext()) {
+ removeLocked(removedIterator.next(), removedList);
+ }
+ Iterator<RadioManager.ProgramInfo> modifiedIterator = chunk.getModified().iterator();
+ while (modifiedIterator.hasNext()) {
+ putLocked(modifiedIterator.next(), changedSet);
+ }
if (chunk.isComplete()) {
mIsComplete = true;
@@ -228,9 +236,11 @@
listCallbacksCopied.get(cbIndex).onItemRemoved(removedList.get(i));
}
}
- for (int i = 0; i < changedList.size(); i++) {
+ Iterator<ProgramSelector.Identifier> changedIterator = changedSet.iterator();
+ while (changedIterator.hasNext()) {
+ ProgramSelector.Identifier changedId = changedIterator.next();
for (int cbIndex = 0; cbIndex < listCallbacksCopied.size(); cbIndex++) {
- listCallbacksCopied.get(cbIndex).onItemChanged(changedList.get(i));
+ listCallbacksCopied.get(cbIndex).onItemChanged(changedId);
}
}
if (chunk.isComplete()) {
@@ -242,20 +252,31 @@
@GuardedBy("mLock")
private void putLocked(RadioManager.ProgramInfo value,
- List<ProgramSelector.Identifier> changedIdentifierList) {
- ProgramSelector.Identifier key = value.getSelector().getPrimaryId();
- mPrograms.put(Objects.requireNonNull(key), value);
- ProgramSelector.Identifier sel = value.getSelector().getPrimaryId();
- changedIdentifierList.add(sel);
+ Set<ProgramSelector.Identifier> changedIdentifierSet) {
+ UniqueProgramIdentifier key = new UniqueProgramIdentifier(
+ value.getSelector());
+ ProgramSelector.Identifier primaryKey = Objects.requireNonNull(key.getPrimaryId());
+ if (!mPrograms.containsKey(primaryKey)) {
+ mPrograms.put(primaryKey, new ArrayMap<>());
+ }
+ mPrograms.get(primaryKey).put(key, value);
+ changedIdentifierSet.add(primaryKey);
}
@GuardedBy("mLock")
- private void removeLocked(ProgramSelector.Identifier key,
+ private void removeLocked(UniqueProgramIdentifier key,
List<ProgramSelector.Identifier> removedIdentifierList) {
- RadioManager.ProgramInfo removed = mPrograms.remove(Objects.requireNonNull(key));
+ ProgramSelector.Identifier primaryKey = Objects.requireNonNull(key.getPrimaryId());
+ if (!mPrograms.containsKey(primaryKey)) {
+ return;
+ }
+ Map<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries = mPrograms
+ .get(primaryKey);
+ RadioManager.ProgramInfo removed = entries.remove(Objects.requireNonNull(key));
if (removed == null) return;
- ProgramSelector.Identifier sel = removed.getSelector().getPrimaryId();
- removedIdentifierList.add(sel);
+ if (entries.size() == 0) {
+ removedIdentifierList.add(primaryKey);
+ }
}
/**
@@ -264,9 +285,20 @@
* @return the new List<> object; it won't receive any further updates
*/
public @NonNull List<RadioManager.ProgramInfo> toList() {
+ List<RadioManager.ProgramInfo> list = new ArrayList<>();
synchronized (mLock) {
- return mPrograms.values().stream().collect(Collectors.toList());
+ Iterator<Map.Entry<ProgramSelector.Identifier, Map<UniqueProgramIdentifier,
+ RadioManager.ProgramInfo>>> listIterator = mPrograms.entrySet().iterator();
+ while (listIterator.hasNext()) {
+ Iterator<Map.Entry<UniqueProgramIdentifier,
+ RadioManager.ProgramInfo>> prorgramsIterator = listIterator.next()
+ .getValue().entrySet().iterator();
+ while (prorgramsIterator.hasNext()) {
+ list.add(prorgramsIterator.next().getValue());
+ }
+ }
}
+ return list;
}
/**
@@ -276,9 +308,15 @@
* @return the program info, or null if there is no such program on the list
*/
public @Nullable RadioManager.ProgramInfo get(@NonNull ProgramSelector.Identifier id) {
+ Map<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries;
synchronized (mLock) {
- return mPrograms.get(Objects.requireNonNull(id));
+ entries = mPrograms.get(Objects.requireNonNull(id,
+ "Primary identifier can not be null"));
}
+ if (entries == null) {
+ return null;
+ }
+ return entries.entrySet().iterator().next().getValue();
}
/**
@@ -404,7 +442,7 @@
* Checks, if non-tunable entries that define tree structure on the
* program list (i.e. DAB ensembles) should be included.
*
- * @see {@link ProgramSelector.Identifier#isCategory()}
+ * @see ProgramSelector.Identifier#isCategoryType()
*/
public boolean areCategoriesIncluded() {
return mIncludeCategories;
@@ -459,11 +497,11 @@
private final boolean mPurge;
private final boolean mComplete;
private final @NonNull Set<RadioManager.ProgramInfo> mModified;
- private final @NonNull Set<ProgramSelector.Identifier> mRemoved;
+ private final @NonNull Set<UniqueProgramIdentifier> mRemoved;
public Chunk(boolean purge, boolean complete,
@Nullable Set<RadioManager.ProgramInfo> modified,
- @Nullable Set<ProgramSelector.Identifier> removed) {
+ @Nullable Set<UniqueProgramIdentifier> removed) {
mPurge = purge;
mComplete = complete;
mModified = (modified != null) ? modified : Collections.emptySet();
@@ -474,7 +512,7 @@
mPurge = in.readByte() != 0;
mComplete = in.readByte() != 0;
mModified = Utils.createSet(in, RadioManager.ProgramInfo.CREATOR);
- mRemoved = Utils.createSet(in, ProgramSelector.Identifier.CREATOR);
+ mRemoved = Utils.createSet(in, UniqueProgramIdentifier.CREATOR);
}
@Override
@@ -512,7 +550,7 @@
return mModified;
}
- public @NonNull Set<ProgramSelector.Identifier> getRemoved() {
+ public @NonNull Set<UniqueProgramIdentifier> getRemoved() {
return mRemoved;
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index f1ae9be..7967db6 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -685,7 +685,12 @@
private ImeTracker.Token mCurStatsToken;
final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
+ Log.i("b/297000797", "IME#OnComputeInternalInsetsListener, start info: " + info
+ + " before onComputeInsets, tmpInsets: " + mTmpInsets,
+ new Throwable());
onComputeInsets(mTmpInsets);
+ Log.i("b/297000797", "IME#OnComputeInternalInsetsListener,"
+ + " after onComputeInsets, tmpInsets: " + mTmpInsets);
if (!mViewsCreated) {
// The IME views are not ready, keep visible insets untouched.
mTmpInsets.visibleTopInsets = 0;
@@ -705,6 +710,7 @@
}
mNavigationBarController.updateTouchableInsets(mTmpInsets, info);
+ Log.i("b/297000797", "IME#OnComputeInternalInsetsListener, end info: " + info);
if (mInputFrame != null) {
setImeExclusionRect(mTmpInsets.visibleTopInsets);
}
@@ -1463,6 +1469,15 @@
proto.write(TOUCHABLE_REGION, touchableRegion.toString());
proto.end(token);
}
+
+ @Override
+ public String toString() {
+ return "Insets{contentTopInsets=" + contentTopInsets
+ + " visibleTopInsets=" + visibleTopInsets
+ + " touchableInsets=" + touchableInsets
+ + " touchableRegion=" + touchableRegion.getBounds()
+ + "}";
+ }
}
/**
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 8be4c58..22792a5 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -31,6 +31,7 @@
import android.graphics.Region;
import android.inputmethodservice.navigationbar.NavigationBarFrame;
import android.inputmethodservice.navigationbar.NavigationBarView;
+import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -114,6 +115,8 @@
}
void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {
+ Log.i("b/297000797", "NavigationBarController#onNavButtonFlagsChanged: " + navButtonFlags,
+ new Throwable());
mImpl.onNavButtonFlagsChanged(navButtonFlags);
}
@@ -235,6 +238,10 @@
if (ENABLE_HIDE_IME_CAPTION_BAR) {
mNavigationBarFrame.setOnApplyWindowInsetsListener((view, insets) -> {
+ Log.i("b/297000797", "NavigationBarController#onApplyWindowInsetsListener:"
+ + " mNavigationBarFrame: " + mNavigationBarFrame
+ + " captionBar visible: " + insets.isVisible(captionBar())
+ + " insets: " + insets);
if (mNavigationBarFrame != null) {
boolean visible = insets.isVisible(captionBar());
mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.GONE);
@@ -453,6 +460,10 @@
mShouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherWhenImeIsShown;
if (ENABLE_HIDE_IME_CAPTION_BAR) {
+ Log.i("b/297000797", "NavigationBarController#onNavButtonFlagsChanged,"
+ + " calling setImeCaptionBarInsetsHeight"
+ + " with: " + getImeCaptionBarHeight(),
+ new Throwable());
mService.mWindow.getWindow().getDecorView().getWindowInsetsController()
.setImeCaptionBarInsetsHeight(getImeCaptionBarHeight());
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c6cb604..80b7d40 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4663,26 +4663,6 @@
}
/**
- * Returns number of full users on the device.
- * @hide
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.MANAGE_USERS,
- android.Manifest.permission.CREATE_USERS
- })
- public int getFullUserCount() {
- List<UserInfo> users = getUsers(/* excludePartial= */ true, /* excludeDying= */ true,
- /* excludePreCreated= */ true);
- int count = 0;
- for (UserInfo user : users) {
- if (user.isFull()) {
- count++;
- }
- }
- return count;
- }
-
- /**
* @deprecated use {@link #getAliveUsers()} for {@code getUsers(true)}, or
* {@link #getUsers()} for @code getUsers(false)}.
*
diff --git a/core/java/android/security/FileIntegrityManager.java b/core/java/android/security/FileIntegrityManager.java
index d6f3bf3..132700d 100644
--- a/core/java/android/security/FileIntegrityManager.java
+++ b/core/java/android/security/FileIntegrityManager.java
@@ -133,13 +133,11 @@
* also use this API to download the best signature on the running device.
*
* @return whether the certificate is trusted in the system
- * @deprecated The feature is no longer supported, and this API now always returns false.
*/
@RequiresPermission(anyOf = {
android.Manifest.permission.INSTALL_PACKAGES,
android.Manifest.permission.REQUEST_INSTALL_PACKAGES
})
- @Deprecated
public boolean isAppSourceCertificateTrusted(@NonNull X509Certificate certificate)
throws CertificateEncodingException {
try {
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index b27dac2..b6c2b83 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -6,3 +6,10 @@
description: "Feature flag for fs-verity API"
bug: "285185747"
}
+
+flag {
+ name: "fix_unlocked_device_required_keys"
+ namespace: "hardware_backed_security"
+ description: "Fix bugs in behavior of UnlockedDeviceRequired keystore keys"
+ bug: "296464083"
+}
diff --git a/core/java/android/service/voice/HotwordTrainingAudio.java b/core/java/android/service/voice/HotwordTrainingAudio.java
index 895b0c0..91e34dc 100644
--- a/core/java/android/service/voice/HotwordTrainingAudio.java
+++ b/core/java/android/service/voice/HotwordTrainingAudio.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.media.AudioFormat;
import android.os.Parcel;
@@ -25,6 +26,8 @@
import com.android.internal.util.DataClass;
+import java.util.Objects;
+
/**
* Represents audio supporting hotword model training.
*
@@ -43,7 +46,10 @@
/** Represents unset value for the hotword offset. */
public static final int HOTWORD_OFFSET_UNSET = -1;
- /** Buffer of hotword audio data for training models. */
+ /**
+ * Buffer of hotword audio data for training models. The data format is expected to match
+ * {@link #getAudioFormat()}.
+ */
@NonNull
private final byte[] mHotwordAudio;
@@ -74,6 +80,24 @@
*/
private int mHotwordOffsetMillis = HOTWORD_OFFSET_UNSET;
+ @DataClass.Suppress("setHotwordAudio")
+ abstract static class BaseBuilder {
+
+ /**
+ * Buffer of hotword audio data for training models. The data format is expected to match
+ * {@link #getAudioFormat()}.
+ */
+ @SuppressLint("UnflaggedApi")
+ public @NonNull HotwordTrainingAudio.Builder setHotwordAudio(@NonNull byte[] value) {
+ Objects.requireNonNull(value, "value should not be null");
+ final HotwordTrainingAudio.Builder builder = (HotwordTrainingAudio.Builder) this;
+ // If the code gen flag in build() is changed, we must update the flag e.g. 0x1 here.
+ builder.mBuilderFieldsSet |= 0x1;
+ builder.mHotwordAudio = value;
+ return builder;
+ }
+ }
+
// Code below generated by codegen v1.0.23.
@@ -110,7 +134,8 @@
}
/**
- * Buffer of hotword audio data for training models.
+ * Buffer of hotword audio data for training models. The data format is expected to match
+ * {@link #getAudioFormat()}.
*/
@DataClass.Generated.Member
public @NonNull byte[] getHotwordAudio() {
@@ -171,7 +196,7 @@
//noinspection PointlessBooleanExpression
return true
&& java.util.Arrays.equals(mHotwordAudio, that.mHotwordAudio)
- && java.util.Objects.equals(mAudioFormat, that.mAudioFormat)
+ && Objects.equals(mAudioFormat, that.mAudioFormat)
&& mAudioType == that.mAudioType
&& mHotwordOffsetMillis == that.mHotwordOffsetMillis;
}
@@ -184,7 +209,7 @@
int _hash = 1;
_hash = 31 * _hash + java.util.Arrays.hashCode(mHotwordAudio);
- _hash = 31 * _hash + java.util.Objects.hashCode(mAudioFormat);
+ _hash = 31 * _hash + Objects.hashCode(mAudioFormat);
_hash = 31 * _hash + mAudioType;
_hash = 31 * _hash + mHotwordOffsetMillis;
return _hash;
@@ -251,7 +276,7 @@
*/
@SuppressWarnings("WeakerAccess")
@DataClass.Generated.Member
- public static final class Builder {
+ public static final class Builder extends BaseBuilder {
private @NonNull byte[] mHotwordAudio;
private @NonNull AudioFormat mAudioFormat;
@@ -264,7 +289,8 @@
* Creates a new Builder.
*
* @param hotwordAudio
- * Buffer of hotword audio data for training models.
+ * Buffer of hotword audio data for training models. The data format is expected to match
+ * {@link #getAudioFormat()}.
* @param audioFormat
* The {@link AudioFormat} of the {@link HotwordTrainingAudio#mHotwordAudio}.
*/
@@ -280,17 +306,6 @@
}
/**
- * Buffer of hotword audio data for training models.
- */
- @DataClass.Generated.Member
- public @NonNull Builder setHotwordAudio(@NonNull byte... value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x1;
- mHotwordAudio = value;
- return this;
- }
-
- /**
* The {@link AudioFormat} of the {@link HotwordTrainingAudio#mHotwordAudio}.
*/
@DataClass.Generated.Member
@@ -353,10 +368,10 @@
}
@DataClass.Generated(
- time = 1692837160437L,
+ time = 1694193905346L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordTrainingAudio.java",
- inputSignatures = "public static final int HOTWORD_OFFSET_UNSET\nprivate final @android.annotation.NonNull byte[] mHotwordAudio\nprivate final @android.annotation.NonNull android.media.AudioFormat mAudioFormat\nprivate final @android.annotation.NonNull int mAudioType\nprivate int mHotwordOffsetMillis\nprivate java.lang.String hotwordAudioToString()\nprivate static int defaultAudioType()\nclass HotwordTrainingAudio extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int HOTWORD_OFFSET_UNSET\nprivate final @android.annotation.NonNull byte[] mHotwordAudio\nprivate final @android.annotation.NonNull android.media.AudioFormat mAudioFormat\nprivate final @android.annotation.NonNull int mAudioType\nprivate int mHotwordOffsetMillis\nprivate java.lang.String hotwordAudioToString()\nprivate static int defaultAudioType()\nclass HotwordTrainingAudio extends java.lang.Object implements [android.os.Parcelable]\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.service.voice.HotwordTrainingAudio.Builder setHotwordAudio(byte[])\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.service.voice.HotwordTrainingAudio.Builder setHotwordAudio(byte[])\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index fb24211..9186e49 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1856,6 +1856,8 @@
return;
}
Rect newFrame = new Rect(mFrame.left, mFrame.bottom - height, mFrame.right, mFrame.bottom);
+ Log.i("b/297000797", "InsetsController#setImeCaptionBarInsetsHeight,"
+ + " height: " + height + " frame: " + mFrame);
InsetsSource source = mState.peekSource(ID_IME_CAPTION_BAR);
if (mImeCaptionBarInsetsHeight != height
|| (source != null && !newFrame.equals(source.getFrame()))) {
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 0d5704e..3e435ae 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -31,6 +31,7 @@
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.WindowInsets.Type.InsetsType;
@@ -196,6 +197,12 @@
* source.
*/
public Insets calculateInsets(Rect relativeFrame, boolean ignoreVisibility) {
+ if (getType() == WindowInsets.Type.ime()) {
+ Log.i("b/297000797", "InsetsSource#calculateInsets tmpFrame: " + mTmpFrame
+ + " ignoreVisibility: " + ignoreVisibility
+ + " frame: " + mFrame
+ + " relativeFrame: " + relativeFrame, new Throwable());
+ }
return calculateInsets(relativeFrame, mFrame, ignoreVisibility);
}
@@ -203,6 +210,12 @@
* Like {@link #calculateInsets(Rect, boolean)}, but will return visible insets.
*/
public Insets calculateVisibleInsets(Rect relativeFrame) {
+ if (getType() == WindowInsets.Type.ime()) {
+ Log.i("b/297000797", "InsetsSource#calculateVisibleInsets tmpFrame: " + mTmpFrame
+ + " frame: " + mFrame
+ + " visibleFrame: " + mVisibleFrame
+ + " relativeFrame: " + relativeFrame, new Throwable());
+ }
return calculateInsets(relativeFrame, mVisibleFrame != null ? mVisibleFrame : mFrame,
false /* ignoreVisibility */);
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 59e0932..eac7408 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -45,6 +45,7 @@
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
@@ -380,6 +381,9 @@
@InternalInsetsSide @Nullable SparseIntArray idSideMap,
@Nullable boolean[] typeVisibilityMap, Insets insets, int type) {
int index = indexOf(type);
+ if (source.getId() == InsetsSource.ID_IME) {
+ Log.i("b/297000797", "InsetsState#processSourceAsPublicType, ime insets: " + insets);
+ }
// Don't put Insets.NONE into typeInsetsMap. Otherwise, two WindowInsets can be considered
// as non-equal while they provide the same insets of each type from WindowInsets#getInsets
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index c9526fd..9e8ca20 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -315,6 +315,15 @@
}
@Override
+ public String toString() {
+ return "InternalInsetsInfo{contentInsets=" + contentInsets
+ + " visibleInsets=" + visibleInsets
+ + " touchableRegion=" + touchableRegion.getBounds()
+ + "}";
+
+ }
+
+ @Override
public int hashCode() {
int result = contentInsets.hashCode();
result = 31 * result + visibleInsets.hashCode();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index b8385c6..e64274e 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3139,15 +3139,6 @@
public static final int PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS = 1 << 10;
/**
- * Flag to force the status bar window to be visible all the time. If the bar is hidden when
- * this flag is set it will be shown again.
- * This can only be set by {@link LayoutParams#TYPE_STATUS_BAR}.
- *
- * {@hide}
- */
- public static final int PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR = 1 << 11;
-
- /**
* Flag to indicate that the window frame should be the requested frame adding the display
* cutout frame. This will only be applied if a specific size smaller than the parent frame
* is given, and the window is covering the display cutout. The extended frame will not be
@@ -3238,15 +3229,6 @@
public static final int PRIVATE_FLAG_NOT_MAGNIFIABLE = 1 << 22;
/**
- * Flag to indicate that the status bar window is in a state such that it forces showing
- * the navigation bar unless the navigation bar window is explicitly set to
- * {@link View#GONE}.
- * It only takes effects if this is set by {@link LayoutParams#TYPE_STATUS_BAR}.
- * @hide
- */
- public static final int PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION = 1 << 23;
-
- /**
* Flag to indicate that the window is color space agnostic, and the color can be
* interpreted to any color space.
* @hide
@@ -3334,7 +3316,6 @@
PRIVATE_FLAG_SYSTEM_ERROR,
PRIVATE_FLAG_OPTIMIZE_MEASURE,
PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS,
- PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT,
PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY,
PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME,
@@ -3345,7 +3326,6 @@
PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION,
PRIVATE_FLAG_NOT_MAGNIFIABLE,
- PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
PRIVATE_FLAG_USE_BLAST,
PRIVATE_FLAG_APPEARANCE_CONTROLLED,
@@ -3401,10 +3381,6 @@
equals = PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS,
name = "DISABLE_WALLPAPER_TOUCH_EVENTS"),
@ViewDebug.FlagToString(
- mask = PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
- equals = PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
- name = "FORCE_STATUS_BAR_VISIBLE"),
- @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT,
equals = PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT,
name = "LAYOUT_SIZE_EXTENDED_BY_CUTOUT"),
@@ -3445,10 +3421,6 @@
equals = PRIVATE_FLAG_NOT_MAGNIFIABLE,
name = "NOT_MAGNIFIABLE"),
@ViewDebug.FlagToString(
- mask = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
- equals = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
- name = "STATUS_FORCE_SHOW_NAVIGATION"),
- @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
equals = PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
name = "COLOR_SPACE_AGNOSTIC"),
@@ -4412,6 +4384,16 @@
public InsetsFrameProvider[] providedInsets;
/**
+ * Specifies which {@link InsetsType}s should be forcibly shown. The types shown by this
+ * method won't affect the app's layout. This field only takes effects if the caller has
+ * {@link android.Manifest.permission#STATUS_BAR_SERVICE} or the caller has the same uid as
+ * the recents component.
+ *
+ * @hide
+ */
+ public @InsetsType int forciblyShownTypes;
+
+ /**
* {@link LayoutParams} to be applied to the window when layout with a assigned rotation.
* This will make layout during rotation change smoothly.
*
@@ -4869,6 +4851,7 @@
out.writeInt(mBlurBehindRadius);
out.writeBoolean(mWallpaperTouchEventsEnabled);
out.writeTypedArray(providedInsets, 0 /* parcelableFlags */);
+ out.writeInt(forciblyShownTypes);
checkNonRecursiveParams();
out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
out.writeInt(mDisplayFlags);
@@ -4940,6 +4923,7 @@
mBlurBehindRadius = in.readInt();
mWallpaperTouchEventsEnabled = in.readBoolean();
providedInsets = in.createTypedArray(InsetsFrameProvider.CREATOR);
+ forciblyShownTypes = in.readInt();
paramsForRotation = in.createTypedArray(LayoutParams.CREATOR);
mDisplayFlags = in.readInt();
}
@@ -5245,6 +5229,11 @@
changes |= LAYOUT_CHANGED;
}
+ if (forciblyShownTypes != o.forciblyShownTypes) {
+ forciblyShownTypes = o.forciblyShownTypes;
+ changes |= PRIVATE_FLAGS_CHANGED;
+ }
+
if (paramsForRotation != o.paramsForRotation) {
if ((changes & LAYOUT_CHANGED) == 0) {
if (paramsForRotation != null && o.paramsForRotation != null
@@ -5482,6 +5471,11 @@
sb.append(prefix).append(" ").append(providedInsets[i]);
}
}
+ if (forciblyShownTypes != 0) {
+ sb.append(System.lineSeparator());
+ sb.append(prefix).append(" forciblyShownTypes=").append(
+ WindowInsets.Type.toString(forciblyShownTypes));
+ }
if (paramsForRotation != null && paramsForRotation.length != 0) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" paramsForRotation:");
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 3e16df4d..9d66174 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1123,6 +1123,7 @@
final Insets systemInsets = clearsCompatInsets
? Insets.NONE
: Insets.min(insets.getInsets(compatInsetsTypes), stableBarInsets);
+ Log.i("b/297000797", "DecorView#updateColorViews, systemInsets: " + systemInsets);
mLastTopInset = systemInsets.top;
mLastBottomInset = systemInsets.bottom;
mLastRightInset = systemInsets.right;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 32fe4e3..3180ffb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1466,10 +1466,9 @@
<!-- Allows an application to initiate a phone call without going through
the Dialer user interface for the user to confirm the call.
- <p>
- <em>Note: An app holding this permission can also call carrier MMI codes to change settings
- such as call forwarding or call waiting preferences.
- <p>Protection level: dangerous
+ <p class="note"><b>Note:</b> An app holding this permission can also call carrier MMI
+ codes to change settings such as call forwarding or call waiting preferences.</p>
+ <p>Protection level: dangerous</p>
-->
<permission android:name="android.permission.CALL_PHONE"
android:permissionGroup="android.permission-group.UNDEFINED"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7d2690e..e7764d8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5717,13 +5717,13 @@
<!-- Blur radius for the Option 3 in R.integer.config_letterboxBackgroundType. Values < 0 are
ignored and 0 is used. -->
- <dimen name="config_letterboxBackgroundWallpaperBlurRadius">24dp</dimen>
+ <dimen name="config_letterboxBackgroundWallpaperBlurRadius">38dp</dimen>
<!-- Alpha of a black translucent scrim showed over wallpaper letterbox background when
the Option 3 is selected for R.integer.config_letterboxBackgroundType.
Values < 0 or >= 1 are ignored and 0.0 (transparent) is used instead. -->
<item name="config_letterboxBackgroundWallaperDarkScrimAlpha" format="float" type="dimen">
- 0.75
+ 0.54
</item>
<!-- Corners appearance of the letterbox background.
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java
index 7c3d2f2..d638fed 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java
@@ -74,18 +74,45 @@
private static final ProgramSelector.Identifier DAB_ENSEMBLE_IDENTIFIER =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
/* value= */ 0x1013);
+ private static final ProgramSelector.Identifier DAB_FREQUENCY_IDENTIFIER_1 =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
+ /* value= */ 222_064);
+ private static final ProgramSelector.Identifier DAB_FREQUENCY_IDENTIFIER_2 =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
+ /* value= */ 220_352);
+
+ private static final ProgramSelector DAB_SELECTOR_1 = new ProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_DAB, DAB_DMB_SID_EXT_IDENTIFIER,
+ new ProgramSelector.Identifier[]{DAB_ENSEMBLE_IDENTIFIER, DAB_FREQUENCY_IDENTIFIER_1},
+ /* vendorIds= */ null);
+ private static final ProgramSelector DAB_SELECTOR_2 = new ProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_DAB, DAB_DMB_SID_EXT_IDENTIFIER,
+ new ProgramSelector.Identifier[]{DAB_ENSEMBLE_IDENTIFIER, DAB_FREQUENCY_IDENTIFIER_2},
+ /* vendorIds= */ null);
+
+ private static final UniqueProgramIdentifier RDS_UNIQUE_IDENTIFIER =
+ new UniqueProgramIdentifier(RDS_IDENTIFIER);
+ private static final UniqueProgramIdentifier DAB_UNIQUE_IDENTIFIER_1 =
+ new UniqueProgramIdentifier(DAB_SELECTOR_1);
+ private static final UniqueProgramIdentifier DAB_UNIQUE_IDENTIFIER_2 =
+ new UniqueProgramIdentifier(DAB_SELECTOR_2);
+
private static final RadioManager.ProgramInfo FM_PROGRAM_INFO = createFmProgramInfo(
createProgramSelector(ProgramSelector.PROGRAM_TYPE_FM, FM_IDENTIFIER));
- private static final RadioManager.ProgramInfo RDS_PROGRAM_INFO = createFmProgramInfo(
- createProgramSelector(ProgramSelector.PROGRAM_TYPE_FM, RDS_IDENTIFIER));
+ private static final RadioManager.ProgramInfo DAB_PROGRAM_INFO_1 = createDabProgramInfo(
+ DAB_SELECTOR_1);
+ private static final RadioManager.ProgramInfo DAB_PROGRAM_INFO_2 = createDabProgramInfo(
+ DAB_SELECTOR_2);
private static final Set<Integer> FILTER_IDENTIFIER_TYPES = Set.of(
- ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, ProgramSelector.IDENTIFIER_TYPE_RDS_PI);
- private static final Set<ProgramSelector.Identifier> FILTER_IDENTIFIERS = Set.of(FM_IDENTIFIER);
+ ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
+ ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT);
+ private static final Set<ProgramSelector.Identifier> FILTER_IDENTIFIERS = Set.of(
+ FM_IDENTIFIER, DAB_DMB_SID_EXT_IDENTIFIER);
- private static final ProgramList.Chunk FM_RDS_ADD_CHUNK = new ProgramList.Chunk(IS_PURGE,
- IS_COMPLETE, Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
- Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
+ private static final ProgramList.Chunk FM_DAB_ADD_CHUNK = new ProgramList.Chunk(IS_PURGE,
+ IS_COMPLETE, Set.of(FM_PROGRAM_INFO, DAB_PROGRAM_INFO_1, DAB_PROGRAM_INFO_2),
+ Set.of(RDS_UNIQUE_IDENTIFIER));
private static final ProgramList.Chunk FM_ADD_INCOMPLETE_CHUNK = new ProgramList.Chunk(IS_PURGE,
/* complete= */ false, Set.of(FM_PROGRAM_INFO), new ArraySet<>());
private static final ProgramList.Filter TEST_FILTER = new ProgramList.Filter(
@@ -213,58 +240,44 @@
@Test
public void isPurge_forChunk() {
- ProgramList.Chunk chunk = new ProgramList.Chunk(IS_PURGE, IS_COMPLETE,
- Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
- Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
-
- assertWithMessage("Puring chunk").that(chunk.isPurge()).isEqualTo(IS_PURGE);
+ assertWithMessage("Puring chunk").that(FM_DAB_ADD_CHUNK.isPurge()).isEqualTo(IS_PURGE);
}
@Test
public void isComplete_forChunk() {
- ProgramList.Chunk chunk = new ProgramList.Chunk(IS_PURGE, IS_COMPLETE,
- Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
- Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
-
- assertWithMessage("Complete chunk").that(chunk.isComplete()).isEqualTo(IS_COMPLETE);
+ assertWithMessage("Complete chunk").that(FM_DAB_ADD_CHUNK.isComplete())
+ .isEqualTo(IS_COMPLETE);
}
@Test
public void getModified_forChunk() {
- ProgramList.Chunk chunk = new ProgramList.Chunk(IS_PURGE, IS_COMPLETE,
- Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
- Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
-
assertWithMessage("Modified program info in chunk")
- .that(chunk.getModified()).containsExactly(FM_PROGRAM_INFO, RDS_PROGRAM_INFO);
+ .that(FM_DAB_ADD_CHUNK.getModified())
+ .containsExactly(FM_PROGRAM_INFO, DAB_PROGRAM_INFO_1, DAB_PROGRAM_INFO_2);
}
@Test
public void getRemoved_forChunk() {
- ProgramList.Chunk chunk = new ProgramList.Chunk(IS_PURGE, IS_COMPLETE,
- Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
- Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
-
- assertWithMessage("Removed program identifiers in chunk").that(chunk.getRemoved())
- .containsExactly(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER);
+ assertWithMessage("Removed program identifiers in chunk")
+ .that(FM_DAB_ADD_CHUNK.getRemoved()).containsExactly(RDS_UNIQUE_IDENTIFIER);
}
@Test
public void describeContents_forChunk() {
- assertWithMessage("Chunk contents").that(FM_RDS_ADD_CHUNK.describeContents()).isEqualTo(0);
+ assertWithMessage("Chunk contents").that(FM_DAB_ADD_CHUNK.describeContents()).isEqualTo(0);
}
@Test
public void writeToParcel_forChunk() {
Parcel parcel = Parcel.obtain();
- FM_RDS_ADD_CHUNK.writeToParcel(parcel, /* flags= */ 0);
+ FM_DAB_ADD_CHUNK.writeToParcel(parcel, /* flags= */ 0);
parcel.setDataPosition(0);
ProgramList.Chunk chunkFromParcel =
ProgramList.Chunk.CREATOR.createFromParcel(parcel);
assertWithMessage("Chunk created from parcel")
- .that(chunkFromParcel).isEqualTo(FM_RDS_ADD_CHUNK);
+ .that(chunkFromParcel).isEqualTo(FM_DAB_ADD_CHUNK);
}
@Test
@@ -336,37 +349,78 @@
}
@Test
- public void onProgramListUpdated_withNewIdsAdded_invokesMockedCallbacks() throws Exception {
+ public void onProgramListUpdated_withNewIdsAdded_invokesCallbacks() throws Exception {
createRadioTuner();
mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
registerListCallbacks(/* numCallbacks= */ 1);
addOnCompleteListeners(/* numListeners= */ 1);
- mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemChanged(FM_IDENTIFIER);
- verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemChanged(RDS_IDENTIFIER);
+ verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemChanged(DAB_DMB_SID_EXT_IDENTIFIER);
verify(mOnCompleteListenerMocks[0], CALLBACK_TIMEOUT).onComplete();
- assertWithMessage("Program info in program list after adding FM and RDS info")
- .that(mProgramList.toList()).containsExactly(FM_PROGRAM_INFO, RDS_PROGRAM_INFO);
+ assertWithMessage("Program info in program list after adding FM and DAB info")
+ .that(mProgramList.toList()).containsExactly(FM_PROGRAM_INFO, DAB_PROGRAM_INFO_1,
+ DAB_PROGRAM_INFO_2);
}
@Test
- public void onProgramListUpdated_withIdsRemoved_invokesMockedCallbacks() throws Exception {
+ public void onProgramListUpdated_withFmIdsRemoved_invokesCallbacks() throws Exception {
+ UniqueProgramIdentifier fmUniqueId = new UniqueProgramIdentifier(FM_IDENTIFIER);
ProgramList.Chunk fmRemovedChunk = new ProgramList.Chunk(/* purge= */ false,
- /* complete= */ false, new ArraySet<>(), Set.of(FM_IDENTIFIER));
+ /* complete= */ false, new ArraySet<>(), Set.of(fmUniqueId));
createRadioTuner();
mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
registerListCallbacks(/* numCallbacks= */ 1);
- mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
mTunerCallback.onProgramListUpdated(fmRemovedChunk);
verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemRemoved(FM_IDENTIFIER);
assertWithMessage("Program info in program list after removing FM id")
- .that(mProgramList.toList()).containsExactly(RDS_PROGRAM_INFO);
- assertWithMessage("Program info FM identifier")
- .that(mProgramList.get(RDS_IDENTIFIER)).isEqualTo(RDS_PROGRAM_INFO);
+ .that(mProgramList.toList()).containsExactly(DAB_PROGRAM_INFO_1,
+ DAB_PROGRAM_INFO_2);
+ }
+
+ @Test
+ public void onProgramListUpdated_withPartOfDabIdsRemoved_doesNotInvokeCallbacks()
+ throws Exception {
+ ProgramList.Chunk dabRemovedChunk1 = new ProgramList.Chunk(/* purge= */ false,
+ /* complete= */ false, new ArraySet<>(), Set.of(DAB_UNIQUE_IDENTIFIER_1));
+ createRadioTuner();
+ mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
+ registerListCallbacks(/* numCallbacks= */ 1);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
+
+ mTunerCallback.onProgramListUpdated(dabRemovedChunk1);
+
+ verify(mListCallbackMocks[0], after(TIMEOUT_MS).never()).onItemRemoved(
+ DAB_DMB_SID_EXT_IDENTIFIER);
+ assertWithMessage("Program info in program list after removing part of DAB ids")
+ .that(mProgramList.toList()).containsExactly(FM_PROGRAM_INFO, DAB_PROGRAM_INFO_2);
+ }
+
+ @Test
+ public void onProgramListUpdated_withAllDabIdsRemoved_invokesCallbacks()
+ throws Exception {
+ ProgramList.Chunk dabRemovedChunk1 = new ProgramList.Chunk(/* purge= */ false,
+ /* complete= */ false, new ArraySet<>(), Set.of(DAB_UNIQUE_IDENTIFIER_1));
+ ProgramList.Chunk dabRemovedChunk2 = new ProgramList.Chunk(/* purge= */ false,
+ /* complete= */ false, new ArraySet<>(), Set.of(DAB_UNIQUE_IDENTIFIER_2));
+ createRadioTuner();
+ mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
+ registerListCallbacks(/* numCallbacks= */ 1);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(dabRemovedChunk1);
+ verify(mListCallbackMocks[0], after(TIMEOUT_MS).never()).onItemRemoved(
+ DAB_DMB_SID_EXT_IDENTIFIER);
+
+ mTunerCallback.onProgramListUpdated(dabRemovedChunk2);
+
+ verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemRemoved(DAB_DMB_SID_EXT_IDENTIFIER);
+ assertWithMessage("Program info in program list after removing all DAB ids")
+ .that(mProgramList.toList()).containsExactly(FM_PROGRAM_INFO);
}
@Test
@@ -388,18 +442,18 @@
createRadioTuner();
mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
registerListCallbacks(/* numCallbacks= */ 1);
- mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
mTunerCallback.onProgramListUpdated(purgeChunk);
verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemRemoved(FM_IDENTIFIER);
- verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemRemoved(RDS_IDENTIFIER);
+ verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemRemoved(DAB_DMB_SID_EXT_IDENTIFIER);
assertWithMessage("Program list after purge chunk applied")
.that(mProgramList.toList()).isEmpty();
}
@Test
- public void onProgramListUpdated_afterProgramListClosed_notInvokeMockedCallbacks()
+ public void onProgramListUpdated_afterProgramListClosed_notInvokeCallbacks()
throws Exception {
createRadioTuner();
mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
@@ -407,7 +461,7 @@
addOnCompleteListeners(/* numListeners= */ 1);
mProgramList.close();
- mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
verify(mListCallbackMocks[0], after(TIMEOUT_MS).never()).onItemChanged(any());
verify(mListCallbackMocks[0], never()).onItemChanged(any());
@@ -462,7 +516,7 @@
throws Exception {
createRadioTuner();
mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
- mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
mTunerCallback.onBackgroundScanComplete();
@@ -487,7 +541,7 @@
mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
mTunerCallback.onBackgroundScanComplete();
- mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
verify(mTunerCallbackMock, CALLBACK_TIMEOUT).onBackgroundScanComplete();
}
@@ -512,7 +566,7 @@
mock(ProgramList.OnCompleteListener.class);
mProgramList.addOnCompleteListener(mExecutor, onCompleteListenerMock);
- mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
verify(onCompleteListenerMock, CALLBACK_TIMEOUT).onComplete();
}
@@ -524,7 +578,7 @@
mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
addOnCompleteListeners(numListeners);
- mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
for (int index = 0; index < numListeners; index++) {
verify(mOnCompleteListenerMocks[index], CALLBACK_TIMEOUT).onComplete();
@@ -538,7 +592,7 @@
addOnCompleteListeners(/* numListeners= */ 1);
mProgramList.removeOnCompleteListener(mOnCompleteListenerMocks[0]);
- mTunerCallback.onProgramListUpdated(FM_RDS_ADD_CHUNK);
+ mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
verify(mOnCompleteListenerMocks[0], after(TIMEOUT_MS).never()).onComplete();
}
@@ -566,6 +620,13 @@
/* vendorInfo= */ null);
}
+ private static RadioManager.ProgramInfo createDabProgramInfo(ProgramSelector selector) {
+ return new RadioManager.ProgramInfo(selector, selector.getPrimaryId(),
+ DAB_ENSEMBLE_IDENTIFIER, /* relatedContents= */ null, /* infoFlags= */ 0,
+ /* signalQuality= */ 1, new RadioMetadata.Builder().build(),
+ /* vendorInfo= */ null);
+ }
+
private void createRadioTuner() throws Exception {
mApplicationInfo.targetSdkVersion = TEST_TARGET_SDK_VERSION;
when(mContextMock.getApplicationInfo()).thenReturn(mApplicationInfo);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java
index 6c70192..4f469bb 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java
@@ -25,6 +25,7 @@
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioMetadata;
+import android.hardware.radio.UniqueProgramIdentifier;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -149,12 +150,12 @@
static ProgramList.Chunk makeChunk(boolean purge, boolean complete,
List<RadioManager.ProgramInfo> modified,
- List<ProgramSelector.Identifier> removed) throws RemoteException {
+ List<UniqueProgramIdentifier> removed) throws RemoteException {
ArraySet<RadioManager.ProgramInfo> modifiedSet = new ArraySet<>();
if (modified != null) {
modifiedSet.addAll(modified);
}
- ArraySet<ProgramSelector.Identifier> removedSet = new ArraySet<>();
+ ArraySet<UniqueProgramIdentifier> removedSet = new ArraySet<>();
if (removed != null) {
removedSet.addAll(removed);
}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
index 2ef923d..89b91cf 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
@@ -25,7 +25,6 @@
import android.hardware.broadcastradio.IdentifierType;
import android.hardware.broadcastradio.ProgramIdentifier;
import android.hardware.broadcastradio.ProgramInfo;
-import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.broadcastradio.Properties;
import android.hardware.broadcastradio.Result;
import android.hardware.broadcastradio.VendorKeyValue;
@@ -33,6 +32,7 @@
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
+import android.hardware.radio.UniqueProgramIdentifier;
import android.os.ServiceSpecificException;
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
@@ -103,12 +103,6 @@
private static final ProgramIdentifier TEST_HAL_DAB_FREQUENCY_ID =
AidlTestUtils.makeHalIdentifier(IdentifierType.DAB_FREQUENCY_KHZ,
TEST_DAB_FREQUENCY_VALUE);
- private static final ProgramIdentifier TEST_HAL_FM_FREQUENCY_ID =
- AidlTestUtils.makeHalIdentifier(IdentifierType.AMFM_FREQUENCY_KHZ,
- TEST_FM_FREQUENCY_VALUE);
- private static final ProgramIdentifier TEST_HAL_VENDOR_ID =
- AidlTestUtils.makeHalIdentifier(IdentifierType.VENDOR_START,
- TEST_VENDOR_ID_VALUE);
private static final ProgramSelector TEST_DAB_SELECTOR = new ProgramSelector(
ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID,
@@ -117,6 +111,12 @@
private static final ProgramSelector TEST_FM_SELECTOR =
AidlTestUtils.makeFmSelector(TEST_FM_FREQUENCY_VALUE);
+ private static final UniqueProgramIdentifier TEST_DAB_UNIQUE_ID = new UniqueProgramIdentifier(
+ TEST_DAB_SELECTOR);
+
+ private static final UniqueProgramIdentifier TEST_VENDOR_UNIQUE_ID =
+ new UniqueProgramIdentifier(TEST_VENDOR_ID);
+
private static final int TEST_ENABLED_TYPE = Announcement.TYPE_EMERGENCY;
private static final int TEST_ANNOUNCEMENT_FREQUENCY = FM_LOWER_LIMIT + FM_SPACING;
@@ -326,57 +326,6 @@
}
@Test
- public void chunkFromHalProgramListChunk_withValidChunk() {
- boolean purge = false;
- boolean complete = true;
- android.hardware.broadcastradio.ProgramSelector halDabSelector =
- AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
- TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID});
- ProgramInfo halDabInfo = AidlTestUtils.makeHalProgramInfo(halDabSelector,
- TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY);
- RadioManager.ProgramInfo dabInfo =
- ConversionUtils.programInfoFromHalProgramInfo(halDabInfo);
- ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(purge, complete,
- new ProgramInfo[]{halDabInfo},
- new ProgramIdentifier[]{TEST_HAL_VENDOR_ID, TEST_HAL_FM_FREQUENCY_ID});
-
- ProgramList.Chunk chunk = ConversionUtils.chunkFromHalProgramListChunk(halChunk);
-
- expect.withMessage("Purged state of the converted valid program list chunk")
- .that(chunk.isPurge()).isEqualTo(purge);
- expect.withMessage("Completion state of the converted valid program list chunk")
- .that(chunk.isComplete()).isEqualTo(complete);
- expect.withMessage("Modified program info in the converted valid program list chunk")
- .that(chunk.getModified()).containsExactly(dabInfo);
- expect.withMessage("Removed program ides in the converted valid program list chunk")
- .that(chunk.getRemoved()).containsExactly(TEST_VENDOR_ID, TEST_FM_FREQUENCY_ID);
- }
-
- @Test
- public void chunkFromHalProgramListChunk_withInvalidModifiedProgramInfo() {
- boolean purge = true;
- boolean complete = false;
- android.hardware.broadcastradio.ProgramSelector halDabSelector =
- AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
- TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID});
- ProgramInfo halDabInfo = AidlTestUtils.makeHalProgramInfo(halDabSelector,
- TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_ENSEMBLE_ID, TEST_SIGNAL_QUALITY);
- ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(purge, complete,
- new ProgramInfo[]{halDabInfo}, new ProgramIdentifier[]{TEST_HAL_FM_FREQUENCY_ID});
-
- ProgramList.Chunk chunk = ConversionUtils.chunkFromHalProgramListChunk(halChunk);
-
- expect.withMessage("Purged state of the converted invalid program list chunk")
- .that(chunk.isPurge()).isEqualTo(purge);
- expect.withMessage("Completion state of the converted invalid program list chunk")
- .that(chunk.isComplete()).isEqualTo(complete);
- expect.withMessage("Modified program info in the converted invalid program list chunk")
- .that(chunk.getModified()).isEmpty();
- expect.withMessage("Removed program ids in the converted invalid program list chunk")
- .that(chunk.getRemoved()).containsExactly(TEST_FM_FREQUENCY_ID);
- }
-
- @Test
public void programSelectorMeetsSdkVersionRequirement_withLowerVersionId_returnsFalse() {
expect.withMessage("Selector %s without required SDK version", TEST_DAB_SELECTOR)
.that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(TEST_DAB_SELECTOR,
@@ -418,7 +367,7 @@
TEST_SIGNAL_QUALITY);
ProgramList.Chunk chunk = new ProgramList.Chunk(/* purge= */ true,
/* complete= */ true, Set.of(dabProgramInfo, fmProgramInfo),
- Set.of(TEST_DAB_SID_EXT_ID, TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID));
+ Set.of(TEST_DAB_UNIQUE_ID, TEST_VENDOR_UNIQUE_ID));
ProgramList.Chunk convertedChunk = ConversionUtils.convertChunkToTargetSdkVersion(chunk,
T_APP_UID);
@@ -434,8 +383,7 @@
.that(convertedChunk.getModified()).containsExactly(fmProgramInfo);
expect.withMessage(
"Removed program ids in the converted program list chunk with lower SDK version")
- .that(convertedChunk.getRemoved())
- .containsExactly(TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID);
+ .that(convertedChunk.getRemoved()).containsExactly(TEST_VENDOR_UNIQUE_ID);
}
@Test
@@ -446,7 +394,7 @@
TEST_SIGNAL_QUALITY);
ProgramList.Chunk chunk = new ProgramList.Chunk(/* purge= */ true,
/* complete= */ true, Set.of(dabProgramInfo, fmProgramInfo),
- Set.of(TEST_DAB_SID_EXT_ID, TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID));
+ Set.of(TEST_DAB_UNIQUE_ID, TEST_VENDOR_UNIQUE_ID));
ProgramList.Chunk convertedChunk = ConversionUtils.convertChunkToTargetSdkVersion(chunk,
U_APP_UID);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java
index d54397e..ce27bc1 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java
@@ -22,6 +22,7 @@
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
+import android.hardware.radio.UniqueProgramIdentifier;
import android.os.RemoteException;
import android.util.ArraySet;
@@ -32,6 +33,7 @@
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -43,6 +45,9 @@
private static final int TEST_SIGNAL_QUALITY = 90;
+ private static final int TEST_MAX_NUM_MODIFIED_PER_CHUNK = 2;
+ private static final int TEST_MAX_NUM_REMOVED_PER_CHUNK = 2;
+
private static final ProgramSelector.Identifier TEST_FM_FREQUENCY_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
/* value= */ 88_500);
@@ -58,6 +63,8 @@
private static final ProgramSelector.Identifier TEST_AM_FREQUENCY_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
/* value= */ 1_700);
+ private static final UniqueProgramIdentifier TEST_AM_UNIQUE_ID = new UniqueProgramIdentifier(
+ TEST_AM_FREQUENCY_ID);
private static final RadioManager.ProgramInfo TEST_AM_INFO = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM,
TEST_AM_FREQUENCY_ID), TEST_AM_FREQUENCY_ID, TEST_AM_FREQUENCY_ID,
@@ -66,6 +73,8 @@
private static final ProgramSelector.Identifier TEST_RDS_PI_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI,
/* value= */ 15_019);
+ private static final UniqueProgramIdentifier TEST_RDS_PI_UNIQUE_ID =
+ new UniqueProgramIdentifier(TEST_RDS_PI_ID);
private static final RadioManager.ProgramInfo TEST_RDS_INFO = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM, TEST_RDS_PI_ID),
TEST_RDS_PI_ID, new ProgramSelector.Identifier(
@@ -81,11 +90,27 @@
private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
/* value= */ 220_352);
- private static final RadioManager.ProgramInfo TEST_DAB_INFO = AidlTestUtils.makeProgramInfo(
- new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_DMB_SID_EXT_ID,
- new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID},
- /* vendorIds= */ null), TEST_DAB_DMB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID,
- TEST_SIGNAL_QUALITY);
+ private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID_ALTERNATIVE =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
+ /* value= */ 220_064);
+ private static final ProgramSelector TEST_DAB_SELECTOR = new ProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_DMB_SID_EXT_ID,
+ new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID},
+ /* vendorIds= */ null);
+ private static final ProgramSelector TEST_DAB_SELECTOR_ALTERNATIVE = new ProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_DMB_SID_EXT_ID,
+ new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID_ALTERNATIVE,
+ TEST_DAB_ENSEMBLE_ID}, /* vendorIds= */ null);
+ private static final UniqueProgramIdentifier TEST_DAB_UNIQUE_ID = new UniqueProgramIdentifier(
+ TEST_DAB_SELECTOR);
+ private static final UniqueProgramIdentifier TEST_DAB_UNIQUE_ID_ALTERNATIVE =
+ new UniqueProgramIdentifier(TEST_DAB_SELECTOR_ALTERNATIVE);
+ private static final RadioManager.ProgramInfo TEST_DAB_INFO =
+ AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR, TEST_DAB_DMB_SID_EXT_ID,
+ TEST_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY);
+ private static final RadioManager.ProgramInfo TEST_DAB_INFO_ALTERNATIVE =
+ AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR_ALTERNATIVE, TEST_DAB_DMB_SID_EXT_ID,
+ TEST_DAB_FREQUENCY_ID_ALTERNATIVE, TEST_SIGNAL_QUALITY);
private static final ProgramSelector.Identifier TEST_VENDOR_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_VENDOR_START,
@@ -95,8 +120,8 @@
TEST_VENDOR_ID), TEST_VENDOR_ID, TEST_VENDOR_ID, TEST_SIGNAL_QUALITY);
private static final ProgramInfoCache FULL_PROGRAM_INFO_CACHE = new ProgramInfoCache(
- /* filter= */ null, /* complete= */ true,
- TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO, TEST_VENDOR_INFO);
+ /* filter= */ null, /* complete= */ true, TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO,
+ TEST_DAB_INFO, TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
@Rule
public final Expect expect = Expect.create();
@@ -163,6 +188,22 @@
}
@Test
+ public void updateFromHalProgramListChunk_withInvalidChunk() {
+ RadioManager.ProgramInfo invalidDabInfo = AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR,
+ TEST_DAB_DMB_SID_EXT_ID, TEST_DAB_ENSEMBLE_ID, TEST_SIGNAL_QUALITY);
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
+ /* complete= */ false);
+ ProgramListChunk chunk = AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, new ProgramInfo[]{AidlTestUtils.programInfoToHalProgramInfo(
+ invalidDabInfo)}, new ProgramIdentifier[]{});
+
+ cache.updateFromHalProgramListChunk(chunk);
+
+ expect.withMessage("Program cache updated with invalid chunk")
+ .that(cache.toProgramInfoList()).isEmpty();
+ }
+
+ @Test
public void filterAndUpdateFromInternal_withNullFilter() {
ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
/* complete= */ true);
@@ -172,7 +213,7 @@
expect.withMessage("Program cache filtered by null filter")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO,
- TEST_VENDOR_INFO);
+ TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
}
@Test
@@ -186,21 +227,21 @@
expect.withMessage("Program cache filtered by empty filter")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO,
- TEST_VENDOR_INFO);
+ TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
}
@Test
public void filterAndUpdateFromInternal_withFilterByIdentifierType() {
ProgramInfoCache cache = new ProgramInfoCache(
new ProgramList.Filter(Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
- ProgramSelector.IDENTIFIER_TYPE_RDS_PI), new ArraySet<>(),
+ ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false));
cache.filterAndUpdateFromInternal(FULL_PROGRAM_INFO_CACHE, /* purge= */ false);
expect.withMessage("Program cache filtered by identifier type")
- .that(cache.toProgramInfoList())
- .containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO);
+ .that(cache.toProgramInfoList()).containsExactly(TEST_FM_INFO, TEST_AM_INFO,
+ TEST_DAB_INFO, TEST_DAB_INFO_ALTERNATIVE);
}
@Test
@@ -208,20 +249,60 @@
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(
new ArraySet<>(), Set.of(TEST_FM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID),
/* includeCategories= */ true, /* excludeModifications= */ false));
- int maxNumModifiedPerChunk = 2;
- int maxNumRemovedPerChunk = 2;
List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(
- FULL_PROGRAM_INFO_CACHE, /* purge= */ true, maxNumModifiedPerChunk,
- maxNumRemovedPerChunk);
+ FULL_PROGRAM_INFO_CACHE, /* purge= */ false, TEST_MAX_NUM_MODIFIED_PER_CHUNK,
+ TEST_MAX_NUM_REMOVED_PER_CHUNK);
expect.withMessage("Program cache filtered by identifier")
- .that(cache.toProgramInfoList()).containsExactly(TEST_FM_INFO, TEST_DAB_INFO);
+ .that(cache.toProgramInfoList()).containsExactly(TEST_FM_INFO, TEST_DAB_INFO,
+ TEST_DAB_INFO_ALTERNATIVE);
verifyChunkListPurge(programListChunks, /* purge= */ true);
- verifyChunkListComplete(programListChunks, FULL_PROGRAM_INFO_CACHE.isComplete());
+ verifyChunkListComplete(programListChunks, cache.isComplete());
+ verifyChunkListModified(programListChunks, TEST_MAX_NUM_MODIFIED_PER_CHUNK, TEST_FM_INFO,
+ TEST_DAB_INFO, TEST_DAB_INFO_ALTERNATIVE);
+ verifyChunkListRemoved(programListChunks, TEST_MAX_NUM_REMOVED_PER_CHUNK);
+ }
+
+ @Test
+ public void filterAndUpdateFromInternal_withPurging() {
+ ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new ArraySet<>(),
+ new ArraySet<>(), /* includeCategories= */ true, /* excludeModifications= */ false),
+ /* complete= */ true, TEST_RDS_INFO, TEST_DAB_INFO);
+ ProgramInfoCache otherCache = new ProgramInfoCache(/* filter= */ null, /* complete= */ true,
+ TEST_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO_ALTERNATIVE);
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(otherCache,
+ /* purge= */ true, TEST_MAX_NUM_MODIFIED_PER_CHUNK, TEST_MAX_NUM_REMOVED_PER_CHUNK);
+
+ expect.withMessage("Program cache filtered with purging").that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO_ALTERNATIVE);
+ verifyChunkListPurge(programListChunks, /* purge= */ true);
+ verifyChunkListModified(programListChunks, TEST_MAX_NUM_MODIFIED_PER_CHUNK, TEST_FM_INFO,
+ TEST_RDS_INFO, TEST_DAB_INFO_ALTERNATIVE);
+ verifyChunkListRemoved(programListChunks, TEST_MAX_NUM_REMOVED_PER_CHUNK);
+ }
+
+ @Test
+ public void filterAndUpdateFromInternal_withoutPurging() {
+ ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new ArraySet<>(),
+ new ArraySet<>(), /* includeCategories= */ true, /* excludeModifications= */ false),
+ /* complete= */ true, TEST_RDS_INFO, TEST_DAB_INFO);
+ ProgramInfoCache otherCache = new ProgramInfoCache(/* filter= */ null, /* complete= */ true,
+ TEST_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO_ALTERNATIVE);
+ int maxNumModifiedPerChunk = 1;
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(otherCache,
+ /* purge= */ false, maxNumModifiedPerChunk, TEST_MAX_NUM_REMOVED_PER_CHUNK);
+
+ expect.withMessage("Program cache filtered without puring").that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO_ALTERNATIVE);
+ verifyChunkListPurge(programListChunks, /* purge= */ false);
+ verifyChunkListComplete(programListChunks, cache.isComplete());
verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO,
- TEST_DAB_INFO);
- verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
+ TEST_DAB_INFO_ALTERNATIVE);
+ verifyChunkListRemoved(programListChunks, TEST_MAX_NUM_REMOVED_PER_CHUNK,
+ TEST_DAB_UNIQUE_ID);
}
@Test
@@ -230,20 +311,19 @@
new ArraySet<>(), /* includeCategories= */ false,
/* excludeModifications= */ false));
int maxNumModifiedPerChunk = 3;
- int maxNumRemovedPerChunk = 2;
List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(
FULL_PROGRAM_INFO_CACHE, /* purge= */ false, maxNumModifiedPerChunk,
- maxNumRemovedPerChunk);
+ TEST_MAX_NUM_REMOVED_PER_CHUNK);
expect.withMessage("Program cache filtered by excluding categories")
- .that(cache.toProgramInfoList())
- .containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO);
+ .that(cache.toProgramInfoList()).containsExactly(TEST_FM_INFO, TEST_AM_INFO,
+ TEST_RDS_INFO, TEST_DAB_INFO, TEST_DAB_INFO_ALTERNATIVE);
verifyChunkListPurge(programListChunks, /* purge= */ true);
- verifyChunkListComplete(programListChunks, FULL_PROGRAM_INFO_CACHE.isComplete());
+ verifyChunkListComplete(programListChunks, cache.isComplete());
verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO,
- TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO);
- verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
+ TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO, TEST_DAB_INFO_ALTERNATIVE);
+ verifyChunkListRemoved(programListChunks, TEST_MAX_NUM_REMOVED_PER_CHUNK);
}
@Test
@@ -254,21 +334,21 @@
ProgramInfoCache cache = new ProgramInfoCache(filterExcludingModifications,
/* complete= */ true, TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO, TEST_DAB_INFO);
ProgramInfoCache halCache = new ProgramInfoCache(/* filter= */ null, /* complete= */ false,
- TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO);
- int maxNumModifiedPerChunk = 2;
- int maxNumRemovedPerChunk = 2;
+ TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(halCache,
- /* purge= */ false, maxNumModifiedPerChunk, maxNumRemovedPerChunk);
+ /* purge= */ false, TEST_MAX_NUM_MODIFIED_PER_CHUNK,
+ TEST_MAX_NUM_REMOVED_PER_CHUNK);
expect.withMessage("Program cache filtered by excluding modifications")
.that(cache.toProgramInfoList())
- .containsExactly(TEST_FM_INFO, TEST_VENDOR_INFO);
+ .containsExactly(TEST_FM_INFO, TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ false);
verifyChunkListComplete(programListChunks, halCache.isComplete());
- verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_VENDOR_INFO);
- verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk, TEST_RDS_PI_ID,
- TEST_AM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID);
+ verifyChunkListModified(programListChunks, TEST_MAX_NUM_MODIFIED_PER_CHUNK,
+ TEST_VENDOR_INFO, TEST_DAB_INFO_ALTERNATIVE);
+ verifyChunkListRemoved(programListChunks, TEST_MAX_NUM_REMOVED_PER_CHUNK,
+ TEST_RDS_PI_UNIQUE_ID, TEST_AM_UNIQUE_ID, TEST_DAB_UNIQUE_ID);
}
@Test
@@ -276,69 +356,88 @@
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new ArraySet<>(),
new ArraySet<>(), /* includeCategories= */ true,
/* excludeModifications= */ false),
- /* complete= */ true, TEST_FM_INFO, TEST_RDS_INFO);
+ /* complete= */ true, TEST_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO);
ProgramInfoCache halCache = new ProgramInfoCache(/* filter= */ null, /* complete= */ false,
- TEST_FM_INFO_MODIFIED, TEST_DAB_INFO, TEST_VENDOR_INFO);
- int maxNumModifiedPerChunk = 2;
- int maxNumRemovedPerChunk = 2;
+ TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(halCache,
- /* purge= */ true, maxNumModifiedPerChunk, maxNumRemovedPerChunk);
+ /* purge= */ true, TEST_MAX_NUM_MODIFIED_PER_CHUNK, TEST_MAX_NUM_REMOVED_PER_CHUNK);
expect.withMessage("Purged program cache").that(cache.toProgramInfoList())
- .containsExactly(TEST_FM_INFO_MODIFIED, TEST_DAB_INFO, TEST_VENDOR_INFO);
+ .containsExactly(TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALTERNATIVE,
+ TEST_VENDOR_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ true);
verifyChunkListComplete(programListChunks, halCache.isComplete());
- verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO_MODIFIED,
- TEST_DAB_INFO, TEST_VENDOR_INFO);
- verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
+ verifyChunkListModified(programListChunks, TEST_MAX_NUM_MODIFIED_PER_CHUNK,
+ TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
+ verifyChunkListRemoved(programListChunks, TEST_MAX_NUM_REMOVED_PER_CHUNK);
}
@Test
- public void filterAndApplyChunkInternal_withPurgingIncompleteChunk() throws RemoteException {
+ public void filterAndApplyChunkInternal_withPurgingAndIncompleteChunk() throws RemoteException {
ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
- /* complete= */ false, TEST_FM_INFO, TEST_DAB_INFO);
- ProgramList.Chunk chunk = AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ false,
- List.of(TEST_FM_INFO_MODIFIED, TEST_RDS_INFO, TEST_VENDOR_INFO),
- List.of(TEST_DAB_DMB_SID_EXT_ID));
- int maxNumModifiedPerChunk = 2;
- int maxNumRemovedPerChunk = 2;
+ /* complete= */ false, TEST_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO);
+ ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(/* purge= */ true,
+ /* complete= */ false, List.of(TEST_FM_INFO_MODIFIED,
+ TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO), new ArrayList<>());
- List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(chunk,
- maxNumModifiedPerChunk, maxNumRemovedPerChunk);
+ List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(halChunk,
+ TEST_MAX_NUM_MODIFIED_PER_CHUNK, TEST_MAX_NUM_REMOVED_PER_CHUNK);
- expect.withMessage("Program cache applied with non-purging and complete chunk")
- .that(cache.toProgramInfoList())
- .containsExactly(TEST_FM_INFO_MODIFIED, TEST_RDS_INFO, TEST_VENDOR_INFO);
+ expect.withMessage("Program cache applied with purge-enabled and complete chunk")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_FM_INFO_MODIFIED,
+ TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ true);
verifyChunkListComplete(programListChunks, /* complete= */ false);
- verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO_MODIFIED,
- TEST_RDS_INFO, TEST_VENDOR_INFO);
- verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
+ verifyChunkListModified(programListChunks, TEST_MAX_NUM_MODIFIED_PER_CHUNK,
+ TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
+ verifyChunkListRemoved(programListChunks, TEST_MAX_NUM_REMOVED_PER_CHUNK);
}
@Test
- public void filterAndApplyChunk_withNonPurgingCompleteChunk() throws RemoteException {
- ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
- /* complete= */ false, TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO, TEST_DAB_INFO);
- ProgramList.Chunk chunk = AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
- List.of(TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO),
+ public void filterAndApplyChunk_withNonPurgingAndIncompleteChunk() throws RemoteException {
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null, /* complete= */ false,
+ TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO, TEST_DAB_INFO);
+ ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ false, List.of(TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALTERNATIVE,
+ TEST_VENDOR_INFO), List.of(TEST_RDS_PI_ID, TEST_AM_FREQUENCY_ID));
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(halChunk,
+ TEST_MAX_NUM_MODIFIED_PER_CHUNK, TEST_MAX_NUM_REMOVED_PER_CHUNK);
+
+ expect.withMessage("Program cache applied with non-purging and incomplete chunk")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_DAB_INFO,
+ TEST_DAB_INFO_ALTERNATIVE, TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO);
+ verifyChunkListPurge(programListChunks, /* purge= */ false);
+ verifyChunkListComplete(programListChunks, /* complete= */ false);
+ verifyChunkListModified(programListChunks, TEST_MAX_NUM_MODIFIED_PER_CHUNK,
+ TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALTERNATIVE, TEST_VENDOR_INFO);
+ verifyChunkListRemoved(programListChunks, TEST_MAX_NUM_REMOVED_PER_CHUNK,
+ TEST_RDS_PI_UNIQUE_ID, TEST_AM_UNIQUE_ID);
+ }
+
+ @Test
+ public void filterAndApplyChunk_withNonPurgingAndCompleteChunk() throws RemoteException {
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null, /* complete= */ false,
+ TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO, TEST_DAB_INFO,
+ TEST_DAB_INFO_ALTERNATIVE);
+ ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO),
List.of(TEST_RDS_PI_ID, TEST_AM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID));
- int maxNumModifiedPerChunk = 2;
- int maxNumRemovedPerChunk = 2;
- List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(chunk,
- maxNumModifiedPerChunk, maxNumRemovedPerChunk);
+ List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(halChunk,
+ TEST_MAX_NUM_MODIFIED_PER_CHUNK, TEST_MAX_NUM_REMOVED_PER_CHUNK);
- expect.withMessage("Program cache applied with purge-enabled complete chunk")
+ expect.withMessage("Program cache applied with non-purging and complete chunk")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ false);
verifyChunkListComplete(programListChunks, /* complete= */ true);
- verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO_MODIFIED,
- TEST_VENDOR_INFO);
- verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk, TEST_RDS_PI_ID,
- TEST_AM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID);
+ verifyChunkListModified(programListChunks, TEST_MAX_NUM_MODIFIED_PER_CHUNK,
+ TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO);
+ verifyChunkListRemoved(programListChunks, TEST_MAX_NUM_REMOVED_PER_CHUNK,
+ TEST_RDS_PI_UNIQUE_ID, TEST_AM_UNIQUE_ID, TEST_DAB_UNIQUE_ID,
+ TEST_DAB_UNIQUE_ID_ALTERNATIVE);
}
private void verifyChunkListPurge(List<ProgramList.Chunk> chunks, boolean purge) {
@@ -387,17 +486,17 @@
.that(actualSet).containsExactlyElementsIn(expectedProgramInfos);
}
- private void verifyChunkListRemoved(List<ProgramList.Chunk> chunks,
- int maxRemovedPerChunk, ProgramSelector.Identifier... expectedIdentifiers) {
+ private void verifyChunkListRemoved(List<ProgramList.Chunk> chunks, int maxRemovedPerChunk,
+ UniqueProgramIdentifier... expectedIdentifiers) {
if (chunks.isEmpty()) {
expect.withMessage("Empty program info list")
.that(expectedIdentifiers.length).isEqualTo(0);
return;
}
- ArraySet<ProgramSelector.Identifier> actualSet = new ArraySet<>();
+ ArraySet<UniqueProgramIdentifier> actualSet = new ArraySet<>();
for (int i = 0; i < chunks.size(); i++) {
- Set<ProgramSelector.Identifier> chunkRemoved = chunks.get(i).getRemoved();
+ Set<UniqueProgramIdentifier> chunkRemoved = chunks.get(i).getRemoved();
actualSet.addAll(chunkRemoved);
expect.withMessage("Chunk %s removed identifier array size ", i)
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index 84aa864..a195228 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -18,8 +18,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -47,6 +45,7 @@
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioTuner;
+import android.hardware.radio.UniqueProgramIdentifier;
import android.os.Binder;
import android.os.ParcelableException;
import android.os.RemoteException;
@@ -59,13 +58,18 @@
import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase;
import com.android.server.broadcastradio.RadioServiceUserController;
+import com.google.common.truth.Expect;
+
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.verification.VerificationWithTimeout;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -94,10 +98,6 @@
private static final ProgramSelector.Identifier TEST_FM_FREQUENCY_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
/* value= */ 88_500);
- private static final ProgramSelector.Identifier TEST_RDS_PI_ID =
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI,
- /* value= */ 15_019);
-
private static final RadioManager.ProgramInfo TEST_FM_INFO = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM,
TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID, TEST_FM_FREQUENCY_ID,
@@ -106,11 +106,37 @@
AidlTestUtils.makeProgramInfo(AidlTestUtils.makeProgramSelector(
ProgramSelector.PROGRAM_TYPE_FM, TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID,
TEST_FM_FREQUENCY_ID, /* signalQuality= */ 100);
- private static final RadioManager.ProgramInfo TEST_RDS_INFO = AidlTestUtils.makeProgramInfo(
- AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM, TEST_RDS_PI_ID),
- TEST_RDS_PI_ID, new ProgramSelector.Identifier(
- ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, /* value= */ 89_500),
- SIGNAL_QUALITY);
+
+ private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
+ /* value= */ 220_352);
+ private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID_ALT =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
+ /* value= */ 220_064);
+ private static final ProgramSelector.Identifier TEST_DAB_SID_EXT_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
+ /* value= */ 0xA000000111L);
+ private static final ProgramSelector.Identifier TEST_DAB_ENSEMBLE_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
+ /* value= */ 0x1001);
+ private static final ProgramSelector TEST_DAB_SELECTOR = new ProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID,
+ new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID},
+ /* vendorIds= */ null);
+ private static final ProgramSelector TEST_DAB_SELECTOR_ALT = new ProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID,
+ new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID_ALT, TEST_DAB_ENSEMBLE_ID},
+ /* vendorIds= */ null);
+ private static final UniqueProgramIdentifier TEST_DAB_UNIQUE_ID = new UniqueProgramIdentifier(
+ TEST_DAB_SELECTOR);
+ private static final UniqueProgramIdentifier TEST_DAB_UNIQUE_ID_ALT =
+ new UniqueProgramIdentifier(TEST_DAB_SELECTOR_ALT);
+ private static final RadioManager.ProgramInfo TEST_DAB_INFO =
+ AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR, TEST_DAB_SID_EXT_ID,
+ TEST_DAB_FREQUENCY_ID, SIGNAL_QUALITY);
+ private static final RadioManager.ProgramInfo TEST_DAB_INFO_ALT =
+ AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR_ALT, TEST_DAB_SID_EXT_ID,
+ TEST_DAB_FREQUENCY_ID_ALT, SIGNAL_QUALITY);
// Mocks
@Mock
@@ -129,6 +155,9 @@
private TunerSession[] mTunerSessions;
+ @Rule
+ public final Expect expect = Expect.create();
+
@Override
protected void initializeSession(StaticMockitoSessionBuilder builder) {
builder.spyStatic(RadioServiceUserController.class).spyStatic(CompatChanges.class)
@@ -225,7 +254,7 @@
openAidlClients(numSessions);
for (int index = 0; index < numSessions; index++) {
- assertWithMessage("Session of index %s close state", index)
+ expect.withMessage("Session of index %s close state", index)
.that(mTunerSessions[index].isClosed()).isFalse();
}
}
@@ -257,7 +286,7 @@
RadioManager.BandConfig config = mTunerSessions[0].getConfiguration();
- assertWithMessage("Session configuration").that(config)
+ expect.withMessage("Session configuration").that(config)
.isEqualTo(FM_BAND_CONFIG);
}
@@ -267,7 +296,7 @@
mTunerSessions[0].setMuted(/* mute= */ false);
- assertWithMessage("Session mute state after setting unmuted")
+ expect.withMessage("Session mute state after setting unmuted")
.that(mTunerSessions[0].isMuted()).isFalse();
}
@@ -277,7 +306,7 @@
mTunerSessions[0].setMuted(/* mute= */ true);
- assertWithMessage("Session mute state after setting muted")
+ expect.withMessage("Session mute state after setting muted")
.that(mTunerSessions[0].isMuted()).isTrue();
}
@@ -287,7 +316,7 @@
mTunerSessions[0].close();
- assertWithMessage("Close state of broadcast radio service session")
+ expect.withMessage("Close state of broadcast radio service session")
.that(mTunerSessions[0].isClosed()).isTrue();
}
@@ -301,11 +330,11 @@
for (int index = 0; index < numSessions; index++) {
if (index == closeIdx) {
- assertWithMessage(
+ expect.withMessage(
"Close state of broadcast radio service session of index %s", index)
.that(mTunerSessions[index].isClosed()).isTrue();
} else {
- assertWithMessage(
+ expect.withMessage(
"Close state of broadcast radio service session of index %s", index)
.that(mTunerSessions[index].isClosed()).isFalse();
}
@@ -320,7 +349,7 @@
mTunerSessions[0].close(errorCode);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onError(errorCode);
- assertWithMessage("Close state of broadcast radio service session")
+ expect.withMessage("Close state of broadcast radio service session")
.that(mTunerSessions[0].isClosed()).isTrue();
}
@@ -334,7 +363,7 @@
for (int index = 0; index < numSessions; index++) {
verify(mAidlTunerCallbackMocks[index], CALLBACK_TIMEOUT).onError(errorCode);
- assertWithMessage("Close state of broadcast radio service session of index %s", index)
+ expect.withMessage("Close state of broadcast radio service session of index %s", index)
.that(mTunerSessions[index].isClosed()).isTrue();
}
}
@@ -383,22 +412,12 @@
@Test
public void tune_withUnsupportedSelector_throwsException() throws Exception {
- ProgramSelector.Identifier dabPrimaryId =
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
- /* value= */ 0xA000000111L);
- ProgramSelector.Identifier[] dabSecondaryIds = new ProgramSelector.Identifier[]{
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
- /* value= */ 1337),
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
- /* value= */ 225648)};
- ProgramSelector unsupportedSelector = new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB,
- dabPrimaryId, dabSecondaryIds, /* vendorIds= */ null);
openAidlClients(/* numClients= */ 1);
UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
- () -> mTunerSessions[0].tune(unsupportedSelector));
+ () -> mTunerSessions[0].tune(TEST_DAB_SELECTOR));
- assertWithMessage("Exception for tuning on unsupported program selector")
+ expect.withMessage("Exception for tuning on unsupported program selector")
.that(thrown).hasMessageThat().contains("tune: NOT_SUPPORTED");
}
@@ -413,7 +432,7 @@
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
() -> mTunerSessions[0].tune(invalidSel));
- assertWithMessage("Exception for tuning on DAB selector without DAB_SID_EXT primary id")
+ expect.withMessage("Exception for tuning on DAB selector without DAB_SID_EXT primary id")
.that(thrown).hasMessageThat().contains("tune: INVALID_ARGUMENTS");
}
@@ -457,7 +476,7 @@
mTunerSessions[0].tune(sel);
});
- assertWithMessage("Unknown error HAL exception when tuning")
+ expect.withMessage("Unknown error HAL exception when tuning")
.that(thrown).hasMessageThat().contains("UNKNOWN_ERROR");
}
@@ -520,7 +539,7 @@
mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false);
});
- assertWithMessage("Exception for stepping when HAL is in invalid state")
+ expect.withMessage("Exception for stepping when HAL is in invalid state")
.that(thrown).hasMessageThat().contains("INVALID_STATE");
}
@@ -599,7 +618,7 @@
mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
});
- assertWithMessage("Internal error HAL exception when seeking")
+ expect.withMessage("Internal error HAL exception when seeking")
.that(thrown).hasMessageThat().contains("INTERNAL_ERROR");
}
@@ -636,7 +655,7 @@
mTunerSessions[0].cancel();
});
- assertWithMessage("Exception for canceling when HAL throws remote exception")
+ expect.withMessage("Exception for canceling when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -649,7 +668,7 @@
mTunerSessions[0].getImage(imageId);
});
- assertWithMessage("Get image exception")
+ expect.withMessage("Get image exception")
.that(thrown).hasMessageThat().contains("Image ID is missing");
}
@@ -660,7 +679,7 @@
Bitmap imageTest = mTunerSessions[0].getImage(imageId);
- assertWithMessage("Null image").that(imageTest).isEqualTo(null);
+ expect.withMessage("Null image").that(imageTest).isEqualTo(null);
}
@Test
@@ -674,7 +693,7 @@
mTunerSessions[0].getImage(/* id= */ 1);
});
- assertWithMessage("Exception for getting image when HAL throws remote exception")
+ expect.withMessage("Exception for getting image when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -702,18 +721,19 @@
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
- ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(filter);
- List<RadioManager.ProgramInfo> modified = List.of(TEST_FM_INFO, TEST_RDS_INFO);
- List<ProgramSelector.Identifier> removed = new ArrayList<>();
+ List<RadioManager.ProgramInfo> modified = List.of(TEST_FM_INFO, TEST_DAB_INFO,
+ TEST_DAB_INFO_ALT);
+ List<ProgramSelector.Identifier> halRemoved = new ArrayList<>();
+ List<UniqueProgramIdentifier> removed = new ArrayList<>();
ProgramListChunk halProgramList = AidlTestUtils.makeHalChunk(/* purge= */ true,
- /* complete= */ true, modified, removed);
+ /* complete= */ true, modified, halRemoved);
ProgramList.Chunk expectedProgramList =
AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true, modified, removed);
mTunerSessions[0].startProgramListUpdates(filter);
mHalTunerCallback.onProgramListUpdated(halProgramList);
- verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+ verifyHalProgramListUpdatesInvocation(filter);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
.onProgramListUpdated(expectedProgramList);
}
@@ -723,19 +743,23 @@
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
+ List<RadioManager.ProgramInfo> modifiedInfo = List.of(TEST_FM_INFO, TEST_DAB_INFO,
+ TEST_DAB_INFO_ALT);
mTunerSessions[0].startProgramListUpdates(filter);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ true,
- /* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ /* complete= */ true, modifiedInfo, new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
- AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
- List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true, modifiedInfo,
+ new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED),
+ List.of(TEST_DAB_SID_EXT_ID)));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
- List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+ List.of(TEST_FM_INFO_MODIFIED),
+ List.of(TEST_DAB_UNIQUE_ID, TEST_DAB_UNIQUE_ID_ALT)));
}
@Test
@@ -743,17 +767,21 @@
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
+ List<RadioManager.ProgramInfo> modifiedInfo = List.of(TEST_FM_INFO, TEST_DAB_INFO,
+ TEST_DAB_INFO_ALT);
mTunerSessions[0].startProgramListUpdates(filter);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ true,
- /* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ /* complete= */ true, modifiedInfo, new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
- AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
- List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true, modifiedInfo,
+ new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED),
+ List.of(TEST_DAB_SID_EXT_ID)));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
- List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+ List.of(TEST_FM_INFO_MODIFIED),
+ List.of(TEST_DAB_UNIQUE_ID, TEST_DAB_UNIQUE_ID_ALT)));
mTunerSessions[0].startProgramListUpdates(filter);
@@ -766,40 +794,44 @@
@Test
public void startProgramListUpdates_withNullFilter() throws Exception {
openAidlClients(/* numClients= */ 1);
+ List<RadioManager.ProgramInfo> modifiedInfo = List.of(TEST_FM_INFO, TEST_DAB_INFO,
+ TEST_DAB_INFO_ALT);
mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ true,
- /* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ /* complete= */ true, modifiedInfo, new ArrayList<>()));
verify(mBroadcastRadioMock).startProgramListUpdates(any());
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
- AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
- List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true, modifiedInfo,
+ new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED),
+ List.of(TEST_DAB_SID_EXT_ID)));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
- List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+ List.of(TEST_FM_INFO_MODIFIED),
+ List.of(TEST_DAB_UNIQUE_ID, TEST_DAB_UNIQUE_ID_ALT)));
}
@Test
public void startProgramListUpdates_withIdFilter() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter idFilter = new ProgramList.Filter(new ArraySet<>(),
- Set.of(TEST_RDS_PI_ID), /* includeCategories= */ true,
+ Set.of(TEST_DAB_SID_EXT_ID), /* includeCategories= */ true,
/* excludeModifications= */ true);
- ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(idFilter);
mTunerSessions[0].startProgramListUpdates(idFilter);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_RDS_INFO), new ArrayList<>()));
+ /* complete= */ true, List.of(TEST_DAB_INFO, TEST_DAB_INFO_ALT),
+ new ArrayList<>()));
- verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+ verifyHalProgramListUpdatesInvocation(idFilter);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
- List.of(TEST_RDS_INFO), new ArrayList<>()));
+ List.of(TEST_DAB_INFO, TEST_DAB_INFO_ALT), new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
@@ -811,50 +843,52 @@
public void startProgramListUpdates_withFilterExcludingModifications() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filterExcludingModifications = new ProgramList.Filter(
- Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
+ Set.of(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
+ ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ true);
- ProgramFilter halFilter =
- ConversionUtils.filterToHalProgramFilter(filterExcludingModifications);
mTunerSessions[0].startProgramListUpdates(filterExcludingModifications);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
+ /* complete= */ true, List.of(TEST_FM_INFO, TEST_DAB_INFO), new ArrayList<>()));
- verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+ verifyHalProgramListUpdatesInvocation(filterExcludingModifications);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
- List.of(TEST_FM_INFO), new ArrayList<>()));
+ List.of(TEST_FM_INFO, TEST_DAB_INFO), new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALT),
+ new ArrayList<>()));
- verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
+ List.of(TEST_DAB_INFO_ALT), new ArrayList<>()));
}
@Test
public void startProgramListUpdates_withFilterIncludingModifications() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filterIncludingModifications = new ProgramList.Filter(
- Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
+ Set.of(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
+ ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
- ProgramFilter halFilter =
- ConversionUtils.filterToHalProgramFilter(filterIncludingModifications);
mTunerSessions[0].startProgramListUpdates(filterIncludingModifications);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
+ /* complete= */ true, List.of(TEST_FM_INFO, TEST_DAB_INFO), new ArrayList<>()));
- verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+ verifyHalProgramListUpdatesInvocation(filterIncludingModifications);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
- List.of(TEST_FM_INFO), new ArrayList<>()));
+ List.of(TEST_FM_INFO, TEST_DAB_INFO), new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALT),
+ new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
- List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
+ List.of(TEST_FM_INFO_MODIFIED, TEST_DAB_INFO_ALT), new ArrayList<>()));
}
@Test
@@ -910,7 +944,7 @@
int numSessions = 3;
openAidlClients(numSessions);
List<ProgramList.Filter> filters = List.of(new ProgramList.Filter(
- Set.of(ProgramSelector.IDENTIFIER_TYPE_RDS_PI), new ArraySet<>(),
+ Set.of(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false),
new ProgramList.Filter(new ArraySet<>(), Set.of(TEST_FM_FREQUENCY_ID),
/* includeCategories= */ false, /* excludeModifications= */ true),
@@ -922,18 +956,20 @@
}
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ /* complete= */ true, List.of(TEST_FM_INFO, TEST_DAB_INFO, TEST_DAB_INFO_ALT),
+ new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
.onProgramListUpdated(AidlTestUtils.makeChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_RDS_INFO), new ArrayList<>()));
+ /* complete= */ true, List.of(TEST_DAB_INFO, TEST_DAB_INFO_ALT),
+ new ArrayList<>()));
verify(mAidlTunerCallbackMocks[1], CALLBACK_TIMEOUT)
.onProgramListUpdated(AidlTestUtils.makeChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[2], CALLBACK_TIMEOUT)
.onProgramListUpdated(AidlTestUtils.makeChunk(/* purge= */ false,
- /* complete= */ true, List.of(TEST_RDS_INFO, TEST_FM_INFO),
- new ArrayList<>()));
+ /* complete= */ true, List.of(TEST_DAB_INFO, TEST_DAB_INFO_ALT,
+ TEST_FM_INFO), new ArrayList<>()));
}
@Test
@@ -958,7 +994,7 @@
mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
});
- assertWithMessage("Unknown error HAL exception when updating program list")
+ expect.withMessage("Unknown error HAL exception when updating program list")
.that(thrown).hasMessageThat().contains("UNKNOWN_ERROR");
}
@@ -995,7 +1031,7 @@
boolean isSupported = mTunerSessions[0].isConfigFlagSupported(flag);
verify(mBroadcastRadioMock).isConfigFlagSet(flag);
- assertWithMessage("Config flag %s is supported", flag).that(isSupported).isFalse();
+ expect.withMessage("Config flag %s is supported", flag).that(isSupported).isFalse();
}
@Test
@@ -1006,7 +1042,7 @@
boolean isSupported = mTunerSessions[0].isConfigFlagSupported(flag);
verify(mBroadcastRadioMock).isConfigFlagSet(flag);
- assertWithMessage("Config flag %s is supported", flag).that(isSupported).isTrue();
+ expect.withMessage("Config flag %s is supported", flag).that(isSupported).isTrue();
}
@Test
@@ -1018,7 +1054,7 @@
mTunerSessions[0].setConfigFlag(flag, /* value= */ true);
});
- assertWithMessage("Exception for setting unsupported flag %s", flag)
+ expect.withMessage("Exception for setting unsupported flag %s", flag)
.that(thrown).hasMessageThat().contains("setConfigFlag: NOT_SUPPORTED");
}
@@ -1063,7 +1099,7 @@
mTunerSessions[0].isConfigFlagSet(flag);
});
- assertWithMessage("Exception for checking if unsupported flag %s is set", flag)
+ expect.withMessage("Exception for checking if unsupported flag %s is set", flag)
.that(thrown).hasMessageThat().contains("isConfigFlagSet: NOT_SUPPORTED");
}
@@ -1076,7 +1112,7 @@
boolean isSet = mTunerSessions[0].isConfigFlagSet(flag);
- assertWithMessage("Config flag %s is set", flag)
+ expect.withMessage("Config flag %s is set", flag)
.that(isSet).isEqualTo(expectedConfigFlagValue);
}
@@ -1090,7 +1126,7 @@
mTunerSessions[0].isConfigFlagSet(flag);
});
- assertWithMessage("Exception for checking config flag when HAL throws remote exception")
+ expect.withMessage("Exception for checking config flag when HAL throws remote exception")
.that(thrown).hasMessageThat().contains("Failed to check flag");
}
@@ -1131,7 +1167,7 @@
mTunerSessions[0].setParameters(parametersSet);
});
- assertWithMessage("Exception for setting parameters when HAL throws remote exception")
+ expect.withMessage("Exception for setting parameters when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -1157,7 +1193,7 @@
mTunerSessions[0].getParameters(parameterKeys);
});
- assertWithMessage("Exception for getting parameters when HAL throws remote exception")
+ expect.withMessage("Exception for getting parameters when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -1264,4 +1300,24 @@
}
return seekFrequency;
}
+
+ private void verifyHalProgramListUpdatesInvocation(ProgramList.Filter filter) throws Exception {
+ ProgramFilter halFilterExpected = ConversionUtils.filterToHalProgramFilter(filter);
+ ArgumentCaptor<ProgramFilter> halFilterCaptor = ArgumentCaptor.forClass(
+ ProgramFilter.class);
+ verify(mBroadcastRadioMock).startProgramListUpdates(halFilterCaptor.capture());
+ ProgramFilter halFilterInvoked = halFilterCaptor.getValue();
+ expect.withMessage("Filtered identifier types").that(
+ halFilterInvoked.identifierTypes).asList().containsExactlyElementsIn(Arrays.stream(
+ halFilterExpected.identifierTypes).boxed().toArray(Integer[]::new));
+ expect.withMessage("Filtered identifiers").that(
+ halFilterInvoked.identifiers).asList()
+ .containsExactlyElementsIn(halFilterExpected.identifiers);
+ expect.withMessage("Categories-included filter")
+ .that(halFilterInvoked.includeCategories)
+ .isEqualTo(halFilterExpected.includeCategories);
+ expect.withMessage("Modifications-excluded filter")
+ .that(halFilterInvoked.excludeModifications)
+ .isEqualTo(halFilterExpected.excludeModifications);
+ }
}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
index ec55ddb..fbb446b 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
@@ -21,12 +21,16 @@
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
+import android.hardware.radio.UniqueProgramIdentifier;
import android.test.suitebuilder.annotation.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase;
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,188 +44,221 @@
@RunWith(AndroidJUnit4.class)
@MediumTest
public class ProgramInfoCacheTest extends ExtendedRadioMockitoTestCase {
- private static final String TAG = "BroadcastRadioTests.ProgramInfoCache";
+ private static final int TEST_QUALITY = 1;
- private final ProgramSelector.Identifier mAmFmIdentifier =
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, 88500);
- private final RadioManager.ProgramInfo mAmFmInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
+ private static final ProgramSelector.Identifier TEST_AM_FM_ID = new ProgramSelector.Identifier(
+ ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, /* value= */ 88500);
+ private static final ProgramSelector TEST_AM_FM_SELECTOR = TestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_FM, TEST_AM_FM_ID);
+ private static final RadioManager.ProgramInfo TEST_AM_FM_INFO = TestUtils.makeProgramInfo(
+ TEST_AM_FM_SELECTOR, TEST_QUALITY);
- private final ProgramSelector.Identifier mRdsIdentifier =
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI, 15019);
- private final RadioManager.ProgramInfo mRdsInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 0);
+ private static final ProgramSelector.Identifier TEST_RDS_ID = new ProgramSelector.Identifier(
+ ProgramSelector.IDENTIFIER_TYPE_RDS_PI, /* value= */ 15019);
+ private static final ProgramSelector TEST_RDS_SELECTOR = TestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_FM, TEST_RDS_ID);
+ private static final RadioManager.ProgramInfo TEST_RDS_INFO = TestUtils.makeProgramInfo(
+ TEST_RDS_SELECTOR, TEST_QUALITY);
- private final ProgramSelector.Identifier mDabEnsembleIdentifier =
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, 1337);
- private final RadioManager.ProgramInfo mDabEnsembleInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_DAB, mDabEnsembleIdentifier, 0);
+ private static final ProgramSelector TEST_HD_SELECTOR = TestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_FM_HD, new ProgramSelector.Identifier(
+ ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT,
+ /* value= */ 0x17C14100000001L));
- private final ProgramSelector.Identifier mVendorCustomIdentifier =
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, 9001);
- private final RadioManager.ProgramInfo mVendorCustomInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_VENDOR_START, mVendorCustomIdentifier, 0);
+ private static final ProgramSelector.Identifier TEST_DAB_SID_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT,
+ /* value= */ 0xA000000111L);
+ private static final ProgramSelector.Identifier TEST_DAB_ENSEMBLE_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
+ /* value= */ 0x1001);
+ private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
+ /* value= */ 220_352);
+ private static final ProgramSelector TEST_DAB_SELECTOR = TestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_ID,
+ new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID});
+ private static final UniqueProgramIdentifier TEST_DAB_UNIQUE_ID =
+ new UniqueProgramIdentifier(TEST_DAB_SELECTOR);
+ private static final RadioManager.ProgramInfo TEST_DAB_INFO = TestUtils.makeProgramInfo(
+ TEST_DAB_SELECTOR, TEST_QUALITY);
+ private static final ProgramSelector.Identifier TEST_VENDOR_ID = new ProgramSelector.Identifier(
+ ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, /* value= */ 9001);
+ private static final ProgramSelector TEST_VENDOR_SELECTOR = TestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_VENDOR_START, TEST_VENDOR_ID);
+ private static final UniqueProgramIdentifier TEST_VENDOR_UNIQUE_ID =
+ new UniqueProgramIdentifier(TEST_VENDOR_SELECTOR);
+ private static final RadioManager.ProgramInfo TEST_VENDOR_INFO = TestUtils.makeProgramInfo(
+ TEST_VENDOR_SELECTOR, TEST_QUALITY);
- // HAL-side ProgramInfoCache containing all of the above ProgramInfos.
- private final ProgramInfoCache mAllProgramInfos = new ProgramInfoCache(null, true, mAmFmInfo,
- mRdsInfo, mDabEnsembleInfo, mVendorCustomInfo);
+ private static final ProgramInfoCache FULL_PROGRAM_INFO_CACHE = new ProgramInfoCache(
+ /* filter= */ null, /* complete= */ true, TEST_AM_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO,
+ TEST_VENDOR_INFO);
+
+ @Rule
+ public final Expect expect = Expect.create();
@Test
public void testUpdateFromHal() {
// First test updating an incomplete cache with a purging, complete chunk.
- ProgramInfoCache cache = new ProgramInfoCache(null, false, mAmFmInfo);
+ ProgramInfoCache cache = new ProgramInfoCache(null, false, TEST_AM_FM_INFO);
ProgramListChunk chunk = new ProgramListChunk();
chunk.purge = true;
chunk.complete = true;
- chunk.modified.add(TestUtils.programInfoToHal(mRdsInfo));
- chunk.modified.add(TestUtils.programInfoToHal(mDabEnsembleInfo));
+ chunk.modified.add(TestUtils.programInfoToHal(TEST_RDS_INFO));
+ chunk.modified.add(TestUtils.programInfoToHal(TEST_DAB_INFO));
cache.updateFromHalProgramListChunk(chunk);
- assertTrue(cache.programInfosAreExactly(mRdsInfo, mDabEnsembleInfo));
+ expect.withMessage("Program info cache updated with a purging complete chunk")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_RDS_INFO, TEST_DAB_INFO);
assertTrue(cache.isComplete());
// Then test a non-purging, incomplete chunk.
chunk.purge = false;
chunk.complete = false;
chunk.modified.clear();
- RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 1);
+ RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(TEST_RDS_SELECTOR, 1);
chunk.modified.add(TestUtils.programInfoToHal(updatedRdsInfo));
- chunk.modified.add(TestUtils.programInfoToHal(mVendorCustomInfo));
- chunk.removed.add(Convert.programIdentifierToHal(mDabEnsembleIdentifier));
+ chunk.modified.add(TestUtils.programInfoToHal(TEST_VENDOR_INFO));
+ chunk.removed.add(Convert.programIdentifierToHal(TEST_DAB_SID_ID));
cache.updateFromHalProgramListChunk(chunk);
- assertTrue(cache.programInfosAreExactly(updatedRdsInfo, mVendorCustomInfo));
+ expect.withMessage("Program info cache updated with non-puring incomplete chunk")
+ .that(cache.toProgramInfoList()).containsExactly(updatedRdsInfo, TEST_VENDOR_INFO);
assertFalse(cache.isComplete());
}
@Test
public void testNullFilter() {
ProgramInfoCache cache = new ProgramInfoCache(null, true);
- cache.filterAndUpdateFrom(mAllProgramInfos, false);
- assertTrue(cache.programInfosAreExactly(mAmFmInfo, mRdsInfo, mDabEnsembleInfo,
- mVendorCustomInfo));
+ cache.filterAndUpdateFrom(FULL_PROGRAM_INFO_CACHE, false);
+ expect.withMessage("Program info cache with null filter")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_AM_FM_INFO, TEST_RDS_INFO,
+ TEST_DAB_INFO, TEST_VENDOR_INFO);
}
@Test
public void testEmptyFilter() {
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new HashSet<Integer>(),
new HashSet<ProgramSelector.Identifier>(), true, false));
- cache.filterAndUpdateFrom(mAllProgramInfos, false);
- assertTrue(cache.programInfosAreExactly(mAmFmInfo, mRdsInfo, mDabEnsembleInfo,
- mVendorCustomInfo));
+ cache.filterAndUpdateFrom(FULL_PROGRAM_INFO_CACHE, false);
+ expect.withMessage("Program info cache with empty filter")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_AM_FM_INFO, TEST_RDS_INFO,
+ TEST_DAB_INFO, TEST_VENDOR_INFO);
}
@Test
public void testFilterByType() {
HashSet<Integer> filterTypes = new HashSet<>();
filterTypes.add(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY);
- filterTypes.add(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE);
+ filterTypes.add(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT);
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(filterTypes,
new HashSet<ProgramSelector.Identifier>(), true, false));
- cache.filterAndUpdateFrom(mAllProgramInfos, false);
- assertTrue(cache.programInfosAreExactly(mAmFmInfo, mDabEnsembleInfo));
+ cache.filterAndUpdateFrom(FULL_PROGRAM_INFO_CACHE, false);
+ expect.withMessage("Program info cache with type filter")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_AM_FM_INFO, TEST_DAB_INFO);
}
@Test
public void testFilterByIdentifier() {
HashSet<ProgramSelector.Identifier> filterIds = new HashSet<>();
- filterIds.add(mRdsIdentifier);
- filterIds.add(mVendorCustomIdentifier);
+ filterIds.add(TEST_RDS_ID);
+ filterIds.add(TEST_VENDOR_ID);
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new HashSet<Integer>(),
filterIds, true, false));
- cache.filterAndUpdateFrom(mAllProgramInfos, false);
- assertTrue(cache.programInfosAreExactly(mRdsInfo, mVendorCustomInfo));
+ cache.filterAndUpdateFrom(FULL_PROGRAM_INFO_CACHE, false);
+ expect.withMessage("Program info cache with identifier filter")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_RDS_INFO, TEST_VENDOR_INFO);
}
@Test
public void testFilterExcludeCategories() {
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new HashSet<Integer>(),
new HashSet<ProgramSelector.Identifier>(), false, false));
- cache.filterAndUpdateFrom(mAllProgramInfos, false);
- assertTrue(cache.programInfosAreExactly(mAmFmInfo, mRdsInfo));
+ cache.filterAndUpdateFrom(FULL_PROGRAM_INFO_CACHE, false);
+ expect.withMessage("Program info cache with filter excluding categories")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_AM_FM_INFO, TEST_RDS_INFO,
+ TEST_DAB_INFO);
}
@Test
public void testPurgeUpdateChunks() {
- ProgramInfoCache cache = new ProgramInfoCache(null, false, mAmFmInfo);
+ ProgramInfoCache cache = new ProgramInfoCache(null, false, TEST_AM_FM_INFO);
List<ProgramList.Chunk> chunks =
- cache.filterAndUpdateFromInternal(mAllProgramInfos, true, 3, 3);
+ cache.filterAndUpdateFromInternal(FULL_PROGRAM_INFO_CACHE, true, 3, 3);
assertEquals(2, chunks.size());
verifyChunkListFlags(chunks, true, true);
- verifyChunkListModified(chunks, 3, mAmFmInfo, mRdsInfo, mDabEnsembleInfo,
- mVendorCustomInfo);
+ verifyChunkListModified(chunks, 3, TEST_AM_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO,
+ TEST_VENDOR_INFO);
verifyChunkListRemoved(chunks, 0);
}
@Test
public void testDeltaUpdateChunksModificationsIncluded() {
// Create a cache with a filter that allows modifications, and set its contents to
- // mAmFmInfo, mRdsInfo, mDabEnsembleInfo, and mVendorCustomInfo.
- ProgramInfoCache cache = new ProgramInfoCache(null, true, mAmFmInfo, mRdsInfo,
- mDabEnsembleInfo, mVendorCustomInfo);
+ // TEST_AM_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO, and TEST_VENDOR_INFO.
+ ProgramInfoCache cache = new ProgramInfoCache(null, true, TEST_AM_FM_INFO, TEST_RDS_INFO,
+ TEST_DAB_INFO, TEST_VENDOR_INFO);
// Create a HAL cache that:
// - Is complete.
- // - Retains mAmFmInfo.
- // - Replaces mRdsInfo with updatedRdsInfo.
- // - Drops mDabEnsembleInfo and mVendorCustomInfo.
- // - Introduces a new SXM info.
- RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 1);
- RadioManager.ProgramInfo newSxmInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_SXM,
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL, 12345),
- 0);
- ProgramInfoCache halCache = new ProgramInfoCache(null, true, mAmFmInfo, updatedRdsInfo,
- newSxmInfo);
+ // - Retains TEST_AM_FM_INFO.
+ // - Replaces TEST_RDS_INFO with updatedRdsInfo.
+ // - Drops TEST_DAB_INFO and TEST_VENDOR_INFO.
+ // - Introduces a new HD info.
+ RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(TEST_RDS_SELECTOR,
+ TEST_QUALITY + 1);
+ RadioManager.ProgramInfo newHdInfo = TestUtils.makeProgramInfo(TEST_HD_SELECTOR,
+ TEST_QUALITY);
+ ProgramInfoCache halCache = new ProgramInfoCache(null, true, TEST_AM_FM_INFO,
+ updatedRdsInfo, newHdInfo);
// Update the cache and verify:
// - The final chunk's complete flag is set.
- // - mAmFmInfo is retained and not reported in the chunks.
- // - updatedRdsInfo should appear as an update to mRdsInfo.
- // - newSxmInfo should appear as a new entry.
- // - mDabEnsembleInfo and mVendorCustomInfo should be reported as removed.
+ // - TEST_AM_FM_INFO is retained and not reported in the chunks.
+ // - updatedRdsInfo should appear as an update to TEST_RDS_INFO.
+ // - newHdInfo should appear as a new entry.
+ // - TEST_DAB_INFO and TEST_VENDOR_INFO should be reported as removed.
List<ProgramList.Chunk> chunks = cache.filterAndUpdateFromInternal(halCache, false, 5, 1);
- assertTrue(cache.programInfosAreExactly(mAmFmInfo, updatedRdsInfo, newSxmInfo));
+ expect.withMessage("Program info cache with modification included")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_AM_FM_INFO, updatedRdsInfo,
+ newHdInfo);
assertEquals(2, chunks.size());
verifyChunkListFlags(chunks, false, true);
- verifyChunkListModified(chunks, 5, updatedRdsInfo, newSxmInfo);
- verifyChunkListRemoved(chunks, 1, mDabEnsembleIdentifier, mVendorCustomIdentifier);
+ verifyChunkListModified(chunks, 5, updatedRdsInfo, newHdInfo);
+ verifyChunkListRemoved(chunks, 1, TEST_DAB_UNIQUE_ID, TEST_VENDOR_UNIQUE_ID);
}
@Test
public void testDeltaUpdateChunksModificationsExcluded() {
// Create a cache with a filter that excludes modifications, and set its contents to
- // mAmFmInfo, mRdsInfo, mDabEnsembleInfo, and mVendorCustomInfo.
+ // TEST_AM_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO, and TEST_VENDOR_INFO.
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new HashSet<Integer>(),
- new HashSet<ProgramSelector.Identifier>(), true, true), true, mAmFmInfo, mRdsInfo,
- mDabEnsembleInfo, mVendorCustomInfo);
+ new HashSet<ProgramSelector.Identifier>(), true, true), true,
+ TEST_AM_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO, TEST_VENDOR_INFO);
// Create a HAL cache that:
// - Is incomplete.
- // - Retains mAmFmInfo.
- // - Replaces mRdsInfo with updatedRdsInfo.
- // - Drops mDabEnsembleInfo and mVendorCustomInfo.
- // - Introduces a new SXM info.
- RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 1);
- RadioManager.ProgramInfo newSxmInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_SXM,
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL, 12345),
- 0);
- ProgramInfoCache halCache = new ProgramInfoCache(null, false, mAmFmInfo, updatedRdsInfo,
- newSxmInfo);
+ // - Retains TEST_AM_FM_INFO.
+ // - Replaces TEST_RDS_INFO with updatedRdsInfo.
+ // - Drops TEST_DAB_INFO and TEST_VENDOR_INFO.
+ // - Introduces a new HD info.
+ RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(TEST_RDS_SELECTOR, 1);
+ RadioManager.ProgramInfo newHdInfo = TestUtils.makeProgramInfo(TEST_HD_SELECTOR,
+ TEST_QUALITY);
+ ProgramInfoCache halCache = new ProgramInfoCache(null, false, TEST_AM_FM_INFO,
+ updatedRdsInfo, newHdInfo);
// Update the cache and verify:
// - All complete flags are false.
- // - mAmFmInfo and mRdsInfo are retained and not reported in the chunks.
- // - newSxmInfo should appear as a new entry.
- // - mDabEnsembleInfo and mVendorCustomInfo should be reported as removed.
+ // - TEST_AM_FM_INFO and TEST_RDS_INFO are retained and not reported in the chunks.
+ // - newHdInfo should appear as a new entry.
+ // - TEST_DAB_INFO and TEST_VENDOR_INFO should be reported as removed.
List<ProgramList.Chunk> chunks = cache.filterAndUpdateFromInternal(halCache, false, 5, 1);
- assertTrue(cache.programInfosAreExactly(mAmFmInfo, mRdsInfo, newSxmInfo));
+ expect.withMessage("Program info cache with modification excluded")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_AM_FM_INFO, TEST_RDS_INFO,
+ newHdInfo);
assertEquals(2, chunks.size());
verifyChunkListFlags(chunks, false, false);
- verifyChunkListModified(chunks, 5, newSxmInfo);
- verifyChunkListRemoved(chunks, 1, mDabEnsembleIdentifier, mVendorCustomIdentifier);
+ verifyChunkListModified(chunks, 5, newHdInfo);
+ verifyChunkListRemoved(chunks, 1, TEST_DAB_UNIQUE_ID, TEST_VENDOR_UNIQUE_ID);
}
// Verifies that:
@@ -271,20 +308,21 @@
// - Each chunk's removed array has a similar number of elements.
// - Each element of expectedIdentifiers appears in a chunk.
private static void verifyChunkListRemoved(List<ProgramList.Chunk> chunks,
- int maxRemovedPerChunk, ProgramSelector.Identifier... expectedIdentifiers) {
+ int maxRemovedPerChunk,
+ UniqueProgramIdentifier... expectedIdentifiers) {
if (chunks.isEmpty()) {
assertEquals(0, expectedIdentifiers.length);
return;
}
- HashSet<ProgramSelector.Identifier> expectedSet = new HashSet<>();
- for (ProgramSelector.Identifier identifier : expectedIdentifiers) {
+ HashSet<UniqueProgramIdentifier> expectedSet = new HashSet<>();
+ for (UniqueProgramIdentifier identifier : expectedIdentifiers) {
expectedSet.add(identifier);
}
- HashSet<ProgramSelector.Identifier> actualSet = new HashSet<>();
+ HashSet<UniqueProgramIdentifier> actualSet = new HashSet<>();
int chunk0NumRemoved = chunks.get(0).getRemoved().size();
for (ProgramList.Chunk chunk : chunks) {
- Set<ProgramSelector.Identifier> chunkRemoved = chunk.getRemoved();
+ Set<UniqueProgramIdentifier> chunkRemoved = chunk.getRemoved();
assertTrue(chunkRemoved.size() <= maxRemovedPerChunk);
assertTrue(Math.abs(chunkRemoved.size() - chunk0NumRemoved) <= 1);
actualSet.addAll(chunkRemoved);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index 7d604d4..8c16d79 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -35,6 +35,7 @@
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
+import android.hardware.radio.UniqueProgramIdentifier;
import android.os.RemoteException;
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
@@ -72,22 +73,42 @@
private TunerSession[] mTunerSessions;
// Data objects used during tests
- private final ProgramSelector.Identifier mAmFmIdentifier =
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, 88500);
- private final RadioManager.ProgramInfo mAmFmInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
- private final RadioManager.ProgramInfo mModifiedAmFmInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 1);
+ private static final int TEST_QUALITY = 0;
+ private static final ProgramSelector.Identifier TEST_AM_FM_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
+ /* value= */ 88_500);
+ private static final ProgramSelector TEST_AM_FM_SELECTOR = TestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_FM, TEST_AM_FM_ID);
+ private static final RadioManager.ProgramInfo TEST_AM_FM_INFO = TestUtils.makeProgramInfo(
+ TEST_AM_FM_SELECTOR, TEST_QUALITY);
+ private static final RadioManager.ProgramInfo TEST_AM_FM_MODIFIED_INFO =
+ TestUtils.makeProgramInfo(TEST_AM_FM_SELECTOR, TEST_QUALITY + 1);
- private final ProgramSelector.Identifier mRdsIdentifier =
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI, 15019);
- private final RadioManager.ProgramInfo mRdsInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 0);
+ private static final ProgramSelector.Identifier TEST_RDS_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI,
+ /* value= */ 15_019);
+ private static final ProgramSelector TEST_RDS_SELECTOR = TestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_FM, TEST_RDS_ID);
- private final ProgramSelector.Identifier mDabEnsembleIdentifier =
- new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, 1337);
- private final RadioManager.ProgramInfo mDabEnsembleInfo = TestUtils.makeProgramInfo(
- ProgramSelector.PROGRAM_TYPE_DAB, mDabEnsembleIdentifier, 0);
+ private static final UniqueProgramIdentifier TEST_RDS_UNIQUE_ID = new UniqueProgramIdentifier(
+ TEST_RDS_ID);
+ private static final RadioManager.ProgramInfo TEST_RDS_INFO = TestUtils.makeProgramInfo(
+ TEST_RDS_SELECTOR, TEST_QUALITY);
+
+ private static final ProgramSelector.Identifier TEST_DAB_SID_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT,
+ /* value= */ 0xA000000111L);
+ private static final ProgramSelector.Identifier TEST_DAB_ENSEMBLE_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
+ /* value= */ 0x1001);
+ private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
+ /* value= */ 220_352);
+ private static final ProgramSelector TEST_DAB_SELECTOR = TestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_ID,
+ new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID});
+ private static final RadioManager.ProgramInfo TEST_DAB_INFO = TestUtils.makeProgramInfo(
+ TEST_DAB_SELECTOR, TEST_QUALITY);
@Override
protected void initializeSession(StaticMockitoSessionBuilder builder) {
@@ -126,18 +147,18 @@
// Initiate a program list update from the HAL side and verify both connected AIDL clients
// receive the update.
- updateHalProgramInfo(true, Arrays.asList(mAmFmInfo, mRdsInfo), null);
+ updateHalProgramInfo(true, Arrays.asList(TEST_AM_FM_INFO, TEST_RDS_INFO), null);
for (int i = 0; i < 2; i++) {
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[i], true, Arrays.asList(
- mAmFmInfo, mRdsInfo), null);
+ TEST_AM_FM_INFO, TEST_RDS_INFO), null);
}
// Repeat with a non-purging update.
- updateHalProgramInfo(false, Arrays.asList(mModifiedAmFmInfo),
- Arrays.asList(mRdsIdentifier));
+ updateHalProgramInfo(false, Arrays.asList(TEST_AM_FM_MODIFIED_INFO),
+ Arrays.asList(TEST_RDS_ID));
for (int i = 0; i < 2; i++) {
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[i], false,
- Arrays.asList(mModifiedAmFmInfo), Arrays.asList(mRdsIdentifier));
+ Arrays.asList(TEST_AM_FM_MODIFIED_INFO), Arrays.asList(TEST_RDS_UNIQUE_ID));
}
// Now start updates on the 3rd client. Verify the HAL function has not been called again
@@ -145,19 +166,19 @@
mTunerSessions[2].startProgramListUpdates(aidlFilter);
verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(any());
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[2], true,
- Arrays.asList(mModifiedAmFmInfo), null);
+ Arrays.asList(TEST_AM_FM_MODIFIED_INFO), null);
}
@Test
public void testFiltering() throws RemoteException {
// Open 4 clients that will use the following filters:
- // [0]: ID mRdsIdentifier, modifications excluded
+ // [0]: ID TEST_RDS_ID, modifications excluded
// [1]: No categories, modifications excluded
// [2]: Type IDENTIFIER_TYPE_AMFM_FREQUENCY, modifications excluded
// [3]: Type IDENTIFIER_TYPE_AMFM_FREQUENCY, modifications included
openAidlClients(4);
ProgramList.Filter idFilter = new ProgramList.Filter(new HashSet<Integer>(),
- new HashSet<ProgramSelector.Identifier>(Arrays.asList(mRdsIdentifier)), true, true);
+ new HashSet<ProgramSelector.Identifier>(Arrays.asList(TEST_RDS_ID)), true, true);
ProgramList.Filter categoryFilter = new ProgramList.Filter(new HashSet<Integer>(),
new HashSet<ProgramSelector.Identifier>(), false, true);
ProgramList.Filter typeFilterWithoutModifications = new ProgramList.Filter(
@@ -188,41 +209,40 @@
halFilter.excludeModifications = false;
verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
- // Adding mRdsInfo should update clients [0] and [1].
- updateHalProgramInfo(false, Arrays.asList(mRdsInfo), null);
- verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false, Arrays.asList(mRdsInfo),
- null);
- verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], false, Arrays.asList(mRdsInfo),
- null);
+ // Adding TEST_RDS_INFO should update clients [0] and [1].
+ updateHalProgramInfo(false, Arrays.asList(TEST_RDS_INFO), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false,
+ Arrays.asList(TEST_RDS_INFO), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], false,
+ Arrays.asList(TEST_RDS_INFO), null);
- // Adding mAmFmInfo should update clients [1], [2], and [3].
- updateHalProgramInfo(false, Arrays.asList(mAmFmInfo), null);
- verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], false, Arrays.asList(mAmFmInfo),
- null);
- verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[2], false, Arrays.asList(mAmFmInfo),
- null);
- verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[3], false, Arrays.asList(mAmFmInfo),
- null);
-
- // Modifying mAmFmInfo to mModifiedAmFmInfo should update only [3].
- updateHalProgramInfo(false, Arrays.asList(mModifiedAmFmInfo), null);
+ // Adding TEST_AM_FM_INFO should update clients [1], [2], and [3].
+ updateHalProgramInfo(false, Arrays.asList(TEST_AM_FM_INFO), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], false,
+ Arrays.asList(TEST_AM_FM_INFO), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[2], false,
+ Arrays.asList(TEST_AM_FM_INFO), null);
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[3], false,
- Arrays.asList(mModifiedAmFmInfo), null);
+ Arrays.asList(TEST_AM_FM_INFO), null);
- // Adding mDabEnsembleInfo should not update any client.
- updateHalProgramInfo(false, Arrays.asList(mDabEnsembleInfo), null);
+ // Modifying TEST_AM_FM_INFO to TEST_AM_FM_MODIFIED_INFO should update only [3].
+ updateHalProgramInfo(false, Arrays.asList(TEST_AM_FM_MODIFIED_INFO), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[3], false,
+ Arrays.asList(TEST_AM_FM_MODIFIED_INFO), null);
+
+ updateHalProgramInfo(false, Arrays.asList(TEST_DAB_INFO), null);
verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
- verify(mAidlTunerCallbackMocks[1], CB_TIMEOUT.times(2)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[1], CB_TIMEOUT.times(3)).onProgramListUpdated(any());
verify(mAidlTunerCallbackMocks[2], CB_TIMEOUT.times(2)).onProgramListUpdated(any());
verify(mAidlTunerCallbackMocks[3], CB_TIMEOUT.times(2)).onProgramListUpdated(any());
}
@Test
public void testClientClosing() throws RemoteException {
- // Open 2 clients that use different filters that are both sensitive to mAmFmIdentifier.
+ // Open 2 clients that use different filters that are both sensitive to TEST_AM_FM_ID.
openAidlClients(2);
ProgramList.Filter idFilter = new ProgramList.Filter(new HashSet<Integer>(),
- new HashSet<ProgramSelector.Identifier>(Arrays.asList(mAmFmIdentifier)), true,
+ new HashSet<ProgramSelector.Identifier>(Arrays.asList(TEST_AM_FM_ID)), true,
false);
ProgramList.Filter typeFilter = new ProgramList.Filter(
new HashSet<Integer>(Arrays.asList(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)),
@@ -237,23 +257,24 @@
halFilter.identifiers.clear();
verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
- // Update the HAL with mAmFmInfo, and verify both clients are updated.
- updateHalProgramInfo(true, Arrays.asList(mAmFmInfo), null);
- verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], true, Arrays.asList(mAmFmInfo),
- null);
- verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true, Arrays.asList(mAmFmInfo),
- null);
+ // Update the HAL with TEST_AM_FM_INFO, and verify both clients are updated.
+ updateHalProgramInfo(true, Arrays.asList(TEST_AM_FM_INFO), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], true,
+ Arrays.asList(TEST_AM_FM_INFO), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true,
+ Arrays.asList(TEST_AM_FM_INFO), null);
// Stop updates on the first client and verify the HAL filter is updated.
mTunerSessions[0].stopProgramListUpdates();
verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(Convert.programFilterToHal(
typeFilter));
- // Update the HAL with mModifiedAmFmInfo, and verify only the remaining client is updated.
- updateHalProgramInfo(true, Arrays.asList(mModifiedAmFmInfo), null);
+ // Update the HAL with TEST_AM_FM_MODIFIED_INFO, and verify only the remaining client is
+ // updated.
+ updateHalProgramInfo(true, Arrays.asList(TEST_AM_FM_MODIFIED_INFO), null);
verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true,
- Arrays.asList(mModifiedAmFmInfo), null);
+ Arrays.asList(TEST_AM_FM_MODIFIED_INFO), null);
// Close the other client without explicitly stopping updates, and verify HAL updates are
// stopped as well.
@@ -269,15 +290,15 @@
// Verify the AIDL client receives all types of updates (e.g. a new program, an update to
// that program, and a category).
- updateHalProgramInfo(true, Arrays.asList(mAmFmInfo, mRdsInfo), null);
+ updateHalProgramInfo(true, Arrays.asList(TEST_AM_FM_INFO, TEST_RDS_INFO), null);
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], true, Arrays.asList(
- mAmFmInfo, mRdsInfo), null);
- updateHalProgramInfo(false, Arrays.asList(mModifiedAmFmInfo), null);
+ TEST_AM_FM_INFO, TEST_RDS_INFO), null);
+ updateHalProgramInfo(false, Arrays.asList(TEST_AM_FM_MODIFIED_INFO), null);
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false,
- Arrays.asList(mModifiedAmFmInfo), null);
- updateHalProgramInfo(false, Arrays.asList(mDabEnsembleInfo), null);
+ Arrays.asList(TEST_AM_FM_MODIFIED_INFO), null);
+ updateHalProgramInfo(false, Arrays.asList(TEST_DAB_INFO), null);
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false,
- Arrays.asList(mDabEnsembleInfo), null);
+ Arrays.asList(TEST_DAB_INFO), null);
// Verify closing the AIDL session also stops HAL updates.
mTunerSessions[0].close();
@@ -313,12 +334,12 @@
private void verifyAidlClientReceivedChunk(android.hardware.radio.ITunerCallback clientMock,
boolean purge, List<RadioManager.ProgramInfo> modified,
- List<ProgramSelector.Identifier> removed) throws RemoteException {
+ List<UniqueProgramIdentifier> removed) throws RemoteException {
HashSet<RadioManager.ProgramInfo> modifiedSet = new HashSet<>();
if (modified != null) {
modifiedSet.addAll(modified);
}
- HashSet<ProgramSelector.Identifier> removedSet = new HashSet<>();
+ HashSet<UniqueProgramIdentifier> removedSet = new HashSet<>();
if (removed != null) {
removedSet.addAll(removed);
}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java
index d4ca8d4..0b16141 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java
@@ -45,6 +45,23 @@
static RadioManager.ProgramInfo makeProgramInfo(ProgramSelector selector,
ProgramSelector.Identifier logicallyTunedTo,
ProgramSelector.Identifier physicallyTunedTo, int signalQuality) {
+ if (logicallyTunedTo == null) {
+ logicallyTunedTo = selector.getPrimaryId();
+ }
+ if (physicallyTunedTo == null) {
+ if (selector.getPrimaryId().getType()
+ == ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT) {
+ for (int i = 0; i < selector.getSecondaryIds().length; i++) {
+ if (selector.getSecondaryIds()[i].getType()
+ == ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY) {
+ physicallyTunedTo = selector.getSecondaryIds()[i];
+ break;
+ }
+ }
+ } else {
+ physicallyTunedTo = selector.getPrimaryId();
+ }
+ }
return new RadioManager.ProgramInfo(selector,
logicallyTunedTo, physicallyTunedTo, /* relatedContents= */ null,
/* infoFlags= */ 0, signalQuality,
@@ -52,14 +69,8 @@
}
static RadioManager.ProgramInfo makeProgramInfo(ProgramSelector selector, int signalQuality) {
- return makeProgramInfo(selector, selector.getPrimaryId(), selector.getPrimaryId(),
- signalQuality);
- }
-
- static RadioManager.ProgramInfo makeProgramInfo(int programType,
- ProgramSelector.Identifier identifier, int signalQuality) {
- return makeProgramInfo(makeProgramSelector(programType, identifier),
- /* logicallyTunedTo= */ null, /* physicallyTunedTo= */ null, signalQuality);
+ return makeProgramInfo(selector, /* logicallyTunedTo= */ null,
+ /* physicallyTunedTo= */ null, signalQuality);
}
static ProgramSelector makeFmSelector(long freq) {
@@ -70,8 +81,12 @@
static ProgramSelector makeProgramSelector(int programType,
ProgramSelector.Identifier identifier) {
- return new ProgramSelector(programType, identifier, /* secondaryIds= */ null,
- /* vendorIds= */ null);
+ return makeProgramSelector(programType, identifier, /* secondaryIds= */ null);
+ }
+
+ static ProgramSelector makeProgramSelector(int programType,
+ ProgramSelector.Identifier primaryId, ProgramSelector.Identifier[] secondaryIds) {
+ return new ProgramSelector(programType, primaryId, secondaryIds, /* vendorIds= */ null);
}
static ProgramInfo programInfoToHal(RadioManager.ProgramInfo info) {
@@ -79,6 +94,21 @@
// function only copies fields that are set by makeProgramInfo().
ProgramInfo hwInfo = new ProgramInfo();
hwInfo.selector = Convert.programSelectorToHal(info.getSelector());
+ hwInfo.logicallyTunedTo = hwInfo.selector.primaryId;
+ if (info.getSelector().getPrimaryId().getType()
+ == ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT) {
+ for (int i = 0; i < info.getSelector().getSecondaryIds().length; i++) {
+ if (info.getSelector().getSecondaryIds()[i].getType()
+ == ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY) {
+ hwInfo.physicallyTunedTo = Convert.programIdentifierToHal(info.getSelector()
+ .getSecondaryIds()[i]);
+ break;
+ }
+ }
+ } else {
+ hwInfo.physicallyTunedTo = Convert.programIdentifierToHal(info.getSelector()
+ .getPrimaryId());
+ }
hwInfo.signalQuality = info.getSignalStrength();
return hwInfo;
}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 0778311..819178f 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -99,7 +99,7 @@
// The first sequence number to try with. Use a large number to avoid conflicts with the first a
// few sequence numbers the framework used to launch the test activity.
- private static final int BASE_SEQ = 10000;
+ private static final int BASE_SEQ = 10000000;
@Rule
public final ActivityTestRule<TestActivity> mActivityTestRule =
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 6057852..721a2db 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -3067,6 +3067,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "643263584": {
+ "message": "Content Recording: Apply transformations of shift %d x %d, scale %f, crop %d x %d for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"644675193": {
"message": "Real start recents",
"level": "DEBUG",
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index a4c655c8c..1ff5a3d 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1779,7 +1779,7 @@
* If the bitmap's internal config is in one of the public formats, return
* that config, otherwise return null.
*/
- @NonNull
+ @Nullable
public final Config getConfig() {
if (mRecycled) {
Log.w(TAG, "Called getConfig() on a recycle()'d bitmap! This is undefined behavior!");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index 9b80063..4640106 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -245,8 +245,8 @@
private boolean shouldShowBackdrop(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change) {
- final Animation a = loadAttributeAnimation(info.getType(), info, change,
- WALLPAPER_TRANSITION_NONE, mTransitionAnimation, false);
+ final Animation a = loadAttributeAnimation(info, change, WALLPAPER_TRANSITION_NONE,
+ mTransitionAnimation, false);
return a != null && a.getShowBackdrop();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 093ecb1..d10de83 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -131,6 +131,7 @@
private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
+ /** Should be kept in sync with value in TaskbarScrimViewController. */
private static final float SCRIM_ALPHA = 0.32f;
/** Minimum alpha value for scrim when alpha is being changed via drag */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index f90ee58..991b699 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -43,6 +43,7 @@
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.app.TaskInfo;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
@@ -814,21 +815,22 @@
final String packageName1 = SplitScreenUtils.getPackageName(intent);
final String packageName2 = getPackageName(reverseSplitPosition(position));
final int userId2 = getUserId(reverseSplitPosition(position));
+ final ComponentName component = intent.getIntent().getComponent();
+
+ // To prevent accumulating large number of instances in the background, reuse task
+ // in the background. If we don't explicitly reuse, new may be created even if the app
+ // isn't multi-instance because WM won't automatically remove/reuse the previous instance
+ final ActivityManager.RecentTaskInfo taskInfo = mRecentTasksOptional
+ .map(recentTasks -> recentTasks.findTaskInBackground(component, userId1))
+ .orElse(null);
+ if (taskInfo != null) {
+ startTask(taskInfo.taskId, position, options);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "Start task in background");
+ return;
+ }
if (samePackage(packageName1, packageName2, userId1, userId2)) {
if (supportMultiInstancesSplit(packageName1)) {
- // To prevent accumulating large number of instances in the background, reuse task
- // in the background with priority.
- final ActivityManager.RecentTaskInfo taskInfo = mRecentTasksOptional
- .map(recentTasks -> recentTasks.findTaskInBackground(
- intent.getIntent().getComponent(), userId1))
- .orElse(null);
- if (taskInfo != null) {
- startTask(taskInfo.taskId, position, options);
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
- "Start task in background");
- return;
- }
-
// Flag with MULTIPLE_TASK if this is launching the same activity into both sides of
// the split and there is no reusable background task.
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index d310ae3..7df658e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -37,12 +37,8 @@
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
-import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.window.TransitionInfo.FLAGS_IS_NON_APP_WINDOW;
import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL;
@@ -338,10 +334,6 @@
boolean isDisplayRotationAnimationStarted = false;
final boolean isDreamTransition = isDreamTransition(info);
final boolean isOnlyTranslucent = isOnlyTranslucent(info);
- final boolean isActivityReplace = checkActivityReplacement(info, startTransaction);
- // Some patterns (eg. activity "replacement") require us to re-interpret the type
- @WindowManager.TransitionType final int transitType =
- isActivityReplace ? TRANSIT_OPEN : info.getType();
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -438,8 +430,7 @@
// Don't animate anything that isn't independent.
if (!TransitionInfo.isIndependent(change, info)) continue;
- Animation a = loadAnimation(transitType, info, change, wallpaperTransit,
- isDreamTransition);
+ Animation a = loadAnimation(info, change, wallpaperTransit, isDreamTransition);
if (a != null) {
if (isTask) {
final boolean isTranslucent = (change.getFlags() & FLAG_TRANSLUCENT) != 0;
@@ -613,53 +604,6 @@
return (translucentOpen + translucentClose) > 0;
}
- /**
- * Checks for an edge-case where an activity calls finish() followed immediately by
- * startActivity() to "replace" itself. If in this case, it will swap the layer of the
- * close/open activities and return `true`. This way, we pretend like we are just "opening"
- * the new activity.
- */
- private static boolean checkActivityReplacement(@NonNull TransitionInfo info,
- SurfaceControl.Transaction t) {
- if (info.getType() != TRANSIT_CLOSE) {
- return false;
- }
- int closing = -1;
- int opening = -1;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if ((change.getTaskInfo() != null || change.hasFlags(FLAG_IS_DISPLAY))
- && !TransitionUtil.isOrderOnly(change)) {
- // This isn't an activity-level transition.
- return false;
- }
- if (change.getTaskInfo() != null
- && change.hasFlags(FLAG_IS_DISPLAY | FLAGS_IS_NON_APP_WINDOW)) {
- // Ignore non-activity containers.
- continue;
- }
- if (TransitionUtil.isClosingType(change.getMode())) {
- closing = i;
- } else if (change.getMode() == TRANSIT_OPEN) {
- // OPEN implies that it is a new launch. If going "back" the opening app will be
- // TO_FRONT
- opening = i;
- } else if (change.getMode() == TRANSIT_TO_FRONT) {
- // Normal "going back", so not a replacement.
- return false;
- }
- }
- if (closing < 0 || opening < 0) {
- return false;
- }
- // Swap the opening and closing z-orders since we're swapping the transit type.
- final int numChanges = info.getChanges().size();
- final int zSplitLine = numChanges + 1;
- t.setLayer(info.getChanges().get(opening).getLeash(), zSplitLine + numChanges - opening);
- t.setLayer(info.getChanges().get(closing).getLeash(), zSplitLine - closing);
- return true;
- }
-
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@@ -712,11 +656,12 @@
}
@Nullable
- private Animation loadAnimation(int type, @NonNull TransitionInfo info,
+ private Animation loadAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, int wallpaperTransit,
boolean isDreamTransition) {
Animation a;
+ final int type = info.getType();
final int flags = info.getFlags();
final int changeMode = change.getMode();
final int changeFlags = change.getFlags();
@@ -771,8 +716,8 @@
// If there's a scene-transition, then jump-cut.
return null;
} else {
- a = loadAttributeAnimation(type, info, change, wallpaperTransit, mTransitionAnimation,
- isDreamTransition);
+ a = loadAttributeAnimation(
+ info, change, wallpaperTransit, mTransitionAnimation, isDreamTransition);
}
if (a != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index c99911d..d07d2b7b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -45,7 +45,6 @@
import android.graphics.Shader;
import android.view.Surface;
import android.view.SurfaceControl;
-import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.window.ScreenCapture;
@@ -62,10 +61,10 @@
/** Loads the animation that is defined through attribute id for the given transition. */
@Nullable
- public static Animation loadAttributeAnimation(@WindowManager.TransitionType int type,
- @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
- int wallpaperTransit, @NonNull TransitionAnimation transitionAnimation,
- boolean isDreamTransition) {
+ public static Animation loadAttributeAnimation(@NonNull TransitionInfo info,
+ @NonNull TransitionInfo.Change change, int wallpaperTransit,
+ @NonNull TransitionAnimation transitionAnimation, boolean isDreamTransition) {
+ final int type = info.getType();
final int changeMode = change.getMode();
final int changeFlags = change.getFlags();
final boolean enter = TransitionUtil.isOpeningType(changeMode);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 568db91..99cd4f3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -36,6 +36,7 @@
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -218,8 +219,7 @@
}
@Test
- public void startIntent_multiInstancesSupported_startTaskInBackgroundBeforeSplitActivated() {
- doReturn(true).when(mSplitScreenController).supportMultiInstancesSplit(any());
+ public void startIntent_multiInstancesNotSupported_startTaskInBackgroundBeforeSplitActivated() {
doNothing().when(mSplitScreenController).startTask(anyInt(), anyInt(), any());
Intent startIntent = createStartIntent("startActivity");
PendingIntent pendingIntent =
@@ -237,6 +237,8 @@
verify(mSplitScreenController).startTask(anyInt(), eq(SPLIT_POSITION_TOP_OR_LEFT),
isNull());
+ verify(mSplitScreenController, never()).supportMultiInstancesSplit(any());
+ verify(mStageCoordinator, never()).switchSplitPosition(any());
}
@Test
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 1ee5aa3..8e9c079 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -931,8 +931,7 @@
* @return a MediaPlayer object, or null if creation failed
*/
public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder) {
- int s = AudioSystem.newAudioSessionId();
- return create(context, uri, holder, null, s > 0 ? s : 0);
+ return create(context, uri, holder, null, AudioSystem.AUDIO_SESSION_ALLOCATE);
}
/**
@@ -994,8 +993,7 @@
* @return a MediaPlayer object, or null if creation failed
*/
public static MediaPlayer create(Context context, int resid) {
- int s = AudioSystem.newAudioSessionId();
- return create(context, resid, null, s > 0 ? s : 0);
+ return create(context, resid, null, AudioSystem.AUDIO_SESSION_ALLOCATE);
}
/**
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index d6921c8..8c63580 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -17,9 +17,11 @@
package android.media;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.media.flags.Flags.FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2;
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -370,14 +372,14 @@
}
/**
- * Registers callback to be invoked when the {@link RouteListingPreference} of the target
- * router changes.
+ * Registers the given callback to be invoked when the {@link RouteListingPreference} of the
+ * target router changes.
*
- * <p>Calls using a previously registered callback will overwrite the callback record.
+ * <p>Calls using a previously registered callback will overwrite the previous executor.
*
* @see #setRouteListingPreference(RouteListingPreference)
- * @hide
*/
+ @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2)
public void registerRouteListingPreferenceCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull RouteListingPreferenceCallback routeListingPreferenceCallback) {
@@ -393,9 +395,8 @@
/**
* Unregisters the given callback to not receive {@link RouteListingPreference} change events.
- *
- * @hide
*/
+ @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2)
public void unregisterRouteListingPreferenceCallback(
@NonNull RouteListingPreferenceCallback callback) {
Objects.requireNonNull(callback, "callback must not be null");
@@ -462,9 +463,12 @@
/**
* Returns the current {@link RouteListingPreference} of the target router.
*
+ * <p>If this instance was created using {@link #getInstance(Context, String)}, then it returns
+ * the last {@link RouteListingPreference} set by the process this router was created for.
+ *
* @see #setRouteListingPreference(RouteListingPreference)
- * @hide
*/
+ @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2)
@Nullable
public RouteListingPreference getRouteListingPreference() {
synchronized (mLock) {
@@ -1201,9 +1205,19 @@
public void onPreferredFeaturesChanged(@NonNull List<String> preferredFeatures) {}
}
- /** @hide */
+ /** Callback for receiving events related to {@link RouteListingPreference}. */
+ @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2)
public abstract static class RouteListingPreferenceCallback {
- /** @hide */
+
+ @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2)
+ public RouteListingPreferenceCallback() {}
+
+ /**
+ * Called when the {@link RouteListingPreference} changes.
+ *
+ * @see #getRouteListingPreference
+ */
+ @FlaggedApi(FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2)
public void onRouteListingPreferenceChanged(@Nullable RouteListingPreference preference) {}
}
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
new file mode 100644
index 0000000..17962ee
--- /dev/null
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.media.flags"
+
+flag {
+ namespace: "media_solutions"
+ name: "enable_rlp_callbacks_in_media_router2"
+ description: "Make RouteListingPreference getter and callbacks public in MediaRouter2."
+ bug: "281067101"
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerUnitTest.java
index f812d5f..f27a568 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerUnitTest.java
@@ -30,6 +30,7 @@
import android.companion.virtual.VirtualDeviceManager;
import android.content.Context;
+import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.test.mock.MockContext;
@@ -37,6 +38,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.mediaframeworktest.R;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,6 +48,8 @@
public class MediaPlayerUnitTest {
private static final int TEST_VIRTUAL_DEVICE_ID = 42;
+ private static final AudioAttributes AUDIO_ATTRIBUTES_MEDIA =
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
@Test
public void testConstructionWithContext_virtualDeviceDefaultAudioPolicy() {
@@ -89,6 +94,49 @@
assertEquals(anotherSessionId, mediaPlayer.getAudioSessionId());
}
+ @Test
+ public void testCreateFromResource_virtualDeviceDefaultAudioPolicy() {
+ int vdmPlaybackSessionId = getContext().getSystemService(
+ AudioManager.class).generateAudioSessionId();
+ VirtualDeviceManager mockVdm = getMockVirtualDeviceManager(TEST_VIRTUAL_DEVICE_ID,
+ vdmPlaybackSessionId, DEVICE_POLICY_DEFAULT);
+ Context virtualDeviceContext = getVirtualDeviceMockContext(TEST_VIRTUAL_DEVICE_ID, mockVdm);
+
+ MediaPlayer mediaPlayer = MediaPlayer.create(virtualDeviceContext, R.raw.testmp3);
+
+ assertNotEquals(vdmPlaybackSessionId, mediaPlayer.getAudioSessionId());
+ assertTrue(mediaPlayer.getAudioSessionId() > 0);
+ }
+
+ @Test
+ public void testCreateFromResource_virtualDeviceCustomAudioPolicy() {
+ int vdmPlaybackSessionId = getContext().getSystemService(
+ AudioManager.class).generateAudioSessionId();
+ VirtualDeviceManager mockVdm = getMockVirtualDeviceManager(TEST_VIRTUAL_DEVICE_ID,
+ vdmPlaybackSessionId, DEVICE_POLICY_CUSTOM);
+ Context virtualDeviceContext = getVirtualDeviceMockContext(TEST_VIRTUAL_DEVICE_ID, mockVdm);
+
+ MediaPlayer mediaPlayer = MediaPlayer.create(virtualDeviceContext, R.raw.testmp3);
+
+ assertEquals(vdmPlaybackSessionId, mediaPlayer.getAudioSessionId());
+ }
+
+ @Test
+ public void testCreateFromResource_explicitSessionIdOverridesContext() {
+ int vdmPlaybackSessionId = getContext().getSystemService(
+ AudioManager.class).generateAudioSessionId();
+ int anotherSessionId = getContext().getSystemService(
+ AudioManager.class).generateAudioSessionId();
+ VirtualDeviceManager mockVdm = getMockVirtualDeviceManager(TEST_VIRTUAL_DEVICE_ID,
+ vdmPlaybackSessionId, DEVICE_POLICY_CUSTOM);
+ Context virtualDeviceContext = getVirtualDeviceMockContext(TEST_VIRTUAL_DEVICE_ID, mockVdm);
+
+ MediaPlayer mediaPlayer = MediaPlayer.create(virtualDeviceContext, R.raw.testmp3,
+ AUDIO_ATTRIBUTES_MEDIA, anotherSessionId);
+
+ assertEquals(anotherSessionId, mediaPlayer.getAudioSessionId());
+ }
+
private Context getContext() {
return InstrumentationRegistry.getInstrumentation().getContext();
}
@@ -98,6 +146,7 @@
when(mockContext.getDeviceId()).thenReturn(deviceId);
when(mockContext.getSystemService(VirtualDeviceManager.class)).thenReturn(vdm);
when(mockContext.getAttributionSource()).thenReturn(getContext().getAttributionSource());
+ when(mockContext.getResources()).thenReturn(getContext().getResources());
return mockContext;
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
index 4a252a9..471f3b9 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
@@ -22,6 +22,7 @@
import com.android.settingslib.spa.framework.common.SpaEnvironment
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
+import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.AlertDialogPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
import com.android.settingslib.spa.gallery.editor.SettingsExposedDropdownMenuBoxPageProvider
@@ -32,7 +33,6 @@
import com.android.settingslib.spa.gallery.itemList.OperateListPageProvider
import com.android.settingslib.spa.gallery.editor.SettingsOutlinedTextFieldPageProvider
import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
-import com.android.settingslib.spa.gallery.page.ChartPageProvider
import com.android.settingslib.spa.gallery.page.FooterPageProvider
import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/BarChartEntry.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/BarChartEntry.kt
new file mode 100644
index 0000000..bf7a8e1
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/BarChartEntry.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.gallery.chart
+
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.widget.chart.BarChart
+import com.android.settingslib.spa.widget.chart.BarChartData
+import com.android.settingslib.spa.widget.chart.BarChartModel
+import com.android.settingslib.spa.widget.chart.ColorPalette
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.github.mikephil.charting.formatter.IAxisValueFormatter
+
+fun createBarChartEntry(owner: SettingsPage) = SettingsEntryBuilder.create("Bar Chart", owner)
+ .setUiLayoutFn {
+ Preference(object : PreferenceModel {
+ override val title = "Bar Chart"
+ })
+ BarChart(
+ barChartModel = object : BarChartModel {
+ override val chartDataList = listOf(
+ BarChartData(x = 0f, y = listOf(12f, 2f)),
+ BarChartData(x = 1f, y = listOf(5f, 1f)),
+ BarChartData(x = 2f, y = listOf(21f, 2f)),
+ BarChartData(x = 3f, y = listOf(5f, 1f)),
+ BarChartData(x = 4f, y = listOf(10f, 0f)),
+ BarChartData(x = 5f, y = listOf(9f, 1f)),
+ BarChartData(x = 6f, y = listOf(1f, 1f)),
+ )
+ override val colors = listOf(ColorPalette.green, ColorPalette.yellow)
+ override val xValueFormatter = IAxisValueFormatter { value, _ ->
+ "4/${value.toInt() + 1}"
+ }
+ override val yValueFormatter = IAxisValueFormatter { value, _ ->
+ "${value.toInt()}m"
+ }
+ override val yAxisMaxValue = 30f
+ }
+ )
+ }.build()
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/ChartPageProvider.kt
similarity index 73%
rename from packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt
rename to packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/ChartPageProvider.kt
index 69c4705..7a6ae2c 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/ChartPageProvider.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settingslib.spa.gallery.page
+package com.android.settingslib.spa.gallery.chart
import android.os.Bundle
import androidx.compose.runtime.Composable
@@ -25,9 +25,6 @@
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.theme.SettingsTheme
-import com.android.settingslib.spa.widget.chart.BarChart
-import com.android.settingslib.spa.widget.chart.BarChartData
-import com.android.settingslib.spa.widget.chart.BarChartModel
import com.android.settingslib.spa.widget.chart.LineChart
import com.android.settingslib.spa.widget.chart.LineChartData
import com.android.settingslib.spa.widget.chart.LineChartModel
@@ -83,36 +80,7 @@
)
}.build()
)
- entryList.add(
- SettingsEntryBuilder.create("Bar Chart", owner)
- .setUiLayoutFn {
- Preference(object : PreferenceModel {
- override val title = "Bar Chart"
- })
- BarChart(
- barChartModel = object : BarChartModel {
- override val chartDataList = listOf(
- BarChartData(x = 0f, y = 12f),
- BarChartData(x = 1f, y = 5f),
- BarChartData(x = 2f, y = 21f),
- BarChartData(x = 3f, y = 5f),
- BarChartData(x = 4f, y = 10f),
- BarChartData(x = 5f, y = 9f),
- BarChartData(x = 6f, y = 1f),
- )
- override val xValueFormatter =
- IAxisValueFormatter { value, _ ->
- "${WeekDay.values()[value.toInt()]}"
- }
- override val yValueFormatter =
- IAxisValueFormatter { value, _ ->
- "${value.toInt()}m"
- }
- override val yAxisMaxValue = 30f
- }
- )
- }.build()
- )
+ entryList.add(createBarChartEntry(owner))
entryList.add(
SettingsEntryBuilder.create("Pie Chart", owner)
.setUiLayoutFn {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
index bb311a5..6cac220 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
@@ -28,12 +28,12 @@
import com.android.settingslib.spa.gallery.R
import com.android.settingslib.spa.gallery.SettingsPageProviderEnum
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
+import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.AlertDialogPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
import com.android.settingslib.spa.gallery.itemList.OperateListPageProvider
import com.android.settingslib.spa.gallery.page.ArgumentPageModel
import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
-import com.android.settingslib.spa.gallery.page.ChartPageProvider
import com.android.settingslib.spa.gallery.page.FooterPageProvider
import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt
index 27d270c..e6decb1 100644
--- a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt
@@ -16,6 +16,7 @@
package com.android.settingslib.spa.screenshot
+import androidx.compose.material3.MaterialTheme
import com.android.settingslib.spa.widget.chart.BarChart
import com.android.settingslib.spa.widget.chart.BarChartData
import com.android.settingslib.spa.widget.chart.BarChartModel
@@ -45,17 +46,19 @@
@Test
fun test() {
screenshotRule.screenshotTest("barChart") {
+ val color = MaterialTheme.colorScheme.surfaceVariant
BarChart(
barChartModel = object : BarChartModel {
override val chartDataList = listOf(
- BarChartData(x = 0f, y = 12f),
- BarChartData(x = 1f, y = 5f),
- BarChartData(x = 2f, y = 21f),
- BarChartData(x = 3f, y = 5f),
- BarChartData(x = 4f, y = 10f),
- BarChartData(x = 5f, y = 9f),
- BarChartData(x = 6f, y = 1f),
+ BarChartData(x = 0f, y = listOf(12f)),
+ BarChartData(x = 1f, y = listOf(5f)),
+ BarChartData(x = 2f, y = listOf(21f)),
+ BarChartData(x = 3f, y = listOf(5f)),
+ BarChartData(x = 4f, y = listOf(10f)),
+ BarChartData(x = 5f, y = listOf(9f)),
+ BarChartData(x = 6f, y = listOf(1f)),
)
+ override val colors = listOf(color)
override val xValueFormatter =
IAxisValueFormatter { value, _ ->
"${WeekDay.values()[value.toInt()]}"
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt
index 0b0f07e..7ca15d9 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt
@@ -31,6 +31,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
@@ -52,6 +53,11 @@
val chartDataList: List<BarChartData>
/**
+ * The color list for [BarChart].
+ */
+ val colors: List<Color>
+
+ /**
* The label text formatter for x value.
*/
val xValueFormatter: IAxisValueFormatter?
@@ -83,34 +89,14 @@
}
data class BarChartData(
- var x: Float?,
- var y: Float?,
+ var x: Float,
+ var y: List<Float>,
)
@Composable
fun BarChart(barChartModel: BarChartModel) {
- BarChart(
- chartDataList = barChartModel.chartDataList,
- xValueFormatter = barChartModel.xValueFormatter,
- yValueFormatter = barChartModel.yValueFormatter,
- yAxisMinValue = barChartModel.yAxisMinValue,
- yAxisMaxValue = barChartModel.yAxisMaxValue,
- yAxisLabelCount = barChartModel.yAxisLabelCount,
- )
-}
-
-@Composable
-fun BarChart(
- chartDataList: List<BarChartData>,
- modifier: Modifier = Modifier,
- xValueFormatter: IAxisValueFormatter? = null,
- yValueFormatter: IAxisValueFormatter? = null,
- yAxisMinValue: Float = 0f,
- yAxisMaxValue: Float = 30f,
- yAxisLabelCount: Int = 4,
-) {
Column(
- modifier = modifier
+ modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
horizontalAlignment = Alignment.CenterHorizontally,
@@ -126,50 +112,61 @@
val colorScheme = MaterialTheme.colorScheme
val labelTextColor = colorScheme.onSurfaceVariant.toArgb()
val labelTextSize = MaterialTheme.typography.bodyMedium.fontSize.value
- Crossfade(targetState = chartDataList) { barChartData ->
- AndroidView(factory = { context ->
- BarChart(context).apply {
- // Fixed Settings.
- layoutParams = LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT,
- )
- this.description.isEnabled = false
- this.legend.isEnabled = false
- this.extraBottomOffset = 4f
- this.setScaleEnabled(false)
+ Crossfade(
+ targetState = barChartModel.chartDataList,
+ label = "chartDataList",
+ ) { barChartData ->
+ AndroidView(
+ factory = { context ->
+ BarChart(context).apply {
+ layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ )
+ description.isEnabled = false
+ legend.isEnabled = false
+ extraBottomOffset = 4f
+ setScaleEnabled(false)
- this.xAxis.position = XAxis.XAxisPosition.BOTTOM
- this.xAxis.setDrawGridLines(false)
- this.xAxis.setDrawAxisLine(false)
- this.xAxis.textColor = labelTextColor
- this.xAxis.textSize = labelTextSize
- this.xAxis.yOffset = 10f
+ xAxis.apply {
+ position = XAxis.XAxisPosition.BOTTOM
+ setDrawAxisLine(false)
+ setDrawGridLines(false)
+ textColor = labelTextColor
+ textSize = labelTextSize
+ valueFormatter = barChartModel.xValueFormatter
+ yOffset = 10f
+ }
- this.axisLeft.isEnabled = false
- this.axisRight.setDrawAxisLine(false)
- this.axisRight.textSize = labelTextSize
- this.axisRight.textColor = labelTextColor
- this.axisRight.gridColor = colorScheme.divider.toArgb()
- this.axisRight.xOffset = 10f
+ axisLeft.apply {
+ axisMaximum = barChartModel.yAxisMaxValue
+ axisMinimum = barChartModel.yAxisMinValue
+ isEnabled = false
+ }
- // Customizable Settings.
- this.xAxis.valueFormatter = xValueFormatter
- this.axisRight.valueFormatter = yValueFormatter
-
- this.axisLeft.axisMinimum = yAxisMinValue
- this.axisLeft.axisMaximum = yAxisMaxValue
- this.axisRight.axisMinimum = yAxisMinValue
- this.axisRight.axisMaximum = yAxisMaxValue
-
- this.axisRight.setLabelCount(yAxisLabelCount, true)
- }
- },
+ axisRight.apply {
+ axisMaximum = barChartModel.yAxisMaxValue
+ axisMinimum = barChartModel.yAxisMinValue
+ gridColor = colorScheme.divider.toArgb()
+ setDrawAxisLine(false)
+ setLabelCount(barChartModel.yAxisLabelCount, true)
+ textColor = labelTextColor
+ textSize = labelTextSize
+ valueFormatter = barChartModel.yValueFormatter
+ xOffset = 10f
+ }
+ }
+ },
modifier = Modifier
.wrapContentSize()
.padding(4.dp),
- update = {
- updateBarChartWithData(it, barChartData, colorScheme)
+ update = { barChart ->
+ updateBarChartWithData(
+ chart = barChart,
+ data = barChartData,
+ colorList = barChartModel.colors,
+ colorScheme = colorScheme,
+ )
}
)
}
@@ -177,26 +174,25 @@
}
}
-fun updateBarChartWithData(
+private fun updateBarChartWithData(
chart: BarChart,
data: List<BarChartData>,
+ colorList: List<Color>,
colorScheme: ColorScheme
) {
- val entries = ArrayList<BarEntry>()
- for (i in data.indices) {
- val item = data[i]
- entries.add(BarEntry(item.x ?: 0.toFloat(), item.y ?: 0.toFloat()))
+ val entries = data.map { item ->
+ BarEntry(item.x, item.y.toFloatArray())
}
- val ds = BarDataSet(entries, "")
- ds.colors = arrayListOf(colorScheme.surfaceVariant.toArgb())
- ds.setDrawValues(false)
- ds.isHighlightEnabled = true
- ds.highLightColor = colorScheme.primary.toArgb()
- ds.highLightAlpha = 255
+ val ds = BarDataSet(entries, "").apply {
+ colors = colorList.map(Color::toArgb)
+ setDrawValues(false)
+ isHighlightEnabled = true
+ highLightColor = colorScheme.primary.toArgb()
+ highLightAlpha = 255
+ }
// TODO: Sets round corners for bars.
- val d = BarData(ds)
- chart.data = d
+ chart.data = BarData(ds)
chart.invalidate()
}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt
index 2230d6c..0fe755f 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt
@@ -17,13 +17,17 @@
package com.android.settingslib.spa.widget.chart
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.SemanticsPropertyKey
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onRoot
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.assertContainsColor
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,22 +65,21 @@
@Test
fun bar_chart_displayed() {
composeTestRule.setContent {
- BarChart(
- chartDataList = listOf(
- BarChartData(x = 0f, y = 12f),
- BarChartData(x = 1f, y = 5f),
- BarChartData(x = 2f, y = 21f),
- BarChartData(x = 3f, y = 5f),
- BarChartData(x = 4f, y = 10f),
- BarChartData(x = 5f, y = 9f),
- BarChartData(x = 6f, y = 1f),
- ),
- yAxisMaxValue = 30f,
- modifier = Modifier.semantics { chart = "bar" }
- )
+ BarChart(object : BarChartModel {
+ override val chartDataList = listOf(
+ BarChartData(x = 0f, y = listOf(12f)),
+ BarChartData(x = 1f, y = listOf(5f)),
+ BarChartData(x = 2f, y = listOf(21f)),
+ BarChartData(x = 3f, y = listOf(5f)),
+ BarChartData(x = 4f, y = listOf(10f)),
+ BarChartData(x = 5f, y = listOf(9f)),
+ BarChartData(x = 6f, y = listOf(1f)),
+ )
+ override val colors = listOf(Color.Blue)
+ })
}
- composeTestRule.onNode(hasChart("bar")).assertIsDisplayed()
+ composeTestRule.onRoot().captureToImage().assertContainsColor(Color.Blue)
}
@Test
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ImageAssertions.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ImageAssertions.kt
new file mode 100644
index 0000000..0190989
--- /dev/null
+++ b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ImageAssertions.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.testutils
+
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.toPixelMap
+
+/**
+ * Asserts that the expected color is present in this bitmap.
+ *
+ * @throws AssertionError if the expected color is not present.
+ */
+fun ImageBitmap.assertContainsColor(expectedColor: Color) {
+ assert(containsColor(expectedColor)) {
+ "The given color $expectedColor was not found in the bitmap."
+ }
+}
+
+private fun ImageBitmap.containsColor(expectedColor: Color): Boolean {
+ val pixels = toPixelMap()
+ for (x in 0 until width) {
+ for (y in 0 until height) {
+ if (pixels[x, y] == expectedColor) return true
+ }
+ }
+ return false
+}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index e46db75..33907ec 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -344,7 +344,9 @@
continue;
}
final ProviderInfo providerInfo = resolved.providerInfo;
- final List<Bundle> entryData = getEntryDataFromProvider(context,
+ final List<Bundle> entryData = getEntryDataFromProvider(
+ // Build new context so the entry data is retrieved for the queried user.
+ context.createContextAsUser(user, 0 /* flags */),
providerInfo.authority);
if (entryData == null || entryData.isEmpty()) {
continue;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 2086466..a8063e8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -35,6 +35,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -52,6 +53,7 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
@@ -69,6 +71,8 @@
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.Arrays;
@@ -88,6 +92,10 @@
private UserManager mUserManager;
@Mock
private ContentResolver mContentResolver;
+ @Mock
+ private Context mUserContext;
+ @Mock
+ private ContentResolver mUserContentResolver;
private static final String URI_GET_SUMMARY = "content://authority/text/summary";
private static final String URI_GET_ICON = "content://authority/icon/my_icon";
@@ -104,6 +112,8 @@
mContentResolver = spy(application.getContentResolver());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getPackageName()).thenReturn("com.android.settings");
+ when(mUserContext.getContentResolver()).thenReturn(mUserContentResolver);
+ ShadowTileUtils.sCallRealEntryDataFromProvider = false;
}
@Test
@@ -375,6 +385,30 @@
}
@Test
+ public void loadTilesForAction_forUserProvider_getEntryDataFromProvider_inContextOfGivenUser() {
+ ShadowTileUtils.sCallRealEntryDataFromProvider = true;
+ UserHandle userHandle = new UserHandle(10);
+
+ doReturn(mUserContext).when(mContext).createContextAsUser(eq(userHandle), anyInt());
+
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+ URI_GET_SUMMARY, null, 123, PROFILE_ALL);
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
+
+ TileUtils.loadTilesForAction(mContext, userHandle, IA_SETTINGS_ACTION,
+ addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */);
+
+ verify(mUserContentResolver, atLeastOnce())
+ .acquireUnstableProvider(any(Uri.class));
+ }
+
+ @Test
public void loadTilesForAction_withPendingIntent_updatesPendingIntentMap() {
Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
List<Tile> outTiles = new ArrayList<>();
@@ -472,8 +506,17 @@
private static Bundle sMetaData;
+ private static boolean sCallRealEntryDataFromProvider;
+
@Implementation
protected static List<Bundle> getEntryDataFromProvider(Context context, String authority) {
+ if (sCallRealEntryDataFromProvider) {
+ return Shadow.directlyOn(
+ TileUtils.class,
+ "getEntryDataFromProvider",
+ ReflectionHelpers.ClassParameter.from(Context.class, context),
+ ReflectionHelpers.ClassParameter.from(String.class, authority));
+ }
return Arrays.asList(sMetaData);
}
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index a892269..78da5a6 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -6,6 +6,7 @@
aaliomer@google.com
aaronjli@google.com
+achalke@google.com
acul@google.com
adamcohen@google.com
aioana@google.com
@@ -72,6 +73,7 @@
patmanning@google.com
peanutbutter@google.com
peskal@google.com
+petrcermak@google.com
pinyaoting@google.com
pixel@google.com
pomini@google.com
@@ -82,13 +84,17 @@
shanh@google.com
snoeberger@google.com
steell@google.com
+stevenckng@google.com
stwu@google.com
syeonlee@google.com
sunnygoyal@google.com
thiruram@google.com
+tkachenkoi@google.com
tracyzhou@google.com
tsuji@google.com
twickham@google.com
+vadimt@google.com
+vanjan@google.com
victortulias@google.com
winsonc@google.com
wleshner@google.com
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 969c148..cb9e9ee 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -1,47 +1,23 @@
{
- // Curious where your @Scenario tests will run?
+ // Curious where your @Scenario tests are running?
//
// @Ignore: Will not run in any configuration
//
- // @FlakyTest: Tests that don't block pre/postsubmit but are staged to run known failures
+ // @FlakyTest: Tests that don't block pre/postsubmit but are staged to run known failures.
+ // Tests will run in postsubmit on sysui-e2e-staged suite.
//
- // @Postsubmit: Runs in platinum suite and blocks droidfood in postsubmit
//
- // @PlatinumTest: As of May, 2023, running in postsubmit. Set to run in presubmit as part of
- // v2/android-platinum/suite-test-mapping-platinum-sysui
- // Please DO NOT annotate new or old tests with @PlatinumTest annotation without discussing
- // with mdb:android-platinum
+ // @PlatinumTest: Marking your test with this annotation will put your tests in presubmit.
+ // Please DO NOT annotate new or old tests with @PlatinumTest annotation
+ // without discussing with mdb:android-platinum
//
- // As of May, 2023, If you don't use @Postsubmit, your new test will immediately
- // block presubmit, which is probably NOT what you want. This will change effectively once
- // we move to @PlatinumTest annotation.
+ // @Postsubmit: Do not use this annotation for e2e tests. This won't have any affect.
- // v2/sysui/test-mapping-presubmit-sysui_cloud-tf
- "presubmit-sysui": [
- {
- "name": "PlatformScenarioTests",
- "options": [
- {
- "include-filter": "android.platform.test.scenario.sysui"
- },
- {
- "include-annotation": "android.platform.test.scenario.annotation.Scenario"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.Postsubmit"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- }
- ],
+ // For all other e2e tests which are not platinum, they run in sysui-silver suite,that
+ // primarily runs in postsubmit with an exception to e2e test related changes.
+ // If you want to see one shot place to monitor all e2e tests, look for
+ // sysui-e2e-staged suite.
+
// v2/android-virtual-infra/test_mapping/presubmit-avd
"presubmit": [
{
@@ -138,31 +114,6 @@
]
}
],
- "silver-sysui": [
- {
- "name": "PlatformScenarioTests",
- "options": [
- {
- "include-filter": "android.platform.test.scenario.sysui"
- },
- {
- "include-annotation": "android.platform.test.scenario.annotation.Scenario"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.PlatinumTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- }
- ],
"postsubmit": [
{
"name": "SystemUIGoogleScreenshotTests",
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/ribbon/ui/composable/Ribbon.kt b/packages/SystemUI/compose/features/src/com/android/systemui/ribbon/ui/composable/Ribbon.kt
new file mode 100644
index 0000000..daa1592
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/ribbon/ui/composable/Ribbon.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.ribbon.ui.composable
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.layout.layout
+import com.android.compose.modifiers.thenIf
+import kotlin.math.PI
+import kotlin.math.cos
+import kotlin.math.roundToInt
+import kotlin.math.sin
+import kotlin.math.tan
+
+/**
+ * Renders a "ribbon" at the bottom right corner of its container.
+ *
+ * The [content] is rendered leaning at an angle of [degrees] degrees (between `1` and `89`,
+ * inclusive), with an alpha of [alpha] (between `0f` and `1f`, inclusive).
+ *
+ * The background color of the strip can be modified by passing a value to the [backgroundColor] or
+ * `null` to remove the strip background.
+ *
+ * Note: this function assumes that it's been placed at the bottom right of its parent by its
+ * caller. It's the caller's responsibility to meet that assumption by actually placing this
+ * composable element at the bottom right.
+ */
+@Composable
+fun BottomRightCornerRibbon(
+ content: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ degrees: Int = 45,
+ alpha: Float = 0.6f,
+ backgroundColor: Color? = Color.Red,
+) {
+ check(degrees in 1..89)
+ check(alpha in 0f..1f)
+
+ val radians = degrees * (PI / 180)
+
+ Box(
+ content = { content() },
+ modifier =
+ modifier
+ .graphicsLayer {
+ this.alpha = alpha
+
+ val w = size.width
+ val h = size.height
+
+ val sine = sin(radians).toFloat()
+ val cosine = cos(radians).toFloat()
+
+ translationX = (w - w * cosine + h * sine) / 2f
+ translationY = (h - w * sine + h * cosine) / 2f
+ rotationZ = 360f - degrees
+ }
+ .thenIf(backgroundColor != null) { Modifier.background(backgroundColor!!) }
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+
+ val tangent = tan(radians)
+ val leftPadding = (placeable.measuredHeight / tangent).roundToInt()
+ val rightPadding = (placeable.measuredHeight * tangent).roundToInt()
+
+ layout(
+ width = placeable.measuredWidth + leftPadding + rightPadding,
+ height = placeable.measuredHeight,
+ ) {
+ placeable.place(leftPadding, 0)
+ }
+ }
+ )
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 019287d..6a5a368 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -18,14 +18,19 @@
package com.android.systemui.scene.ui.composable
+import android.os.SystemProperties
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.motionEventSpy
import androidx.compose.ui.input.pointer.pointerInput
@@ -37,6 +42,7 @@
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.UserAction as SceneTransitionUserAction
import com.android.compose.animation.scene.observableTransitionState
+import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
@@ -75,53 +81,70 @@
val currentDestinations: Map<UserAction, SceneModel> by
currentScene.destinationScenes().collectAsState()
val state = remember { SceneTransitionLayoutState(currentSceneKey.toTransitionSceneKey()) }
+ val isRibbonEnabled = remember { SystemProperties.getBoolean("flexi.ribbon", false) }
DisposableEffect(viewModel, state) {
viewModel.setTransitionState(state.observableTransitionState().map { it.toModel() })
onDispose { viewModel.setTransitionState(null) }
}
- SceneTransitionLayout(
- currentScene = currentSceneKey.toTransitionSceneKey(),
- onChangeScene = viewModel::onSceneChanged,
- transitions = SceneContainerTransitions,
- state = state,
- modifier =
- modifier
- .fillMaxSize()
- .motionEventSpy { event -> viewModel.onMotionEvent(event) }
- .pointerInput(Unit) {
- awaitPointerEventScope {
- while (true) {
- awaitPointerEvent(PointerEventPass.Final)
- viewModel.onMotionEventComplete()
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ ) {
+ SceneTransitionLayout(
+ currentScene = currentSceneKey.toTransitionSceneKey(),
+ onChangeScene = viewModel::onSceneChanged,
+ transitions = SceneContainerTransitions,
+ state = state,
+ modifier =
+ modifier
+ .fillMaxSize()
+ .motionEventSpy { event -> viewModel.onMotionEvent(event) }
+ .pointerInput(Unit) {
+ awaitPointerEventScope {
+ while (true) {
+ awaitPointerEvent(PointerEventPass.Final)
+ viewModel.onMotionEventComplete()
+ }
}
}
- }
- ) {
- sceneByKey.forEach { (sceneKey, composableScene) ->
- scene(
- key = sceneKey.toTransitionSceneKey(),
- userActions =
- if (sceneKey == currentSceneKey) {
- currentDestinations
- } else {
- composableScene.destinationScenes().value
- }
- .map { (userAction, destinationSceneModel) ->
- toTransitionModels(userAction, destinationSceneModel)
- }
- .toMap(),
- ) {
- with(composableScene) {
- this@scene.Content(
- modifier =
- Modifier.element(sceneKey.toTransitionSceneKey().rootElementKey)
- .fillMaxSize(),
- )
+ ) {
+ sceneByKey.forEach { (sceneKey, composableScene) ->
+ scene(
+ key = sceneKey.toTransitionSceneKey(),
+ userActions =
+ if (sceneKey == currentSceneKey) {
+ currentDestinations
+ } else {
+ composableScene.destinationScenes().value
+ }
+ .map { (userAction, destinationSceneModel) ->
+ toTransitionModels(userAction, destinationSceneModel)
+ }
+ .toMap(),
+ ) {
+ with(composableScene) {
+ this@scene.Content(
+ modifier =
+ Modifier.element(sceneKey.toTransitionSceneKey().rootElementKey)
+ .fillMaxSize(),
+ )
+ }
}
}
}
+
+ if (isRibbonEnabled) {
+ BottomRightCornerRibbon(
+ content = {
+ Text(
+ text = "flexi\uD83E\uDD43",
+ color = Color.White,
+ )
+ },
+ modifier = Modifier.align(Alignment.BottomEnd),
+ )
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
index 5d6dd3b..23d3089 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
@@ -48,10 +48,11 @@
*/
fun SystemUIDialogFactory.create(
context: Context = this.applicationContext,
+ theme: Int = SystemUIDialog.DEFAULT_THEME,
dismissOnDeviceLock: Boolean = SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK,
content: @Composable (SystemUIDialog) -> Unit,
): ComponentSystemUIDialog {
- val dialog = create(context, dismissOnDeviceLock)
+ val dialog = create(context, theme, dismissOnDeviceLock)
// Create the dialog so that it is properly constructed before we set the Compose content.
// Otherwise, the ComposeView won't render properly.
diff --git a/packages/SystemUI/res/layout/media_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml
index e474938..b77f78d 100644
--- a/packages/SystemUI/res/layout/media_projection_app_selector.xml
+++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml
@@ -20,10 +20,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
- androidprv:maxCollapsedHeight="0dp"
+ androidprv:maxCollapsedHeight="10000dp"
androidprv:maxCollapsedHeightSmall="56dp"
androidprv:maxWidth="@*android:dimen/chooser_width"
android:id="@*android:id/contentPanel">
+ <!-- maxCollapsedHeight above is huge, to make sure the layout is always expanded. -->
<LinearLayout
android:id="@*android:id/chooser_header"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 62c4424..b086ed8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1232,6 +1232,7 @@
<dimen name="magnification_setting_image_button_open_in_full_padding_horizontal">28dp</dimen>
<dimen name="magnification_setting_drag_corner_radius">28dp</dimen>
<dimen name="magnification_setting_drag_size">56dp</dimen>
+ <fraction name="magnification_resize_window_size_amount">10%</fraction>
<!-- Seekbar with icon buttons -->
<dimen name="seekbar_icon_size">24dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index d8c8080..bd251bd 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -172,6 +172,10 @@
<item type="id" name="accessibility_action_move_right"/>
<item type="id" name="accessibility_action_move_up"/>
<item type="id" name="accessibility_action_move_down"/>
+ <item type="id" name="accessibility_action_increase_window_width"/>
+ <item type="id" name="accessibility_action_decrease_window_width"/>
+ <item type="id" name="accessibility_action_increase_window_height"/>
+ <item type="id" name="accessibility_action_decrease_window_height"/>
<!-- Accessibility actions for Accessibility floating menu. -->
<item type="id" name="action_move_top_left"/>
@@ -207,13 +211,14 @@
<!-- keyboard backlight indicator-->
<item type="id" name="backlight_icon" />
+ <!-- IDs for use in the keyguard/lockscreen scene -->
<item type="id" name="keyguard_root_view" />
<item type="id" name="keyguard_indication_area" />
<item type="id" name="keyguard_indication_text" />
<item type="id" name="keyguard_indication_text_bottom" />
<item type="id" name="nssl_guideline" />
- <item type="id" name="nssl_top_barrier" />
- <item type="id" name="nssl_bottom_barrier" />
+ <item type="id" name="nssl_placeholder" />
+ <item type="id" name="aod_notification_icon_container" />
<item type="id" name="split_shade_guideline" />
<item type="id" name="lock_icon" />
<item type="id" name="lock_icon_bg" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6840108..29c9767 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2403,6 +2403,16 @@
<string name="accessibility_control_move_left">Move left</string>
<!-- Action in accessibility menu to move the magnification window right. [CHAR LIMIT=30] -->
<string name="accessibility_control_move_right">Move right</string>
+
+ <!-- Action in accessibility menu to increase the magnification window width. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_increase_window_width">Increase width of magnifier</string>
+ <!-- Action in accessibility menu to decrease the magnification window width. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_decrease_window_width">Decrease width of magnifier</string>
+ <!-- Action in accessibility menu to increase the magnification window height. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_increase_window_height">Increase height of magnifier</string>
+ <!-- Action in accessibility menu to decrease the magnification window height. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_decrease_window_height">Decrease height of magnifier</string>
+
<!-- Content description for magnification mode switch. [CHAR LIMIT=NONE] -->
<string name="magnification_mode_switch_description">Magnification switch</string>
<!-- A11y state description for magnification mode switch that device is in full-screen mode. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index d897960..11f9589 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -18,7 +18,6 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
@@ -42,6 +41,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.log.LogBuffer;
@@ -240,7 +240,9 @@
View nic = mView.findViewById(
R.id.left_aligned_notification_icon_container);
- nic.setVisibility(View.GONE);
+ if (nic != null) {
+ nic.setVisibility(View.GONE);
+ }
}
@Override
@@ -307,7 +309,11 @@
}
int getNotificationIconAreaHeight() {
- return mNotificationIconAreaController.getHeight();
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ return 0;
+ } else {
+ return mNotificationIconAreaController.getHeight();
+ }
}
@Override
@@ -518,10 +524,12 @@
}
private void updateAodIcons() {
- NotificationIconContainer nic = (NotificationIconContainer)
- mView.findViewById(
- com.android.systemui.R.id.left_aligned_notification_icon_container);
- mNotificationIconAreaController.setupAodIcons(nic);
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ NotificationIconContainer nic = (NotificationIconContainer)
+ mView.findViewById(
+ com.android.systemui.R.id.left_aligned_notification_icon_container);
+ mNotificationIconAreaController.setupAodIcons(nic);
+ }
}
private void setClock(ClockController clock) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index f1cebba..773241e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -26,6 +26,7 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
@@ -719,6 +720,18 @@
}
/**
+ * Sets the window frame size with given width and height in pixels without changing the
+ * window center.
+ *
+ * @param width the window frame width in pixels
+ * @param height the window frame height in pixels.
+ */
+ @MainThread
+ private void setMagnificationFrameSize(int width, int height) {
+ setWindowSize(width + 2 * mMirrorSurfaceMargin, height + 2 * mMirrorSurfaceMargin);
+ }
+
+ /**
* Sets the window size with given width and height in pixels without changing the
* window center. The width or the height will be clamped in the range
* [{@link #mMinWindowSize}, screen width or height].
@@ -1496,19 +1509,50 @@
AccessibilityAction.ACTION_CLICK.getId(), getClickAccessibilityActionLabel());
info.addAction(clickAction);
info.setClickable(true);
+
info.addAction(
new AccessibilityAction(R.id.accessibility_action_zoom_in,
mContext.getString(R.string.accessibility_control_zoom_in)));
info.addAction(new AccessibilityAction(R.id.accessibility_action_zoom_out,
mContext.getString(R.string.accessibility_control_zoom_out)));
- info.addAction(new AccessibilityAction(R.id.accessibility_action_move_up,
- mContext.getString(R.string.accessibility_control_move_up)));
- info.addAction(new AccessibilityAction(R.id.accessibility_action_move_down,
- mContext.getString(R.string.accessibility_control_move_down)));
- info.addAction(new AccessibilityAction(R.id.accessibility_action_move_left,
- mContext.getString(R.string.accessibility_control_move_left)));
- info.addAction(new AccessibilityAction(R.id.accessibility_action_move_right,
- mContext.getString(R.string.accessibility_control_move_right)));
+
+ if (!mEditSizeEnable) {
+ info.addAction(new AccessibilityAction(R.id.accessibility_action_move_up,
+ mContext.getString(R.string.accessibility_control_move_up)));
+ info.addAction(new AccessibilityAction(R.id.accessibility_action_move_down,
+ mContext.getString(R.string.accessibility_control_move_down)));
+ info.addAction(new AccessibilityAction(R.id.accessibility_action_move_left,
+ mContext.getString(R.string.accessibility_control_move_left)));
+ info.addAction(new AccessibilityAction(R.id.accessibility_action_move_right,
+ mContext.getString(R.string.accessibility_control_move_right)));
+ } else {
+ if ((mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin)
+ < mWindowBounds.width()) {
+ info.addAction(new AccessibilityAction(
+ R.id.accessibility_action_increase_window_width,
+ mContext.getString(
+ R.string.accessibility_control_increase_window_width)));
+ }
+ if ((mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin)
+ < mWindowBounds.height()) {
+ info.addAction(new AccessibilityAction(
+ R.id.accessibility_action_increase_window_height,
+ mContext.getString(
+ R.string.accessibility_control_increase_window_height)));
+ }
+ if ((mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin) > mMinWindowSize) {
+ info.addAction(new AccessibilityAction(
+ R.id.accessibility_action_decrease_window_width,
+ mContext.getString(
+ R.string.accessibility_control_decrease_window_width)));
+ }
+ if ((mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin) > mMinWindowSize) {
+ info.addAction(new AccessibilityAction(
+ R.id.accessibility_action_decrease_window_height,
+ mContext.getString(
+ R.string.accessibility_control_decrease_window_height)));
+ }
+ }
info.setContentDescription(mContext.getString(R.string.magnification_window_title));
info.setStateDescription(formatStateDescription(getScale()));
@@ -1523,6 +1567,11 @@
}
private boolean performA11yAction(int action) {
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+
if (action == AccessibilityAction.ACTION_CLICK.getId()) {
if (mEditSizeEnable) {
// When edit mode is enabled, click the magnifier to exit edit mode.
@@ -1544,9 +1593,26 @@
move(-mSourceBounds.width(), 0);
} else if (action == R.id.accessibility_action_move_right) {
move(mSourceBounds.width(), 0);
+ } else if (action == R.id.accessibility_action_increase_window_width) {
+ int newFrameWidth =
+ (int) (mMagnificationFrame.width() * (1 + changeWindowSizeAmount));
+ setMagnificationFrameSize(newFrameWidth, mMagnificationFrame.height());
+ } else if (action == R.id.accessibility_action_increase_window_height) {
+ int newFrameHeight =
+ (int) (mMagnificationFrame.height() * (1 + changeWindowSizeAmount));
+ setMagnificationFrameSize(mMagnificationFrame.width(), newFrameHeight);
+ } else if (action == R.id.accessibility_action_decrease_window_width) {
+ int newFrameWidth =
+ (int) (mMagnificationFrame.width() * (1 - changeWindowSizeAmount));
+ setMagnificationFrameSize(newFrameWidth, mMagnificationFrame.height());
+ } else if (action == R.id.accessibility_action_decrease_window_height) {
+ int newFrameHeight =
+ (int) (mMagnificationFrame.height() * (1 - changeWindowSizeAmount));
+ setMagnificationFrameSize(mMagnificationFrame.width(), newFrameHeight);
} else {
return false;
}
+
mWindowMagnifierCallback.onAccessibilityActionPerformed(mDisplayId);
return true;
}
@@ -1557,4 +1623,5 @@
mDisplayId, scale, /* updatePersistence= */ true);
}
}
+
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index daff5fe..aa33100 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -16,13 +16,19 @@
package com.android.systemui.biometrics.data.repository
+import android.Manifest.permission.USE_BIOMETRIC_INTERNAL
+import android.annotation.RequiresPermission
+import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.biometrics.SensorProperties
import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.biometrics.shared.model.toSensorStrength
+import com.android.systemui.biometrics.shared.model.toSensorType
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
@@ -31,11 +37,10 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
/**
* A repository for the global state of FingerprintProperty.
@@ -44,22 +49,17 @@
*/
interface FingerprintPropertyRepository {
- /**
- * If the repository is initialized or not. Other properties are defaults until this is true.
- */
- val isInitialized: Flow<Boolean>
-
/** The id of fingerprint sensor. */
- val sensorId: StateFlow<Int>
+ val sensorId: Flow<Int>
/** The security strength of sensor (convenience, weak, strong). */
- val strength: StateFlow<SensorStrength>
+ val strength: Flow<SensorStrength>
/** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */
- val sensorType: StateFlow<FingerprintSensorType>
+ val sensorType: Flow<FingerprintSensorType>
/** The sensor location relative to each physical display. */
- val sensorLocations: StateFlow<Map<String, SensorLocationInternal>>
+ val sensorLocations: Flow<Map<String, SensorLocationInternal>>
}
@SysUISingleton
@@ -70,64 +70,64 @@
private val fingerprintManager: FingerprintManager?,
) : FingerprintPropertyRepository {
- override val isInitialized: Flow<Boolean> =
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ private val props: StateFlow<FingerprintSensorPropertiesInternal> =
conflatedCallbackFlow {
val callback =
object : IFingerprintAuthenticatorsRegisteredCallback.Stub() {
override fun onAllAuthenticatorsRegistered(
sensors: List<FingerprintSensorPropertiesInternal>
) {
- if (sensors.isNotEmpty()) {
- setProperties(sensors[0])
- trySendWithFailureLogging(true, TAG, "initialize properties")
+ if (sensors.isEmpty()) {
+ trySendWithFailureLogging(
+ DEFAULT_PROPS,
+ TAG,
+ "no registered sensors, use default props"
+ )
+ } else {
+ trySendWithFailureLogging(
+ sensors[0],
+ TAG,
+ "update properties on authenticators registered"
+ )
}
}
}
fingerprintManager?.addAuthenticatorsRegisteredCallback(callback)
- trySendWithFailureLogging(false, TAG, "initial value defaulting to false")
awaitClose {}
}
- .shareIn(scope = applicationScope, started = SharingStarted.Eagerly, replay = 1)
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = DEFAULT_PROPS,
+ )
- private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
- override val sensorId: StateFlow<Int> = _sensorId.asStateFlow()
+ override val sensorId: Flow<Int> = props.map { it.sensorId }
- private val _strength: MutableStateFlow<SensorStrength> =
- MutableStateFlow(SensorStrength.CONVENIENCE)
- override val strength = _strength.asStateFlow()
+ override val strength: Flow<SensorStrength> = props.map { it.sensorStrength.toSensorStrength() }
- private val _sensorType: MutableStateFlow<FingerprintSensorType> =
- MutableStateFlow(FingerprintSensorType.UNKNOWN)
- override val sensorType = _sensorType.asStateFlow()
+ override val sensorType: Flow<FingerprintSensorType> =
+ props.map { it.sensorType.toSensorType() }
- private val _sensorLocations: MutableStateFlow<Map<String, SensorLocationInternal>> =
- MutableStateFlow(mapOf("" to SensorLocationInternal.DEFAULT))
- override val sensorLocations: StateFlow<Map<String, SensorLocationInternal>> =
- _sensorLocations.asStateFlow()
-
- private fun setProperties(prop: FingerprintSensorPropertiesInternal) {
- _sensorId.value = prop.sensorId
- _strength.value = prop.sensorStrength.toSensorStrength()
- _sensorType.value = sensorTypeIntToObject(prop.sensorType)
- _sensorLocations.value =
- prop.allLocations.associateBy { sensorLocationInternal ->
+ override val sensorLocations: Flow<Map<String, SensorLocationInternal>> =
+ props.map {
+ it.allLocations.associateBy { sensorLocationInternal ->
sensorLocationInternal.displayId
}
- }
+ }
companion object {
private const val TAG = "FingerprintPropertyRepositoryImpl"
- }
-}
-
-private fun sensorTypeIntToObject(value: Int): FingerprintSensorType {
- return when (value) {
- 0 -> FingerprintSensorType.UNKNOWN
- 1 -> FingerprintSensorType.REAR
- 2 -> FingerprintSensorType.UDFPS_ULTRASONIC
- 3 -> FingerprintSensorType.UDFPS_OPTICAL
- 4 -> FingerprintSensorType.POWER_BUTTON
- 5 -> FingerprintSensorType.HOME_BUTTON
- else -> throw IllegalArgumentException("Invalid SensorType value: $value")
+ private val DEFAULT_PROPS =
+ FingerprintSensorPropertiesInternal(
+ -1 /* sensorId */,
+ SensorProperties.STRENGTH_CONVENIENCE,
+ 0 /* maxEnrollmentsPerUser */,
+ listOf<ComponentInfoInternal>(),
+ FingerprintSensorProperties.TYPE_UNKNOWN,
+ false /* halControlsIllumination */,
+ true /* resetLockoutRequiresHardwareAuthToken */,
+ listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT)
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index 5badcaf..a6ad24e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -32,7 +32,6 @@
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -69,7 +68,7 @@
val isConfirmationRequired: Flow<Boolean>
/** Fingerprint sensor type */
- val sensorType: StateFlow<FingerprintSensorType>
+ val sensorType: Flow<FingerprintSensorType>
/** Use biometrics for authentication. */
fun useBiometricsForAuthentication(
@@ -95,7 +94,7 @@
class PromptSelectorInteractorImpl
@Inject
constructor(
- private val fingerprintPropertyRepository: FingerprintPropertyRepository,
+ fingerprintPropertyRepository: FingerprintPropertyRepository,
private val promptRepository: PromptRepository,
lockPatternUtils: LockPatternUtils,
) : PromptSelectorInteractor {
@@ -147,8 +146,7 @@
}
}
- override val sensorType: StateFlow<FingerprintSensorType> =
- fingerprintPropertyRepository.sensorType
+ override val sensorType: Flow<FingerprintSensorType> = fingerprintPropertyRepository.sensorType
override fun useBiometricsForAuthentication(
promptInfo: PromptInfo,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt
index aa85e5f3..75ae061 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt
@@ -17,32 +17,43 @@
package com.android.systemui.biometrics.domain.interactor
import android.hardware.biometrics.SensorLocationInternal
-import android.util.Log
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
/** Business logic for SideFps overlay offsets. */
interface SideFpsOverlayInteractor {
- /** Get the corresponding offsets based on different displayId. */
- fun getOverlayOffsets(displayId: String): SensorLocationInternal
+ /** The displayId of the current display. */
+ val displayId: Flow<String>
+
+ /** Overlay offsets corresponding to given displayId. */
+ val overlayOffsets: Flow<SensorLocationInternal>
+
+ /** Called on display changes, used to keep the display state in sync */
+ fun onDisplayChanged(displayId: String)
}
@SysUISingleton
class SideFpsOverlayInteractorImpl
@Inject
-constructor(private val fingerprintPropertyRepository: FingerprintPropertyRepository) :
+constructor(fingerprintPropertyRepository: FingerprintPropertyRepository) :
SideFpsOverlayInteractor {
- override fun getOverlayOffsets(displayId: String): SensorLocationInternal {
- val offsets = fingerprintPropertyRepository.sensorLocations.value
- return if (offsets.containsKey(displayId)) {
- offsets[displayId]!!
- } else {
- Log.w(TAG, "No location specified for display: $displayId")
- offsets[""]!!
+ private val _displayId: MutableStateFlow<String> = MutableStateFlow("")
+ override val displayId: Flow<String> = _displayId.asStateFlow()
+
+ override val overlayOffsets: Flow<SensorLocationInternal> =
+ combine(displayId, fingerprintPropertyRepository.sensorLocations) { displayId, offsets ->
+ offsets[displayId] ?: SensorLocationInternal.DEFAULT
}
+
+ override fun onDisplayChanged(displayId: String) {
+ _displayId.value = displayId
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
index df5cefd..c6fdcb3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
@@ -27,3 +27,15 @@
POWER_BUTTON,
HOME_BUTTON,
}
+
+/** Convert [this] to corresponding [FingerprintSensorType] */
+fun Int.toSensorType(): FingerprintSensorType =
+ when (this) {
+ FingerprintSensorProperties.TYPE_UNKNOWN -> FingerprintSensorType.UNKNOWN
+ FingerprintSensorProperties.TYPE_REAR -> FingerprintSensorType.REAR
+ FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC -> FingerprintSensorType.UDFPS_ULTRASONIC
+ FingerprintSensorProperties.TYPE_UDFPS_OPTICAL -> FingerprintSensorType.UDFPS_OPTICAL
+ FingerprintSensorProperties.TYPE_POWER_BUTTON -> FingerprintSensorType.POWER_BUTTON
+ FingerprintSensorProperties.TYPE_HOME_BUTTON -> FingerprintSensorType.HOME_BUTTON
+ else -> throw IllegalArgumentException("Invalid SensorType value: $this")
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
index 30e865e..476daac 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
@@ -28,8 +28,8 @@
/** Convert [this] to corresponding [SensorStrength] */
fun Int.toSensorStrength(): SensorStrength =
when (this) {
- 0 -> SensorStrength.CONVENIENCE
- 1 -> SensorStrength.WEAK
- 2 -> SensorStrength.STRONG
+ SensorProperties.STRENGTH_CONVENIENCE -> SensorStrength.CONVENIENCE
+ SensorProperties.STRENGTH_WEAK -> SensorStrength.WEAK
+ SensorProperties.STRENGTH_STRONG -> SensorStrength.STRONG
else -> throw IllegalArgumentException("Invalid SensorStrength value: $this")
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
index 9b30acb..b406ea4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
@@ -33,7 +33,7 @@
@Inject
constructor(
private val displayStateInteractor: DisplayStateInteractor,
- private val promptSelectorInteractor: PromptSelectorInteractor,
+ promptSelectorInteractor: PromptSelectorInteractor,
) {
/** Current device rotation. */
private var rotation: Int = Surface.ROTATION_0
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
index ecc9d0e..f730935 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
@@ -34,7 +34,8 @@
context: Context,
private val onStartMirroringClickListener: View.OnClickListener,
private val onCancelMirroring: View.OnClickListener,
-) : Dialog(context, R.style.Theme_SystemUI_Dialog) {
+ theme: Int = R.style.Theme_SystemUI_Dialog,
+) : Dialog(context, theme) {
private lateinit var mirrorButton: TextView
private lateinit var dismissButton: TextView
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 1e5fcbe..bb4fcc8 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -785,7 +785,8 @@
/** TODO(b/296223317): Enables the new keyguard presentation containing a clock. */
@JvmField
- val ENABLE_CLOCK_KEYGUARD_PRESENTATION = unreleasedFlag("enable_clock_keyguard_presentation")
+ val ENABLE_CLOCK_KEYGUARD_PRESENTATION =
+ unreleasedFlag("enable_clock_keyguard_presentation", teamfood = true)
/** Enable the Compose implementation of the PeopleSpaceActivity. */
@JvmField
@@ -802,4 +803,8 @@
/** Enable haptic slider component in the brightness slider */
@JvmField
val HAPTIC_BRIGHTNESS_SLIDER = unreleasedFlag("haptic_brightness_slider")
+
+ // TODO(b/287205379): Tracking bug
+ @JvmField
+ val QS_CONTAINER_GRAPH_OPTIMIZER = unreleasedFlag( "qs_container_graph_optimizer")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
index b5b56b2..6f25f7c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -44,7 +44,8 @@
context: Context,
initialCurrentLevel: Int,
initialMaxLevel: Int,
-) : Dialog(context, R.style.Theme_SystemUI_Dialog) {
+ theme: Int = R.style.Theme_SystemUI_Dialog,
+) : Dialog(context, theme) {
private data class RootProperties(
val cornerRadius: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 8954947..b82e01b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -50,7 +50,6 @@
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.log.SessionTracker
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.UserRepository
@@ -66,9 +65,10 @@
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
@@ -77,6 +77,7 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -153,7 +154,7 @@
private val faceAuthLogger: FaceAuthenticationLogger,
private val biometricSettingsRepository: BiometricSettingsRepository,
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
- private val trustRepository: TrustRepository,
+ trustRepository: TrustRepository,
private val keyguardRepository: KeyguardRepository,
private val keyguardInteractor: KeyguardInteractor,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
@@ -202,11 +203,9 @@
private val keyguardSessionId: InstanceId?
get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD)
- private val _canRunFaceAuth = MutableStateFlow(false)
override val canRunFaceAuth: StateFlow<Boolean>
- get() = _canRunFaceAuth
- private val canRunDetection = MutableStateFlow(false)
+ private val canRunDetection: StateFlow<Boolean>
private val _isAuthenticated = MutableStateFlow(false)
override val isAuthenticated: Flow<Boolean>
@@ -252,10 +251,58 @@
dumpManager.registerCriticalDumpable("DeviceEntryFaceAuthRepositoryImpl", this)
if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
+ canRunFaceAuth =
+ listOf(
+ *gatingConditionsForAuthAndDetect(),
+ Pair(isLockedOut.isFalse(), "isNotInLockOutState"),
+ Pair(
+ trustRepository.isCurrentUserTrusted.isFalse(),
+ "currentUserIsNotTrusted"
+ ),
+ Pair(
+ biometricSettingsRepository.isFaceAuthCurrentlyAllowed,
+ "isFaceAuthCurrentlyAllowed"
+ ),
+ Pair(isAuthenticated.isFalse(), "faceNotAuthenticated"),
+ )
+ .andAllFlows("canFaceAuthRun", faceAuthLog)
+ .flowOn(mainDispatcher)
+ .stateIn(applicationScope, SharingStarted.Eagerly, false)
+
+ // Face detection can run only when lockscreen bypass is enabled
+ // & detection is supported
+ // & biometric unlock is not allowed
+ // or user is trusted by trust manager & we want to run face detect to dismiss
+ // keyguard
+ canRunDetection =
+ listOf(
+ *gatingConditionsForAuthAndDetect(),
+ Pair(isBypassEnabled, "isBypassEnabled"),
+ Pair(
+ biometricSettingsRepository.isFaceAuthCurrentlyAllowed
+ .isFalse()
+ .or(trustRepository.isCurrentUserTrusted),
+ "faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted"
+ ),
+ // We don't want to run face detect if fingerprint can be used to unlock the
+ // device
+ // but it's not possible to authenticate with FP from the bouncer (UDFPS)
+ Pair(
+ and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning)
+ .isFalse(),
+ "udfpsAuthIsNotPossibleAnymore"
+ )
+ )
+ .andAllFlows("canFaceDetectRun", faceDetectLog)
+ .flowOn(mainDispatcher)
+ .stateIn(applicationScope, SharingStarted.Eagerly, false)
observeFaceAuthGatingChecks()
observeFaceDetectGatingChecks()
observeFaceAuthResettingConditions()
listenForSchedulingWatchdog()
+ } else {
+ canRunFaceAuth = MutableStateFlow(false).asStateFlow()
+ canRunDetection = MutableStateFlow(false).asStateFlow()
}
}
@@ -298,39 +345,13 @@
}
private fun observeFaceDetectGatingChecks() {
- // Face detection can run only when lockscreen bypass is enabled
- // & detection is supported
- // & biometric unlock is not allowed
- // or user is trusted by trust manager & we want to run face detect to dismiss keyguard
- listOf(
- canFaceAuthOrDetectRun(faceDetectLog),
- logAndObserve(isBypassEnabled, "isBypassEnabled", faceDetectLog),
- logAndObserve(
- biometricSettingsRepository.isFaceAuthCurrentlyAllowed
- .isFalse()
- .or(trustRepository.isCurrentUserTrusted),
- "faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted",
- faceDetectLog
- ),
- // We don't want to run face detect if fingerprint can be used to unlock the device
- // but it's not possible to authenticate with FP from the bouncer (UDFPS)
- logAndObserve(
- and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning).isFalse(),
- "udfpsAuthIsNotPossibleAnymore",
- faceDetectLog
- )
- )
- .reduce(::and)
- .distinctUntilChanged()
+ canRunDetection
.onEach {
- faceAuthLogger.canRunDetectionChanged(it)
- canRunDetection.value = it
if (!it) {
cancelDetection()
}
}
.flowOn(mainDispatcher)
- .logDiffsForTable(faceDetectLog, "", "canFaceDetectRun", false)
.launchIn(applicationScope)
}
@@ -339,76 +360,44 @@
it == BiometricType.UNDER_DISPLAY_FINGERPRINT
}
- private fun canFaceAuthOrDetectRun(tableLogBuffer: TableLogBuffer): Flow<Boolean> {
- return listOf(
- logAndObserve(
- biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
- "isFaceAuthEnrolledAndEnabled",
- tableLogBuffer
- ),
- logAndObserve(faceAuthPaused.isFalse(), "faceAuthIsNotPaused", tableLogBuffer),
- logAndObserve(
- keyguardRepository.isKeyguardGoingAway.isFalse(),
- "keyguardNotGoingAway",
- tableLogBuffer
- ),
- logAndObserve(
- keyguardRepository.wakefulness.map { it.isStartingToSleep() }.isFalse(),
- "deviceNotStartingToSleep",
- tableLogBuffer
- ),
- logAndObserve(
- keyguardInteractor.isSecureCameraActive
- .isFalse()
- .or(
- alternateBouncerInteractor.isVisible.or(
- keyguardInteractor.primaryBouncerShowing
- )
- ),
- "secureCameraNotActiveOrAnyBouncerIsShowing",
- tableLogBuffer
- ),
- logAndObserve(
- biometricSettingsRepository.isFaceAuthSupportedInCurrentPosture,
- "isFaceAuthSupportedInCurrentPosture",
- tableLogBuffer
- ),
- logAndObserve(
- biometricSettingsRepository.isCurrentUserInLockdown.isFalse(),
- "userHasNotLockedDownDevice",
- tableLogBuffer
- ),
- logAndObserve(
- keyguardRepository.isKeyguardShowing,
- "isKeyguardShowing",
- tableLogBuffer
- )
- )
- .reduce(::and)
+ private fun gatingConditionsForAuthAndDetect(): Array<Pair<Flow<Boolean>, String>> {
+ return arrayOf(
+ Pair(
+ biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
+ "isFaceAuthEnrolledAndEnabled"
+ ),
+ Pair(faceAuthPaused.isFalse(), "faceAuthIsNotPaused"),
+ Pair(keyguardRepository.isKeyguardGoingAway.isFalse(), "keyguardNotGoingAway"),
+ Pair(
+ keyguardRepository.wakefulness.map { it.isStartingToSleep() }.isFalse(),
+ "deviceNotStartingToSleep"
+ ),
+ Pair(
+ keyguardInteractor.isSecureCameraActive
+ .isFalse()
+ .or(
+ alternateBouncerInteractor.isVisible.or(
+ keyguardInteractor.primaryBouncerShowing
+ )
+ ),
+ "secureCameraNotActiveOrAnyBouncerIsShowing"
+ ),
+ Pair(
+ biometricSettingsRepository.isFaceAuthSupportedInCurrentPosture,
+ "isFaceAuthSupportedInCurrentPosture"
+ ),
+ Pair(
+ biometricSettingsRepository.isCurrentUserInLockdown.isFalse(),
+ "userHasNotLockedDownDevice"
+ ),
+ Pair(keyguardRepository.isKeyguardShowing, "isKeyguardShowing")
+ )
}
private fun observeFaceAuthGatingChecks() {
- // Face auth can run only if all of the gating conditions are true.
- listOf(
- canFaceAuthOrDetectRun(faceAuthLog),
- logAndObserve(isLockedOut.isFalse(), "isNotInLockOutState", faceAuthLog),
- logAndObserve(
- trustRepository.isCurrentUserTrusted.isFalse(),
- "currentUserIsNotTrusted",
- faceAuthLog
- ),
- logAndObserve(
- biometricSettingsRepository.isFaceAuthCurrentlyAllowed,
- "isFaceAuthCurrentlyAllowed",
- faceAuthLog
- ),
- logAndObserve(isAuthenticated.isFalse(), "faceNotAuthenticated", faceAuthLog),
- )
- .reduce(::and)
- .distinctUntilChanged()
+ canRunFaceAuth
.onEach {
faceAuthLogger.canFaceAuthRunChanged(it)
- _canRunFaceAuth.value = it
if (!it) {
// Cancel currently running auth if any of the gating checks are false.
faceAuthLogger.cancellingFaceAuth()
@@ -416,7 +405,6 @@
}
}
.flowOn(mainDispatcher)
- .logDiffsForTable(faceAuthLog, "", "canFaceAuthRun", false)
.launchIn(applicationScope)
}
@@ -618,22 +606,6 @@
_isAuthRunning.value = false
}
- private fun logAndObserve(
- cond: Flow<Boolean>,
- conditionName: String,
- logBuffer: TableLogBuffer
- ): Flow<Boolean> {
- return cond
- .distinctUntilChanged()
- .logDiffsForTable(
- logBuffer,
- columnName = conditionName,
- columnPrefix = "",
- initialValue = false
- )
- .onEach { faceAuthLogger.observedConditionChanged(it, conditionName) }
- }
-
companion object {
const val TAG = "DeviceEntryFaceAuthRepository"
@@ -688,3 +660,18 @@
private fun Flow<Boolean>.isFalse(): Flow<Boolean> {
return this.map { !it }
}
+
+private fun List<Pair<Flow<Boolean>, String>>.andAllFlows(
+ combinedLoggingInfo: String,
+ tableLogBuffer: TableLogBuffer
+): Flow<Boolean> {
+ return combine(this.map { it.first }) {
+ val combinedValue =
+ it.reduceIndexed { index, accumulator, current ->
+ tableLogBuffer.logChange(prefix = "", columnName = this[index].second, current)
+ return@reduceIndexed accumulator && current
+ }
+ tableLogBuffer.logChange(prefix = "", combinedLoggingInfo, combinedValue)
+ return@combine combinedValue
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
index f91ae74..f5ef27d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
@@ -24,6 +24,7 @@
import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT
import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule
import java.io.PrintWriter
+import java.util.TreeMap
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -52,11 +53,12 @@
blueprints: Set<@JvmSuppressWildcards KeyguardBlueprint>,
@Application private val applicationScope: CoroutineScope,
) {
- private val blueprintIdMap: Map<String, KeyguardBlueprint> = blueprints.associateBy { it.id }
+ private val blueprintIdMap: TreeMap<String, KeyguardBlueprint> = TreeMap()
private val _blueprint: MutableSharedFlow<KeyguardBlueprint> = MutableSharedFlow(replay = 1)
val blueprint: Flow<KeyguardBlueprint> = _blueprint.asSharedFlow()
init {
+ blueprintIdMap.putAll(blueprints.associateBy { it.id })
applyBlueprint(blueprintIdMap[DEFAULT]!!)
applicationScope.launch {
configurationRepository.onAnyConfigurationChange.collect { refreshBlueprint() }
@@ -69,6 +71,20 @@
* @param blueprintId
* @return whether the transition has succeeded.
*/
+ fun applyBlueprint(index: Int): Boolean {
+ ArrayList(blueprintIdMap.values)[index]?.let {
+ applyBlueprint(it)
+ return true
+ }
+ return false
+ }
+
+ /**
+ * Emits the blueprint value to the collectors.
+ *
+ * @param blueprintId
+ * @return whether the transition has succeeded.
+ */
fun applyBlueprint(blueprintId: String?): Boolean {
val blueprint = blueprintIdMap[blueprintId] ?: return false
applyBlueprint(blueprint)
@@ -89,6 +105,6 @@
/** Prints all available blueprints to the PrintWriter. */
fun printBlueprints(pw: PrintWriter) {
- blueprintIdMap.forEach { entry -> pw.println("${entry.key}") }
+ blueprintIdMap.onEachIndexed { index, entry -> pw.println("$index: ${entry.key}") }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index 390ad7e..6ce9185 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -37,6 +37,16 @@
return keyguardBlueprintRepository.applyBlueprint(blueprintId)
}
+ /**
+ * Transitions to a blueprint.
+ *
+ * @param blueprintId
+ * @return whether the transition has succeeded.
+ */
+ fun transitionToBlueprint(blueprintId: Int): Boolean {
+ return keyguardBlueprintRepository.applyBlueprint(blueprintId)
+ }
+
/** Re-emits the blueprint value to the collectors. */
fun refreshBlueprint() {
keyguardBlueprintRepository.refreshBlueprint()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 8b0b0ae..9503f2c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -177,14 +177,13 @@
oldRight: Int,
oldBottom: Int
) {
- val ksv = v.findViewById(R.id.keyguard_status_view) as View?
- val lockIcon = v.findViewById(R.id.lock_icon_view) as View?
+ val nsslPlaceholder = v.findViewById(R.id.nssl_placeholder) as View?
- if (ksv != null && lockIcon != null) {
+ if (nsslPlaceholder != null) {
// After layout, ensure the notifications are positioned correctly
viewModel.onSharedNotificationContainerPositionChanged(
- ksv!!.top.toFloat() + ksv!!.height,
- lockIcon!!.y
+ nsslPlaceholder.top.toFloat(),
+ nsslPlaceholder.bottom.toFloat(),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt
index 36d21f1..ce7ec0e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.ui.view.layout
+import androidx.core.text.isDigitsOnly
import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.statusbar.commandline.Command
@@ -45,7 +46,11 @@
return
}
- if (keyguardBlueprintInteractor.transitionToBlueprint(arg)) {
+ if (
+ arg.isDigitsOnly() && keyguardBlueprintInteractor.transitionToBlueprint(arg.toInt())
+ ) {
+ pw.println("Transition succeeded!")
+ } else if (keyguardBlueprintInteractor.transitionToBlueprint(arg)) {
pw.println("Transition succeeded!")
} else {
pw.println("Invalid argument! To see available blueprint ids, run:")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
index b0c969f..15bb909 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
@@ -22,6 +22,7 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
+import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection
@@ -50,6 +51,7 @@
defaultStatusViewSection: DefaultStatusViewSection,
defaultNotificationStackScrollLayoutSection: DefaultNotificationStackScrollLayoutSection,
splitShadeGuidelines: SplitShadeGuidelines,
+ aodNotificationIconsSection: AodNotificationIconsSection,
private val featureFlags: FeatureFlags,
) : KeyguardBlueprint {
override val id: String = DEFAULT
@@ -64,6 +66,7 @@
defaultStatusViewSection,
defaultNotificationStackScrollLayoutSection,
splitShadeGuidelines,
+ aodNotificationIconsSection,
)
override fun replaceViews(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
index bb3af6c..6534dcf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
@@ -20,6 +20,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.sections.AlignShortcutsToUdfpsSection
+import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection
@@ -42,6 +43,7 @@
defaultStatusViewSection: DefaultStatusViewSection,
splitShadeGuidelines: SplitShadeGuidelines,
defaultNotificationStackScrollLayoutSection: DefaultNotificationStackScrollLayoutSection,
+ aodNotificationIconsSection: AodNotificationIconsSection,
) : KeyguardBlueprint {
override val id: String = SHORTCUTS_BESIDE_UDFPS
@@ -55,9 +57,10 @@
defaultStatusViewSection,
defaultNotificationStackScrollLayoutSection,
splitShadeGuidelines,
+ aodNotificationIconsSection,
)
companion object {
- const val SHORTCUTS_BESIDE_UDFPS = "shortcutsBesideUdfps"
+ const val SHORTCUTS_BESIDE_UDFPS = "shortcuts-besides-udfps"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
index 79b7157..5aba229 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
@@ -18,8 +18,6 @@
package com.android.systemui.keyguard.ui.view.layout.sections
import android.content.res.Resources
-import android.view.View
-import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
@@ -27,13 +25,10 @@
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.RIGHT
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import androidx.core.content.res.ResourcesCompat
import com.android.systemui.R
-import com.android.systemui.animation.view.LaunchableImageView
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
@@ -53,10 +48,7 @@
private val falsingManager: FalsingManager,
private val indicationController: KeyguardIndicationController,
private val vibratorHelper: VibratorHelper,
-) : KeyguardSection() {
- private var leftShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
- private var rightShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
-
+) : BaseShortcutSection() {
override fun addViews(constraintLayout: ConstraintLayout) {
if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
addLeftShortcut(constraintLayout)
@@ -109,67 +101,4 @@
connect(R.id.end_button, BOTTOM, R.id.lock_icon_view, BOTTOM)
}
}
-
- override fun removeViews(constraintLayout: ConstraintLayout) {
- leftShortcutHandle?.destroy()
- rightShortcutHandle?.destroy()
- constraintLayout.removeView(R.id.start_button)
- constraintLayout.removeView(R.id.end_button)
- }
-
- private fun addLeftShortcut(constraintLayout: ConstraintLayout) {
- val padding =
- constraintLayout.resources.getDimensionPixelSize(
- R.dimen.keyguard_affordance_fixed_padding
- )
- val view =
- LaunchableImageView(constraintLayout.context, null).apply {
- id = R.id.start_button
- scaleType = ImageView.ScaleType.FIT_CENTER
- background =
- ResourcesCompat.getDrawable(
- context.resources,
- R.drawable.keyguard_bottom_affordance_bg,
- context.theme
- )
- foreground =
- ResourcesCompat.getDrawable(
- context.resources,
- R.drawable.keyguard_bottom_affordance_selected_border,
- context.theme
- )
- visibility = View.INVISIBLE
- setPadding(padding, padding, padding, padding)
- }
- constraintLayout.addView(view)
- }
-
- private fun addRightShortcut(constraintLayout: ConstraintLayout) {
- if (constraintLayout.findViewById<View>(R.id.end_button) != null) return
-
- val padding =
- constraintLayout.resources.getDimensionPixelSize(
- R.dimen.keyguard_affordance_fixed_padding
- )
- val view =
- LaunchableImageView(constraintLayout.context, null).apply {
- id = R.id.end_button
- scaleType = ImageView.ScaleType.FIT_CENTER
- background =
- ResourcesCompat.getDrawable(
- context.resources,
- R.drawable.keyguard_bottom_affordance_bg,
- context.theme
- )
- foreground =
- ResourcesCompat.getDrawable(
- context.resources,
- R.drawable.keyguard_bottom_affordance_selected_border,
- context.theme
- )
- visibility = View.INVISIBLE
- setPadding(padding, padding, padding, padding)
- }
- constraintLayout.addView(view)
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
new file mode 100644
index 0000000..ac11ba5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.content.Context
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.systemui.R
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.statusbar.phone.NotificationIconContainer
+import javax.inject.Inject
+
+class AodNotificationIconsSection
+@Inject
+constructor(
+ private val context: Context,
+ private val featureFlags: FeatureFlags,
+ private val notificationPanelView: NotificationPanelView,
+ private val notificationIconAreaController: NotificationIconAreaController,
+) : KeyguardSection() {
+ private val nicId = R.id.aod_notification_icon_container
+ private lateinit var nic: NotificationIconContainer
+
+ override fun addViews(constraintLayout: ConstraintLayout) {
+ if (!featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ return
+ }
+ nic =
+ NotificationIconContainer(context, null).apply {
+ id = nicId
+ setPaddingRelative(
+ resources.getDimensionPixelSize(R.dimen.below_clock_padding_start_icons),
+ 0,
+ 0,
+ 0
+ )
+ setVisibility(View.INVISIBLE)
+ }
+
+ constraintLayout.addView(nic)
+ }
+
+ override fun bindData(constraintLayout: ConstraintLayout) {
+ if (!featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ return
+ }
+
+ notificationIconAreaController.setupAodIcons(nic)
+ }
+
+ override fun applyConstraints(constraintSet: ConstraintSet) {
+ if (!featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ return
+ }
+ val bottomMargin =
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin)
+
+ val useSplitShade = context.resources.getBoolean(R.bool.config_use_split_notification_shade)
+
+ val topAlignment =
+ if (useSplitShade) {
+ TOP
+ } else {
+ BOTTOM
+ }
+
+ constraintSet.apply {
+ connect(nicId, TOP, R.id.keyguard_status_view, topAlignment, bottomMargin)
+ connect(nicId, START, PARENT_ID, START)
+ connect(nicId, END, PARENT_ID, END)
+ constrainHeight(
+ nicId,
+ context.resources.getDimensionPixelSize(R.dimen.notification_shelf_height)
+ )
+ }
+ }
+
+ override fun removeViews(constraintLayout: ConstraintLayout) {
+ constraintLayout.removeView(nicId)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/BaseShortcutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/BaseShortcutSection.kt
new file mode 100644
index 0000000..d046a19
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/BaseShortcutSection.kt
@@ -0,0 +1,99 @@
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.view.View
+import android.widget.ImageView
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.content.res.ResourcesCompat
+import com.android.systemui.R
+import com.android.systemui.animation.view.LaunchableImageView
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
+
+abstract class BaseShortcutSection : KeyguardSection() {
+ protected var leftShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
+ protected var rightShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
+
+ override fun removeViews(constraintLayout: ConstraintLayout) {
+ leftShortcutHandle?.destroy()
+ rightShortcutHandle?.destroy()
+ constraintLayout.removeView(R.id.start_button)
+ constraintLayout.removeView(R.id.end_button)
+ }
+
+ protected fun addLeftShortcut(constraintLayout: ConstraintLayout) {
+ val padding =
+ constraintLayout.resources.getDimensionPixelSize(
+ R.dimen.keyguard_affordance_fixed_padding
+ )
+ val view =
+ LaunchableImageView(constraintLayout.context, null).apply {
+ id = R.id.start_button
+ scaleType = ImageView.ScaleType.FIT_CENTER
+ background =
+ ResourcesCompat.getDrawable(
+ context.resources,
+ R.drawable.keyguard_bottom_affordance_bg,
+ context.theme
+ )
+ foreground =
+ ResourcesCompat.getDrawable(
+ context.resources,
+ R.drawable.keyguard_bottom_affordance_selected_border,
+ context.theme
+ )
+ visibility = View.INVISIBLE
+ setPadding(padding, padding, padding, padding)
+ }
+ constraintLayout.addView(view)
+ }
+
+ protected fun addRightShortcut(constraintLayout: ConstraintLayout) {
+ if (constraintLayout.findViewById<View>(R.id.end_button) != null) return
+
+ val padding =
+ constraintLayout.resources.getDimensionPixelSize(
+ R.dimen.keyguard_affordance_fixed_padding
+ )
+ val view =
+ LaunchableImageView(constraintLayout.context, null).apply {
+ id = R.id.end_button
+ scaleType = ImageView.ScaleType.FIT_CENTER
+ background =
+ ResourcesCompat.getDrawable(
+ context.resources,
+ R.drawable.keyguard_bottom_affordance_bg,
+ context.theme
+ )
+ foreground =
+ ResourcesCompat.getDrawable(
+ context.resources,
+ R.drawable.keyguard_bottom_affordance_selected_border,
+ context.theme
+ )
+ visibility = View.INVISIBLE
+ setPadding(padding, padding, padding, padding)
+ }
+ constraintLayout.addView(view)
+ }
+ /**
+ * Defines equality as same class.
+ *
+ * This is to enable set operations to be done as an optimization to blueprint transitions.
+ */
+ override fun equals(other: Any?): Boolean {
+ return other is BaseShortcutSection
+ }
+
+ /**
+ * Defines hashcode as class.
+ *
+ * This is to enable set operations to be done as an optimization to blueprint transitions.
+ */
+ override fun hashCode(): Int {
+ return KEY.hashCode()
+ }
+
+ companion object {
+ private const val KEY = "shortcuts"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt
index 3e91d93..9c6e953 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt
@@ -54,15 +54,15 @@
if (!featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)) {
return
}
- notificationPanelView.findViewById<View>(R.id.lock_icon_view).let {
+ notificationPanelView.findViewById<View>(lockIconViewId).let {
notificationPanelView.removeView(it)
}
- val view = LockIconView(context, null).apply { id = R.id.lock_icon_view }
+ val view = LockIconView(context, null).apply { id = lockIconViewId }
constraintLayout.addView(view)
}
override fun bindData(constraintLayout: ConstraintLayout) {
- constraintLayout.findViewById<LockIconView?>(R.id.lock_icon_view)?.let {
+ constraintLayout.findViewById<LockIconView?>(lockIconViewId)?.let {
lockIconViewController.setLockIconView(it)
}
}
@@ -97,7 +97,7 @@
}
override fun removeViews(constraintLayout: ConstraintLayout) {
- constraintLayout.removeView(R.id.lock_icon_view)
+ constraintLayout.removeView(lockIconViewId)
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
index 59c5d78..7fff43b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
@@ -17,10 +17,16 @@
package com.android.systemui.keyguard.ui.view.layout.sections
+import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.systemui.R
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -35,12 +41,15 @@
class DefaultNotificationStackScrollLayoutSection
@Inject
constructor(
+ private val context: Context,
private val featureFlags: FeatureFlags,
private val notificationPanelView: NotificationPanelView,
private val sharedNotificationContainer: SharedNotificationContainer,
private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
private val controller: NotificationStackScrollLayoutController,
) : KeyguardSection() {
+ private val placeHolderId = R.id.nssl_placeholder
+
override fun addViews(constraintLayout: ConstraintLayout) {
if (!featureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
return
@@ -51,19 +60,52 @@
(it.parent as ViewGroup).removeView(it)
sharedNotificationContainer.addNotificationStackScrollLayout(it)
}
+
+ val view = View(context, null).apply { id = placeHolderId }
+ constraintLayout.addView(view)
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (featureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
- SharedNotificationContainerBinder.bind(
- sharedNotificationContainer,
- sharedNotificationContainerViewModel,
- controller,
+ if (!featureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ return
+ }
+ SharedNotificationContainerBinder.bind(
+ sharedNotificationContainer,
+ sharedNotificationContainerViewModel,
+ controller,
+ )
+ }
+
+ override fun applyConstraints(constraintSet: ConstraintSet) {
+ if (!featureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ return
+ }
+ constraintSet.apply {
+ val bottomMargin =
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin)
+ val useSplitShade =
+ context.resources.getBoolean(R.bool.config_use_split_notification_shade)
+
+ val topAlignment =
+ if (useSplitShade) {
+ TOP
+ } else {
+ BOTTOM
+ }
+ connect(
+ R.id.nssl_placeholder,
+ TOP,
+ R.id.keyguard_status_view,
+ topAlignment,
+ bottomMargin
)
+ connect(R.id.nssl_placeholder, START, PARENT_ID, START)
+ connect(R.id.nssl_placeholder, END, PARENT_ID, END)
+ connect(R.id.nssl_placeholder, BOTTOM, R.id.lock_icon_view, TOP)
}
}
- override fun applyConstraints(constraintSet: ConstraintSet) {}
-
- override fun removeViews(constraintLayout: ConstraintLayout) {}
+ override fun removeViews(constraintLayout: ConstraintLayout) {
+ constraintLayout.removeView(placeHolderId)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
index a2db1df..13ef985 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
@@ -18,21 +18,16 @@
package com.android.systemui.keyguard.ui.view.layout.sections
import android.content.res.Resources
-import android.view.View
-import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
import androidx.constraintlayout.widget.ConstraintSet.LEFT
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.RIGHT
-import androidx.core.content.res.ResourcesCompat
import com.android.systemui.R
-import com.android.systemui.animation.view.LaunchableImageView
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
@@ -52,10 +47,7 @@
private val falsingManager: FalsingManager,
private val indicationController: KeyguardIndicationController,
private val vibratorHelper: VibratorHelper,
-) : KeyguardSection() {
- private var leftShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
- private var rightShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
-
+) : BaseShortcutSection() {
override fun addViews(constraintLayout: ConstraintLayout) {
if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
addLeftShortcut(constraintLayout)
@@ -108,67 +100,4 @@
connect(R.id.end_button, BOTTOM, PARENT_ID, BOTTOM, verticalOffsetMargin)
}
}
-
- override fun removeViews(constraintLayout: ConstraintLayout) {
- leftShortcutHandle?.destroy()
- rightShortcutHandle?.destroy()
- constraintLayout.removeView(R.id.start_button)
- constraintLayout.removeView(R.id.end_button)
- }
-
- private fun addLeftShortcut(constraintLayout: ConstraintLayout) {
- val padding =
- constraintLayout.resources.getDimensionPixelSize(
- R.dimen.keyguard_affordance_fixed_padding
- )
- val view =
- LaunchableImageView(constraintLayout.context, null).apply {
- id = R.id.start_button
- scaleType = ImageView.ScaleType.FIT_CENTER
- background =
- ResourcesCompat.getDrawable(
- context.resources,
- R.drawable.keyguard_bottom_affordance_bg,
- context.theme
- )
- foreground =
- ResourcesCompat.getDrawable(
- context.resources,
- R.drawable.keyguard_bottom_affordance_selected_border,
- context.theme
- )
- visibility = View.INVISIBLE
- setPadding(padding, padding, padding, padding)
- }
- constraintLayout.addView(view)
- }
-
- private fun addRightShortcut(constraintLayout: ConstraintLayout) {
- if (constraintLayout.findViewById<View>(R.id.end_button) != null) return
-
- val padding =
- constraintLayout.resources.getDimensionPixelSize(
- R.dimen.keyguard_affordance_fixed_padding
- )
- val view =
- LaunchableImageView(constraintLayout.context, null).apply {
- id = R.id.end_button
- scaleType = ImageView.ScaleType.FIT_CENTER
- background =
- ResourcesCompat.getDrawable(
- context.resources,
- R.drawable.keyguard_bottom_affordance_bg,
- context.theme
- )
- foreground =
- ResourcesCompat.getDrawable(
- context.resources,
- R.drawable.keyguard_bottom_affordance_selected_border,
- context.theme
- )
- visibility = View.INVISIBLE
- setPadding(padding, padding, padding, padding)
- }
- constraintLayout.addView(view)
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
index b144f7a..b1dd373 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
@@ -72,6 +72,11 @@
.inflate(R.layout.keyguard_status_view, constraintLayout, false)
as KeyguardStatusView)
.apply { clipChildren = false }
+
+ // This is diassembled and moved to [AodNotificationIconsSection]
+ keyguardStatusView.findViewById<View>(R.id.left_aligned_notification_icon_container)?.let {
+ it.setVisibility(View.GONE)
+ }
constraintLayout.addView(keyguardStatusView)
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
index 98f2fee..5154067 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -16,10 +16,8 @@
package com.android.systemui.screenshot
-import android.graphics.Insets
import android.util.Log
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
-import com.android.internal.util.ScreenshotRequest
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
@@ -49,64 +47,6 @@
/** For the Java Async version, to invoke the callback. */
@Application private val mainScope: CoroutineScope
) : ScreenshotRequestProcessor {
- /**
- * Inspects the incoming request, returning a potentially modified request depending on policy.
- *
- * @param request the request to process
- */
- // TODO: Delete once SCREENSHOT_METADATA flag is launched
- suspend fun process(request: ScreenshotRequest): ScreenshotRequest {
- var result = request
-
- // Apply work profile screenshots policy:
- //
- // If the focused app belongs to a work profile, transforms a full screen
- // (or partial) screenshot request to a task snapshot (provided image) screenshot.
-
- // Whenever displayContentInfo is fetched, the topComponent is also populated
- // regardless of the managed profile status.
-
- if (request.type != TAKE_SCREENSHOT_PROVIDED_IMAGE) {
- val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
- Log.d(TAG, "findPrimaryContent: $info")
-
- result = if (policy.isManagedProfile(info.user.identifier)) {
- val image = capture.captureTask(info.taskId)
- ?: error("Task snapshot returned a null Bitmap!")
-
- // Provide the task snapshot as the screenshot
- ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source)
- .setTopComponent(info.component)
- .setTaskId(info.taskId)
- .setUserId(info.user.identifier)
- .setBitmap(image)
- .setBoundsOnScreen(info.bounds)
- .setInsets(Insets.NONE)
- .build()
- } else {
- // Create a new request of the same type which includes the top component
- ScreenshotRequest.Builder(request.type, request.source)
- .setTopComponent(info.component).build()
- }
- }
-
- return result
- }
-
- /**
- * Note: This is for compatibility with existing Java. Prefer the suspending function when
- * calling from a Coroutine context.
- *
- * @param request the request to process
- * @param callback the callback to provide the processed request, invoked from the main thread
- */
- // TODO: Delete once SCREENSHOT_METADATA flag is launched
- fun processAsync(request: ScreenshotRequest, callback: Consumer<ScreenshotRequest>) {
- mainScope.launch {
- val result = process(request)
- callback.accept(result)
- }
- }
override suspend fun process(screenshot: ScreenshotData): ScreenshotData {
var result = screenshot
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
index 6c886fc..c5bc2fb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
@@ -4,6 +4,7 @@
import android.os.Trace
import android.util.Log
import android.view.Display
+import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import com.android.internal.logging.UiEventLogger
import com.android.internal.util.ScreenshotRequest
import com.android.systemui.dagger.SysUISingleton
@@ -55,7 +56,7 @@
onSaved: (Uri) -> Unit,
requestCallback: RequestCallback
) {
- val displayIds = getDisplaysToScreenshot()
+ val displayIds = getDisplaysToScreenshot(screenshotRequest.type)
val resultCallbackWrapper = MultiResultCallbackWrapper(requestCallback)
screenshotRequest.oneForEachDisplay(displayIds).forEach { screenshotData: ScreenshotData ->
dispatchToController(
@@ -93,8 +94,13 @@
.handleScreenshot(screenshotData, onSaved, callback)
}
- private fun getDisplaysToScreenshot(): List<Int> {
- return displays.value.filter { it.type in ALLOWED_DISPLAY_TYPES }.map { it.displayId }
+ private fun getDisplaysToScreenshot(requestType: Int): List<Int> {
+ return if (requestType == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
+ // If this is a provided image, let's show the UI on the default display only.
+ listOf(Display.DEFAULT_DISPLAY)
+ } else {
+ displays.value.filter { it.type in ALLOWED_DISPLAY_TYPES }.map { it.displayId }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 4a76dd0..2dbcbc9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -40,6 +40,7 @@
import android.view.IWindowSession;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
@@ -409,9 +410,9 @@
private void applyForceShowNavigationFlag(NotificationShadeWindowState state) {
if (state.panelExpanded || state.bouncerShowing
|| ENABLE_REMOTE_INPUT && state.remoteInputActive) {
- mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ mLpChanged.forciblyShownTypes |= WindowInsets.Type.navigationBars();
} else {
- mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ mLpChanged.forciblyShownTypes &= ~WindowInsets.Type.navigationBars();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index 3f7512a..f1e75b1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -76,7 +76,7 @@
scenesProvider: Provider<Set<@JvmSuppressWildcards Scene>>,
layoutInsetController: NotificationInsetsController,
): WindowRootView {
- return if (sceneContainerFlags.isEnabled()) {
+ return if (Flags.SCENE_CONTAINER_ENABLED && sceneContainerFlags.isEnabled()) {
val sceneWindowRootView =
layoutInflater.inflate(R.layout.scene_window_root, null) as SceneWindowRootView
sceneWindowRootView.init(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index ac80010..d5e4902 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -102,18 +102,21 @@
mLogger.logRemoveRemoteInput(
entry.getKey() /* entryKey*/,
true /* remoteEditImeVisible */,
- true /* remoteEditImeAnimatingAway */);
+ true /* remoteEditImeAnimatingAway */,
+ isRemoteInputActive(entry) /* isRemoteInputActiveForEntry */,
+ isRemoteInputActive() /* isRemoteInputActive */);
return;
}
// If the view is being removed, this may be called even though we're not active
- boolean remoteInputActive = isRemoteInputActive(entry);
+ boolean remoteInputActiveForEntry = isRemoteInputActive(entry);
mLogger.logRemoveRemoteInput(
- entry.getKey() /* entryKey*/,
+ entry.getKey() /* entryKey */,
entry.mRemoteEditImeVisible /* remoteEditImeVisible */,
entry.mRemoteEditImeAnimatingAway /* remoteEditImeAnimatingAway */,
- remoteInputActive /* isRemoteInputActive */);
+ remoteInputActiveForEntry /* isRemoteInputActiveForEntry */,
+ isRemoteInputActive()/* isRemoteInputActive */);
- if (!remoteInputActive) return;
+ if (!remoteInputActiveForEntry) return;
pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
index 7809eaa..39b999c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
@@ -51,7 +51,8 @@
entryKey: String,
remoteEditImeVisible: Boolean,
remoteEditImeAnimatingAway: Boolean,
- isRemoteInputActive: Boolean? = null
+ isRemoteInputActiveForEntry: Boolean,
+ isRemoteInputActive: Boolean
) =
logBuffer.log(
TAG,
@@ -60,11 +61,13 @@
str1 = entryKey
bool1 = remoteEditImeVisible
bool2 = remoteEditImeAnimatingAway
- str2 = isRemoteInputActive?.toString() ?: "N/A"
+ bool3 = isRemoteInputActiveForEntry
+ bool4 = isRemoteInputActive
},
{
"removeRemoteInput entry: $str1, remoteEditImeVisible: $bool1" +
- ", remoteEditImeAnimatingAway: $bool2, isActive: $str2"
+ ", remoteEditImeAnimatingAway: $bool2, isRemoteInputActiveForEntry: $bool3" +
+ ", isRemoteInputActive: $bool4"
}
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 6f4adeb..f750fed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -44,7 +44,13 @@
shadeInteractor: ShadeInteractor,
) {
private val statesForConstrainedNotifications =
- setOf(KeyguardState.LOCKSCREEN, KeyguardState.AOD, KeyguardState.DOZING)
+ setOf(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.AOD,
+ KeyguardState.DOZING,
+ KeyguardState.ALTERNATE_BOUNCER,
+ KeyguardState.PRIMARY_BOUNCER
+ )
val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
interactor.configurationBasedDimensions
@@ -126,6 +132,7 @@
/**
* When on keyguard, there is limited space to display notifications so calculate how many could
* be shown. Otherwise, there is no limit since the vertical space will be scrollable.
+ *
* TODO: b/296606746 - Need to rerun logic when notifs change
*/
val maxNotifications: Flow<Int> =
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 b797c63..b45a688 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2680,6 +2680,7 @@
&& mStatusBarStateController.getDozeAmount() == 1f
&& mWakefulnessLifecycle.getLastWakeReason()
== PowerManager.WAKE_REASON_POWER_BUTTON
+ && mFingerprintManager.get() != null
&& mFingerprintManager.get().isPowerbuttonFps()
&& mKeyguardUpdateMonitor
.getCachedIsUnlockWithFingerprintPossible(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt
index 3b15065..d91ca92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt
@@ -48,13 +48,14 @@
*/
fun create(
context: Context = this.applicationContext,
+ theme: Int = SystemUIDialog.DEFAULT_THEME,
dismissOnDeviceLock: Boolean = SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK,
): ComponentSystemUIDialog {
Assert.isMainThread()
return ComponentSystemUIDialog(
context,
- SystemUIDialog.DEFAULT_THEME,
+ theme,
dismissOnDeviceLock,
featureFlags,
dialogManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
index 24987ab..f4cc0ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -21,7 +21,6 @@
import static android.view.WindowInsets.Type.tappableElement;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
@@ -44,6 +43,7 @@
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.WindowManager;
import com.android.internal.policy.SystemBarUtils;
@@ -361,9 +361,9 @@
|| state.mIsLaunchAnimationRunning
// Don't force-show the status bar if the user has already dismissed it.
|| state.mOngoingProcessRequiresStatusBarVisible) {
- mLpChanged.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
+ mLpChanged.forciblyShownTypes |= WindowInsets.Type.statusBars();
} else {
- mLpChanged.privateFlags &= ~PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
+ mLpChanged.forciblyShownTypes &= ~WindowInsets.Type.statusBars();
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
index 1be8746..3d87196 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -20,6 +20,7 @@
import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+import static com.android.systemui.flags.Flags.MIGRATE_KEYGUARD_STATUS_VIEW;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
@@ -165,6 +166,7 @@
mFakeFeatureFlags = new FakeFeatureFlags();
mFakeFeatureFlags.set(FACE_AUTH_REFACTOR, false);
mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
+ mFakeFeatureFlags.set(MIGRATE_KEYGUARD_STATUS_VIEW, false);
mController = new KeyguardClockSwitchController(
mView,
mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 0fb0b03..39fe6fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -751,6 +751,245 @@
}
@Test
+ public void windowWidthIsNotMax_performA11yActionIncreaseWidth_windowWidthIncreased() {
+ final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ final int startingWidth = (int) (windowBounds.width() * 0.8);
+ final int startingHeight = (int) (windowBounds.height() * 0.8);
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mirrorView.performAccessibilityAction(
+ R.id.accessibility_action_increase_window_width, null);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+ R.dimen.magnification_mirror_surface_margin);
+ // Window width includes the magnifier frame and the margin. Increasing the window size
+ // will be increasing the amount of the frame size only.
+ int newWindowWidth =
+ (int) ((startingWidth - 2 * mirrorSurfaceMargin) * (1 + changeWindowSizeAmount))
+ + 2 * mirrorSurfaceMargin;
+ assertEquals(newWindowWidth, actualWindowWidth.get());
+ assertEquals(startingHeight, actualWindowHeight.get());
+ }
+
+ @Test
+ public void windowHeightIsNotMax_performA11yActionIncreaseHeight_windowHeightIncreased() {
+ final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ final int startingWidth = (int) (windowBounds.width() * 0.8);
+ final int startingHeight = (int) (windowBounds.height() * 0.8);
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mirrorView.performAccessibilityAction(
+ R.id.accessibility_action_increase_window_height, null);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+ R.dimen.magnification_mirror_surface_margin);
+ // Window height includes the magnifier frame and the margin. Increasing the window size
+ // will be increasing the amount of the frame size only.
+ int newWindowHeight =
+ (int) ((startingHeight - 2 * mirrorSurfaceMargin) * (1 + changeWindowSizeAmount))
+ + 2 * mirrorSurfaceMargin;
+ assertEquals(startingWidth, actualWindowWidth.get());
+ assertEquals(newWindowHeight, actualWindowHeight.get());
+ }
+
+ @Test
+ public void windowWidthIsMax_noIncreaseWindowWidthA11yAction() {
+ final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ final int startingWidth = windowBounds.width();
+ final int startingHeight = windowBounds.height();
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AccessibilityNodeInfo accessibilityNodeInfo =
+ mirrorView.createAccessibilityNodeInfo();
+ assertFalse(accessibilityNodeInfo.getActionList().contains(
+ new AccessibilityAction(R.id.accessibility_action_increase_window_width, null)));
+ }
+
+ @Test
+ public void windowHeightIsMax_noIncreaseWindowHeightA11yAction() {
+ final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ final int startingWidth = windowBounds.width();
+ final int startingHeight = windowBounds.height();
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AccessibilityNodeInfo accessibilityNodeInfo =
+ mirrorView.createAccessibilityNodeInfo();
+ assertFalse(accessibilityNodeInfo.getActionList().contains(
+ new AccessibilityAction(R.id.accessibility_action_increase_window_height, null)));
+ }
+
+ @Test
+ public void windowWidthIsNotMin_performA11yActionDecreaseWidth_windowWidthDecreased() {
+ int mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int startingSize = (int) (mMinWindowSize * 1.1);
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mirrorView.performAccessibilityAction(
+ R.id.accessibility_action_decrease_window_width, null);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+ R.dimen.magnification_mirror_surface_margin);
+ // Window width includes the magnifier frame and the margin. Decreasing the window size
+ // will be decreasing the amount of the frame size only.
+ int newWindowWidth =
+ (int) ((startingSize - 2 * mirrorSurfaceMargin) * (1 - changeWindowSizeAmount))
+ + 2 * mirrorSurfaceMargin;
+ assertEquals(newWindowWidth, actualWindowWidth.get());
+ assertEquals(startingSize, actualWindowHeight.get());
+ }
+
+ @Test
+ public void windowHeightIsNotMin_performA11yActionDecreaseHeight_windowHeightDecreased() {
+ int mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int startingSize = (int) (mMinWindowSize * 1.1);
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mirrorView.performAccessibilityAction(
+ R.id.accessibility_action_decrease_window_height, null);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+ R.dimen.magnification_mirror_surface_margin);
+ // Window height includes the magnifier frame and the margin. Decreasing the window size
+ // will be decreasing the amount of the frame size only.
+ int newWindowHeight =
+ (int) ((startingSize - 2 * mirrorSurfaceMargin) * (1 - changeWindowSizeAmount))
+ + 2 * mirrorSurfaceMargin;
+ assertEquals(startingSize, actualWindowWidth.get());
+ assertEquals(newWindowHeight, actualWindowHeight.get());
+ }
+
+ @Test
+ public void windowWidthIsMin_noDecreaseWindowWidthA11yAction() {
+ int mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int startingSize = mMinWindowSize;
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AccessibilityNodeInfo accessibilityNodeInfo =
+ mirrorView.createAccessibilityNodeInfo();
+ assertFalse(accessibilityNodeInfo.getActionList().contains(
+ new AccessibilityAction(R.id.accessibility_action_decrease_window_width, null)));
+ }
+
+ @Test
+ public void windowHeightIsMin_noDecreaseWindowHeightA11yAcyion() {
+ int mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int startingSize = mMinWindowSize;
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AccessibilityNodeInfo accessibilityNodeInfo =
+ mirrorView.createAccessibilityNodeInfo();
+ assertFalse(accessibilityNodeInfo.getActionList().contains(
+ new AccessibilityAction(R.id.accessibility_action_decrease_window_height, null)));
+ }
+
+ @Test
public void enableWindowMagnification_hasA11yWindowTitle() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
@@ -1210,4 +1449,5 @@
when(mContext.getDisplay()).thenReturn(display);
return newRotation;
}
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
index 239e317..ed9ae5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.coroutines.collectLastValue
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -44,6 +45,7 @@
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class FingerprintRepositoryImplTest : SysuiTestCase() {
@@ -73,10 +75,15 @@
@Test
fun initializeProperties() =
testScope.runTest {
- val isInitialized = collectLastValue(repository.isInitialized)
+ val sensorId by collectLastValue(repository.sensorId)
+ val strength by collectLastValue(repository.strength)
+ val sensorType by collectLastValue(repository.sensorType)
+ val sensorLocations by collectLastValue(repository.sensorLocations)
- assertDefaultProperties()
- assertThat(isInitialized()).isFalse()
+ // Assert default properties.
+ assertThat(sensorId).isEqualTo(-1)
+ assertThat(strength).isEqualTo(SensorStrength.CONVENIENCE)
+ assertThat(sensorType).isEqualTo(FingerprintSensorType.UNKNOWN)
val fingerprintProps =
listOf(
@@ -115,31 +122,24 @@
fingerprintAuthenticatorsCaptor.value.onAllAuthenticatorsRegistered(fingerprintProps)
- assertThat(repository.sensorId.value).isEqualTo(1)
- assertThat(repository.strength.value).isEqualTo(SensorStrength.STRONG)
- assertThat(repository.sensorType.value).isEqualTo(FingerprintSensorType.REAR)
+ assertThat(sensorId).isEqualTo(1)
+ assertThat(strength).isEqualTo(SensorStrength.STRONG)
+ assertThat(sensorType).isEqualTo(FingerprintSensorType.REAR)
- assertThat(repository.sensorLocations.value.size).isEqualTo(2)
- assertThat(repository.sensorLocations.value).containsKey("display_id_1")
- with(repository.sensorLocations.value["display_id_1"]!!) {
+ assertThat(sensorLocations?.size).isEqualTo(2)
+ assertThat(sensorLocations).containsKey("display_id_1")
+ with(sensorLocations?.get("display_id_1")!!) {
assertThat(displayId).isEqualTo("display_id_1")
assertThat(sensorLocationX).isEqualTo(100)
assertThat(sensorLocationY).isEqualTo(300)
assertThat(sensorRadius).isEqualTo(20)
}
- assertThat(repository.sensorLocations.value).containsKey("")
- with(repository.sensorLocations.value[""]!!) {
+ assertThat(sensorLocations).containsKey("")
+ with(sensorLocations?.get("")!!) {
assertThat(displayId).isEqualTo("")
assertThat(sensorLocationX).isEqualTo(540)
assertThat(sensorLocationY).isEqualTo(1636)
assertThat(sensorRadius).isEqualTo(130)
}
- assertThat(isInitialized()).isTrue()
}
-
- private fun assertDefaultProperties() {
- assertThat(repository.sensorId.value).isEqualTo(-1)
- assertThat(repository.strength.value).isEqualTo(SensorStrength.CONVENIENCE)
- assertThat(repository.sensorType.value).isEqualTo(FingerprintSensorType.UNKNOWN)
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt
index fd96cf4..712eef1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt
@@ -22,6 +22,7 @@
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.coroutines.collectLastValue
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -51,7 +52,7 @@
}
@Test
- fun testGetOverlayOffsets() =
+ fun testOverlayOffsetUpdates() =
testScope.runTest {
fingerprintRepository.setProperties(
sensorId = 1,
@@ -76,16 +77,32 @@
)
)
- var offsets = interactor.getOverlayOffsets("display_id_1")
- assertThat(offsets.displayId).isEqualTo("display_id_1")
- assertThat(offsets.sensorLocationX).isEqualTo(100)
- assertThat(offsets.sensorLocationY).isEqualTo(300)
- assertThat(offsets.sensorRadius).isEqualTo(20)
+ val displayId by collectLastValue(interactor.displayId)
+ val offsets by collectLastValue(interactor.overlayOffsets)
- offsets = interactor.getOverlayOffsets("invalid_display_id")
- assertThat(offsets.displayId).isEqualTo("")
- assertThat(offsets.sensorLocationX).isEqualTo(540)
- assertThat(offsets.sensorLocationY).isEqualTo(1636)
- assertThat(offsets.sensorRadius).isEqualTo(130)
+ // Assert offsets of empty displayId.
+ assertThat(displayId).isEqualTo("")
+ assertThat(offsets?.displayId).isEqualTo("")
+ assertThat(offsets?.sensorLocationX).isEqualTo(540)
+ assertThat(offsets?.sensorLocationY).isEqualTo(1636)
+ assertThat(offsets?.sensorRadius).isEqualTo(130)
+
+ // Offsets should be updated correctly.
+ interactor.onDisplayChanged("display_id_1")
+ assertThat(displayId).isEqualTo("display_id_1")
+ assertThat(offsets?.displayId).isEqualTo("display_id_1")
+ assertThat(offsets?.sensorLocationX).isEqualTo(100)
+ assertThat(offsets?.sensorLocationY).isEqualTo(300)
+ assertThat(offsets?.sensorRadius).isEqualTo(20)
+
+ // Should return default offset when the displayId is invalid.
+ interactor.onDisplayChanged("invalid_display_id")
+ assertThat(displayId).isEqualTo("invalid_display_id")
+ assertThat(offsets?.displayId).isEqualTo(SensorLocationInternal.DEFAULT.displayId)
+ assertThat(offsets?.sensorLocationX)
+ .isEqualTo(SensorLocationInternal.DEFAULT.sensorLocationX)
+ assertThat(offsets?.sensorLocationY)
+ .isEqualTo(SensorLocationInternal.DEFAULT.sensorLocationY)
+ assertThat(offsets?.sensorRadius).isEqualTo(SensorLocationInternal.DEFAULT.sensorRadius)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
index bb73dc6..dbf6a29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
@@ -81,4 +81,10 @@
command().execute(pw, listOf("fake"))
verify(keyguardBlueprintInteractor).transitionToBlueprint("fake")
}
+
+ @Test
+ fun testValidArg_Int() {
+ command().execute(pw, listOf("1"))
+ verify(keyguardBlueprintInteractor).transitionToBlueprint(1)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
index 41ba1f4..681fce8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection
@@ -61,6 +62,8 @@
@Mock private lateinit var defaultStatusViewSection: DefaultStatusViewSection
@Mock private lateinit var defaultNSSLSection: DefaultNotificationStackScrollLayoutSection
@Mock private lateinit var splitShadeGuidelines: SplitShadeGuidelines
+ @Mock private lateinit var aodNotificationIconsSection: AodNotificationIconsSection
+
private val featureFlags = FakeFeatureFlags()
@Before
@@ -77,6 +80,7 @@
defaultStatusViewSection,
defaultNSSLSection,
splitShadeGuidelines,
+ aodNotificationIconsSection,
featureFlags,
)
featureFlags.set(Flags.LAZY_INFLATE_KEYGUARD, false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
index 1e47f78..0d694ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -51,30 +51,6 @@
/** Tests the Java-compatible function wrapper, ensures callback is invoked. */
@Test
- fun testProcessAsync() {
- val request =
- ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_KEY_OTHER)
- .setBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
- .build()
- val processor = RequestProcessor(imageCapture, policy, flags, scope)
-
- var result: ScreenshotRequest? = null
- var callbackCount = 0
- val callback: (ScreenshotRequest) -> Unit = { processedRequest: ScreenshotRequest ->
- result = processedRequest
- callbackCount++
- }
-
- // runs synchronously, using Unconfined Dispatcher
- processor.processAsync(request, callback)
-
- // Callback invoked once returning the same request (no changes)
- assertThat(callbackCount).isEqualTo(1)
- assertThat(result).isEqualTo(request)
- }
-
- /** Tests the Java-compatible function wrapper, ensures callback is invoked. */
- @Test
fun testProcessAsync_ScreenshotData() {
val request =
ScreenshotData.fromRequest(
@@ -112,13 +88,6 @@
ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER).build()
val processor = RequestProcessor(imageCapture, policy, flags, scope)
- val processedRequest = processor.process(request)
-
- // Request has topComponent added, but otherwise unchanged.
- assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_FULLSCREEN)
- assertThat(processedRequest.source).isEqualTo(SCREENSHOT_OTHER)
- assertThat(processedRequest.topComponent).isEqualTo(component)
-
val processedData = processor.process(ScreenshotData.fromRequest(request))
// Request has topComponent added, but otherwise unchanged.
@@ -144,18 +113,6 @@
ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER).build()
val processor = RequestProcessor(imageCapture, policy, flags, scope)
- val processedRequest = processor.process(request)
-
- // Expect a task snapshot is taken, overriding the full screen mode
- assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_PROVIDED_IMAGE)
- assertThat(bitmap.equalsHardwareBitmap(processedRequest.bitmap)).isTrue()
- assertThat(processedRequest.boundsInScreen).isEqualTo(bounds)
- assertThat(processedRequest.insets).isEqualTo(Insets.NONE)
- assertThat(processedRequest.taskId).isEqualTo(TASK_ID)
- assertThat(imageCapture.requestedTaskId).isEqualTo(TASK_ID)
- assertThat(processedRequest.userId).isEqualTo(USER_ID)
- assertThat(processedRequest.topComponent).isEqualTo(component)
-
val processedData = processor.process(ScreenshotData.fromRequest(request))
// Expect a task snapshot is taken, overriding the full screen mode
@@ -165,8 +122,6 @@
assertThat(processedData.insets).isEqualTo(Insets.NONE)
assertThat(processedData.taskId).isEqualTo(TASK_ID)
assertThat(imageCapture.requestedTaskId).isEqualTo(TASK_ID)
- assertThat(processedRequest.userId).isEqualTo(USER_ID)
- assertThat(processedRequest.topComponent).isEqualTo(component)
}
@Test
@@ -186,9 +141,6 @@
val processor = RequestProcessor(imageCapture, policy, flags, scope)
Assert.assertThrows(IllegalStateException::class.java) {
- runBlocking { processor.process(request) }
- }
- Assert.assertThrows(IllegalStateException::class.java) {
runBlocking { processor.process(ScreenshotData.fromRequest(request)) }
}
}
@@ -212,11 +164,6 @@
.setInsets(Insets.NONE)
.build()
- val processedRequest = processor.process(request)
-
- // No changes
- assertThat(processedRequest).isEqualTo(request)
-
val screenshotData = ScreenshotData.fromRequest(request)
val processedData = processor.process(screenshotData)
@@ -243,14 +190,10 @@
.setInsets(Insets.NONE)
.build()
- val processedRequest = processor.process(request)
-
- // Work profile, but already a task snapshot, so no changes
- assertThat(processedRequest).isEqualTo(request)
-
val screenshotData = ScreenshotData.fromRequest(request)
val processedData = processor.process(screenshotData)
+ // Work profile, but already a task snapshot, so no changes
assertThat(processedData).isEqualTo(screenshotData)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
index 97c2ed4..cfdf66e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
@@ -1,6 +1,7 @@
package com.android.systemui.screenshot
import android.content.ComponentName
+import android.graphics.Bitmap
import android.net.Uri
import android.testing.AndroidTestingRunner
import android.view.Display
@@ -10,6 +11,7 @@
import android.view.Display.TYPE_VIRTUAL
import android.view.Display.TYPE_WIFI
import android.view.WindowManager
+import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.util.ScreenshotRequest
@@ -95,6 +97,35 @@
}
@Test
+ fun executeScreenshots_providedImageType_callsOnlyDefaultDisplayController() =
+ testScope.runTest {
+ setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
+ val onSaved = { _: Uri -> }
+ screenshotExecutor.executeScreenshots(
+ createScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE),
+ onSaved,
+ callback
+ )
+
+ verify(controllerFactory).create(eq(0))
+ verify(controllerFactory, never()).create(eq(1))
+
+ val capturer = ArgumentCaptor<ScreenshotData>()
+
+ verify(controller0).handleScreenshot(capturer.capture(), any(), any())
+ assertThat(capturer.value.displayId).isEqualTo(0)
+ // OnSaved callback should be different.
+ verify(controller1, never()).handleScreenshot(any(), any(), any())
+
+ assertThat(eventLogger.numLogs()).isEqualTo(1)
+ assertThat(eventLogger.get(0).eventId)
+ .isEqualTo(ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER.id)
+ assertThat(eventLogger.get(0).packageName).isEqualTo(topComponent.packageName)
+
+ screenshotExecutor.onDestroy()
+ }
+
+ @Test
fun executeScreenshots_onlyVirtualDisplays_noInteractionsWithControllers() =
testScope.runTest {
setDisplays(display(TYPE_VIRTUAL, id = 0), display(TYPE_VIRTUAL, id = 1))
@@ -283,12 +314,14 @@
runCurrent()
}
- private fun createScreenshotRequest() =
- ScreenshotRequest.Builder(
- WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
- WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER
- )
+ private fun createScreenshotRequest(type: Int = WindowManager.TAKE_SCREENSHOT_FULLSCREEN) =
+ ScreenshotRequest.Builder(type, WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER)
.setTopComponent(topComponent)
+ .also {
+ if (type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
+ it.setBitmap(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888))
+ }
+ }
.build()
private class FakeRequestProcessor : ScreenshotRequestProcessor {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index a08cda6..6205d90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -20,10 +20,6 @@
import android.app.admin.DevicePolicyResources.Strings.SystemUi.SCREENSHOT_BLOCKED_BY_ADMIN
import android.app.admin.DevicePolicyResourcesManager
import android.content.ComponentName
-import android.graphics.Bitmap
-import android.graphics.Bitmap.Config.HARDWARE
-import android.graphics.ColorSpace
-import android.hardware.HardwareBuffer
import android.os.UserHandle
import android.os.UserManager
import android.testing.AndroidTestingRunner
@@ -94,14 +90,6 @@
// Stub request processor as a synchronous no-op for tests with the flag enabled
doAnswer {
- val request: ScreenshotRequest = it.getArgument(0) as ScreenshotRequest
- val consumer: Consumer<ScreenshotRequest> = it.getArgument(1)
- consumer.accept(request)
- }
- .whenever(requestProcessor)
- .processAsync(/* request= */ any(ScreenshotRequest::class.java), /* callback= */ any())
-
- doAnswer {
val request: ScreenshotData = it.getArgument(0) as ScreenshotData
val consumer: Consumer<ScreenshotData> = it.getArgument(1)
consumer.accept(request)
@@ -353,23 +341,3 @@
return service
}
}
-
-private fun Bitmap.equalsHardwareBitmap(other: Bitmap): Boolean {
- return config == HARDWARE &&
- other.config == HARDWARE &&
- hardwareBuffer == other.hardwareBuffer &&
- colorSpace == other.colorSpace
-}
-
-/** A hardware Bitmap is mandated by use of ScreenshotHelper.HardwareBitmapBundler */
-private fun makeHardwareBitmap(width: Int, height: Int): Bitmap {
- val buffer =
- HardwareBuffer.create(
- width,
- height,
- HardwareBuffer.RGBA_8888,
- 1,
- HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
- )
- return Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!!
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 75fb22d..ff68eb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -220,6 +220,14 @@
)
)
assertThat(isOnLockscreen).isTrue()
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ to = KeyguardState.PRIMARY_BOUNCER,
+ transitionState = TransitionState.FINISHED
+ )
+ )
+ assertThat(isOnLockscreen).isTrue()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 137566b..bd3fb9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -399,7 +399,6 @@
when(mGradientColors.supportsDarkText()).thenReturn(true);
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
- ConfigurationController configurationController = new ConfigurationControllerImpl(mContext);
when(mLockscreenWallpaperLazy.get()).thenReturn(mLockscreenWallpaper);
when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
@@ -438,6 +437,11 @@
when(mUserTracker.getUserHandle()).thenReturn(
UserHandle.of(ActivityManager.getCurrentUser()));
+ createCentralSurfaces();
+ }
+
+ private void createCentralSurfaces() {
+ ConfigurationController configurationController = new ConfigurationControllerImpl(mContext);
mCentralSurfaces = new CentralSurfacesImpl(
mContext,
mNotificationsController,
@@ -1083,6 +1087,27 @@
verify(mNotificationPanelViewController).setTouchAndAnimationDisabled(true);
}
+ /** Regression test for b/298355063 */
+ @Test
+ public void fingerprintManagerNull_noNPE() {
+ // GIVEN null fingerprint manager
+ mFingerprintManager = null;
+ createCentralSurfaces();
+
+ // GIVEN should animate doze wakeup
+ when(mDozeServiceHost.shouldAnimateWakeup()).thenReturn(true);
+ when(mBiometricUnlockController.getMode()).thenReturn(
+ BiometricUnlockController.MODE_ONLY_WAKE);
+ when(mDozeServiceHost.isPulsing()).thenReturn(false);
+ when(mStatusBarStateController.getDozeAmount()).thenReturn(1f);
+
+ // WHEN waking up from the power button
+ mWakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+ mCentralSurfaces.mWakefulnessObserver.onStartedWakingUp();
+
+ // THEN no NPE when fingerprintManager is null
+ }
+
/**
* Configures the appropriate mocks and then calls {@link CentralSurfacesImpl#updateIsKeyguard}
* to reconfigure the keyguard to reflect the requested showing/occluded states.
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
index 2362a52..0c5e438 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
@@ -20,16 +20,12 @@
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
class FakeFingerprintPropertyRepository : FingerprintPropertyRepository {
- private val _isInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false)
- override val isInitialized = _isInitialized.asStateFlow()
-
private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
- override val sensorId: StateFlow<Int> = _sensorId.asStateFlow()
+ override val sensorId = _sensorId.asStateFlow()
private val _strength: MutableStateFlow<SensorStrength> =
MutableStateFlow(SensorStrength.CONVENIENCE)
@@ -37,12 +33,11 @@
private val _sensorType: MutableStateFlow<FingerprintSensorType> =
MutableStateFlow(FingerprintSensorType.UNKNOWN)
- override val sensorType: StateFlow<FingerprintSensorType> = _sensorType.asStateFlow()
+ override val sensorType = _sensorType.asStateFlow()
private val _sensorLocations: MutableStateFlow<Map<String, SensorLocationInternal>> =
MutableStateFlow(mapOf("" to SensorLocationInternal.DEFAULT))
- override val sensorLocations: StateFlow<Map<String, SensorLocationInternal>> =
- _sensorLocations.asStateFlow()
+ override val sensorLocations = _sensorLocations.asStateFlow()
fun setProperties(
sensorId: Int,
@@ -54,6 +49,5 @@
_strength.value = strength
_sensorType.value = sensorType
_sensorLocations.value = sensorLocations
- _isInitialized.value = true
}
}
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index bf8a9af..e9bb763 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -27,4 +27,20 @@
"services.core",
"androidx.annotation_annotation",
],
+ static_libs: [
+ "com_android_server_accessibility_flags_lib",
+ ],
+}
+
+aconfig_declarations {
+ name: "com_android_server_accessibility_flags",
+ package: "com.android.server.accessibility",
+ srcs: [
+ "accessibility.aconfig",
+ ],
+}
+
+java_aconfig_library {
+ name: "com_android_server_accessibility_flags_lib",
+ aconfig_declarations: "com_android_server_accessibility_flags",
}
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
new file mode 100644
index 0000000..b5fc2b6
--- /dev/null
+++ b/services/accessibility/accessibility.aconfig
@@ -0,0 +1,7 @@
+package: "com.android.server.accessibility"
+flag {
+ name: "proxy_use_apps_on_virtual_device_listener"
+ namespace: "accessibility"
+ description: "Fixes race condition described in b/286587811"
+ bug: "286587811"
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
index 119f575..ed77476 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
@@ -33,6 +33,7 @@
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -42,6 +43,7 @@
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IntPair;
import com.android.server.LocalServices;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
@@ -96,6 +98,9 @@
private final SystemSupport mSystemSupport;
+ private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener
+ mAppsOnVirtualDeviceListener;
+
/**
* Callbacks into AccessibilityManagerService.
*/
@@ -174,6 +179,16 @@
synchronized (mLock) {
mProxyA11yServiceConnections.put(displayId, connection);
+ if (Flags.proxyUseAppsOnVirtualDeviceListener()) {
+ if (mAppsOnVirtualDeviceListener == null) {
+ mAppsOnVirtualDeviceListener = allRunningUids ->
+ notifyProxyOfRunningAppsChange(allRunningUids);
+ final VirtualDeviceManagerInternal localVdm = getLocalVdm();
+ if (localVdm != null) {
+ localVdm.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
+ }
+ }
+ }
}
// If the client dies, make sure to remove the connection.
@@ -276,11 +291,21 @@
}
}
});
- // If there isn't an existing proxy for the device id, reset clients. Resetting
+ // If there isn't an existing proxy for the device id, reset app clients. Resetting
// will usually happen, since in most cases there will only be one proxy for a
// device.
if (!isProxyedDeviceId(deviceId)) {
synchronized (mLock) {
+ if (Flags.proxyUseAppsOnVirtualDeviceListener()) {
+ if (mProxyA11yServiceConnections.size() == 0) {
+ final VirtualDeviceManagerInternal localVdm = getLocalVdm();
+ if (localVdm != null && mAppsOnVirtualDeviceListener != null) {
+ localVdm.unregisterAppsOnVirtualDeviceListener(
+ mAppsOnVirtualDeviceListener);
+ mAppsOnVirtualDeviceListener = null;
+ }
+ }
+ }
mSystemSupport.removeDeviceIdLocked(deviceId);
mLastStates.delete(deviceId);
}
@@ -307,7 +332,7 @@
* Returns {@code true} if {@code deviceId} is being proxy-ed.
*/
public boolean isProxyedDeviceId(int deviceId) {
- if (deviceId == DEVICE_ID_DEFAULT && deviceId == DEVICE_ID_INVALID) {
+ if (deviceId == DEVICE_ID_DEFAULT || deviceId == DEVICE_ID_INVALID) {
return false;
}
boolean isTrackingDeviceId;
@@ -566,7 +591,7 @@
* This is similar to onUserStateChangeLocked and onClientChangeLocked, but does not require an
* A11yUserState and only checks proxy-relevant settings.
*/
- public void onProxyChanged(int deviceId) {
+ private void onProxyChanged(int deviceId, boolean forceUpdate) {
if (DEBUG) {
Slog.v(LOG_TAG, "onProxyChanged called for deviceId: " + deviceId);
}
@@ -584,7 +609,7 @@
// Calls A11yManager#setRelevantEventTypes (test these)
updateRelevantEventTypesLocked(deviceId);
// Calls A11yManager#setState
- scheduleUpdateProxyClientsIfNeededLocked(deviceId);
+ scheduleUpdateProxyClientsIfNeededLocked(deviceId, forceUpdate);
//Calls A11yManager#notifyServicesStateChanged(timeout)
scheduleNotifyProxyClientsOfServicesStateChangeLocked(deviceId);
// Calls A11yManager#setFocusAppearance
@@ -594,16 +619,25 @@
}
/**
+ * Handles proxy changes, but does not force an update of app clients.
+ */
+ public void onProxyChanged(int deviceId) {
+ onProxyChanged(deviceId, false);
+ }
+
+ /**
* Updates the states of the app AccessibilityManagers.
*/
- private void scheduleUpdateProxyClientsIfNeededLocked(int deviceId) {
+ private void scheduleUpdateProxyClientsIfNeededLocked(int deviceId, boolean forceUpdate) {
final int proxyState = getStateLocked(deviceId);
if (DEBUG) {
Slog.v(LOG_TAG, "State for device id " + deviceId + " is " + proxyState);
Slog.v(LOG_TAG, "Last state for device id " + deviceId + " is "
+ getLastSentStateLocked(deviceId));
+ Slog.v(LOG_TAG, "force update: " + forceUpdate);
}
- if ((getLastSentStateLocked(deviceId)) != proxyState) {
+ if ((getLastSentStateLocked(deviceId)) != proxyState
+ || (Flags.proxyUseAppsOnVirtualDeviceListener() && forceUpdate)) {
setLastStateLocked(deviceId, proxyState);
mMainHandler.post(() -> {
synchronized (mLock) {
@@ -792,7 +826,7 @@
}
/**
- * Updates the device ids of IAccessibilityManagerClients if needed.
+ * Updates the device ids of IAccessibilityManagerClients if needed after a proxy change.
*/
private void updateDeviceIdsIfNeededLocked(int deviceId,
@NonNull RemoteCallbackList<IAccessibilityManagerClient> clients) {
@@ -804,13 +838,66 @@
for (int i = 0; i < clients.getRegisteredCallbackCount(); i++) {
final AccessibilityManagerService.Client client =
((AccessibilityManagerService.Client) clients.getRegisteredCallbackCookie(i));
- if (deviceId != DEVICE_ID_DEFAULT && deviceId != DEVICE_ID_INVALID
- && localVdm.getDeviceIdsForUid(client.mUid).contains(deviceId)) {
- if (DEBUG) {
- Slog.v(LOG_TAG, "Packages moved to device id " + deviceId + " are "
- + Arrays.toString(client.mPackageNames));
+ if (Flags.proxyUseAppsOnVirtualDeviceListener()) {
+ if (deviceId == DEVICE_ID_DEFAULT || deviceId == DEVICE_ID_INVALID) {
+ continue;
}
- client.mDeviceId = deviceId;
+ boolean uidBelongsToDevice =
+ localVdm.getDeviceIdsForUid(client.mUid).contains(deviceId);
+ if (client.mDeviceId != deviceId && uidBelongsToDevice) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "Packages moved to device id " + deviceId + " are "
+ + Arrays.toString(client.mPackageNames));
+ }
+ client.mDeviceId = deviceId;
+ } else if (client.mDeviceId == deviceId && !uidBelongsToDevice) {
+ client.mDeviceId = DEVICE_ID_DEFAULT;
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "Packages moved to the default device from device id "
+ + deviceId + " are " + Arrays.toString(client.mPackageNames));
+ }
+ }
+ } else {
+ if (deviceId != DEVICE_ID_DEFAULT && deviceId != DEVICE_ID_INVALID
+ && localVdm.getDeviceIdsForUid(client.mUid).contains(deviceId)) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "Packages moved to device id " + deviceId + " are "
+ + Arrays.toString(client.mPackageNames));
+ }
+ client.mDeviceId = deviceId;
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ void notifyProxyOfRunningAppsChange(Set<Integer> allRunningUids) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "notifyProxyOfRunningAppsChange: " + allRunningUids);
+ }
+ synchronized (mLock) {
+ if (mProxyA11yServiceConnections.size() == 0) {
+ return;
+ }
+ final VirtualDeviceManagerInternal localVdm = getLocalVdm();
+ if (localVdm == null) {
+ return;
+ }
+ final ArraySet<Integer> deviceIdsToUpdate = new ArraySet<>();
+ for (int i = 0; i < mProxyA11yServiceConnections.size(); i++) {
+ final ProxyAccessibilityServiceConnection proxy =
+ mProxyA11yServiceConnections.valueAt(i);
+ if (proxy != null) {
+ final int proxyDeviceId = proxy.getDeviceId();
+ for (Integer uid : allRunningUids) {
+ if (localVdm.getDeviceIdsForUid(uid).contains(proxyDeviceId)) {
+ deviceIdsToUpdate.add(proxyDeviceId);
+ }
+ }
+ }
+ }
+ for (Integer proxyDeviceId : deviceIdsToUpdate) {
+ onProxyChanged(proxyDeviceId, true);
}
}
}
@@ -843,6 +930,11 @@
return mLocalVdm;
}
+ @VisibleForTesting
+ void setLocalVirtualDeviceManager(VirtualDeviceManagerInternal localVdm) {
+ mLocalVdm = localVdm;
+ }
+
/**
* Prints information belonging to each display that is controlled by an
* AccessibilityDisplayProxy.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 39756df..cae047f 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -18,7 +18,6 @@
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
import static android.service.autofill.AutofillService.EXTRA_RESULT;
-
import static com.android.server.autofill.AutofillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS;
import android.os.Bundle;
@@ -155,20 +154,31 @@
pw.println("");
}
+ Method[] flagMethods = {};
+
try {
- Method[] flagMethods = Flags.class.getMethods();
- // For some reason, unreferenced flags do not show up here
- // Maybe compiler optomized them out of bytecode?
- for (Method method : flagMethods) {
- if (Modifier.isPublic(method.getModifiers())) {
- pw.println(method.getName() + ": " + method.invoke(null));
- }
- }
- } catch (Exception ex) {
- pw.println(ex);
+ flagMethods = Flags.class.getDeclaredMethods();
+ } catch (SecurityException ex) {
+ ex.printStackTrace(pw);
return -1;
}
+ // For some reason, unreferenced flags do not show up here
+ // Maybe compiler optomized them out of bytecode?
+ for (Method method : flagMethods) {
+ if (!Modifier.isPublic(method.getModifiers())) {
+ continue;
+ }
+ try {
+ pw.print(method.getName() + ": ");
+ pw.print(method.invoke(null));
+ } catch (Exception ex) {
+ ex.printStackTrace(pw);
+ } finally {
+ pw.println("");
+ }
+ }
+
return 0;
}
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index b07a0bb..102c262 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -47,7 +47,6 @@
import java.util.Set;
-
/**
* A controller to control the policies of the windows that can be displayed on the virtual display.
*/
@@ -106,12 +105,14 @@
public static final long ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE = 201712607L;
@NonNull
private final ArraySet<UserHandle> mAllowedUsers;
- private final boolean mActivityLaunchAllowedByDefault;
+ @GuardedBy("mGenericWindowPolicyControllerLock")
+ private boolean mActivityLaunchAllowedByDefault;
@NonNull
- private final ArraySet<ComponentName> mActivityPolicyExceptions;
+ @GuardedBy("mGenericWindowPolicyControllerLock")
+ private final Set<ComponentName> mActivityPolicyExemptions;
private final boolean mCrossTaskNavigationAllowedByDefault;
@NonNull
- private final ArraySet<ComponentName> mCrossTaskNavigationExceptions;
+ private final ArraySet<ComponentName> mCrossTaskNavigationExemptions;
private final Object mGenericWindowPolicyControllerLock = new Object();
@Nullable private final ActivityBlockedCallback mActivityBlockedCallback;
private int mDisplayId = Display.INVALID_DISPLAY;
@@ -142,11 +143,11 @@
* @param allowedUsers The set of users that are allowed to stream in this display.
* @param activityLaunchAllowedByDefault Whether activities are default allowed to be launched
* or blocked.
- * @param activityPolicyExceptions The set of activities explicitly exempt from the default
+ * @param activityPolicyExemptions The set of activities explicitly exempt from the default
* activity policy.
* @param crossTaskNavigationAllowedByDefault Whether cross task navigations are allowed by
* default or not.
- * @param crossTaskNavigationExceptions The set of components explicitly exempt from the default
+ * @param crossTaskNavigationExemptions The set of components explicitly exempt from the default
* navigation policy.
* @param activityListener Activity listener to listen for activity changes.
* @param activityBlockedCallback Callback that is called when an activity is blocked from
@@ -157,12 +158,14 @@
* passed in filters.
* @param showTasksInHostDeviceRecents whether to show activities in recents on the host device.
*/
- public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
+ public GenericWindowPolicyController(
+ int windowFlags,
+ int systemWindowFlags,
@NonNull ArraySet<UserHandle> allowedUsers,
boolean activityLaunchAllowedByDefault,
- @NonNull Set<ComponentName> activityPolicyExceptions,
+ @NonNull Set<ComponentName> activityPolicyExemptions,
boolean crossTaskNavigationAllowedByDefault,
- @NonNull Set<ComponentName> crossTaskNavigationExceptions,
+ @NonNull Set<ComponentName> crossTaskNavigationExemptions,
@Nullable ActivityListener activityListener,
@Nullable PipBlockedCallback pipBlockedCallback,
@Nullable ActivityBlockedCallback activityBlockedCallback,
@@ -173,9 +176,9 @@
super();
mAllowedUsers = allowedUsers;
mActivityLaunchAllowedByDefault = activityLaunchAllowedByDefault;
- mActivityPolicyExceptions = new ArraySet<>(activityPolicyExceptions);
+ mActivityPolicyExemptions = activityPolicyExemptions;
mCrossTaskNavigationAllowedByDefault = crossTaskNavigationAllowedByDefault;
- mCrossTaskNavigationExceptions = new ArraySet<>(crossTaskNavigationExceptions);
+ mCrossTaskNavigationExemptions = new ArraySet<>(crossTaskNavigationExemptions);
mActivityBlockedCallback = activityBlockedCallback;
setInterestedWindowFlags(windowFlags, systemWindowFlags);
mActivityListener = activityListener;
@@ -202,6 +205,24 @@
}
}
+ void setActivityLaunchDefaultAllowed(boolean activityLaunchDefaultAllowed) {
+ synchronized (mGenericWindowPolicyControllerLock) {
+ mActivityLaunchAllowedByDefault = activityLaunchDefaultAllowed;
+ }
+ }
+
+ void addActivityPolicyExemption(@NonNull ComponentName componentName) {
+ synchronized (mGenericWindowPolicyControllerLock) {
+ mActivityPolicyExemptions.add(componentName);
+ }
+ }
+
+ void removeActivityPolicyExemption(@NonNull ComponentName componentName) {
+ synchronized (mGenericWindowPolicyControllerLock) {
+ mActivityPolicyExemptions.remove(componentName);
+ }
+ }
+
/** Register a listener for running applications changes. */
public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
synchronized (mGenericWindowPolicyControllerLock) {
@@ -265,14 +286,17 @@
+ mDisplayCategories);
return false;
}
- if (!isAllowedByPolicy(mActivityLaunchAllowedByDefault, mActivityPolicyExceptions,
- activityComponent)) {
- Slog.d(TAG, "Virtual device launch disallowed by policy: " + activityComponent);
- return false;
+ synchronized (mGenericWindowPolicyControllerLock) {
+ if (!isAllowedByPolicy(mActivityLaunchAllowedByDefault, mActivityPolicyExemptions,
+ activityComponent)) {
+ Slog.d(TAG, "Virtual device launch disallowed by policy: "
+ + activityComponent);
+ return false;
+ }
}
if (isNewTask && launchingFromDisplayId != DEFAULT_DISPLAY
&& !isAllowedByPolicy(mCrossTaskNavigationAllowedByDefault,
- mCrossTaskNavigationExceptions, activityComponent)) {
+ mCrossTaskNavigationExemptions, activityComponent)) {
Slog.d(TAG, "Virtual device cross task navigation disallowed by policy: "
+ activityComponent);
return false;
@@ -378,11 +402,11 @@
&& mDisplayCategories.contains(activityInfo.requiredDisplayCategory);
}
- private boolean isAllowedByPolicy(boolean allowedByDefault, ArraySet<ComponentName> exceptions,
- ComponentName component) {
- // Either allowed and the exceptions do not contain the component,
- // or disallowed and the exceptions contain the component.
- return allowedByDefault != exceptions.contains(component);
+ private static boolean isAllowedByPolicy(boolean allowedByDefault,
+ Set<ComponentName> exemptions, ComponentName component) {
+ // Either allowed and the exemptions do not contain the component,
+ // or disallowed and the exemptions contain the component.
+ return allowedByDefault != exemptions.contains(component);
}
@VisibleForTesting
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 8f765e4..3b13410 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -22,6 +22,7 @@
import static android.companion.virtual.VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -93,7 +94,6 @@
import android.view.WindowManager;
import android.widget.Toast;
-
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.BlockedAppStreamingActivity;
@@ -174,11 +174,15 @@
@NonNull
private final VirtualDevice mPublicVirtualDeviceObject;
+ @GuardedBy("mVirtualDeviceLock")
+ @NonNull
+ private final Set<ComponentName> mActivityPolicyExemptions;
+
private ActivityListener createListenerAdapter() {
return new ActivityListener() {
@Override
- public void onTopActivityChanged(int displayId, ComponentName topActivity) {
+ public void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity) {
try {
mActivityListener.onTopActivityChanged(displayId, topActivity,
UserHandle.USER_NULL);
@@ -188,7 +192,7 @@
}
@Override
- public void onTopActivityChanged(int displayId, ComponentName topActivity,
+ public void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity,
@UserIdInt int userId) {
try {
mActivityListener.onTopActivityChanged(displayId, topActivity, userId);
@@ -295,6 +299,18 @@
mPublicVirtualDeviceObject = new VirtualDevice(
this, getDeviceId(), getPersistentDeviceId(), mParams.getName());
+
+ if (Flags.dynamicPolicy()) {
+ mActivityPolicyExemptions = new ArraySet<>(
+ mParams.getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT
+ ? mParams.getBlockedActivities()
+ : mParams.getAllowedActivities());
+ } else {
+ mActivityPolicyExemptions =
+ mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED
+ ? mParams.getBlockedActivities()
+ : mParams.getAllowedActivities();
+ }
}
@VisibleForTesting
@@ -414,6 +430,34 @@
}
}
+ @Override // Binder call
+ @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+ public void addActivityPolicyExemption(@NonNull ComponentName componentName) {
+ super.addActivityPolicyExemption_enforcePermission();
+ synchronized (mVirtualDeviceLock) {
+ if (mActivityPolicyExemptions.add(componentName)) {
+ for (int i = 0; i < mVirtualDisplays.size(); i++) {
+ mVirtualDisplays.valueAt(i).getWindowPolicyController()
+ .addActivityPolicyExemption(componentName);
+ }
+ }
+ }
+ }
+
+ @Override // Binder call
+ @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+ public void removeActivityPolicyExemption(@NonNull ComponentName componentName) {
+ super.removeActivityPolicyExemption_enforcePermission();
+ synchronized (mVirtualDeviceLock) {
+ if (mActivityPolicyExemptions.remove(componentName)) {
+ for (int i = 0; i < mVirtualDisplays.size(); i++) {
+ mVirtualDisplays.valueAt(i).getWindowPolicyController()
+ .removeActivityPolicyExemption(componentName);
+ }
+ }
+ }
+ }
+
private void sendPendingIntent(int displayId, PendingIntent pendingIntent)
throws PendingIntent.CanceledException {
final ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(displayId);
@@ -543,6 +587,16 @@
}
}
break;
+ case POLICY_TYPE_ACTIVITY:
+ synchronized (mVirtualDeviceLock) {
+ mDevicePolicies.put(policyType, devicePolicy);
+ for (int i = 0; i < mVirtualDisplays.size(); i++) {
+ mVirtualDisplays.valueAt(i).getWindowPolicyController()
+ .setActivityLaunchDefaultAllowed(
+ devicePolicy == DEVICE_POLICY_DEFAULT);
+ }
+ }
+ break;
default:
throw new IllegalArgumentException("Device policy " + policyType
+ " cannot be changed at runtime. ");
@@ -840,24 +894,26 @@
mSensorController.dump(fout);
}
- private GenericWindowPolicyController createWindowPolicyController(
+ @GuardedBy("mVirtualDeviceLock")
+ private GenericWindowPolicyController createWindowPolicyControllerLocked(
@NonNull Set<String> displayCategories) {
final boolean activityLaunchAllowedByDefault =
- mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED;
+ Flags.dynamicPolicy()
+ ? getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT
+ : mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED;
final boolean crossTaskNavigationAllowedByDefault =
mParams.getDefaultNavigationPolicy() == NAVIGATION_POLICY_DEFAULT_ALLOWED;
final boolean showTasksInHostDeviceRecents =
- mParams.getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
+ getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
FLAG_SECURE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
getAllowedUserHandles(),
activityLaunchAllowedByDefault,
- /*activityPolicyExceptions=*/activityLaunchAllowedByDefault
- ? mParams.getBlockedActivities() : mParams.getAllowedActivities(),
+ mActivityPolicyExemptions,
crossTaskNavigationAllowedByDefault,
- /*crossTaskNavigationExceptions=*/crossTaskNavigationAllowedByDefault
+ /*crossTaskNavigationExemptions=*/crossTaskNavigationAllowedByDefault
? mParams.getBlockedCrossTaskNavigations()
: mParams.getAllowedCrossTaskNavigations(),
createListenerAdapter(),
@@ -873,8 +929,10 @@
int createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
@NonNull IVirtualDisplayCallback callback, String packageName) {
- GenericWindowPolicyController gwpc = createWindowPolicyController(
- virtualDisplayConfig.getDisplayCategories());
+ GenericWindowPolicyController gwpc;
+ synchronized (mVirtualDeviceLock) {
+ gwpc = createWindowPolicyControllerLocked(virtualDisplayConfig.getDisplayCategories());
+ }
DisplayManagerInternal displayManager = LocalServices.getService(
DisplayManagerInternal.class);
int displayId;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 7329f1a..b941aaf 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -180,7 +180,6 @@
"android.hardware.rebootescrow-V1-java",
"android.hardware.power.stats-V2-java",
"android.hidl.manager-V1.2-java",
- "com.android.server.security.flags-aconfig-java",
"cbor-java",
"display_flags_lib",
"icu4j_calendar_astronomer",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0d265a0..b5911f6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9543,6 +9543,14 @@
}
} else {
worker.start();
+ if (process != null && process.mPid == MY_PID && "crash".equals(eventType)) {
+ // We're actually crashing, let's wait for up to 2 seconds before killing ourselves,
+ // so the data could be persisted into the dropbox.
+ try {
+ worker.join(2000);
+ } catch (InterruptedException ignored) {
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index d3176ee4..87077a6 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2823,9 +2823,7 @@
}
}
- if (schedGroup < SCHED_GROUP_TOP_APP
- && cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP)
- && clientIsSystem) {
+ if (cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP) && clientIsSystem) {
schedGroup = SCHED_GROUP_TOP_APP;
state.setScheduleLikeTopApp(true);
}
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
index fdf607d..64691e0 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
@@ -53,6 +53,9 @@
static final int MAXIMUM_ENROLLMENT_NOTIFICATIONS = 1;
@NonNull private final Context mContext;
+ @NonNull private final PackageManager mPackageManager;
+ @NonNull private final FaceManager mFaceManager;
+ @NonNull private final FingerprintManager mFingerprintManager;
private final float mThreshold;
private final int mModality;
@@ -86,6 +89,10 @@
mModality = modality;
mBiometricNotification = biometricNotification;
+ mPackageManager = context.getPackageManager();
+ mFaceManager = mContext.getSystemService(FaceManager.class);
+ mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
context.registerReceiver(mBroadcastReceiver, intentFilter);
@@ -108,6 +115,13 @@
/** Update total authentication and rejected attempts. */
public void authenticate(int userId, boolean authenticated) {
+
+ // Don't collect data for single-modality devices or user has both biometrics enrolled.
+ if (isSingleModalityDevice()
+ || (hasEnrolledFace(userId) && hasEnrolledFingerprint(userId))) {
+ return;
+ }
+
// SharedPreference is not ready when starting system server, initialize
// mUserAuthenticationStatsMap in authentication to ensure SharedPreference
// is ready for application use.
@@ -150,25 +164,9 @@
authenticationStats.resetData();
- final PackageManager packageManager = mContext.getPackageManager();
+ final boolean hasEnrolledFace = hasEnrolledFace(userId);
+ final boolean hasEnrolledFingerprint = hasEnrolledFingerprint(userId);
- // Don't send notification to single-modality devices.
- if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
- || !packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
- return;
- }
-
- final FaceManager faceManager = mContext.getSystemService(FaceManager.class);
- final boolean hasEnrolledFace = faceManager.hasEnrolledTemplates(userId);
-
- final FingerprintManager fingerprintManager = mContext
- .getSystemService(FingerprintManager.class);
- final boolean hasEnrolledFingerprint = fingerprintManager.hasEnrolledTemplates(userId);
-
- // Don't send notification when both face and fingerprint are enrolled.
- if (hasEnrolledFace && hasEnrolledFingerprint) {
- return;
- }
if (hasEnrolledFace && !hasEnrolledFingerprint) {
mBiometricNotification.sendFpEnrollNotification(mContext);
authenticationStats.updateNotificationCounter();
@@ -199,6 +197,19 @@
}
}
+ private boolean isSingleModalityDevice() {
+ return !mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
+ || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE);
+ }
+
+ private boolean hasEnrolledFace(int userId) {
+ return mFaceManager.hasEnrolledTemplates(userId);
+ }
+
+ private boolean hasEnrolledFingerprint(int userId) {
+ return mFingerprintManager.hasEnrolledTemplates(userId);
+ }
+
/**
* Only being used in tests. Callers should not make any changes to the returned
* authentication stats.
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
index f1c74f0..2aec9ae 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
@@ -176,6 +176,7 @@
.setSmallIcon(R.drawable.ic_lock)
.setContentTitle(title)
.setContentText(content)
+ .setStyle(new Notification.BigTextStyle().bigText(content))
.setSubText(name)
.setOnlyAlertOnce(true)
.setLocalOnly(true)
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
index adea13f..d4232ab 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
@@ -29,7 +29,6 @@
import android.hardware.broadcastradio.ProgramFilter;
import android.hardware.broadcastradio.ProgramIdentifier;
import android.hardware.broadcastradio.ProgramInfo;
-import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.broadcastradio.Properties;
import android.hardware.broadcastradio.Result;
import android.hardware.broadcastradio.VendorKeyValue;
@@ -38,6 +37,7 @@
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioMetadata;
import android.hardware.radio.RadioTuner;
+import android.hardware.radio.UniqueProgramIdentifier;
import android.os.Build;
import android.os.ParcelableException;
import android.os.ServiceSpecificException;
@@ -553,31 +553,6 @@
return hwFilter;
}
- static ProgramList.Chunk chunkFromHalProgramListChunk(ProgramListChunk chunk) {
- Set<RadioManager.ProgramInfo> modified = new ArraySet<>(chunk.modified.length);
- for (int i = 0; i < chunk.modified.length; i++) {
- RadioManager.ProgramInfo modifiedInfo =
- programInfoFromHalProgramInfo(chunk.modified[i]);
- if (modifiedInfo == null) {
- Slogf.w(TAG, "Program info %s in program list chunk is not valid",
- chunk.modified[i]);
- continue;
- }
- modified.add(modifiedInfo);
- }
- Set<ProgramSelector.Identifier> removed = new ArraySet<>();
- if (chunk.removed != null) {
- for (int i = 0; i < chunk.removed.length; i++) {
- ProgramSelector.Identifier removedId =
- identifierFromHalProgramIdentifier(chunk.removed[i]);
- if (removedId != null) {
- removed.add(removedId);
- }
- }
- }
- return new ProgramList.Chunk(chunk.purge, chunk.complete, modified, removed);
- }
-
private static boolean isNewIdentifierInU(ProgramSelector.Identifier id) {
return id.getType() == ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT;
}
@@ -630,11 +605,11 @@
modified.add(info);
}
}
- Set<ProgramSelector.Identifier> removed = new ArraySet<>();
- Iterator<ProgramSelector.Identifier> removedIterator = chunk.getRemoved().iterator();
+ Set<UniqueProgramIdentifier> removed = new ArraySet<>();
+ Iterator<UniqueProgramIdentifier> removedIterator = chunk.getRemoved().iterator();
while (removedIterator.hasNext()) {
- ProgramSelector.Identifier id = removedIterator.next();
- if (!isNewIdentifierInU(id)) {
+ UniqueProgramIdentifier id = removedIterator.next();
+ if (!isNewIdentifierInU(id.getPrimaryId())) {
removed.add(id);
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/ProgramInfoCache.java b/services/core/java/com/android/server/broadcastradio/aidl/ProgramInfoCache.java
index c9ae735..756dbbb 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/ProgramInfoCache.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/ProgramInfoCache.java
@@ -17,9 +17,11 @@
package com.android.server.broadcastradio.aidl;
import android.annotation.Nullable;
+import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.radio.ProgramList;
-import android.hardware.radio.ProgramSelector;
+import android.hardware.radio.ProgramSelector.Identifier;
import android.hardware.radio.RadioManager;
+import android.hardware.radio.UniqueProgramIdentifier;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -30,7 +32,6 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
@@ -40,24 +41,25 @@
private static final String TAG = "BcRadioAidlSrv.cache";
/**
- * Maximum number of {@link RadioManager#ProgramInfo} elements that will be put into a
+ * Maximum number of {@link RadioManager.ProgramInfo} elements that will be put into a
* ProgramList.Chunk.mModified array. Used to try to ensure a single ProgramList.Chunk
* stays within the AIDL data size limit.
*/
private static final int MAX_NUM_MODIFIED_PER_CHUNK = 100;
/**
- * Maximum number of {@link ProgramSelector#Identifier} elements that will be put
- * into the removed array of {@link ProgramList#Chunk}. Used to try to ensure a single
- * {@link ProgramList#Chunk} stays within the AIDL data size limit.
+ * Maximum number of {@link Identifier} elements that will be put into the removed array
+ * of {@link ProgramList.Chunk}. Use to attempt and keep the single {@link ProgramList.Chunk}
+ * within the AIDL data size limit.
*/
private static final int MAX_NUM_REMOVED_PER_CHUNK = 500;
/**
- * Map from primary identifier to corresponding {@link RadioManager#ProgramInfo}.
+ * Map from primary identifier to {@link UniqueProgramIdentifier} and then to corresponding
+ * {@link RadioManager.ProgramInfo}.
*/
- private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mProgramInfoMap =
- new ArrayMap<>();
+ private final ArrayMap<Identifier, ArrayMap<UniqueProgramIdentifier, RadioManager.ProgramInfo>>
+ mProgramInfoMap = new ArrayMap<>();
/**
* Flag indicating whether mProgramInfoMap is considered complete based upon the received
@@ -81,13 +83,17 @@
mFilter = filter;
mComplete = complete;
for (int i = 0; i < programInfos.length; i++) {
- mProgramInfoMap.put(programInfos[i].getSelector().getPrimaryId(), programInfos[i]);
+ putInfo(programInfos[i]);
}
}
@VisibleForTesting
List<RadioManager.ProgramInfo> toProgramInfoList() {
- return new ArrayList<>(mProgramInfoMap.values());
+ List<RadioManager.ProgramInfo> programInfoList = new ArrayList<>();
+ for (int index = 0; index < mProgramInfoMap.size(); index++) {
+ programInfoList.addAll(mProgramInfoMap.valueAt(index).values());
+ }
+ return programInfoList;
}
@Override
@@ -97,10 +103,14 @@
sb.append(", mFilter = ");
sb.append(mFilter);
sb.append(", mProgramInfoMap = [");
- mProgramInfoMap.forEach((id, programInfo) -> {
- sb.append(", ");
- sb.append(programInfo);
- });
+ for (int index = 0; index < mProgramInfoMap.size(); index++) {
+ ArrayMap<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries =
+ mProgramInfoMap.valueAt(index);
+ for (int entryIndex = 0; entryIndex < entries.size(); entryIndex++) {
+ sb.append(", ");
+ sb.append(entries.valueAt(entryIndex));
+ }
+ }
return sb.append("])").toString();
}
@@ -114,8 +124,7 @@
}
@VisibleForTesting
- void updateFromHalProgramListChunk(
- android.hardware.broadcastradio.ProgramListChunk chunk) {
+ void updateFromHalProgramListChunk(ProgramListChunk chunk) {
if (chunk.purge) {
mProgramInfoMap.clear();
}
@@ -125,8 +134,9 @@
if (programInfo == null) {
Slogf.e(TAG, "Program info in program info %s in chunk is not valid",
chunk.modified[i]);
+ continue;
}
- mProgramInfoMap.put(programInfo.getSelector().getPrimaryId(), programInfo);
+ putInfo(programInfo);
}
if (chunk.removed != null) {
for (int i = 0; i < chunk.removed.length; i++) {
@@ -155,25 +165,31 @@
purge = true;
}
- Set<RadioManager.ProgramInfo> modified = new ArraySet<>();
- Set<ProgramSelector.Identifier> removed = new ArraySet<>(mProgramInfoMap.keySet());
- for (Map.Entry<ProgramSelector.Identifier, RadioManager.ProgramInfo> entry
- : other.mProgramInfoMap.entrySet()) {
- ProgramSelector.Identifier id = entry.getKey();
+ ArraySet<RadioManager.ProgramInfo> modified = new ArraySet<>();
+ ArraySet<UniqueProgramIdentifier> removed = new ArraySet<>();
+ for (int index = 0; index < mProgramInfoMap.size(); index++) {
+ removed.addAll(mProgramInfoMap.valueAt(index).keySet());
+ }
+ for (int index = 0; index < other.mProgramInfoMap.size(); index++) {
+ Identifier id = other.mProgramInfoMap.keyAt(index);
if (!passesFilter(id)) {
continue;
}
- removed.remove(id);
+ ArrayMap<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries =
+ other.mProgramInfoMap.valueAt(index);
+ for (int entryIndex = 0; entryIndex < entries.size(); entryIndex++) {
+ removed.remove(entries.keyAt(entryIndex));
- RadioManager.ProgramInfo newInfo = entry.getValue();
- if (!shouldIncludeInModified(newInfo)) {
- continue;
+ RadioManager.ProgramInfo newInfo = entries.valueAt(entryIndex);
+ if (!shouldIncludeInModified(newInfo)) {
+ continue;
+ }
+ putInfo(newInfo);
+ modified.add(newInfo);
}
- mProgramInfoMap.put(id, newInfo);
- modified.add(newInfo);
}
- for (ProgramSelector.Identifier rem : removed) {
- mProgramInfoMap.remove(rem);
+ for (int removedIndex = 0; removedIndex < removed.size(); removedIndex++) {
+ removeUniqueId(removed.valueAt(removedIndex));
}
mComplete = other.mComplete;
return buildChunks(purge, mComplete, modified, maxNumModifiedPerChunk, removed,
@@ -181,45 +197,61 @@
}
@Nullable
- List<ProgramList.Chunk> filterAndApplyChunk(ProgramList.Chunk chunk) {
+ List<ProgramList.Chunk> filterAndApplyChunk(ProgramListChunk chunk) {
return filterAndApplyChunkInternal(chunk, MAX_NUM_MODIFIED_PER_CHUNK,
MAX_NUM_REMOVED_PER_CHUNK);
}
@VisibleForTesting
@Nullable
- List<ProgramList.Chunk> filterAndApplyChunkInternal(ProgramList.Chunk chunk,
+ List<ProgramList.Chunk> filterAndApplyChunkInternal(ProgramListChunk chunk,
int maxNumModifiedPerChunk, int maxNumRemovedPerChunk) {
- if (chunk.isPurge()) {
+ if (chunk.purge) {
mProgramInfoMap.clear();
}
Set<RadioManager.ProgramInfo> modified = new ArraySet<>();
- Set<ProgramSelector.Identifier> removed = new ArraySet<>();
- for (RadioManager.ProgramInfo info : chunk.getModified()) {
- ProgramSelector.Identifier id = info.getSelector().getPrimaryId();
- if (!passesFilter(id) || !shouldIncludeInModified(info)) {
+ for (int i = 0; i < chunk.modified.length; i++) {
+ RadioManager.ProgramInfo info =
+ ConversionUtils.programInfoFromHalProgramInfo(chunk.modified[i]);
+ if (info == null) {
+ Slogf.w(TAG, "Program info %s in program list chunk is not valid",
+ chunk.modified[i]);
continue;
}
- mProgramInfoMap.put(id, info);
+ Identifier primaryId = info.getSelector().getPrimaryId();
+ if (!passesFilter(primaryId) || !shouldIncludeInModified(info)) {
+ continue;
+ }
+ putInfo(info);
modified.add(info);
}
- for (ProgramSelector.Identifier id : chunk.getRemoved()) {
- if (mProgramInfoMap.containsKey(id)) {
- mProgramInfoMap.remove(id);
- removed.add(id);
+ Set<UniqueProgramIdentifier> removed = new ArraySet<>();
+ if (chunk.removed != null) {
+ for (int i = 0; i < chunk.removed.length; i++) {
+ Identifier removedId = ConversionUtils.identifierFromHalProgramIdentifier(
+ chunk.removed[i]);
+ if (removedId == null) {
+ Slogf.w(TAG, "Removed identifier %s in program list chunk is not valid",
+ chunk.modified[i]);
+ continue;
+ }
+ if (mProgramInfoMap.containsKey(removedId)) {
+ removed.addAll(mProgramInfoMap.get(removedId).keySet());
+ mProgramInfoMap.remove(removedId);
+ }
}
}
- if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.isComplete()
- && !chunk.isPurge()) {
+ if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.complete
+ && !chunk.purge) {
return null;
}
- mComplete = chunk.isComplete();
- return buildChunks(chunk.isPurge(), mComplete, modified, maxNumModifiedPerChunk, removed,
+ mComplete = chunk.complete;
+ return buildChunks(chunk.purge, mComplete, modified, maxNumModifiedPerChunk, removed,
maxNumRemovedPerChunk);
}
- private boolean passesFilter(ProgramSelector.Identifier id) {
+ private boolean passesFilter(Identifier id) {
if (mFilter == null) {
return true;
}
@@ -233,9 +265,32 @@
return mFilter.areCategoriesIncluded() || !id.isCategoryType();
}
+ private void putInfo(RadioManager.ProgramInfo info) {
+ Identifier primaryId = info.getSelector().getPrimaryId();
+ if (!mProgramInfoMap.containsKey(primaryId)) {
+ mProgramInfoMap.put(primaryId, new ArrayMap<>());
+ }
+ mProgramInfoMap.get(primaryId).put(new UniqueProgramIdentifier(info.getSelector()), info);
+ }
+
+ private void removeUniqueId(UniqueProgramIdentifier uniqueId) {
+ Identifier primaryId = uniqueId.getPrimaryId();
+ if (!mProgramInfoMap.containsKey(primaryId)) {
+ return;
+ }
+ mProgramInfoMap.get(primaryId).remove(uniqueId);
+ if (mProgramInfoMap.get(primaryId).isEmpty()) {
+ mProgramInfoMap.remove(primaryId);
+ }
+ }
+
private boolean shouldIncludeInModified(RadioManager.ProgramInfo newInfo) {
- RadioManager.ProgramInfo oldInfo = mProgramInfoMap.get(
- newInfo.getSelector().getPrimaryId());
+ Identifier primaryId = newInfo.getSelector().getPrimaryId();
+ RadioManager.ProgramInfo oldInfo = null;
+ if (mProgramInfoMap.containsKey(primaryId)) {
+ UniqueProgramIdentifier uniqueId = new UniqueProgramIdentifier(newInfo.getSelector());
+ oldInfo = mProgramInfoMap.get(primaryId).get(uniqueId);
+ }
if (oldInfo == null) {
return true;
}
@@ -251,7 +306,7 @@
private static List<ProgramList.Chunk> buildChunks(boolean purge, boolean complete,
@Nullable Collection<RadioManager.ProgramInfo> modified, int maxNumModifiedPerChunk,
- @Nullable Collection<ProgramSelector.Identifier> removed, int maxNumRemovedPerChunk) {
+ @Nullable Collection<UniqueProgramIdentifier> removed, int maxNumRemovedPerChunk) {
// Communication protocol requires that if purge is set, removed is empty.
if (purge) {
removed = null;
@@ -275,7 +330,7 @@
int modifiedPerChunk = 0;
int removedPerChunk = 0;
Iterator<RadioManager.ProgramInfo> modifiedIter = null;
- Iterator<ProgramSelector.Identifier> removedIter = null;
+ Iterator<UniqueProgramIdentifier> removedIter = null;
if (modified != null) {
modifiedPerChunk = roundUpFraction(modified.size(), numChunks);
modifiedIter = modified.iterator();
@@ -287,7 +342,7 @@
List<ProgramList.Chunk> chunks = new ArrayList<>(numChunks);
for (int i = 0; i < numChunks; i++) {
ArraySet<RadioManager.ProgramInfo> modifiedChunk = new ArraySet<>();
- ArraySet<ProgramSelector.Identifier> removedChunk = new ArraySet<>();
+ ArraySet<UniqueProgramIdentifier> removedChunk = new ArraySet<>();
if (modifiedIter != null) {
for (int j = 0; j < modifiedPerChunk && modifiedIter.hasNext(); j++) {
modifiedChunk.add(modifiedIter.next());
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
index 7c87c6c..2ae7f95 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
@@ -142,12 +142,11 @@
public void onProgramListUpdated(ProgramListChunk programListChunk) {
fireLater(() -> {
synchronized (mLock) {
- android.hardware.radio.ProgramList.Chunk chunk =
- ConversionUtils.chunkFromHalProgramListChunk(programListChunk);
- mProgramInfoCache.filterAndApplyChunk(chunk);
+ mProgramInfoCache.filterAndApplyChunk(programListChunk);
for (int i = 0; i < mAidlTunerSessions.size(); i++) {
- mAidlTunerSessions.valueAt(i).onMergedProgramListUpdateFromHal(chunk);
+ mAidlTunerSessions.valueAt(i).onMergedProgramListUpdateFromHal(
+ programListChunk);
}
}
});
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
index beff7bd..4ed36ec 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
@@ -20,6 +20,7 @@
import android.graphics.Bitmap;
import android.hardware.broadcastradio.ConfigFlag;
import android.hardware.broadcastradio.IBroadcastRadio;
+import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.radio.ITuner;
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
@@ -297,7 +298,7 @@
}
}
- void onMergedProgramListUpdateFromHal(ProgramList.Chunk mergedChunk) {
+ void onMergedProgramListUpdateFromHal(ProgramListChunk mergedChunk) {
List<ProgramList.Chunk> clientUpdateChunks;
synchronized (mLock) {
if (mProgramInfoCache == null) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index e6908b1..fb1138f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -28,7 +28,6 @@
import android.hardware.broadcastradio.V2_0.ProgramFilter;
import android.hardware.broadcastradio.V2_0.ProgramIdentifier;
import android.hardware.broadcastradio.V2_0.ProgramInfo;
-import android.hardware.broadcastradio.V2_0.ProgramListChunk;
import android.hardware.broadcastradio.V2_0.Properties;
import android.hardware.broadcastradio.V2_0.Result;
import android.hardware.broadcastradio.V2_0.VendorKeyValue;
@@ -425,16 +424,6 @@
return hwFilter;
}
- static @NonNull ProgramList.Chunk programListChunkFromHal(@NonNull ProgramListChunk chunk) {
- Set<RadioManager.ProgramInfo> modified = chunk.modified.stream().
- map(info -> programInfoFromHal(info)).collect(Collectors.toSet());
- Set<ProgramSelector.Identifier> removed = chunk.removed.stream().
- map(id -> Objects.requireNonNull(programIdentifierFromHal(id))).
- collect(Collectors.toSet());
-
- return new ProgramList.Chunk(chunk.purge, chunk.complete, modified, removed);
- }
-
public static @NonNull android.hardware.radio.Announcement announcementFromHal(
@NonNull Announcement hwAnnouncement) {
return new android.hardware.radio.Announcement(
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
index 9831af6..111953d 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
@@ -16,21 +16,21 @@
package com.android.server.broadcastradio.hal2;
-import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.broadcastradio.V2_0.ProgramListChunk;
import android.hardware.radio.ProgramList;
-import android.hardware.radio.ProgramSelector;
+import android.hardware.radio.ProgramSelector.Identifier;
import android.hardware.radio.RadioManager;
+import android.hardware.radio.UniqueProgramIdentifier;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
final class ProgramInfoCache {
@@ -40,13 +40,14 @@
private static final int MAX_NUM_MODIFIED_PER_CHUNK = 100;
// Maximum number of ProgramSelector.Identifier elements that will be put into a
- // ProgramList.Chunk.mRemoved array. Used to try to ensure a single ProgramList.Chunk stays
+ // ProgramList.Chunk.mRemoved array. Use to attempt and keep the single ProgramList.Chunk
// within the AIDL data size limit.
private static final int MAX_NUM_REMOVED_PER_CHUNK = 500;
- // Map from primary identifier to corresponding ProgramInfo.
- private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mProgramInfoMap =
- new HashMap<>();
+ // Map from primary identifier to a map of unique identifiers and program info, where the
+ // containing map has unique identifiers to program info.
+ private final ArrayMap<Identifier, ArrayMap<UniqueProgramIdentifier, RadioManager.ProgramInfo>>
+ mProgramInfoMap = new ArrayMap<>();
// Flag indicating whether mProgramInfoMap is considered complete based upon the received
// updates.
@@ -66,18 +67,18 @@
RadioManager.ProgramInfo... programInfos) {
mFilter = filter;
mComplete = complete;
- for (RadioManager.ProgramInfo programInfo : programInfos) {
- mProgramInfoMap.put(programInfo.getSelector().getPrimaryId(), programInfo);
+ for (int i = 0; i < programInfos.length; i++) {
+ putInfo(programInfos[i]);
}
}
@VisibleForTesting
- boolean programInfosAreExactly(RadioManager.ProgramInfo... programInfos) {
- Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> expectedMap = new HashMap<>();
- for (RadioManager.ProgramInfo programInfo : programInfos) {
- expectedMap.put(programInfo.getSelector().getPrimaryId(), programInfo);
+ List<RadioManager.ProgramInfo> toProgramInfoList() {
+ List<RadioManager.ProgramInfo> programInfoList = new ArrayList<>();
+ for (int index = 0; index < mProgramInfoMap.size(); index++) {
+ programInfoList.addAll(mProgramInfoMap.valueAt(index).values());
}
- return expectedMap.equals(mProgramInfoMap);
+ return programInfoList;
}
@Override
@@ -87,10 +88,14 @@
sb.append(", mFilter = ");
sb.append(mFilter);
sb.append(", mProgramInfoMap = [");
- mProgramInfoMap.forEach((id, programInfo) -> {
- sb.append("\n");
- sb.append(programInfo.toString());
- });
+ for (int index = 0; index < mProgramInfoMap.size(); index++) {
+ ArrayMap<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries =
+ mProgramInfoMap.valueAt(index);
+ for (int entryIndex = 0; entryIndex < entries.size(); entryIndex++) {
+ sb.append(", ");
+ sb.append(entries.valueAt(entryIndex));
+ }
+ }
sb.append("]");
return sb.toString();
}
@@ -103,14 +108,13 @@
return mFilter;
}
- void updateFromHalProgramListChunk(
- @NonNull android.hardware.broadcastradio.V2_0.ProgramListChunk chunk) {
+ void updateFromHalProgramListChunk(ProgramListChunk chunk) {
if (chunk.purge) {
mProgramInfoMap.clear();
}
for (android.hardware.broadcastradio.V2_0.ProgramInfo halProgramInfo : chunk.modified) {
RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo);
- mProgramInfoMap.put(programInfo.getSelector().getPrimaryId(), programInfo);
+ putInfo(programInfo);
}
for (android.hardware.broadcastradio.V2_0.ProgramIdentifier halProgramId : chunk.removed) {
mProgramInfoMap.remove(Convert.programIdentifierFromHal(halProgramId));
@@ -118,14 +122,13 @@
mComplete = chunk.complete;
}
- @NonNull List<ProgramList.Chunk> filterAndUpdateFrom(@NonNull ProgramInfoCache other,
- boolean purge) {
+ List<ProgramList.Chunk> filterAndUpdateFrom(ProgramInfoCache other, boolean purge) {
return filterAndUpdateFromInternal(other, purge, MAX_NUM_MODIFIED_PER_CHUNK,
MAX_NUM_REMOVED_PER_CHUNK);
}
@VisibleForTesting
- @NonNull List<ProgramList.Chunk> filterAndUpdateFromInternal(@NonNull ProgramInfoCache other,
+ List<ProgramList.Chunk> filterAndUpdateFromInternal(ProgramInfoCache other,
boolean purge, int maxNumModifiedPerChunk, int maxNumRemovedPerChunk) {
if (purge) {
mProgramInfoMap.clear();
@@ -136,69 +139,82 @@
purge = true;
}
- Set<RadioManager.ProgramInfo> modified = new HashSet<>();
- Set<ProgramSelector.Identifier> removed = new HashSet<>(mProgramInfoMap.keySet());
- for (Map.Entry<ProgramSelector.Identifier, RadioManager.ProgramInfo> entry
- : other.mProgramInfoMap.entrySet()) {
- ProgramSelector.Identifier id = entry.getKey();
+ ArraySet<RadioManager.ProgramInfo> modified = new ArraySet<>();
+ ArraySet<UniqueProgramIdentifier> removed = new ArraySet<>();
+ for (int index = 0; index < mProgramInfoMap.size(); index++) {
+ removed.addAll(mProgramInfoMap.valueAt(index).keySet());
+ }
+ for (int index = 0; index < other.mProgramInfoMap.size(); index++) {
+ Identifier id = other.mProgramInfoMap.keyAt(index);
if (!passesFilter(id)) {
continue;
}
- removed.remove(id);
+ ArrayMap<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries =
+ other.mProgramInfoMap.valueAt(index);
+ for (int entryIndex = 0; entryIndex < entries.size(); entryIndex++) {
+ removed.remove(entries.keyAt(entryIndex));
- RadioManager.ProgramInfo newInfo = entry.getValue();
- if (!shouldIncludeInModified(newInfo)) {
- continue;
+ RadioManager.ProgramInfo newInfo = entries.valueAt(entryIndex);
+ if (!shouldIncludeInModified(newInfo)) {
+ continue;
+ }
+ putInfo(newInfo);
+ modified.add(newInfo);
}
- mProgramInfoMap.put(id, newInfo);
- modified.add(newInfo);
}
- for (ProgramSelector.Identifier rem : removed) {
- mProgramInfoMap.remove(rem);
+ for (int removedIndex = 0; removedIndex < removed.size(); removedIndex++) {
+ removeUniqueId(removed.valueAt(removedIndex));
}
mComplete = other.mComplete;
return buildChunks(purge, mComplete, modified, maxNumModifiedPerChunk, removed,
maxNumRemovedPerChunk);
}
- @Nullable List<ProgramList.Chunk> filterAndApplyChunk(@NonNull ProgramList.Chunk chunk) {
+ @Nullable
+ List<ProgramList.Chunk> filterAndApplyChunk(ProgramListChunk chunk) {
return filterAndApplyChunkInternal(chunk, MAX_NUM_MODIFIED_PER_CHUNK,
MAX_NUM_REMOVED_PER_CHUNK);
}
@VisibleForTesting
- @Nullable List<ProgramList.Chunk> filterAndApplyChunkInternal(@NonNull ProgramList.Chunk chunk,
+ @Nullable
+ List<ProgramList.Chunk> filterAndApplyChunkInternal(ProgramListChunk chunk,
int maxNumModifiedPerChunk, int maxNumRemovedPerChunk) {
- if (chunk.isPurge()) {
+ if (chunk.purge) {
mProgramInfoMap.clear();
}
- Set<RadioManager.ProgramInfo> modified = new HashSet<>();
- Set<ProgramSelector.Identifier> removed = new HashSet<>();
- for (RadioManager.ProgramInfo info : chunk.getModified()) {
- ProgramSelector.Identifier id = info.getSelector().getPrimaryId();
- if (!passesFilter(id) || !shouldIncludeInModified(info)) {
+ Set<RadioManager.ProgramInfo> modified = new ArraySet<>();
+ for (android.hardware.broadcastradio.V2_0.ProgramInfo halProgramInfo : chunk.modified) {
+ RadioManager.ProgramInfo info = Convert.programInfoFromHal(halProgramInfo);
+ Identifier primaryId = info.getSelector().getPrimaryId();
+ if (!passesFilter(primaryId) || !shouldIncludeInModified(info)) {
continue;
}
- mProgramInfoMap.put(id, info);
+ putInfo(info);
modified.add(info);
}
- for (ProgramSelector.Identifier id : chunk.getRemoved()) {
- if (mProgramInfoMap.containsKey(id)) {
- mProgramInfoMap.remove(id);
- removed.add(id);
+ Set<UniqueProgramIdentifier> removed = new ArraySet<>();
+ for (android.hardware.broadcastradio.V2_0.ProgramIdentifier halProgramId : chunk.removed) {
+ Identifier removedId = Convert.programIdentifierFromHal(halProgramId);
+ if (removedId == null) {
+ continue;
+ }
+ if (mProgramInfoMap.containsKey(removedId)) {
+ removed.addAll(mProgramInfoMap.get(removedId).keySet());
+ mProgramInfoMap.remove(removedId);
}
}
- if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.isComplete()
- && !chunk.isPurge()) {
+ if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.complete
+ && !chunk.purge) {
return null;
}
- mComplete = chunk.isComplete();
- return buildChunks(chunk.isPurge(), mComplete, modified, maxNumModifiedPerChunk, removed,
+ mComplete = chunk.complete;
+ return buildChunks(chunk.purge, mComplete, modified, maxNumModifiedPerChunk, removed,
maxNumRemovedPerChunk);
}
- private boolean passesFilter(ProgramSelector.Identifier id) {
+ private boolean passesFilter(Identifier id) {
if (mFilter == null) {
return true;
}
@@ -215,9 +231,33 @@
return true;
}
+ private void putInfo(RadioManager.ProgramInfo info) {
+ Identifier primaryId = info.getSelector().getPrimaryId();
+ if (!mProgramInfoMap.containsKey(primaryId)) {
+ mProgramInfoMap.put(primaryId, new ArrayMap<>());
+ }
+ mProgramInfoMap.get(primaryId).put(new UniqueProgramIdentifier(
+ info.getSelector()), info);
+ }
+
+ private void removeUniqueId(UniqueProgramIdentifier uniqueId) {
+ Identifier primaryId = uniqueId.getPrimaryId();
+ if (!mProgramInfoMap.containsKey(primaryId)) {
+ return;
+ }
+ mProgramInfoMap.get(primaryId).remove(uniqueId);
+ if (mProgramInfoMap.get(primaryId).isEmpty()) {
+ mProgramInfoMap.remove(primaryId);
+ }
+ }
+
private boolean shouldIncludeInModified(RadioManager.ProgramInfo newInfo) {
- RadioManager.ProgramInfo oldInfo = mProgramInfoMap.get(
- newInfo.getSelector().getPrimaryId());
+ Identifier primaryId = newInfo.getSelector().getPrimaryId();
+ RadioManager.ProgramInfo oldInfo = null;
+ if (mProgramInfoMap.containsKey(primaryId)) {
+ UniqueProgramIdentifier uniqueId = new UniqueProgramIdentifier(newInfo.getSelector());
+ oldInfo = mProgramInfoMap.get(primaryId).get(uniqueId);
+ }
if (oldInfo == null) {
return true;
}
@@ -231,9 +271,9 @@
return (numerator / denominator) + (numerator % denominator > 0 ? 1 : 0);
}
- private static @NonNull List<ProgramList.Chunk> buildChunks(boolean purge, boolean complete,
+ private static List<ProgramList.Chunk> buildChunks(boolean purge, boolean complete,
@Nullable Collection<RadioManager.ProgramInfo> modified, int maxNumModifiedPerChunk,
- @Nullable Collection<ProgramSelector.Identifier> removed, int maxNumRemovedPerChunk) {
+ @Nullable Collection<UniqueProgramIdentifier> removed, int maxNumRemovedPerChunk) {
// Communication protocol requires that if purge is set, removed is empty.
if (purge) {
removed = null;
@@ -257,7 +297,7 @@
int modifiedPerChunk = 0;
int removedPerChunk = 0;
Iterator<RadioManager.ProgramInfo> modifiedIter = null;
- Iterator<ProgramSelector.Identifier> removedIter = null;
+ Iterator<UniqueProgramIdentifier> removedIter = null;
if (modified != null) {
modifiedPerChunk = roundUpFraction(modified.size(), numChunks);
modifiedIter = modified.iterator();
@@ -268,8 +308,8 @@
}
List<ProgramList.Chunk> chunks = new ArrayList<ProgramList.Chunk>(numChunks);
for (int i = 0; i < numChunks; i++) {
- HashSet<RadioManager.ProgramInfo> modifiedChunk = new HashSet<>();
- HashSet<ProgramSelector.Identifier> removedChunk = new HashSet<>();
+ ArraySet<RadioManager.ProgramInfo> modifiedChunk = new ArraySet<>();
+ ArraySet<UniqueProgramIdentifier> removedChunk = new ArraySet<>();
if (modifiedIter != null) {
for (int j = 0; j < modifiedPerChunk && modifiedIter.hasNext(); j++) {
modifiedChunk.add(modifiedIter.next());
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 7b5cb898..a54af2e 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -111,13 +111,11 @@
@Override
public void onProgramListUpdated(ProgramListChunk programListChunk) {
fireLater(() -> {
- android.hardware.radio.ProgramList.Chunk chunk =
- Convert.programListChunkFromHal(programListChunk);
synchronized (mLock) {
- mProgramInfoCache.filterAndApplyChunk(chunk);
+ mProgramInfoCache.filterAndApplyChunk(programListChunk);
for (TunerSession tunerSession : mAidlTunerSessions) {
- tunerSession.onMergedProgramListUpdateFromHal(chunk);
+ tunerSession.onMergedProgramListUpdateFromHal(programListChunk);
}
}
});
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 1efc4a5..978dc01 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -21,6 +21,7 @@
import android.graphics.Bitmap;
import android.hardware.broadcastradio.V2_0.ConfigFlag;
import android.hardware.broadcastradio.V2_0.ITunerSession;
+import android.hardware.broadcastradio.V2_0.ProgramListChunk;
import android.hardware.broadcastradio.V2_0.Result;
import android.hardware.radio.ITuner;
import android.hardware.radio.ProgramList;
@@ -267,7 +268,7 @@
}
}
- void onMergedProgramListUpdateFromHal(ProgramList.Chunk mergedChunk) {
+ void onMergedProgramListUpdateFromHal(ProgramListChunk mergedChunk) {
List<ProgramList.Chunk> clientUpdateChunks = null;
synchronized (mLock) {
if (mProgramInfoCache == null) {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index b890bbd..9805fd3 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1754,7 +1754,7 @@
eventType = parser.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
}
- } catch (XmlPullParserException e) {
+ } catch (XmlPullParserException | ArrayIndexOutOfBoundsException e) {
Slog.w(TAG, "Error reading accounts", e);
return;
} catch (java.io.IOException e) {
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 4d3bf400..b5a373e 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -464,10 +464,7 @@
if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
clearPackageStateAndReturn = true;
} else {
- // We need to set it back to 'installed' so the uninstall
- // broadcasts will be sent correctly.
if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");
- ps.setInstalled(true, userId);
mPm.mSettings.writeKernelMappingLPr(ps);
clearPackageStateAndReturn = false;
}
diff --git a/services/core/java/com/android/server/pm/PackageArchiverService.java b/services/core/java/com/android/server/pm/PackageArchiverService.java
index c7f067b..e052407 100644
--- a/services/core/java/com/android/server/pm/PackageArchiverService.java
+++ b/services/core/java/com/android/server/pm/PackageArchiverService.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
import static android.os.PowerExemptionManager.REASON_PACKAGE_UNARCHIVE;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -24,6 +25,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.content.Context;
@@ -33,24 +35,37 @@
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageArchiver;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Environment;
import android.os.ParcelableException;
+import android.os.SELinux;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.pkg.ArchiveState;
import com.android.server.pm.pkg.ArchiveState.ArchiveActivityInfo;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserStateInternal;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
/**
* Responsible archiving apps and returning information about archived apps.
@@ -61,6 +76,8 @@
*/
public class PackageArchiverService extends IPackageArchiverService.Stub {
+ private static final String TAG = "PackageArchiverService";
+
/**
* The maximum time granted for an app store to start a foreground service when unarchival
* is requested.
@@ -68,6 +85,8 @@
// TODO(b/297358628) Make this configurable through a flag.
private static final int DEFAULT_UNARCHIVE_FOREGROUND_TIMEOUT_MS = 120 * 1000;
+ private static final String ARCHIVE_ICONS_DIR = "package_archiver";
+
private final Context mContext;
private final PackageManagerService mPm;
@@ -97,25 +116,44 @@
snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
"archiveApp");
verifyCaller(providedUid, binderUid);
- ArchiveState archiveState;
+ CompletableFuture<ArchiveState> archiveStateFuture;
try {
- archiveState = createArchiveState(packageName, userId);
- // TODO(b/282952870) Should be reverted if uninstall fails/cancels
- storeArchiveState(packageName, archiveState, userId);
+ archiveStateFuture = createArchiveState(packageName, userId);
} catch (PackageManager.NameNotFoundException e) {
+ Slog.d(TAG, TextUtils.formatSimple("Failed to archive %s with message %s",
+ packageName, e.getMessage()));
throw new ParcelableException(e);
}
- // TODO(b/278553670) Add special strings for the delete dialog
- mPm.mInstallerService.uninstall(
- new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
- callerPackageName, DELETE_KEEP_DATA, intentSender, userId);
+ archiveStateFuture
+ .thenAccept(
+ archiveState -> {
+ // TODO(b/282952870) Should be reverted if uninstall fails/cancels
+ try {
+ storeArchiveState(packageName, archiveState, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ sendFailureStatus(intentSender, packageName, e.getMessage());
+ return;
+ }
+
+ // TODO(b/278553670) Add special strings for the delete dialog
+ mPm.mInstallerService.uninstall(
+ new VersionedPackage(packageName,
+ PackageManager.VERSION_CODE_HIGHEST),
+ callerPackageName, DELETE_KEEP_DATA, intentSender, userId,
+ binderUid);
+ })
+ .exceptionally(
+ e -> {
+ sendFailureStatus(intentSender, packageName, e.getMessage());
+ return null;
+ });
}
/**
* Creates archived state for the package and user.
*/
- public ArchiveState createArchiveState(String packageName, int userId)
+ public CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId)
throws PackageManager.NameNotFoundException {
PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(),
Binder.getCallingUid(), userId);
@@ -123,16 +161,56 @@
verifyInstaller(responsibleInstallerPackage);
List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps, userId);
+ final CompletableFuture<ArchiveState> archiveState = new CompletableFuture<>();
+ mPm.mHandler.post(() -> {
+ try {
+ archiveState.complete(
+ createArchiveStateInternal(packageName, userId, mainActivities,
+ responsibleInstallerPackage));
+ } catch (IOException e) {
+ archiveState.completeExceptionally(e);
+ }
+ });
+ return archiveState;
+ }
+
+ private ArchiveState createArchiveStateInternal(String packageName, int userId,
+ List<LauncherActivityInfo> mainActivities, String installerPackage)
+ throws IOException {
List<ArchiveActivityInfo> archiveActivityInfos = new ArrayList<>();
for (int i = 0; i < mainActivities.size(); i++) {
- // TODO(b/278553670) Extract and store launcher icons
+ LauncherActivityInfo mainActivity = mainActivities.get(i);
+ Path iconPath = storeIcon(packageName, mainActivity, userId);
ArchiveActivityInfo activityInfo = new ArchiveActivityInfo(
- mainActivities.get(i).getLabel().toString(),
- Path.of("/TODO"), null);
+ mainActivity.getLabel().toString(), iconPath, null);
archiveActivityInfos.add(activityInfo);
}
- return new ArchiveState(archiveActivityInfos, responsibleInstallerPackage);
+ return new ArchiveState(archiveActivityInfos, installerPackage);
+ }
+
+ // TODO(b/298452477) Handle monochrome icons.
+ @VisibleForTesting
+ Path storeIcon(String packageName, LauncherActivityInfo mainActivity,
+ @UserIdInt int userId)
+ throws IOException {
+ int iconResourceId = mainActivity.getActivityInfo().getIconResource();
+ if (iconResourceId == 0) {
+ // The app doesn't define an icon. No need to store anything.
+ return null;
+ }
+ File iconsDir = createIconsDir(userId);
+ File iconFile = new File(iconsDir, packageName + "-" + mainActivity.getName() + ".png");
+ Bitmap icon = drawableToBitmap(mainActivity.getIcon(/* density= */ 0));
+ try (FileOutputStream out = new FileOutputStream(iconFile)) {
+ // Note: Quality is ignored for PNGs.
+ if (!icon.compress(Bitmap.CompressFormat.PNG, /* quality= */ 100, out)) {
+ throw new IOException(TextUtils.formatSimple("Failure to store icon file %s",
+ iconFile.getName()));
+ }
+ out.flush();
+ }
+ return iconFile.toPath();
}
private void verifyInstaller(String installerPackage)
@@ -313,6 +391,29 @@
return ps;
}
+ private void sendFailureStatus(IntentSender statusReceiver, String packageName,
+ String message) {
+ Slog.d(TAG, TextUtils.formatSimple("Failed to archive %s with message %s", packageName,
+ message));
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, message);
+ try {
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityStartMode(
+ MODE_BACKGROUND_ACTIVITY_START_DENIED);
+ statusReceiver.sendIntent(mContext, 0, fillIn, /* onFinished= */ null,
+ /* handler= */ null, /* requiredPermission= */ null, options.toBundle());
+ } catch (IntentSender.SendIntentException e) {
+ Slog.e(
+ TAG,
+ TextUtils.formatSimple("Failed to send failure status for %s with message %s",
+ packageName, message),
+ e);
+ }
+ }
+
private static void verifyCaller(int providedUid, int binderUid) {
if (providedUid != binderUid) {
throw new SecurityException(
@@ -323,4 +424,44 @@
binderUid));
}
}
+
+ private File createIconsDir(@UserIdInt int userId) throws IOException {
+ File iconsDir = getIconsDir(userId);
+ if (!iconsDir.isDirectory()) {
+ iconsDir.delete();
+ iconsDir.mkdirs();
+ if (!iconsDir.isDirectory()) {
+ throw new IOException("Unable to create directory " + iconsDir);
+ }
+ }
+ SELinux.restorecon(iconsDir);
+ return iconsDir;
+ }
+
+ private File getIconsDir(int userId) {
+ return new File(Environment.getDataSystemCeDirectory(userId), ARCHIVE_ICONS_DIR);
+ }
+
+ private static Bitmap drawableToBitmap(Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+
+ }
+
+ Bitmap bitmap;
+ if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
+ // Needed for drawables that are just a single color.
+ bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ } else {
+ bitmap =
+ Bitmap.createBitmap(
+ drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(),
+ Bitmap.Config.ARGB_8888);
+ }
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index e360256..fabef76 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1240,8 +1240,18 @@
@Override
public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
IntentSender statusReceiver, int userId) {
+ uninstall(
+ versionedPackage,
+ callerPackageName,
+ flags,
+ statusReceiver,
+ userId,
+ Binder.getCallingUid());
+ }
+
+ void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
+ IntentSender statusReceiver, int userId, int callingUid) {
final Computer snapshot = mPm.snapshotComputer();
- final int callingUid = Binder.getCallingUid();
snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
if (!PackageManagerServiceUtils.isRootOrShell(callingUid)) {
mAppOps.checkPackage(callingUid, callerPackageName);
@@ -1257,7 +1267,7 @@
final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
statusReceiver, versionedPackage.getPackageName(),
canSilentlyInstallPackage, userId);
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES)
== PackageManager.PERMISSION_GRANTED) {
// Sweet, call straight through!
mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index e8e6470..0dd4111ad 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -3641,9 +3641,6 @@
@GuardedBy("mLock")
private void maybeStageFsveritySignatureLocked(File origFile, File targetFile,
boolean fsVerityRequired) throws PackageManagerException {
- if (com.android.server.security.Flags.deprecateFsvSig()) {
- return;
- }
final File originalSignature = new File(
VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
if (originalSignature.exists()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 0423249..2028231 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -543,9 +543,6 @@
/** Returns true if standard APK Verity is enabled. */
static boolean isApkVerityEnabled() {
- if (com.android.server.security.Flags.deprecateFsvSig()) {
- return false;
- }
return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.R
|| SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED)
== FSVERITY_ENABLED;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d9f1df5..a0c9cd1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2784,33 +2784,111 @@
private int runGrantRevokePermission(boolean grant) throws RemoteException {
int userId = UserHandle.USER_SYSTEM;
- String opt = null;
+ String opt;
+ boolean allPermissions = false;
while ((opt = getNextOption()) != null) {
if (opt.equals("--user")) {
userId = UserHandle.parseUserArg(getNextArgRequired());
}
+ if (opt.equals("--all-permissions")) {
+ allPermissions = true;
+ }
}
String pkg = getNextArg();
- if (pkg == null) {
+ if (!allPermissions && pkg == null) {
getErrPrintWriter().println("Error: no package specified");
return 1;
}
String perm = getNextArg();
- if (perm == null) {
+ if (!allPermissions && perm == null) {
getErrPrintWriter().println("Error: no permission specified");
return 1;
}
+ if (allPermissions && perm != null) {
+ getErrPrintWriter().println("Error: permission specified but not expected");
+ return 1;
+ }
final UserHandle translatedUser = UserHandle.of(translateUserId(userId,
UserHandle.USER_NULL, "runGrantRevokePermission"));
- if (grant) {
- mPermissionManager.grantRuntimePermission(pkg, perm, translatedUser);
+
+ List<PackageInfo> packageInfos;
+ if (pkg == null) {
+ packageInfos = mContext.getPackageManager().getInstalledPackages(
+ PackageManager.GET_PERMISSIONS);
} else {
- mPermissionManager.revokeRuntimePermission(pkg, perm, translatedUser, null);
+ try {
+ packageInfos = Collections.singletonList(
+ mContext.getPackageManager().getPackageInfo(pkg,
+ PackageManager.GET_PERMISSIONS));
+ } catch (NameNotFoundException e) {
+ getErrPrintWriter().println("Error: package not found");
+ return 1;
+ }
+ }
+
+ for (PackageInfo packageInfo : packageInfos) {
+ List<String> permissions = Collections.singletonList(perm);
+ if (allPermissions) {
+ permissions = getRequestedRuntimePermissions(packageInfo);
+ }
+ for (String permission : permissions) {
+ if (grant) {
+ try {
+ mPermissionManager.grantRuntimePermission(packageInfo.packageName,
+ permission,
+ translatedUser);
+ } catch (Exception e) {
+ if (!allPermissions) {
+ throw e;
+ } else {
+ Slog.w(TAG, "Could not grant permission " + permission, e);
+ }
+ }
+ } else {
+ try {
+ mPermissionManager.revokeRuntimePermission(packageInfo.packageName,
+ permission,
+ translatedUser, null);
+ } catch (Exception e) {
+ if (!allPermissions) {
+ throw e;
+ } else {
+ Slog.w(TAG, "Could not grant permission " + permission, e);
+ }
+ }
+ }
+ }
}
return 0;
}
+ private List<String> getRequestedRuntimePermissions(PackageInfo info) {
+ // No requested permissions
+ if (info.requestedPermissions == null) {
+ return new ArrayList<>();
+ }
+ List<String> result = new ArrayList<>();
+ PackageManager pm = mContext.getPackageManager();
+ // Iterate through requested permissions for denied ones
+ for (String permission : info.requestedPermissions) {
+ PermissionInfo pi = null;
+ try {
+ pi = pm.getPermissionInfo(permission, 0);
+ } catch (NameNotFoundException nnfe) {
+ // ignore
+ }
+ if (pi == null) {
+ continue;
+ }
+ if (pi.getProtection() != PermissionInfo.PROTECTION_DANGEROUS) {
+ continue;
+ }
+ result.add(permission);
+ }
+ return result;
+ }
+
private int runResetPermissions() throws RemoteException {
mLegacyPermissionManager.resetRuntimePermissions();
return 0;
@@ -4643,11 +4721,15 @@
pw.println(" get-distracting-restriction [--user USER_ID] PACKAGE [PACKAGE...]");
pw.println(" Gets the specified restriction flags of given package(s) (of the user).");
pw.println("");
- pw.println(" grant [--user USER_ID] PACKAGE PERMISSION");
- pw.println(" revoke [--user USER_ID] PACKAGE PERMISSION");
+ pw.println(" grant [--user USER_ID] [--all-permissions] PACKAGE PERMISSION");
+ pw.println(" revoke [--user USER_ID] [--all-permissions] PACKAGE PERMISSION");
pw.println(" These commands either grant or revoke permissions to apps. The permissions");
pw.println(" must be declared as used in the app's manifest, be runtime permissions");
pw.println(" (protection level dangerous), and the app targeting SDK greater than Lollipop MR1.");
+ pw.println(" Flags are:");
+ pw.println(" --user: Specifies the user for which the operation needs to be performed");
+ pw.println(" --all-permissions: If specified all the missing runtime permissions will");
+ pw.println(" be granted to the PACKAGE or to all the packages if none is specified.");
pw.println("");
pw.println(" set-permission-flags [--user USER_ID] PACKAGE PERMISSION [FLAGS..]");
pw.println(" clear-permission-flags [--user USER_ID] PACKAGE PERMISSION [FLAGS..]");
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 88184c0..114f80d 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -35,6 +35,7 @@
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
import android.service.pm.PackageProto;
+import android.service.pm.PackageProto.UserInfoProto.ArchiveState.ArchiveActivityInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1161,18 +1162,15 @@
for (ArchiveState.ArchiveActivityInfo activityInfo : archiveState.getActivityInfos()) {
long activityInfoToken = proto.start(
PackageProto.UserInfoProto.ArchiveState.ACTIVITY_INFOS);
- proto.write(PackageProto.UserInfoProto.ArchiveState.ArchiveActivityInfo.TITLE,
- activityInfo.getTitle());
- proto.write(
- PackageProto.UserInfoProto.ArchiveState.ArchiveActivityInfo.ICON_BITMAP_PATH,
- activityInfo.getIconBitmap().toAbsolutePath().toString());
- proto.write(
- PackageProto
- .UserInfoProto
- .ArchiveState
- .ArchiveActivityInfo
- .MONOCHROME_ICON_BITMAP_PATH,
- activityInfo.getMonochromeIconBitmap().toAbsolutePath().toString());
+ proto.write(ArchiveActivityInfo.TITLE, activityInfo.getTitle());
+ if (activityInfo.getIconBitmap() != null) {
+ proto.write(ArchiveActivityInfo.ICON_BITMAP_PATH,
+ activityInfo.getIconBitmap().toAbsolutePath().toString());
+ }
+ if (activityInfo.getMonochromeIconBitmap() != null) {
+ proto.write(ArchiveActivityInfo.MONOCHROME_ICON_BITMAP_PATH,
+ activityInfo.getMonochromeIconBitmap().toAbsolutePath().toString());
+ }
proto.end(activityInfoToken);
}
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 2aedf0d..8dec425 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -22,7 +22,6 @@
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
-
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
@@ -400,6 +399,21 @@
changedUsers);
mPm.postPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
}
+ } else if (!deletedPs.isSystem() && outInfo != null && !outInfo.mIsUpdate
+ && outInfo.mRemovedUsers != null) {
+ // For non-system uninstalls with DELETE_KEEP_DATA, set the installed state to false
+ // for affected users. This does not apply to app updates where the old apk is replaced
+ // but the old data remains.
+ if (DEBUG_REMOVE) {
+ Slog.d(TAG, "Updating installed state to false because of DELETE_KEEP_DATA");
+ }
+ for (int userId : outInfo.mRemovedUsers) {
+ if (DEBUG_REMOVE) {
+ final boolean wasInstalled = deletedPs.getInstalled(userId);
+ Slog.d(TAG, " user " + userId + ": " + wasInstalled + " => " + false);
+ }
+ deletedPs.setInstalled(/* installed= */ false, userId);
+ }
}
// make sure to preserve per-user installed state if this removal was just
// a downgrade of a system app to the factory package
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1137681..111a32d 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2062,8 +2062,9 @@
if (tagName.equals(TAG_ARCHIVE_ACTIVITY_INFO)) {
String title = parser.getAttributeValue(null,
ATTR_ARCHIVE_ACTIVITY_TITLE);
- Path iconPath = Path.of(parser.getAttributeValue(null,
- ATTR_ARCHIVE_ICON_PATH));
+ String iconAttribute = parser.getAttributeValue(null,
+ ATTR_ARCHIVE_ICON_PATH);
+ Path iconPath = iconAttribute == null ? null : Path.of(iconAttribute);
String monochromeAttribute = parser.getAttributeValue(null,
ATTR_ARCHIVE_MONOCHROME_ICON_PATH);
Path monochromeIconPath = monochromeAttribute == null ? null : Path.of(
@@ -2447,8 +2448,10 @@
for (ArchiveState.ArchiveActivityInfo activityInfo : archiveState.getActivityInfos()) {
serializer.startTag(null, TAG_ARCHIVE_ACTIVITY_INFO);
serializer.attribute(null, ATTR_ARCHIVE_ACTIVITY_TITLE, activityInfo.getTitle());
- serializer.attribute(null, ATTR_ARCHIVE_ICON_PATH,
- activityInfo.getIconBitmap().toAbsolutePath().toString());
+ if (activityInfo.getIconBitmap() != null) {
+ serializer.attribute(null, ATTR_ARCHIVE_ICON_PATH,
+ activityInfo.getIconBitmap().toAbsolutePath().toString());
+ }
if (activityInfo.getMonochromeIconBitmap() != null) {
serializer.attribute(null, ATTR_ARCHIVE_MONOCHROME_ICON_PATH,
activityInfo.getMonochromeIconBitmap().toAbsolutePath().toString());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 803b94b..e365e83 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2750,7 +2750,8 @@
}
}
- private void setUserRestrictionInner(int userId, @NonNull String key, boolean value) {
+ @VisibleForTesting
+ void setUserRestrictionInner(int userId, @NonNull String key, boolean value) {
if (!UserRestrictionsUtils.isValidRestriction(key)) {
Slog.e(LOG_TAG, "Setting invalid restriction " + key);
return;
@@ -4360,11 +4361,11 @@
UserRestrictionsUtils.writeRestrictions(serializer,
mDevicePolicyUserRestrictions.getRestrictions(UserHandle.USER_ALL),
- TAG_DEVICE_POLICY_RESTRICTIONS);
+ TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS);
UserRestrictionsUtils.writeRestrictions(serializer,
mDevicePolicyUserRestrictions.getRestrictions(userInfo.id),
- TAG_DEVICE_POLICY_RESTRICTIONS);
+ TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS);
}
if (userData.account != null) {
diff --git a/services/core/java/com/android/server/pm/pkg/ArchiveState.java b/services/core/java/com/android/server/pm/pkg/ArchiveState.java
index d44ae16..4916a4a 100644
--- a/services/core/java/com/android/server/pm/pkg/ArchiveState.java
+++ b/services/core/java/com/android/server/pm/pkg/ArchiveState.java
@@ -56,8 +56,11 @@
@NonNull
private final String mTitle;
- /** The path to the stored icon of the activity in the app's locale. */
- @NonNull
+ /**
+ * The path to the stored icon of the activity in the app's locale. Null if the app does
+ * not define any icon (default icon would be shown on the launcher).
+ */
+ @Nullable
private final Path mIconBitmap;
/** See {@link #mIconBitmap}. Only set if the app defined a monochrome icon. */
@@ -85,21 +88,20 @@
* @param title
* Corresponds to the activity's android:label in the app's locale.
* @param iconBitmap
- * The path to the stored icon of the activity in the app's locale.
+ * The path to the stored icon of the activity in the app's locale. Null if the app does
+ * not define any icon (default icon would be shown on the launcher).
* @param monochromeIconBitmap
* See {@link #mIconBitmap}. Only set if the app defined a monochrome icon.
*/
@DataClass.Generated.Member
public ArchiveActivityInfo(
@NonNull String title,
- @NonNull Path iconBitmap,
+ @Nullable Path iconBitmap,
@Nullable Path monochromeIconBitmap) {
this.mTitle = title;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mTitle);
this.mIconBitmap = iconBitmap;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mIconBitmap);
this.mMonochromeIconBitmap = monochromeIconBitmap;
// onConstructed(); // You can define this method to get a callback
@@ -114,10 +116,11 @@
}
/**
- * The path to the stored icon of the activity in the app's locale.
+ * The path to the stored icon of the activity in the app's locale. Null if the app does
+ * not define any icon (default icon would be shown on the launcher).
*/
@DataClass.Generated.Member
- public @NonNull Path getIconBitmap() {
+ public @Nullable Path getIconBitmap() {
return mIconBitmap;
}
@@ -174,10 +177,10 @@
}
@DataClass.Generated(
- time = 1689169065133L,
+ time = 1693590309015L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/ArchiveState.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mTitle\nprivate final @android.annotation.NonNull java.nio.file.Path mIconBitmap\nprivate final @android.annotation.Nullable java.nio.file.Path mMonochromeIconBitmap\nclass ArchiveActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mTitle\nprivate final @android.annotation.Nullable java.nio.file.Path mIconBitmap\nprivate final @android.annotation.Nullable java.nio.file.Path mMonochromeIconBitmap\nclass ArchiveActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)")
@Deprecated
private void __metadata() {}
@@ -292,7 +295,7 @@
}
@DataClass.Generated(
- time = 1689169065144L,
+ time = 1693590309027L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/ArchiveState.java",
inputSignatures = "private final @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.ArchiveActivityInfo> mActivityInfos\nprivate final @android.annotation.NonNull java.lang.String mInstallerTitle\nclass ArchiveState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)")
diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java
index 0879d95..3aed6e3 100644
--- a/services/core/java/com/android/server/security/FileIntegrityService.java
+++ b/services/core/java/com/android/server/security/FileIntegrityService.java
@@ -90,13 +90,6 @@
@NonNull String packageName) {
checkCallerPermission(packageName);
- if (Flags.deprecateFsvSig()) {
- // When deprecated, stop telling the caller that any app source certificate is
- // trusted on the current device. This behavior is also consistent with devices
- // without this feature support.
- return false;
- }
-
try {
if (!VerityUtils.isFsVeritySupported()) {
return false;
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 9905ddf..635e11b 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -159,10 +159,26 @@
private VirtualDeviceManagerInternal mVirtualDeviceManager;
private enum TrustState {
- UNTRUSTED, // the phone is not unlocked by any trustagents
- TRUSTABLE, // the phone is in a semi-locked state that can be unlocked if
- // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE is passed and a trustagent is trusted
- TRUSTED // the phone is unlocked
+ // UNTRUSTED means that TrustManagerService is currently *not* giving permission for the
+ // user's Keyguard to be dismissed, and grants of trust by trust agents are remembered in
+ // the corresponding TrustAgentWrapper but are not recognized until the device is unlocked
+ // for the user. I.e., if the device is locked and the state is UNTRUSTED, it cannot be
+ // unlocked by a trust agent. Automotive devices are an exception; grants of trust are
+ // always recognized on them.
+ UNTRUSTED,
+
+ // TRUSTABLE is the same as UNTRUSTED except that new grants of trust using
+ // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE are recognized for moving to TRUSTED. I.e., if
+ // the device is locked and the state is TRUSTABLE, it can be unlocked by a trust agent,
+ // provided that the trust agent chooses to use Active Unlock. The TRUSTABLE state is only
+ // possible as a result of a downgrade from TRUSTED, after a trust agent used
+ // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE in its most recent grant.
+ TRUSTABLE,
+
+ // TRUSTED means that TrustManagerService is currently giving permission for the user's
+ // Keyguard to be dismissed. This implies that the device is unlocked for the user (where
+ // the case of Keyguard showing but dismissible just with swipe counts as "unlocked").
+ TRUSTED
};
@GuardedBy("mUserTrustState")
@@ -744,6 +760,12 @@
}
}
+ private TrustState getUserTrustStateInner(int userId) {
+ synchronized (mUserTrustState) {
+ return mUserTrustState.get(userId, TrustState.UNTRUSTED);
+ }
+ }
+
boolean isDeviceLockedInner(int userId) {
synchronized (mDeviceLockedForUser) {
return mDeviceLockedForUser.get(userId, true);
@@ -806,7 +828,12 @@
continue;
}
- boolean trusted = aggregateIsTrusted(id);
+ final boolean trusted;
+ if (android.security.Flags.fixUnlockedDeviceRequiredKeys()) {
+ trusted = getUserTrustStateInner(id) == TrustState.TRUSTED;
+ } else {
+ trusted = aggregateIsTrusted(id);
+ }
boolean showingKeyguard = true;
boolean biometricAuthenticated = false;
boolean currentUserIsUnlocked = false;
@@ -1627,7 +1654,7 @@
if (isCurrent) {
fout.print(" (current)");
}
- fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id)));
+ fout.print(": trustState=" + getUserTrustStateInner(user.id));
fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id)));
fout.print(", deviceLocked=" + dumpBool(isDeviceLockedInner(user.id)));
fout.print(", isActiveUnlockRunning=" + dumpBool(
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index d430dda..b823e73 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1170,9 +1170,7 @@
fullscreenRequest, r);
reportMultiwindowFullscreenRequestValidatingResult(callback, validateResult);
if (validateResult != RESULT_APPROVED) {
- if (queued) {
- transition.abort();
- }
+ transition.abort();
return;
}
transition.collect(topFocusedRootTask);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index fd42077..4aea70c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -68,7 +68,6 @@
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
-
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DREAM;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
@@ -3660,6 +3659,9 @@
synchronized (mGlobalLock) {
if (r.getParent() == null) {
Slog.e(TAG, "Skip enterPictureInPictureMode, destroyed " + r);
+ if (transition != null) {
+ transition.abort();
+ }
return;
}
EventLogTags.writeWmEnterPip(r.mUserId, System.identityHashCode(r),
@@ -5628,6 +5630,15 @@
}
}
+ void registerCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id,
+ @NonNull CompatScaleProvider provider) {
+ mCompatModePackages.registerCompatScaleProvider(id, provider);
+ }
+
+ void unregisterCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id) {
+ mCompatModePackages.unregisterCompatScaleProvider(id);
+ }
+
/**
* Returns {@code true} if the process represented by the pid passed as argument is
* instrumented and the instrumentation source was granted with the permission also
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index c6978fd..e906b18 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -20,7 +20,10 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.CompatScaleProvider.COMPAT_SCALE_MODE_SYSTEM_FIRST;
+import static com.android.server.wm.CompatScaleProvider.COMPAT_SCALE_MODE_SYSTEM_LAST;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.GameManagerInternal;
@@ -32,6 +35,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.res.CompatibilityInfo;
+import android.content.res.CompatibilityInfo.CompatScale;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Handler;
@@ -332,6 +336,8 @@
private final HashMap<String, Integer> mPackages = new HashMap<>();
private final CompatHandler mHandler;
+ private final SparseArray<CompatScaleProvider> mProviders = new SparseArray<>();
+
public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) {
mService = service;
mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"), "compat-mode");
@@ -441,13 +447,38 @@
public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
final boolean forceCompat = getPackageCompatModeEnabledLocked(ai);
- final float compatScale = getCompatScale(ai.packageName, ai.uid);
+ final CompatScale compatScale = getCompatScaleFromProvider(ai.packageName, ai.uid);
+ final float appScale = compatScale != null
+ ? compatScale.mScaleFactor
+ : getCompatScale(ai.packageName, ai.uid, /* checkProvider= */ false);
+ final float densityScale = compatScale != null ? compatScale.mDensityScaleFactor : 1f;
final Configuration config = mService.getGlobalConfiguration();
return new CompatibilityInfo(ai, config.screenLayout, config.smallestScreenWidthDp,
- forceCompat, compatScale);
+ forceCompat, appScale, densityScale);
}
float getCompatScale(String packageName, int uid) {
+ return getCompatScale(packageName, uid, /* checkProvider= */ true);
+ }
+
+ private CompatScale getCompatScaleFromProvider(String packageName, int uid) {
+ for (int i = 0; i < mProviders.size(); i++) {
+ final CompatScaleProvider provider = mProviders.valueAt(i);
+ final CompatScale compatScale = provider.getCompatScale(packageName, uid);
+ if (compatScale != null) {
+ return compatScale;
+ }
+ }
+ return null;
+ }
+
+ private float getCompatScale(String packageName, int uid, boolean checkProviders) {
+ if (checkProviders) {
+ final CompatScale compatScale = getCompatScaleFromProvider(packageName, uid);
+ if (compatScale != null) {
+ return compatScale.mScaleFactor;
+ }
+ }
final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
if (mGameManager == null) {
mGameManager = LocalServices.getService(GameManagerInternal.class);
@@ -487,6 +518,36 @@
return 1f;
}
+ void registerCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id,
+ @NonNull CompatScaleProvider provider) {
+ synchronized (mService.mGlobalLock) {
+ if (mProviders.contains(id)) {
+ throw new IllegalArgumentException("Duplicate id provided: " + id);
+ }
+ if (provider == null) {
+ throw new IllegalArgumentException("The passed CompatScaleProvider "
+ + "can not be null");
+ }
+ if (!CompatScaleProvider.isValidOrderId(id)) {
+ throw new IllegalArgumentException(
+ "Provided id " + id + " is not in range of valid ids for system "
+ + "services [" + COMPAT_SCALE_MODE_SYSTEM_FIRST + ","
+ + COMPAT_SCALE_MODE_SYSTEM_LAST + "]");
+ }
+ mProviders.put(id, provider);
+ }
+ }
+
+ void unregisterCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id) {
+ synchronized (mService.mGlobalLock) {
+ if (!mProviders.contains(id)) {
+ throw new IllegalArgumentException(
+ "CompatScaleProvider with id (" + id + ") is not registered");
+ }
+ mProviders.remove(id);
+ }
+ }
+
private static float getScalingFactor(String packageName, UserHandle userHandle) {
if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) {
return 0.9f;
diff --git a/services/core/java/com/android/server/wm/CompatScaleProvider.java b/services/core/java/com/android/server/wm/CompatScaleProvider.java
new file mode 100644
index 0000000..5474ece
--- /dev/null
+++ b/services/core/java/com/android/server/wm/CompatScaleProvider.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.wm;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.CompatibilityInfo.CompatScale;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An interface for services that need to provide compatibility scale different than
+ * the default android compatibility.
+ */
+public interface CompatScaleProvider {
+
+ /**
+ * The unique id of each provider registered by a system service which determines the order
+ * it will execute in.
+ */
+ @IntDef(prefix = { "COMPAT_SCALE_MODE_" }, value = {
+ // Order Ids for system services
+ COMPAT_SCALE_MODE_SYSTEM_FIRST,
+ COMPAT_SCALE_MODE_GAME,
+ COMPAT_SCALE_MODE_PRODUCT,
+ COMPAT_SCALE_MODE_SYSTEM_LAST, // Update this when adding new ids
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface CompatScaleModeOrderId {}
+
+ /**
+ * The first id, used by the framework to determine the valid range of ids.
+ * @hide
+ */
+ int COMPAT_SCALE_MODE_SYSTEM_FIRST = 0;
+
+ /**
+ * TODO(b/295207384)
+ * The identifier for {@link android.app.GameManagerInternal} provider
+ * @hide
+ */
+ int COMPAT_SCALE_MODE_GAME = 1;
+
+ /**
+ * The identifier for a provider which is specific to the type of android product like
+ * Automotive, Wear, TV etc.
+ * @hide
+ */
+ int COMPAT_SCALE_MODE_PRODUCT = 2;
+
+ /**
+ * The final id, used by the framework to determine the valid range of ids. Update this when
+ * adding new ids.
+ * @hide
+ */
+ int COMPAT_SCALE_MODE_SYSTEM_LAST = COMPAT_SCALE_MODE_PRODUCT;
+
+ /**
+ * Returns {@code true} if the id is in the range of valid system services
+ * @hide
+ */
+ static boolean isValidOrderId(int id) {
+ return (id >= COMPAT_SCALE_MODE_SYSTEM_FIRST && id <= COMPAT_SCALE_MODE_SYSTEM_LAST);
+ }
+
+ /**
+ * @return an instance of {@link CompatScale} to apply for the given package
+ */
+ @Nullable
+ CompatScale getCompatScale(@NonNull String packageName, int uid);
+}
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 5aa7c97..f0e4149 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -35,6 +35,7 @@
import android.os.ServiceManager;
import android.provider.DeviceConfig;
import android.view.ContentRecordingSession;
+import android.view.ContentRecordingSession.RecordContent;
import android.view.Display;
import android.view.SurfaceControl;
@@ -84,6 +85,7 @@
/**
* The last configuration orientation.
*/
+ @Configuration.Orientation
private int mLastOrientation = ORIENTATION_UNDEFINED;
ContentRecorder(@NonNull DisplayContent displayContent) {
@@ -156,7 +158,8 @@
// Retrieve the size of the region to record, and continue with the update
// if the bounds or orientation has changed.
final Rect recordedContentBounds = mRecordedWindowContainer.getBounds();
- int recordedContentOrientation = mRecordedWindowContainer.getOrientation();
+ @Configuration.Orientation int recordedContentOrientation =
+ mRecordedWindowContainer.getConfiguration().orientation;
if (!mLastRecordedBounds.equals(recordedContentBounds)
|| lastOrientation != recordedContentOrientation) {
Point surfaceSize = fetchSurfaceSizeIfPresent();
@@ -356,7 +359,7 @@
*/
@Nullable
private WindowContainer retrieveRecordedWindowContainer() {
- final int contentToRecord = mContentRecordingSession.getContentToRecord();
+ @RecordContent final int contentToRecord = mContentRecordingSession.getContentToRecord();
final IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
switch (contentToRecord) {
case RECORD_CONTENT_DISPLAY:
@@ -472,6 +475,12 @@
shiftedY = (surfaceSize.y - scaledHeight) / 2;
}
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Content Recording: Apply transformations of shift %d x %d, scale %f, crop %d x "
+ + "%d for display %d",
+ shiftedX, shiftedY, scale, recordedContentBounds.width(),
+ recordedContentBounds.height(), mDisplayContent.getDisplayId());
+
transaction
// Crop the area to capture to exclude the 'extra' wallpaper that is used
// for parallax (b/189930234).
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 707b779..395ab3a 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -269,6 +269,8 @@
private boolean mIsFreeformWindowOverlappingWithNavBar;
+ private @InsetsType int mForciblyShownTypes;
+
private boolean mIsImmersiveMode;
// The windows we were told about in focusChanged.
@@ -1402,6 +1404,7 @@
mAllowLockscreenWhenOn = false;
mShowingDream = false;
mIsFreeformWindowOverlappingWithNavBar = false;
+ mForciblyShownTypes = 0;
}
/**
@@ -1459,6 +1462,10 @@
}
}
+ if (win.mSession.mCanForceShowingInsets) {
+ mForciblyShownTypes |= win.mAttrs.forciblyShownTypes;
+ }
+
if (!affectsSystemUi) {
return;
}
@@ -1640,6 +1647,10 @@
mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
}
+ boolean areTypesForciblyShownTransiently(@InsetsType int types) {
+ return (mForciblyShownTypes & types) == types;
+ }
+
/**
* Applies the keyguard policy to a specific window.
*
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 835c92d..d0d7f49 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -23,8 +23,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.InsetsSource.ID_IME;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import android.annotation.NonNull;
@@ -77,6 +75,18 @@
/** Used to show system bars permanently. This will affect the layout. */
private final InsetsControlTarget mPermanentControlTarget;
+ /**
+ * Used to override the visibility of {@link Type#statusBars()} when dispatching insets to
+ * clients.
+ */
+ private InsetsControlTarget mFakeStatusControlTarget;
+
+ /**
+ * Used to override the visibility of {@link Type#navigationBars()} when dispatching insets to
+ * clients.
+ */
+ private InsetsControlTarget mFakeNavControlTarget;
+
private WindowState mFocusedWin;
private final BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
private final BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
@@ -103,25 +113,25 @@
abortTransient();
}
mFocusedWin = focusedWin;
- final InsetsControlTarget statusControlTarget =
- getStatusControlTarget(focusedWin, false /* fake */);
- final InsetsControlTarget navControlTarget =
- getNavControlTarget(focusedWin, false /* fake */);
final WindowState notificationShade = mPolicy.getNotificationShade();
final WindowState topApp = mPolicy.getTopFullscreenOpaqueWindow();
+ final InsetsControlTarget statusControlTarget =
+ getStatusControlTarget(focusedWin, false /* fake */);
+ mFakeStatusControlTarget = statusControlTarget == mTransientControlTarget
+ ? getStatusControlTarget(focusedWin, true /* fake */)
+ : statusControlTarget == notificationShade
+ ? getStatusControlTarget(topApp, true /* fake */)
+ : null;
+ final InsetsControlTarget navControlTarget =
+ getNavControlTarget(focusedWin, false /* fake */);
+ mFakeNavControlTarget = navControlTarget == mTransientControlTarget
+ ? getNavControlTarget(focusedWin, true /* fake */)
+ : navControlTarget == notificationShade
+ ? getNavControlTarget(topApp, true /* fake */)
+ : null;
mStateController.onBarControlTargetChanged(
- statusControlTarget,
- statusControlTarget == mTransientControlTarget
- ? getStatusControlTarget(focusedWin, true /* fake */)
- : statusControlTarget == notificationShade
- ? getStatusControlTarget(topApp, true /* fake */)
- : null,
- navControlTarget,
- navControlTarget == mTransientControlTarget
- ? getNavControlTarget(focusedWin, true /* fake */)
- : navControlTarget == notificationShade
- ? getNavControlTarget(topApp, true /* fake */)
- : null);
+ statusControlTarget, mFakeStatusControlTarget,
+ navControlTarget, mFakeNavControlTarget);
mStatusBar.updateVisibility(statusControlTarget, Type.statusBars());
mNavBar.updateVisibility(navControlTarget, Type.navigationBars());
}
@@ -206,7 +216,7 @@
boolean includesTransient) {
InsetsState state;
if (!includesTransient) {
- state = adjustVisibilityForTransientTypes(originalState);
+ state = adjustVisibilityForFakeControllingSources(originalState);
} else {
state = originalState;
}
@@ -321,24 +331,40 @@
return state;
}
- private InsetsState adjustVisibilityForTransientTypes(InsetsState originalState) {
+ private InsetsState adjustVisibilityForFakeControllingSources(InsetsState originalState) {
+ if (mFakeStatusControlTarget == null && mFakeNavControlTarget == null) {
+ return originalState;
+ }
InsetsState state = originalState;
for (int i = state.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
- if (isTransient(source.getType()) && source.isVisible()) {
- if (state == originalState) {
- // The source will be modified, create a non-deep copy to store the new one.
- state = new InsetsState(originalState);
- }
- // Replace the source with a copy in invisible state.
- final InsetsSource outSource = new InsetsSource(source);
- outSource.setVisible(false);
- state.addSource(outSource);
- }
+ state = adjustVisibilityForFakeControllingSource(state, Type.statusBars(), source,
+ mFakeStatusControlTarget);
+ state = adjustVisibilityForFakeControllingSource(state, Type.navigationBars(), source,
+ mFakeNavControlTarget);
}
return state;
}
+ private static InsetsState adjustVisibilityForFakeControllingSource(InsetsState originalState,
+ @InsetsType int type, InsetsSource source, InsetsControlTarget target) {
+ if (source.getType() != type || target == null) {
+ return originalState;
+ }
+ final boolean isRequestedVisible = target.isRequestedVisible(type);
+ if (source.isVisible() == isRequestedVisible) {
+ return originalState;
+ }
+ // The source will be modified, create a non-deep copy to store the new one.
+ final InsetsState state = new InsetsState(originalState);
+
+ // Replace the source with a copy with the overridden visibility.
+ final InsetsSource outSource = new InsetsSource(source);
+ outSource.setVisible(isRequestedVisible);
+ state.addSource(outSource);
+ return state;
+ }
+
private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
boolean copyState) {
if (w.mIsImWindow) {
@@ -473,7 +499,7 @@
// we will dispatch the real visibility of status bar to the client.
return mPermanentControlTarget;
}
- if (forceShowsStatusBarTransiently() && !fake) {
+ if (mPolicy.areTypesForciblyShownTransiently(Type.statusBars()) && !fake) {
// Status bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
@@ -505,7 +531,7 @@
if (imeWin != null && imeWin.isVisible() && !mHideNavBarForKeyboard) {
// Force showing navigation bar while IME is visible and if navigation bar is not
// configured to be hidden by the IME.
- return null;
+ return mPermanentControlTarget;
}
if (!fake && isTransient(Type.navigationBars())) {
return mTransientControlTarget;
@@ -533,7 +559,7 @@
// bar, and we will dispatch the real visibility of navigation bar to the client.
return mPermanentControlTarget;
}
- if (forceShowsNavigationBarTransiently() && !fake) {
+ if (mPolicy.areTypesForciblyShownTransiently(Type.navigationBars()) && !fake) {
// Navigation bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
@@ -603,17 +629,6 @@
&& focusedWin.getAttrs().type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
}
- private boolean forceShowsStatusBarTransiently() {
- final WindowState win = mPolicy.getStatusBar();
- return win != null && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
- }
-
- private boolean forceShowsNavigationBarTransiently() {
- final WindowState win = mPolicy.getNotificationShade();
- return win != null
- && (win.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
- }
-
private void dispatchTransientSystemBarsVisibilityChanged(
@Nullable WindowState focusedWindow,
boolean areVisible,
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 1845ae8..0674ec1 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -23,6 +23,7 @@
import static android.Manifest.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION;
import static android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.STATUS_BAR_SERVICE;
import static android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
@@ -108,6 +109,7 @@
private final ArraySet<WindowSurfaceController> mAlertWindowSurfaces = new ArraySet<>();
private final DragDropController mDragDropController;
final boolean mCanAddInternalSystemWindow;
+ boolean mCanForceShowingInsets;
private final boolean mCanStartTasksFromRecents;
final boolean mCanCreateSystemApplicationOverlay;
@@ -131,6 +133,9 @@
mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
+ mCanForceShowingInsets = service.mAtmService.isCallerRecents(mUid)
+ || service.mContext.checkCallingOrSelfPermission(STATUS_BAR_SERVICE)
+ == PERMISSION_GRANTED;
mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission(
HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED
|| service.mContext.checkCallingOrSelfPermission(HIDE_OVERLAY_WINDOWS)
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index a6c6491..843e6d1 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1487,6 +1487,11 @@
return;
}
+ if (mState != STATE_STARTED) {
+ Slog.e(TAG, "Playing a Transition which hasn't started! #" + mSyncId + " This will "
+ + "likely cause an exception in Shell");
+ }
+
mState = STATE_PLAYING;
mStartTransaction = transaction;
mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 55deb22..176bc283 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -42,6 +42,7 @@
#include <android_view_VerifiedMotionEvent.h>
#include <batteryservice/include/batteryservice/BatteryServiceConstants.h>
#include <binder/IServiceManager.h>
+#include <com_android_input_flags.h>
#include <input/Input.h>
#include <input/PointerController.h>
#include <input/SpriteController.h>
@@ -81,6 +82,8 @@
static constexpr std::chrono::milliseconds MAX_VIBRATE_PATTERN_DELAY_MILLIS =
std::chrono::duration_cast<std::chrono::milliseconds>(MAX_VIBRATE_PATTERN_DELAY);
+namespace input_flags = com::android::input::flags;
+
namespace android {
// The exponent used to calculate the pointer speed scaling factor.
@@ -733,7 +736,7 @@
ensureSpriteControllerLocked();
static const bool ENABLE_POINTER_CHOREOGRAPHER =
- sysprop::InputProperties::enable_pointer_choreographer().value_or(false);
+ input_flags::enable_pointer_choreographer();
// Disable the functionality of the legacy PointerController if PointerChoreographer is
// enabled.
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index b4a66bd..76b41b7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -1895,6 +1895,13 @@
assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
assertBfsl(app2);
+
+ bindService(client2, app1, null, 0, mock(IBinder.class));
+ bindService(app1, client2, null, 0, mock(IBinder.class));
+ client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
+ updateOomAdj(app1, client1, client2);
+ assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
+ SCHED_GROUP_TOP_APP);
}
@SuppressWarnings("GuardedBy")
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
index 80576a6..60b28d3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
@@ -25,6 +25,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -34,11 +35,15 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageArchiver;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -62,6 +67,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -74,9 +80,10 @@
private static final String PACKAGE = "com.example";
private static final String CALLER_PACKAGE = "com.caller";
private static final String INSTALLER_PACKAGE = "com.installer";
+ private static final Path ICON_PATH = Path.of("icon.png");
@Rule
- public final MockSystemRule mMockSystem = new MockSystemRule();
+ public final MockSystemRule rule = new MockSystemRule();
@Mock
private IntentSender mIntentSender;
@@ -87,9 +94,13 @@
@Mock
private LauncherApps mLauncherApps;
@Mock
+ private PackageManager mPackageManager;
+ @Mock
private PackageInstallerService mInstallerService;
@Mock
private PackageStateInternal mPackageState;
+ @Mock
+ private Bitmap mIcon;
private final InstallSource mInstallSource =
InstallSource.create(
@@ -102,7 +113,6 @@
/* packageSource= */ 0);
private final List<LauncherActivityInfo> mLauncherActivityInfos = createLauncherActivities();
-
private final int mUserId = UserHandle.CURRENT.getIdentifier();
private PackageUserStateImpl mUserState;
@@ -114,10 +124,10 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mMockSystem.system().stageNominalSystemState();
- when(mMockSystem.mocks().getInjector().getPackageInstallerService()).thenReturn(
+ rule.system().stageNominalSystemState();
+ when(rule.mocks().getInjector().getPackageInstallerService()).thenReturn(
mInstallerService);
- PackageManagerService pm = spy(new PackageManagerService(mMockSystem.mocks().getInjector(),
+ PackageManagerService pm = spy(new PackageManagerService(rule.mocks().getInjector(),
/* factoryTest= */false,
MockSystem.Companion.getDEFAULT_VERSION_INFO().fingerprint,
/* isEngBuild= */ false,
@@ -132,18 +142,27 @@
when(mPackageState.getPackageName()).thenReturn(PACKAGE);
when(mPackageState.getInstallSource()).thenReturn(mInstallSource);
mPackageSetting = createBasicPackageSetting();
- when(mMockSystem.mocks().getSettings().getPackageLPr(eq(PACKAGE))).thenReturn(
+ when(rule.mocks().getSettings().getPackageLPr(eq(PACKAGE))).thenReturn(
mPackageSetting);
mUserState = new PackageUserStateImpl().setInstalled(true);
mPackageSetting.setUserState(mUserId, mUserState);
when(mPackageState.getUserStateOrDefault(eq(mUserId))).thenReturn(mUserState);
+
when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps);
when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn(
mLauncherActivityInfos);
doReturn(mComputer).when(pm).snapshotComputer();
when(mComputer.getPackageUid(eq(CALLER_PACKAGE), eq(0L), eq(mUserId))).thenReturn(
Binder.getCallingUid());
- mArchiveService = new PackageArchiverService(mContext, pm);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getResourcesForApplication(eq(PACKAGE))).thenReturn(
+ mock(Resources.class));
+ when(mIcon.compress(eq(Bitmap.CompressFormat.PNG), eq(100), any())).thenReturn(true);
+
+ mArchiveService = spy(new PackageArchiverService(mContext, pm));
+ doReturn(ICON_PATH).when(mArchiveService).storeIcon(eq(PACKAGE),
+ any(LauncherActivityInfo.class), eq(mUserId));
}
@Test
@@ -175,15 +194,20 @@
}
@Test
- public void archiveApp_packageNotInstalledForUser() {
+ public void archiveApp_packageNotInstalledForUser() throws IntentSender.SendIntentException {
mPackageSetting.modifyUserState(UserHandle.CURRENT.getIdentifier()).setInstalled(false);
- Exception e = assertThrows(
- ParcelableException.class,
- () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender,
- UserHandle.CURRENT));
- assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
- assertThat(e.getCause()).hasMessageThat().isEqualTo(
+ mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT);
+ rule.mocks().getHandler().flush();
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mIntentSender).sendIntent(any(), anyInt(), intentCaptor.capture(), any(), any(),
+ any(), any());
+ Intent value = intentCaptor.getValue();
+ assertThat(value.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME)).isEqualTo(PACKAGE);
+ assertThat(value.getIntExtra(PackageInstaller.EXTRA_STATUS, 0)).isEqualTo(
+ PackageInstaller.STATUS_FAILURE);
+ assertThat(value.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)).isEqualTo(
String.format("Package %s not found.", PACKAGE));
}
@@ -223,13 +247,34 @@
}
@Test
+ public void archiveApp_storeIconFails() throws IntentSender.SendIntentException, IOException {
+ IOException e = new IOException("IO");
+ doThrow(e).when(mArchiveService).storeIcon(eq(PACKAGE),
+ any(LauncherActivityInfo.class), eq(mUserId));
+
+ mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT);
+ rule.mocks().getHandler().flush();
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mIntentSender).sendIntent(any(), anyInt(), intentCaptor.capture(), any(), any(),
+ any(), any());
+ Intent value = intentCaptor.getValue();
+ assertThat(value.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME)).isEqualTo(PACKAGE);
+ assertThat(value.getIntExtra(PackageInstaller.EXTRA_STATUS, 0)).isEqualTo(
+ PackageInstaller.STATUS_FAILURE);
+ assertThat(value.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)).isEqualTo(
+ e.toString());
+ }
+
+ @Test
public void archiveApp_success() {
mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT);
+ rule.mocks().getHandler().flush();
verify(mInstallerService).uninstall(
eq(new VersionedPackage(PACKAGE, PackageManager.VERSION_CODE_HIGHEST)),
eq(CALLER_PACKAGE), eq(DELETE_KEEP_DATA), eq(mIntentSender),
- eq(UserHandle.CURRENT.getIdentifier()));
+ eq(UserHandle.CURRENT.getIdentifier()), anyInt());
assertThat(mPackageSetting.readUserState(
UserHandle.CURRENT.getIdentifier()).getArchiveState()).isEqualTo(
createArchiveState());
@@ -305,7 +350,7 @@
mUserState.setArchiveState(createArchiveState()).setInstalled(false);
mArchiveService.requestUnarchive(PACKAGE, CALLER_PACKAGE, UserHandle.CURRENT);
- mMockSystem.mocks().getHandler().flush();
+ rule.mocks().getHandler().flush();
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).sendOrderedBroadcastAsUser(
@@ -331,20 +376,22 @@
private static ArchiveState createArchiveState() {
List<ArchiveState.ArchiveActivityInfo> activityInfos = new ArrayList<>();
for (LauncherActivityInfo mainActivity : createLauncherActivities()) {
- // TODO(b/278553670) Extract and store launcher icons
ArchiveState.ArchiveActivityInfo activityInfo = new ArchiveState.ArchiveActivityInfo(
mainActivity.getLabel().toString(),
- Path.of("/TODO"), null);
+ ICON_PATH, null);
activityInfos.add(activityInfo);
}
return new ArchiveState(activityInfos, INSTALLER_PACKAGE);
}
private static List<LauncherActivityInfo> createLauncherActivities() {
+ ActivityInfo activityInfo = mock(ActivityInfo.class);
LauncherActivityInfo activity1 = mock(LauncherActivityInfo.class);
when(activity1.getLabel()).thenReturn("activity1");
+ when(activity1.getActivityInfo()).thenReturn(activityInfo);
LauncherActivityInfo activity2 = mock(LauncherActivityInfo.class);
when(activity2.getLabel()).thenReturn("activity2");
+ when(activity2.getActivityInfo()).thenReturn(activityInfo);
return List.of(activity1, activity2);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
index 94fff22..a3917765 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -55,6 +55,7 @@
@Mock
private InternalResourceService mIrs;
+ private Agent mAgent;
private Scribe mScribe;
private static class MockScribe extends Scribe {
@@ -80,10 +81,13 @@
doReturn(mIrs).when(mIrs).getLock();
doReturn(mock(AlarmManager.class)).when(mContext).getSystemService(Context.ALARM_SERVICE);
mScribe = new MockScribe(mIrs, mAnalyst);
+ mAgent = new Agent(mIrs, mScribe, mAnalyst);
}
@After
public void tearDown() {
+ mAgent.tearDownLocked();
+
if (mMockingSession != null) {
mMockingSession.finishMocking();
}
@@ -99,7 +103,6 @@
final int userId = 0;
final String pkgName = "com.test";
- final Agent agent = new Agent(mIrs, mScribe, mAnalyst);
final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
doReturn(consumptionLimit).when(mIrs).getConsumptionLimitLocked();
@@ -107,66 +110,64 @@
.getMaxSatiatedBalance(anyInt(), anyString());
Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 10);
- agent.recordTransactionLocked(userId, pkgName, ledger, transaction, false);
+ mAgent.recordTransactionLocked(userId, pkgName, ledger, transaction, false);
assertEquals(5, ledger.getCurrentBalance());
assertEquals(remainingCakes - 10, mScribe.getRemainingConsumableCakesLocked());
- agent.onPackageRemovedLocked(userId, pkgName);
+ mAgent.onPackageRemovedLocked(userId, pkgName);
assertEquals(remainingCakes - 10, mScribe.getRemainingConsumableCakesLocked());
assertLedgersEqual(new Ledger(), mScribe.getLedgerLocked(userId, pkgName));
}
@Test
public void testRecordTransaction_UnderMax() {
- Agent agent = new Agent(mIrs, mScribe, mAnalyst);
Ledger ledger = new Ledger();
doReturn(1_000_000L).when(mIrs).getConsumptionLimitLocked();
doReturn(1_000_000L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(5, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, 995, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(1000, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, -500, 250);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(500, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, 999_500L, 500);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(1_000_000L, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, -1_000_001L, 1000);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(-1, ledger.getCurrentBalance());
}
@Test
public void testRecordTransaction_MaxConsumptionLimit() {
- Agent agent = new Agent(mIrs, mScribe, mAnalyst);
Ledger ledger = new Ledger();
doReturn(1000L).when(mIrs).getConsumptionLimitLocked();
doReturn(1_000_000L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(5, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, 995, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(1000, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, -500, 250);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(500, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, 2000, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(2500, ledger.getCurrentBalance());
// ConsumptionLimit can change as the battery level changes. Ledger balances shouldn't be
@@ -174,57 +175,56 @@
doReturn(900L).when(mIrs).getConsumptionLimitLocked();
transaction = new Ledger.Transaction(0, 0, 0, null, 100, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(2600, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, -50, 50);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(2550, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, -200, 100);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(2350, ledger.getCurrentBalance());
doReturn(800L).when(mIrs).getConsumptionLimitLocked();
transaction = new Ledger.Transaction(0, 0, 0, null, 100, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(2450, ledger.getCurrentBalance());
}
@Test
public void testRecordTransaction_MaxSatiatedBalance() {
- Agent agent = new Agent(mIrs, mScribe, mAnalyst);
Ledger ledger = new Ledger();
doReturn(1_000_000L).when(mIrs).getConsumptionLimitLocked();
doReturn(1000L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(5, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, 995, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(1000, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, -500, 250);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(500, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, 999_500L, 1000);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(1_000, ledger.getCurrentBalance());
// Shouldn't change in normal operation, but adding test case in case it does.
doReturn(900L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
transaction = new Ledger.Transaction(0, 0, 0, null, 500, 0);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(1_000, ledger.getCurrentBalance());
transaction = new Ledger.Transaction(0, 0, 0, null, -1001, 500);
- agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+ mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
assertEquals(-1, ledger.getCurrentBalance());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
index 6c7b995..035bef6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
@@ -23,7 +23,14 @@
import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_CLASS_NAME;
import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_PACKAGE_NAME;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityGestureEvent;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -40,6 +47,7 @@
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArraySet;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -48,6 +56,8 @@
import android.view.accessibility.IAccessibilityManagerClient;
import android.view.inputmethod.EditorInfo;
+import androidx.test.InstrumentationRegistry;
+
import com.android.internal.R;
import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
@@ -58,20 +68,12 @@
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.wm.WindowManagerInternal;
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.InstrumentationRegistry;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@@ -87,6 +89,10 @@
private static final int DEVICE_ID = 10;
private static final int STREAMED_CALLING_UID = 9876;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+
@Mock private Context mMockContext;
@Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
@Mock private AccessibilityWindowManager mMockA11yWindowManager;
@@ -110,6 +116,8 @@
MockitoAnnotations.initMocks(this);
final Resources resources = InstrumentationRegistry.getContext().getResources();
+ mSetFlagsRule.enableFlags(Flags.FLAG_PROXY_USE_APPS_ON_VIRTUAL_DEVICE_LISTENER);
+
mFocusStrokeWidthDefaultValue =
resources.getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width);
mFocusColorDefaultValue = resources.getColor(R.color.accessibility_focus_highlight_color);
@@ -218,6 +226,39 @@
}
/**
+ * Tests that the manager's AppsOnVirtualDeviceListener implementation propagates the running
+ * app changes to the proxy device.
+ */
+ @Test
+ public void testUpdateProxyOfRunningAppsChange_changedUidIsStreamedApp_propagatesChange() {
+ final VirtualDeviceManagerInternal localVdm =
+ Mockito.mock(VirtualDeviceManagerInternal.class);
+ when(localVdm.getDeviceIdsForUid(anyInt())).thenReturn(new ArraySet(Set.of(DEVICE_ID)));
+
+ mProxyManager.setLocalVirtualDeviceManager(localVdm);
+ registerProxy(DISPLAY_ID);
+ verify(localVdm).registerAppsOnVirtualDeviceListener(any());
+
+ final ArraySet<Integer> runningUids = new ArraySet(Set.of(STREAMED_CALLING_UID));
+
+ // Flush any existing messages. The messages after this come from onProxyChanged.
+ mMessageCapturingHandler.sendAllMessages();
+
+ // The virtual device has been updated with the streamed app's UID, so the proxy is
+ // updated.
+ mProxyManager.notifyProxyOfRunningAppsChange(runningUids);
+
+ verify(localVdm).getDeviceIdsForUid(STREAMED_CALLING_UID);
+ verify(mMockProxySystemSupport).getCurrentUserClientsLocked();
+ verify(mMockProxySystemSupport).getGlobalClientsLocked();
+ // Messages to notify IAccessibilityManagerClients should be posted.
+ assertThat(mMessageCapturingHandler.hasMessages()).isTrue();
+
+ mProxyManager.unregisterProxy(DISPLAY_ID);
+ verify(localVdm).unregisterAppsOnVirtualDeviceListener(any());
+ }
+
+ /**
* Tests that getting the first device id for an app uid, such as when an app queries for
* device-specific state, returns the right device id.
*/
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
index 0b730f1..fa6e7f6 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
@@ -115,6 +115,11 @@
// Assert that the user doesn't exist in the map initially.
assertThat(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1)).isNull();
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
mAuthenticationStatsCollector.authenticate(USER_ID_1, true /* authenticated */);
AuthenticationStats authenticationStats =
@@ -130,6 +135,11 @@
// Assert that the user doesn't exist in the map initially.
assertThat(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1)).isNull();
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
AuthenticationStats authenticationStats =
@@ -176,6 +186,11 @@
40 /* rejectedAttempts */, 0 /* enrollmentNotifications */,
0 /* modality */));
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
// Assert that no notification should be sent.
@@ -233,13 +248,13 @@
// Assert that no notification should be sent.
verify(mBiometricNotification, never()).sendFaceEnrollNotification(any());
verify(mBiometricNotification, never()).sendFpEnrollNotification(any());
- // Assert that data has been reset.
+ // Assert that data hasn't been reset.
AuthenticationStats authenticationStats = mAuthenticationStatsCollector
.getAuthenticationStatsForUser(USER_ID_1);
- assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
- assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(500);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(400);
assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0);
- assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(0.8f);
}
@Test
@@ -260,13 +275,13 @@
// Assert that no notification should be sent.
verify(mBiometricNotification, never()).sendFaceEnrollNotification(any());
verify(mBiometricNotification, never()).sendFpEnrollNotification(any());
- // Assert that data has been reset.
+ // Assert that data hasn't been reset.
AuthenticationStats authenticationStats = mAuthenticationStatsCollector
.getAuthenticationStatsForUser(USER_ID_1);
- assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
- assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(500);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(400);
assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0);
- assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(0.8f);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index 78655a5..c40ad28 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -79,9 +79,9 @@
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
/* allowedUsers= */ new ArraySet<>(),
/* activityLaunchAllowedByDefault= */ true,
- /* activityPolicyExceptions= */ new ArraySet<>(),
+ /* activityPolicyExemptions= */ new ArraySet<>(),
/* crossTaskNavigationAllowedByDefault= */ true,
- /* crossTaskNavigationExceptions= */ new ArraySet<>(),
+ /* crossTaskNavigationExemptions= */ new ArraySet<>(),
/* activityListener= */ null,
/* pipBlockedCallback= */ null,
/* activityBlockedCallback= */ null,
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index 2273fcd..9f75cf8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -113,6 +113,42 @@
assertUserInfoEquals(data.info, read.info, /* parcelCopy= */ false);
}
+ /** Tests that device policy restrictions are written/read properly. */
+ @Test
+ public void testWriteReadDevicePolicyUserRestrictions() throws Exception {
+ final String globalRestriction = UserManager.DISALLOW_FACTORY_RESET;
+ final String localRestriction = UserManager.DISALLOW_CONFIG_DATE_TIME;
+
+ UserData data = new UserData();
+ data.info = createUser(100, FLAG_FULL, "A type");
+
+ mUserManagerService.putUserInfo(data.info);
+
+ // Set a global and user restriction so they get written out to the user file.
+ setUserRestrictions(data.info.id, globalRestriction, localRestriction, true);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(baos);
+ mUserManagerService.writeUserLP(data, out);
+ byte[] bytes = baos.toByteArray();
+
+ // Clear the restrictions to see if they are properly read in from the user file.
+ setUserRestrictions(data.info.id, globalRestriction, localRestriction, false);
+
+ mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(bytes));
+ assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(globalRestriction));
+ assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(localRestriction));
+ }
+
+ /** Sets a global and local restriction and verifies they were set properly **/
+ private void setUserRestrictions(int id, String global, String local, boolean enabled) {
+ mUserManagerService.setUserRestrictionInner(UserHandle.USER_ALL, global, enabled);
+ assertEquals(mUserManagerService.hasUserRestrictionOnAnyUser(global), enabled);
+
+ mUserManagerService.setUserRestrictionInner(id, local, enabled);
+ assertEquals(mUserManagerService.hasUserRestrictionOnAnyUser(local), enabled);
+ }
+
@Test
public void testParcelUnparcelUserInfo() throws Exception {
UserInfo info = createUser();
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index b22798e..5dfce06 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -326,24 +326,6 @@
assertThat(hasUser(user2.id)).isTrue();
}
-
- @MediumTest
- @Test
- public void testGetFullUserCount() throws Exception {
- assertThat(mUserManager.getFullUserCount()).isEqualTo(1);
- UserInfo user1 = createUser("User 1", UserInfo.FLAG_FULL);
- UserInfo user2 = createUser("User 2", UserInfo.FLAG_ADMIN);
-
- assertThat(user1).isNotNull();
- assertThat(user2).isNotNull();
-
- assertThat(mUserManager.getFullUserCount()).isEqualTo(3);
- removeUser(user1.id);
- assertThat(mUserManager.getFullUserCount()).isEqualTo(2);
- removeUser(user2.id);
- assertThat(mUserManager.getFullUserCount()).isEqualTo(1);
- }
-
/**
* Tests that UserManager knows how many users can be created.
*
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index c25f0cb..0eec9cd 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -89,6 +89,7 @@
import android.view.InputDevice;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.FrameworkStatsLog;
@@ -834,6 +835,7 @@
eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString());
}
+ @FlakyTest
@Test
public void vibrate_withOngoingRepeatingVibration_ignoresEffect() throws Exception {
mockVibrators(1);
@@ -920,6 +922,7 @@
cancelVibrate(service); // Clean up repeating effect.
}
+ @FlakyTest
@Test
public void vibrate_withNewSameImportanceVibrationButOngoingIsRepeating_ignoreNewVibration()
throws Exception {
@@ -973,6 +976,7 @@
cancelVibrate(service); // Clean up repeating effect.
}
+ @FlakyTest
@Test
public void vibrate_withNewUnknownUsageVibrationAndNotRepeating_ignoreNewVibration()
throws Exception {
@@ -1764,6 +1768,7 @@
cancelVibrate(service); // Clean up long effect.
}
+ @FlakyTest
@Test
public void onExternalVibration_withNewSameImportanceButRepeating_cancelsOngoingVibration()
throws Exception {
diff --git a/services/tests/wmtests/src/com/android/server/wm/CompatScaleProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/CompatScaleProviderTest.java
new file mode 100644
index 0000000..96e3cb1
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/CompatScaleProviderTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+
+/**
+ * Tests for the {@link CompatScaleProvider} interface.
+ * See {@link CompatModePackages} class for implementation.
+ *
+ * Build/Install/Run:
+ * atest WmTests:CompatScaleProviderTest
+ */
+@SmallTest
+@Presubmit
+public class CompatScaleProviderTest extends SystemServiceTestsBase {
+ private static final String TEST_PACKAGE = "compat.mode.packages";
+ static final int TEST_USER_ID = 1;
+
+ private ActivityTaskManagerService mAtm;
+
+ /**
+ * setup method before every test.
+ */
+ @Before
+ public void setUp() {
+ mAtm = mSystemServicesTestRule.getActivityTaskManagerService();
+ }
+
+ /**
+ * Registering a {@link CompatScaleProvider} with an invalid id should throw an exception.
+ */
+ @Test
+ public void registerCompatScaleProviderWithInvalidId() {
+ CompatScaleProvider compatScaleProvider = mock(CompatScaleProvider.class);
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> mAtm.registerCompatScaleProvider(-1, compatScaleProvider)
+ );
+ }
+
+ /**
+ * Registering a {@code null} {@link CompatScaleProvider} should throw an exception.
+ */
+ @Test
+ public void registerCompatScaleProviderFailIfCallbackIsNull() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> mAtm.registerCompatScaleProvider(
+ CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT, null)
+ );
+ }
+
+ /**
+ * Registering a {@link CompatScaleProvider} with a already registered id should throw an
+ * exception.
+ */
+ @Test
+ public void registerCompatScaleProviderFailIfIdIsAlreadyRegistered() {
+ CompatScaleProvider compatScaleProvider = mock(CompatScaleProvider.class);
+ mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT,
+ compatScaleProvider);
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> mAtm.registerCompatScaleProvider(
+ CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT, compatScaleProvider)
+ );
+ mAtm.unregisterCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT);
+ }
+
+ /**
+ * Successfully registering a {@link CompatScaleProvider} with should result in callbacks
+ * getting called.
+ */
+ @Test
+ public void registerCompatScaleProviderSuccessfully() {
+ CompatScaleProvider compatScaleProvider = mock(CompatScaleProvider.class);
+ mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT,
+ compatScaleProvider);
+ mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID);
+ verify(compatScaleProvider, times(1)).getCompatScale(TEST_PACKAGE, TEST_USER_ID);
+ mAtm.unregisterCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT);
+ }
+
+ /**
+ * Unregistering a {@link CompatScaleProvider} with a unregistered id should throw an exception.
+ */
+ @Test
+ public void unregisterCompatScaleProviderFailIfIdNotRegistered() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> mAtm.unregisterCompatScaleProvider(
+ CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT)
+ );
+ }
+
+ /**
+ * Unregistering a {@link CompatScaleProvider} with an invalid id should throw an exception.
+ */
+ @Test
+ public void unregisterCompatScaleProviderFailIfIdNotInRange() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> mAtm.unregisterCompatScaleProvider(-1)
+ );
+ }
+
+ /**
+ * Successfully unregistering a {@link CompatScaleProvider} should stop the callbacks from
+ * getting called.
+ */
+ @Test
+ public void unregisterCompatScaleProviderSuccessfully() {
+ CompatScaleProvider compatScaleProvider = mock(CompatScaleProvider.class);
+ mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT,
+ compatScaleProvider);
+ mAtm.unregisterCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT);
+ mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID);
+ verify(compatScaleProvider, never()).getCompatScale(TEST_PACKAGE, TEST_USER_ID);
+ }
+
+ /**
+ * Order of calling {@link CompatScaleProvider} is same as the id that was used for
+ * registering it.
+ */
+ @Test
+ public void registerCompatScaleProviderRespectsOrderId() {
+ CompatScaleProvider gameModeCompatScaleProvider = mock(CompatScaleProvider.class);
+ CompatScaleProvider productCompatScaleProvider = mock(CompatScaleProvider.class);
+ mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_GAME,
+ gameModeCompatScaleProvider);
+ mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT,
+ productCompatScaleProvider);
+ mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID);
+ InOrder inOrder = inOrder(gameModeCompatScaleProvider, productCompatScaleProvider);
+ inOrder.verify(gameModeCompatScaleProvider).getCompatScale(TEST_PACKAGE, TEST_USER_ID);
+ inOrder.verify(productCompatScaleProvider).getCompatScale(TEST_PACKAGE, TEST_USER_ID);
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index c84eab3..622e81e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -77,6 +79,7 @@
@RunWith(WindowTestRunner.class)
public class ContentRecorderTests extends WindowTestsBase {
private static IBinder sTaskWindowContainerToken;
+ private DisplayContent mVirtualDisplayContent;
private Task mTask;
private final ContentRecordingSession mDisplaySession =
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
@@ -107,11 +110,11 @@
displayInfo.logicalWidth = sSurfaceSize.x;
displayInfo.logicalHeight = sSurfaceSize.y;
displayInfo.state = STATE_ON;
- final DisplayContent virtualDisplayContent = createNewDisplay(displayInfo);
- final int displayId = virtualDisplayContent.getDisplayId();
- mContentRecorder = new ContentRecorder(virtualDisplayContent,
+ mVirtualDisplayContent = createNewDisplay(displayInfo);
+ final int displayId = mVirtualDisplayContent.getDisplayId();
+ mContentRecorder = new ContentRecorder(mVirtualDisplayContent,
mMediaProjectionManagerWrapper);
- spyOn(virtualDisplayContent);
+ spyOn(mVirtualDisplayContent);
// GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
// record.
@@ -119,7 +122,7 @@
mDisplaySession.setDisplayToRecord(mDefaultDisplay.mDisplayId);
// GIVEN there is a window token associated with a task to record.
- sTaskWindowContainerToken = setUpTaskWindowContainerToken(virtualDisplayContent);
+ sTaskWindowContainerToken = setUpTaskWindowContainerToken(mVirtualDisplayContent);
mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
mTaskSession.setVirtualDisplayId(displayId);
@@ -252,7 +255,11 @@
public void testOnConfigurationChanged_resizesSurface() {
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
- mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
+ // Ensure a different orientation when we check if something has changed.
+ @Configuration.Orientation final int lastOrientation =
+ mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ mContentRecorder.onConfigurationChanged(lastOrientation);
verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
anyFloat());
@@ -261,12 +268,53 @@
}
@Test
+ public void testOnConfigurationChanged_resizesVirtualDisplay() {
+ final int newWidth = 55;
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+
+ // The user rotates the device, so the host app resizes the virtual display for the capture.
+ resizeDisplay(mDisplayContent, newWidth, sSurfaceSize.y);
+ resizeDisplay(mVirtualDisplayContent, newWidth, sSurfaceSize.y);
+ mContentRecorder.onConfigurationChanged(mDisplayContent.getConfiguration().orientation);
+
+ verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
+ anyFloat());
+ verify(mTransaction, atLeast(2)).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
+ anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testOnConfigurationChanged_rotateVirtualDisplay() {
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+
+ // Change a value that we shouldn't rely upon; it has the wrong type.
+ mVirtualDisplayContent.setOverrideOrientation(SCREEN_ORIENTATION_FULL_SENSOR);
+ mContentRecorder.onConfigurationChanged(
+ mVirtualDisplayContent.getConfiguration().orientation);
+
+ // No resize is issued, only the initial transformations when we started recording.
+ verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(),
+ anyFloat());
+ verify(mTransaction).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
+ anyFloat(), anyFloat());
+ }
+
+ @Test
public void testOnTaskOrientationConfigurationChanged_resizesSurface() {
mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
Configuration config = mTask.getConfiguration();
- config.orientation = ORIENTATION_PORTRAIT;
+ // Ensure a different orientation when we compare.
+ @Configuration.Orientation final int orientation =
+ config.orientation == ORIENTATION_PORTRAIT ? ORIENTATION_LANDSCAPE
+ : ORIENTATION_PORTRAIT;
+ final Rect lastBounds = config.windowConfiguration.getBounds();
+ config.orientation = orientation;
+ config.windowConfiguration.setBounds(
+ new Rect(0, 0, lastBounds.height(), lastBounds.width()));
mTask.onConfigurationChanged(config);
verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
@@ -279,13 +327,15 @@
public void testOnTaskBoundsConfigurationChanged_notifiesCallback() {
mTask.getRootTask().setWindowingMode(WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
+ final int minWidth = 222;
+ final int minHeight = 777;
final int recordedWidth = 333;
final int recordedHeight = 999;
final ActivityInfo info = new ActivityInfo();
info.windowLayout = new ActivityInfo.WindowLayout(-1 /* width */,
-1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */,
- Gravity.NO_GRAVITY, recordedWidth, recordedHeight);
+ Gravity.NO_GRAVITY, minWidth, minHeight);
mTask.setMinDimensions(info);
// WHEN a recording is ongoing.
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 994dcf1..ffa1ed9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -23,8 +23,6 @@
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
@@ -108,7 +106,7 @@
@Test
public void testControlsForDispatch_forceStatusBarVisible() {
- addStatusBar().mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
+ addStatusBar().mAttrs.forciblyShownTypes |= statusBars();
addNavigationBar();
final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
@@ -120,8 +118,8 @@
@Test
public void testControlsForDispatch_statusBarForceShowNavigation() {
- addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade").mAttrs.privateFlags |=
- PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade").mAttrs.forciblyShownTypes |=
+ navigationBars();
addStatusBar();
addNavigationBar();
@@ -135,7 +133,7 @@
@Test
public void testControlsForDispatch_statusBarForceShowNavigation_butFocusedAnyways() {
WindowState notifShade = addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade");
- notifShade.mAttrs.privateFlags |= PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ notifShade.mAttrs.forciblyShownTypes |= navigationBars();
addNavigationBar();
mDisplayContent.getInsetsPolicy().updateBarControlTarget(notifShade);
@@ -329,6 +327,7 @@
addNavigationBar().getControllableInsetProvider().getSource();
statusBarSource.setVisible(false);
navBarSource.setVisible(false);
+ mAppWindow.setRequestedVisibleTypes(0, navigationBars() | statusBars());
mAppWindow.mAboveInsetsState.addSource(navBarSource);
mAppWindow.mAboveInsetsState.addSource(statusBarSource);
final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
@@ -389,6 +388,50 @@
assertFalse(policy.isTransient(navigationBars()));
}
+ @Test
+ public void testFakeControlTarget_overrideVisibilityReceivedByWindows() {
+ final WindowState statusBar = addStatusBar();
+ final InsetsSourceProvider statusBarProvider = statusBar.getControllableInsetProvider();
+ statusBar.mSession.mCanForceShowingInsets = true;
+ statusBar.setHasSurface(true);
+ statusBarProvider.setServerVisible(true);
+
+ final InsetsSource statusBarSource = statusBarProvider.getSource();
+ final int statusBarId = statusBarSource.getId();
+ assertTrue(statusBarSource.isVisible());
+
+ final WindowState app1 = addWindow(TYPE_APPLICATION, "app1");
+ app1.mAboveInsetsState.addSource(statusBarSource);
+ assertTrue(app1.getInsetsState().peekSource(statusBarId).isVisible());
+
+ final WindowState app2 = addWindow(TYPE_APPLICATION, "app2");
+ app2.mAboveInsetsState.addSource(statusBarSource);
+ assertTrue(app2.getInsetsState().peekSource(statusBarId).isVisible());
+
+ app2.setRequestedVisibleTypes(0, navigationBars() | statusBars());
+ mDisplayContent.getInsetsPolicy().updateBarControlTarget(app2);
+ waitUntilWindowAnimatorIdle();
+
+ // app2 is the real control target now. It can override the visibility of all sources that
+ // it controls.
+ assertFalse(statusBarSource.isVisible());
+ assertFalse(app1.getInsetsState().peekSource(statusBarId).isVisible());
+ assertFalse(app2.getInsetsState().peekSource(statusBarId).isVisible());
+
+ statusBar.mAttrs.forciblyShownTypes = statusBars();
+ mDisplayContent.getDisplayPolicy().applyPostLayoutPolicyLw(
+ statusBar, statusBar.mAttrs, null, null);
+ mDisplayContent.getInsetsPolicy().updateBarControlTarget(app2);
+ waitUntilWindowAnimatorIdle();
+
+ // app2 is the fake control target now. It can only override the visibility of sources
+ // received by windows, but not the raw source.
+ assertTrue(statusBarSource.isVisible());
+ assertFalse(app1.getInsetsState().peekSource(statusBarId).isVisible());
+ assertFalse(app2.getInsetsState().peekSource(statusBarId).isVisible());
+
+ }
+
private WindowState addNavigationBar() {
final Binder owner = new Binder();
final WindowState win = createWindow(null, TYPE_NAVIGATION_BAR, "navBar");
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 114796d..2085d61 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -367,9 +367,11 @@
doReturn(rotatedState).when(app.mToken).getFixedRotationTransformInsetsState();
assertTrue(rotatedState.isSourceOrDefaultVisible(ID_STATUS_BAR, statusBars()));
- provider.getSource().setVisible(false);
+ app.setRequestedVisibleTypes(0, statusBars());
+ mDisplayContent.getInsetsPolicy().updateBarControlTarget(app);
mDisplayContent.getInsetsPolicy().showTransient(statusBars(),
true /* isGestureOnSystemBar */);
+ waitUntilWindowAnimatorIdle();
assertTrue(mDisplayContent.getInsetsPolicy().isTransient(statusBars()));
assertFalse(app.getInsetsState().isSourceOrDefaultVisible(ID_STATUS_BAR, statusBars()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 0cdd9b8..8f68c0f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -112,6 +112,7 @@
import android.view.WindowInsets;
import android.view.WindowManager;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.internal.policy.SystemBarUtils;
@@ -2361,6 +2362,7 @@
}
@Test
+ @FlakyTest(bugId = 299220009)
public void testUserOverrideAspectRatioNotEnabled() {
setUpDisplaySizeWithApp(/* dw */ 1600, /* dh */ 1400);
@@ -2409,8 +2411,9 @@
.setUid(android.os.Process.myUid())
.build();
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- activity.mWmService.mLetterboxConfiguration
- .setUserAppAspectRatioSettingsOverrideEnabled(enabled);
+ spyOn(activity.mWmService.mLetterboxConfiguration);
+ doReturn(enabled).when(activity.mWmService.mLetterboxConfiguration)
+ .isUserAppAspectRatioSettingsEnabled();
// Set user aspect ratio override
final IPackageManager pm = mAtm.getPackageManager();
try {
@@ -4249,6 +4252,7 @@
// Set up a display in landscape with a fixed-orientation PORTRAIT app
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setIsAutomaticReachabilityInBookModeEnabled(false);
mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f);
prepareUnresizable(mActivity, 1.75f, SCREEN_ORIENTATION_PORTRAIT);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index f1c5865..b028b47 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -22,6 +22,7 @@
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.os.Build;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1567,6 +1568,13 @@
}
}
+ void deleteDataFor(String pkg) {
+ // reuse the existing prune method to delete data for the specified package.
+ // we'll use the current timestamp so that all events before now get pruned.
+ prunePackagesDataOnUpgrade(
+ new HashMap<>(Collections.singletonMap(pkg, SystemClock.elapsedRealtime())));
+ }
+
IntervalStats readIntervalStatsForFile(int interval, long fileName) {
synchronized (mLock) {
final IntervalStats stats = new IntervalStats();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 90b798c..7db32a9 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2043,6 +2043,12 @@
mAppStandby.clearLastUsedTimestampsForTest(packageName, userId);
}
+ void deletePackageData(@NonNull String packageName, @UserIdInt int userId) {
+ synchronized (mLock) {
+ mUserState.get(userId).deleteDataFor(packageName);
+ }
+ }
+
private final class BinderService extends IUsageStatsManager.Stub {
private boolean hasPermission(String callingPackage) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java b/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java
index 772b22a..4cb31f9 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java
@@ -38,6 +38,8 @@
switch (cmd) {
case "clear-last-used-timestamps":
return runClearLastUsedTimestamps();
+ case "delete-package-data":
+ return deletePackageData();
default:
return handleDefaultCommands(cmd);
}
@@ -51,14 +53,38 @@
pw.println(" Print this help text.");
pw.println();
pw.println("clear-last-used-timestamps PACKAGE_NAME [-u | --user USER_ID]");
- pw.println(" Clears any existing usage data for the given package.");
+ pw.println(" Clears the last used timestamps for the given package.");
+ pw.println();
+ pw.println("delete-package-data PACKAGE_NAME [-u | --user USER_ID]");
+ pw.println(" Deletes all the usage stats for the given package.");
pw.println();
}
@SuppressLint("AndroidFrameworkRequiresPermission")
private int runClearLastUsedTimestamps() {
final String packageName = getNextArgRequired();
+ final int userId = getUserId();
+ if (userId == -1) {
+ return -1;
+ }
+ mService.clearLastUsedTimestamps(packageName, userId);
+ return 0;
+ }
+
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ private int deletePackageData() {
+ final String packageName = getNextArgRequired();
+ final int userId = getUserId();
+ if (userId == -1) {
+ return -1;
+ }
+
+ mService.deletePackageData(packageName, userId);
+ return 0;
+ }
+
+ private int getUserId() {
int userId = UserHandle.USER_CURRENT;
String opt;
while ((opt = getNextOption()) != null) {
@@ -72,8 +98,6 @@
if (userId == UserHandle.USER_CURRENT) {
userId = ActivityManager.getCurrentUser();
}
-
- mService.clearLastUsedTimestamps(packageName, userId);
- return 0;
+ return userId;
}
}
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index fd56b6e..7d2e1a4 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -974,6 +974,10 @@
mDatabase.dumpMappings(ipw);
}
+ void deleteDataFor(String pkg) {
+ mDatabase.deleteDataFor(pkg);
+ }
+
void dumpFile(IndentingPrintWriter ipw, String[] args) {
if (args == null || args.length == 0) {
// dump all files for every interval for specified user
diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp
index a1b888a..c216bce 100644
--- a/tests/TrustTests/Android.bp
+++ b/tests/TrustTests/Android.bp
@@ -25,6 +25,7 @@
"androidx.test.rules",
"androidx.test.ext.junit",
"androidx.test.uiautomator_uiautomator",
+ "flag-junit",
"mockito-target-minus-junit4",
"servicestests-utils",
"truth-prebuilt",
diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
index f864fed..1dfd5c0 100644
--- a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
@@ -16,6 +16,10 @@
package android.trust.test
+import android.content.pm.PackageManager
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.service.trust.GrantTrustResult
import android.trust.BaseTrustAgentService
import android.trust.TrustTestActivity
@@ -27,6 +31,7 @@
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.uiautomator.UiDevice
import com.android.server.testutils.mock
+import org.junit.Assume.assumeFalse
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -45,6 +50,7 @@
private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
private val lockStateTrackingRule = LockStateTrackingRule()
private val trustAgentRule = TrustAgentRule<GrantAndRevokeTrustAgent>()
+ private val packageManager = getInstrumentation().getTargetContext().getPackageManager()
@get:Rule
val rule: RuleChain = RuleChain
@@ -52,6 +58,7 @@
.around(ScreenLockRule())
.around(lockStateTrackingRule)
.around(trustAgentRule)
+ .around(DeviceFlagsValueProvider.createCheckFlagsRule())
@Before
fun manageTrust() {
@@ -72,7 +79,7 @@
trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {}
uiDevice.sleep()
- lockStateTrackingRule.assertUnlocked()
+ lockStateTrackingRule.assertUnlockedAndTrusted()
}
@Test
@@ -86,6 +93,51 @@
}
@Test
+ @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS)
+ fun grantCannotActivelyUnlockDevice() {
+ // On automotive, trust agents can actively unlock the device.
+ assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
+
+ // Lock the device.
+ uiDevice.sleep()
+ lockStateTrackingRule.assertLocked()
+
+ // Grant trust.
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {}
+
+ // The grant should not have unlocked the device. Wait a bit so that
+ // TrustManagerService probably will have finished processing the grant.
+ await()
+ lockStateTrackingRule.assertLocked()
+
+ // Turn the screen on and off to cause TrustManagerService to refresh
+ // its deviceLocked state. Then verify the state is still locked. This
+ // part failed before the fix for b/296464083.
+ uiDevice.wakeUp()
+ uiDevice.sleep()
+ await()
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ @RequiresFlagsDisabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS)
+ fun grantCouldCauseWrongDeviceLockedStateDueToBug() {
+ // On automotive, trust agents can actively unlock the device.
+ assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
+
+ // Verify that b/296464083 exists. That is, when the device is locked
+ // and a trust agent grants trust, the deviceLocked state incorrectly
+ // becomes false even though the device correctly remains locked.
+ uiDevice.sleep()
+ lockStateTrackingRule.assertLocked()
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {}
+ uiDevice.wakeUp()
+ uiDevice.sleep()
+ await()
+ lockStateTrackingRule.assertUnlockedButNotReally()
+ }
+
+ @Test
fun grantDoesNotCallBack() {
val callback = mock<(GrantTrustResult) -> Unit>()
trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0, callback)
diff --git a/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
index ae72247..96362b8 100644
--- a/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
@@ -102,7 +102,7 @@
trustAgentRule.agent.grantTrust(
GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
- lockStateTrackingRule.assertUnlocked()
+ lockStateTrackingRule.assertUnlockedAndTrusted()
}
@Test
@@ -125,7 +125,7 @@
Log.i(TAG, "Callback received; status=${it.status}")
result = it
}
- lockStateTrackingRule.assertUnlocked()
+ lockStateTrackingRule.assertUnlockedAndTrusted()
wait("callback triggered") { result?.status == STATUS_UNLOCKED_BY_GRANT }
}
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index c1a7bd9..5a8f828 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -16,6 +16,7 @@
package android.trust.test.lib
+import android.app.KeyguardManager
import android.app.trust.TrustManager
import android.content.Context
import android.util.Log
@@ -26,18 +27,23 @@
import org.junit.runners.model.Statement
/**
- * Rule for tracking the lock state of the device based on events emitted to [TrustListener].
+ * Rule for tracking the trusted state of the device based on events emitted to
+ * [TrustListener]. Provides helper methods for verifying that the trusted
+ * state has a particular value and is consistent with (a) the keyguard "locked"
+ * (i.e. showing) value when applicable, and (b) the device locked value that is
+ * tracked by TrustManagerService and is queryable via KeyguardManager.
*/
class LockStateTrackingRule : TestRule {
private val context: Context = getApplicationContext()
private val windowManager = checkNotNull(WindowManagerGlobal.getWindowManagerService())
+ private val keyguardManager = context.getSystemService(KeyguardManager::class.java) as KeyguardManager
- @Volatile lateinit var lockState: LockState
+ @Volatile lateinit var trustState: TrustState
private set
override fun apply(base: Statement, description: Description) = object : Statement() {
override fun evaluate() {
- lockState = LockState(locked = windowManager.isKeyguardLocked)
+ trustState = TrustState()
val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager
val listener = Listener()
@@ -51,12 +57,25 @@
}
fun assertLocked() {
- wait("un-locked per TrustListener") { lockState.locked == true }
- wait("keyguard lock") { windowManager.isKeyguardLocked }
+ wait("device locked") { keyguardManager.isDeviceLocked }
+ // isDeviceLocked implies isKeyguardLocked && !trusted.
+ wait("keyguard locked") { windowManager.isKeyguardLocked }
+ wait("not trusted") { trustState.trusted == false }
}
- fun assertUnlocked() {
- wait("locked per TrustListener") { lockState.locked == false }
+ // TODO(b/299298338) remove this when removing FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS
+ fun assertUnlockedButNotReally() {
+ wait("device unlocked") { !keyguardManager.isDeviceLocked }
+ wait("not trusted") { trustState.trusted == false }
+ wait("keyguard locked") { windowManager.isKeyguardLocked }
+ }
+
+ fun assertUnlockedAndTrusted() {
+ wait("device unlocked") { !keyguardManager.isDeviceLocked }
+ wait("trusted") { trustState.trusted == true }
+ // Can't check for !isKeyguardLocked here, since isKeyguardLocked
+ // returns true in the case where the keyguard is dismissible with
+ // swipe, which is considered "device unlocked"!
}
inner class Listener : TestTrustListener() {
@@ -68,12 +87,12 @@
trustGrantedMessages: MutableList<String>
) {
Log.d(TAG, "Device became trusted=$enabled")
- lockState = lockState.copy(locked = !enabled)
+ trustState = trustState.copy(trusted=enabled)
}
}
- data class LockState(
- val locked: Boolean? = null
+ data class TrustState(
+ val trusted: Boolean? = null
)
companion object {
diff --git a/tools/aapt/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp
index 5339285..6886993 100644
--- a/tools/aapt/ZipEntry.cpp
+++ b/tools/aapt/ZipEntry.cpp
@@ -18,6 +18,8 @@
// Access to entries in a Zip archive.
//
+#define _POSIX_THREAD_SAFE_FUNCTIONS // For mingw localtime_r().
+
#define LOG_TAG "zip"
#include "ZipEntry.h"
@@ -337,39 +339,26 @@
/*
* Set the CDE/LFH timestamp from UNIX time.
*/
-void ZipEntry::setModWhen(time_t when)
-{
-#if !defined(_WIN32)
- struct tm tmResult;
-#endif
- time_t even;
- unsigned short zdate, ztime;
-
- struct tm* ptm;
-
+void ZipEntry::setModWhen(time_t when) {
/* round up to an even number of seconds */
- even = (time_t)(((unsigned long)(when) + 1) & (~1));
+ time_t even = (time_t)(((unsigned long)(when) + 1) & (~1));
/* expand */
-#if !defined(_WIN32)
- ptm = localtime_r(&even, &tmResult);
-#else
- ptm = localtime(&even);
-#endif
+ struct tm tmResult;
+ struct tm* ptm = localtime_r(&even, &tmResult);
int year;
year = ptm->tm_year;
if (year < 80)
year = 80;
- zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
- ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
+ unsigned short zdate = (year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday;
+ unsigned short ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
}
-
/*
* ===========================================================================
* ZipEntry::LocalFileHeader
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.h b/tools/aapt2/compile/InlineXmlFormatParser.h
index 4300023..3a5161b 100644
--- a/tools/aapt2/compile/InlineXmlFormatParser.h
+++ b/tools/aapt2/compile/InlineXmlFormatParser.h
@@ -21,8 +21,8 @@
#include <vector>
#include "android-base/macros.h"
-
#include "process/IResourceTableConsumer.h"
+#include "xml/XmlDom.h"
namespace aapt {
diff --git a/tools/aapt2/format/Archive_test.cpp b/tools/aapt2/format/Archive_test.cpp
index 3c44da7..fd50af9 100644
--- a/tools/aapt2/format/Archive_test.cpp
+++ b/tools/aapt2/format/Archive_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <stdlib.h>
+
#include "test/Test.h"
namespace aapt {
@@ -34,6 +36,29 @@
std::string error_;
};
+class TzSetter {
+ public:
+ explicit TzSetter(const std::string& new_tz) {
+ old_tz_ = getenv("TZ");
+ new_tz_ = "TZ=" + new_tz;
+ putenv(const_cast<char*>(new_tz_.c_str()));
+ tzset();
+ }
+
+ ~TzSetter() {
+ if (old_tz_) {
+ putenv(old_tz_);
+ } else {
+ putenv(const_cast<char*>("TZ"));
+ }
+ tzset();
+ }
+
+ private:
+ char* old_tz_;
+ std::string new_tz_;
+};
+
std::unique_ptr<uint8_t[]> MakeTestArray() {
auto array = std::make_unique<uint8_t[]>(kTestDataLength);
for (int index = 0; index < kTestDataLength; ++index) {
@@ -86,6 +111,22 @@
}
}
+void VerifyZipFileTimestamps(const std::string& output_path) {
+ std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(output_path, nullptr);
+ auto it = zip->Iterator();
+ while (it->HasNext()) {
+ auto file = it->Next();
+ struct tm modification_time;
+ ASSERT_TRUE(file->GetModificationTime(&modification_time));
+ EXPECT_EQ(modification_time.tm_year, 80);
+ EXPECT_EQ(modification_time.tm_mon, 0);
+ EXPECT_EQ(modification_time.tm_mday, 1);
+ EXPECT_EQ(modification_time.tm_hour, 0);
+ EXPECT_EQ(modification_time.tm_min, 0);
+ EXPECT_EQ(modification_time.tm_sec, 0);
+ }
+}
+
TEST_F(ArchiveTest, DirectoryWriteEntrySuccess) {
std::string output_path = GetTestPath("output");
std::unique_ptr<IArchiveWriter> writer = MakeDirectoryWriter(output_path);
@@ -206,4 +247,73 @@
ASSERT_EQ("ZipFileWriteFileError", writer->GetError());
}
+TEST_F(ArchiveTest, ZipFileTimeZoneUTC) {
+ TzSetter tz("UTC0");
+ std::string output_path = GetTestPath("output.apk");
+ std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path);
+ std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
+ std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
+
+ ASSERT_TRUE(writer->StartEntry("test1", 0));
+ ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength));
+ ASSERT_TRUE(writer->FinishEntry());
+ ASSERT_FALSE(writer->HadError());
+
+ ASSERT_TRUE(writer->StartEntry("test2", 0));
+ ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength));
+ ASSERT_TRUE(writer->FinishEntry());
+ ASSERT_FALSE(writer->HadError());
+
+ writer.reset();
+
+ // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832
+ VerifyZipFileTimestamps(output_path);
+}
+
+TEST_F(ArchiveTest, ZipFileTimeZoneWestOfUTC) {
+ TzSetter tz("PST8");
+ std::string output_path = GetTestPath("output.apk");
+ std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path);
+ std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
+ std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
+
+ ASSERT_TRUE(writer->StartEntry("test1", 0));
+ ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength));
+ ASSERT_TRUE(writer->FinishEntry());
+ ASSERT_FALSE(writer->HadError());
+
+ ASSERT_TRUE(writer->StartEntry("test2", 0));
+ ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength));
+ ASSERT_TRUE(writer->FinishEntry());
+ ASSERT_FALSE(writer->HadError());
+
+ writer.reset();
+
+ // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832
+ VerifyZipFileTimestamps(output_path);
+}
+
+TEST_F(ArchiveTest, ZipFileTimeZoneEastOfUTC) {
+ TzSetter tz("EET-2");
+ std::string output_path = GetTestPath("output.apk");
+ std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path);
+ std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
+ std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
+
+ ASSERT_TRUE(writer->StartEntry("test1", 0));
+ ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength));
+ ASSERT_TRUE(writer->FinishEntry());
+ ASSERT_FALSE(writer->HadError());
+
+ ASSERT_TRUE(writer->StartEntry("test2", 0));
+ ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength));
+ ASSERT_TRUE(writer->FinishEntry());
+ ASSERT_FALSE(writer->HadError());
+
+ writer.reset();
+
+ // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832
+ VerifyZipFileTimestamps(output_path);
+}
+
} // namespace aapt
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index 08d497d..673d1b7 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -57,6 +57,11 @@
return false;
}
+ // Fills in buf with the last modification time of the file. Returns true if successful,
+ // otherwise false (i.e., the operation is not supported or the file system is unable to provide
+ // a last modification time).
+ virtual bool GetModificationTime(struct tm* buf) const = 0;
+
private:
// Any segments created from this IFile need to be owned by this IFile, so
// keep them
@@ -79,6 +84,10 @@
return file_->GetSource();
}
+ bool GetModificationTime(struct tm* buf) const override {
+ return file_->GetModificationTime(buf);
+ };
+
private:
DISALLOW_COPY_AND_ASSIGN(FileSegment);
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index a64982a..6a692e4 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -14,9 +14,12 @@
* limitations under the License.
*/
+#define _POSIX_THREAD_SAFE_FUNCTIONS // For mingw localtime_r().
+
#include "io/FileSystem.h"
#include <dirent.h>
+#include <sys/stat.h>
#include "android-base/errors.h"
#include "androidfw/Source.h"
@@ -54,6 +57,23 @@
return source_;
}
+bool RegularFile::GetModificationTime(struct tm* buf) const {
+ if (buf == nullptr) {
+ return false;
+ }
+ struct stat stat_buf;
+ if (stat(source_.path.c_str(), &stat_buf) != 0) {
+ return false;
+ }
+
+ struct tm* ptm;
+ struct tm tm_result;
+ ptm = localtime_r(&stat_buf.st_mtime, &tm_result);
+
+ *buf = *ptm;
+ return true;
+}
+
FileCollectionIterator::FileCollectionIterator(FileCollection* collection)
: current_(collection->files_.begin()), end_(collection->files_.end()) {}
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index 0e798fc..f975196 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -32,6 +32,7 @@
std::unique_ptr<IData> OpenAsData() override;
std::unique_ptr<io::InputStream> OpenInputStream() override;
const android::Source& GetSource() const override;
+ bool GetModificationTime(struct tm* buf) const override;
private:
DISALLOW_COPY_AND_ASSIGN(RegularFile);
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 4a5385d..cb5bbe9 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -75,6 +75,14 @@
return zip_entry_.method != kCompressStored;
}
+bool ZipFile::GetModificationTime(struct tm* buf) const {
+ if (buf == nullptr) {
+ return false;
+ }
+ *buf = zip_entry_.GetModificationTime();
+ return true;
+}
+
ZipFileCollectionIterator::ZipFileCollectionIterator(
ZipFileCollection* collection)
: current_(collection->files_.begin()), end_(collection->files_.end()) {}
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index c263aa4..ac125d0 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -38,6 +38,7 @@
std::unique_ptr<io::InputStream> OpenInputStream() override;
const android::Source& GetSource() const override;
bool WasCompressed() override;
+ bool GetModificationTime(struct tm* buf) const override;
private:
::ZipArchiveHandle zip_handle_;
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 83a0f3f..e48668c 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -98,6 +98,10 @@
return source_;
}
+ bool GetModificationTime(struct tm* buf) const override {
+ return false;
+ };
+
private:
DISALLOW_COPY_AND_ASSIGN(TestFile);
diff --git a/tools/lint/common/Android.bp b/tools/lint/common/Android.bp
index 898f88b..8bfbfe5 100644
--- a/tools/lint/common/Android.bp
+++ b/tools/lint/common/Android.bp
@@ -27,3 +27,30 @@
libs: ["lint_api"],
kotlincflags: ["-Xjvm-default=all"],
}
+
+java_defaults {
+ name: "AndroidLintCheckerTestDefaults",
+ srcs: ["checks/src/test/java/**/*.kt"],
+ static_libs: [
+ "junit",
+ "lint",
+ "lint_tests",
+ ],
+ test_options: {
+ unit_test: true,
+ tradefed_options: [
+ {
+ // lint bundles in some classes that were built with older versions
+ // of libraries, and no longer load. Since tradefed tries to load
+ // all classes in the jar to look for tests, it crashes loading them.
+ // Exclude these classes from tradefed's search.
+ name: "exclude-paths",
+ value: "org/apache",
+ },
+ {
+ name: "exclude-paths",
+ value: "META-INF",
+ },
+ ],
+ },
+}
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt b/tools/lint/common/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt
similarity index 100%
rename from tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt
rename to tools/lint/common/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt b/tools/lint/common/src/main/java/com/google/android/lint/aidl/Constants.kt
similarity index 99%
rename from tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
rename to tools/lint/common/src/main/java/com/google/android/lint/aidl/Constants.kt
index f1727b7..a18ed15 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
+++ b/tools/lint/common/src/main/java/com/google/android/lint/aidl/Constants.kt
@@ -29,9 +29,10 @@
const val BINDER_CLASS = "android.os.Binder"
const val IINTERFACE_INTERFACE = "android.os.IInterface"
-const val AIDL_PERMISSION_HELPER_SUFFIX = "_enforcePermission"
const val PERMISSION_PREFIX_LITERAL = "android.permission."
+const val AIDL_PERMISSION_HELPER_SUFFIX = "_enforcePermission"
+
/**
* If a non java (e.g. c++) backend is enabled, the @EnforcePermission
* annotation cannot be used. At time of writing, the mechanism
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt b/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
similarity index 100%
rename from tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
rename to tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
diff --git a/tools/lint/fix/soong_lint_fix.py b/tools/lint/fix/soong_lint_fix.py
index cd4d778d..acc0ad0 100644
--- a/tools/lint/fix/soong_lint_fix.py
+++ b/tools/lint/fix/soong_lint_fix.py
@@ -29,6 +29,39 @@
PATH_SUFFIX = "android_common/lint"
FIX_ZIP = "suggested-fixes.zip"
+
+class SoongModule:
+ """A Soong module to lint.
+
+ The constructor takes the name of the module (for example,
+ "framework-minus-apex"). find() must be called to extract the intermediate
+ module path from Soong's module-info.json
+ """
+ def __init__(self, name):
+ self._name = name
+
+ def find(self, module_info):
+ """Finds the module in the loaded module_info.json."""
+ if self._name not in module_info:
+ raise Exception(f"Module {self._name} not found!")
+
+ partial_path = module_info[self._name]["path"][0]
+ print(f"Found module {partial_path}/{self._name}.")
+ self._path = f"{PATH_PREFIX}/{partial_path}/{self._name}/{PATH_SUFFIX}"
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def lint_report(self):
+ return f"{self._path}/lint-report.txt"
+
+ @property
+ def suggested_fixes(self):
+ return f"{self._path}/{FIX_ZIP}"
+
+
class SoongLintFix:
"""
This class creates a command line tool that will
@@ -53,16 +86,14 @@
self._parser = _setup_parser()
self._args = None
self._kwargs = None
- self._path = None
- self._target = None
+ self._modules = []
-
- def run(self, additional_setup=None, custom_fix=None):
+ def run(self):
"""
Run the script
"""
self._setup()
- self._find_module()
+ self._find_modules()
self._lint()
if not self._args.no_fix:
@@ -87,8 +118,6 @@
os.chdir(ANDROID_BUILD_TOP)
-
- def _find_module(self):
print("Refreshing soong modules...")
try:
os.mkdir(ANDROID_PRODUCT_OUT)
@@ -97,48 +126,47 @@
subprocess.call(f"{SOONG_UI} --make-mode {PRODUCT_OUT}/module-info.json", **self._kwargs)
print("done.")
+
+ def _find_modules(self):
with open(f"{ANDROID_PRODUCT_OUT}/module-info.json") as f:
module_info = json.load(f)
- if self._args.module not in module_info:
- sys.exit(f"Module {self._args.module} not found!")
-
- module_path = module_info[self._args.module]["path"][0]
- print(f"Found module {module_path}/{self._args.module}.")
-
- self._path = f"{PATH_PREFIX}/{module_path}/{self._args.module}/{PATH_SUFFIX}"
- self._target = f"{self._path}/lint-report.txt"
-
+ for module_name in self._args.modules:
+ module = SoongModule(module_name)
+ module.find(module_info)
+ self._modules.append(module)
def _lint(self):
print("Cleaning up any old lint results...")
- try:
- os.remove(f"{self._target}")
- os.remove(f"{self._path}/{FIX_ZIP}")
- except FileNotFoundError:
- pass
+ for module in self._modules:
+ try:
+ os.remove(f"{module.lint_report}")
+ os.remove(f"{module.suggested_fixes}")
+ except FileNotFoundError:
+ pass
print("done.")
- print(f"Generating {self._target}")
- subprocess.call(f"{SOONG_UI} --make-mode {self._target}", **self._kwargs)
+ target = " ".join([ module.lint_report for module in self._modules ])
+ print(f"Generating {target}")
+ subprocess.call(f"{SOONG_UI} --make-mode {target}", **self._kwargs)
print("done.")
-
def _fix(self):
- print("Copying suggested fixes to the tree...")
- with zipfile.ZipFile(f"{self._path}/{FIX_ZIP}") as zip:
- for name in zip.namelist():
- if name.startswith("out") or not name.endswith(".java"):
- continue
- with zip.open(name) as src, open(f"{ANDROID_BUILD_TOP}/{name}", "wb") as dst:
- shutil.copyfileobj(src, dst)
+ for module in self._modules:
+ print(f"Copying suggested fixes for {module.name} to the tree...")
+ with zipfile.ZipFile(f"{module.suggested_fixes}") as zip:
+ for name in zip.namelist():
+ if name.startswith("out") or not name.endswith(".java"):
+ continue
+ with zip.open(name) as src, open(f"{ANDROID_BUILD_TOP}/{name}", "wb") as dst:
+ shutil.copyfileobj(src, dst)
print("done.")
-
def _print(self):
- print("### lint-report.txt ###", end="\n\n")
- with open(self._target, "r") as f:
- print(f.read())
+ for module in self._modules:
+ print(f"### lint-report.txt {module.name} ###", end="\n\n")
+ with open(module.lint_report, "r") as f:
+ print(f.read())
def _setup_parser():
@@ -151,7 +179,8 @@
**Gotcha**: You must have run `source build/envsetup.sh` and `lunch` first.
""", formatter_class=argparse.RawTextHelpFormatter)
- parser.add_argument('module',
+ parser.add_argument('modules',
+ nargs='+',
help='The soong build module to run '
'(e.g. framework-minus-apex or services.core.unboosted)')
@@ -170,4 +199,4 @@
return parser
if __name__ == "__main__":
- SoongLintFix().run()
\ No newline at end of file
+ SoongLintFix().run()
diff --git a/tools/lint/framework/Android.bp b/tools/lint/framework/Android.bp
index 30a6daa..5acdf43 100644
--- a/tools/lint/framework/Android.bp
+++ b/tools/lint/framework/Android.bp
@@ -37,28 +37,9 @@
java_test_host {
name: "AndroidFrameworkLintCheckerTest",
+ defaults: ["AndroidLintCheckerTestDefaults"],
srcs: ["checks/src/test/java/**/*.kt"],
static_libs: [
"AndroidFrameworkLintChecker",
- "junit",
- "lint",
- "lint_tests",
],
- test_options: {
- unit_test: true,
- tradefed_options: [
- {
- // lint bundles in some classes that were built with older versions
- // of libraries, and no longer load. Since tradefed tries to load
- // all classes in the jar to look for tests, it crashes loading them.
- // Exclude these classes from tradefed's search.
- name: "exclude-paths",
- value: "org/apache",
- },
- {
- name: "exclude-paths",
- value: "META-INF",
- },
- ],
- },
}
diff --git a/tools/lint/global/Android.bp b/tools/lint/global/Android.bp
index bedb7bd..3e74171 100644
--- a/tools/lint/global/Android.bp
+++ b/tools/lint/global/Android.bp
@@ -38,28 +38,9 @@
java_test_host {
name: "AndroidGlobalLintCheckerTest",
+ defaults: ["AndroidLintCheckerTestDefaults"],
srcs: ["checks/src/test/java/**/*.kt"],
static_libs: [
"AndroidGlobalLintChecker",
- "junit",
- "lint",
- "lint_tests",
],
- test_options: {
- unit_test: true,
- tradefed_options: [
- {
- // lint bundles in some classes that were built with older versions
- // of libraries, and no longer load. Since tradefed tries to load
- // all classes in the jar to look for tests, it crashes loading them.
- // Exclude these classes from tradefed's search.
- name: "exclude-paths",
- value: "org/apache",
- },
- {
- name: "exclude-paths",
- value: "META-INF",
- },
- ],
- },
}
diff --git a/tools/lint/utils/Android.bp b/tools/lint/utils/Android.bp
new file mode 100644
index 0000000..75e8d68
--- /dev/null
+++ b/tools/lint/utils/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2023 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"],
+}
+
+java_library_host {
+ name: "AndroidUtilsLintChecker",
+ srcs: ["checks/src/main/java/**/*.kt"],
+ plugins: ["auto_service_plugin"],
+ libs: [
+ "auto_service_annotations",
+ "lint_api",
+ ],
+ static_libs: [
+ "AndroidCommonLint",
+ ],
+ kotlincflags: ["-Xjvm-default=all"],
+}
+
+java_test_host {
+ name: "AndroidUtilsLintCheckerTest",
+ defaults: ["AndroidLintCheckerTestDefaults"],
+ srcs: ["checks/src/test/java/**/*.kt"],
+ static_libs: [
+ "AndroidUtilsLintChecker",
+ ],
+}
diff --git a/tools/lint/utils/checks/src/main/java/com/google/android/lint/AndroidUtilsIssueRegistry.kt b/tools/lint/utils/checks/src/main/java/com/google/android/lint/AndroidUtilsIssueRegistry.kt
new file mode 100644
index 0000000..fa61c42
--- /dev/null
+++ b/tools/lint/utils/checks/src/main/java/com/google/android/lint/AndroidUtilsIssueRegistry.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.client.api.IssueRegistry
+import com.android.tools.lint.client.api.Vendor
+import com.android.tools.lint.detector.api.CURRENT_API
+import com.google.android.lint.aidl.AnnotatedAidlCounter
+import com.google.auto.service.AutoService
+
+@AutoService(IssueRegistry::class)
+@Suppress("UnstableApiUsage")
+class AndroidUtilsIssueRegistry : IssueRegistry() {
+ override val issues = listOf(
+ AnnotatedAidlCounter.ISSUE_ANNOTATED_AIDL_COUNTER,
+ )
+
+ override val api: Int
+ get() = CURRENT_API
+
+ override val minApi: Int
+ get() = 8
+
+ override val vendor: Vendor = Vendor(
+ vendorName = "Android",
+ feedbackUrl = "http://b/issues/new?component=315013",
+ contact = "tweek@google.com"
+ )
+}
diff --git a/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/AnnotatedAidlCounter.kt b/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/AnnotatedAidlCounter.kt
new file mode 100644
index 0000000..f0ec3f4
--- /dev/null
+++ b/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/AnnotatedAidlCounter.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint.aidl
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Context
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Location
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import org.jetbrains.uast.UBlockExpression
+import org.jetbrains.uast.UMethod
+
+import java.util.TreeMap
+
+/**
+ * Count the number of AIDL interfaces. Reports the number of annotated and
+ * non-annotated methods.
+ */
+@Suppress("UnstableApiUsage")
+class AnnotatedAidlCounter : AidlImplementationDetector() {
+
+ private data class Stat(
+ var unannotated: Int = 0,
+ var enforced: Int = 0,
+ var notRequired: Int = 0,
+ )
+
+ private var packagesStats: TreeMap<String, Stat> = TreeMap<String, Stat>()
+
+ override fun visitAidlMethod(
+ context: JavaContext,
+ node: UMethod,
+ interfaceName: String,
+ body: UBlockExpression
+ ) {
+ val packageName = context.uastFile?.packageName ?: "<unknown>"
+ var packageStat = packagesStats.getOrDefault(packageName, Stat())
+ when {
+ node.hasAnnotation(ANNOTATION_ENFORCE_PERMISSION) -> packageStat.enforced += 1
+ node.hasAnnotation(ANNOTATION_REQUIRES_NO_PERMISSION) -> packageStat.notRequired += 1
+ else -> packageStat.unannotated += 1
+ }
+ packagesStats.put(packageName, packageStat)
+ // context.driver.client.log(null, "%s.%s#%s".format(packageName, interfaceName, node.name))
+ }
+
+ override fun afterCheckRootProject(context: Context) {
+ var total = Stat()
+ for ((packageName, stat) in packagesStats) {
+ context.client.log(null, "package $packageName => $stat")
+ total.unannotated += stat.unannotated
+ total.enforced += stat.enforced
+ total.notRequired += stat.notRequired
+ }
+ val location = Location.create(context.project.dir)
+ context.report(
+ ISSUE_ANNOTATED_AIDL_COUNTER,
+ location,
+ "module ${context.project.name} => $total"
+ )
+ }
+
+ companion object {
+
+ @JvmField
+ val ISSUE_ANNOTATED_AIDL_COUNTER = Issue.create(
+ id = "AnnotatedAidlCounter",
+ briefDescription = "Statistics on the number of annotated AIDL methods.",
+ explanation = "",
+ category = Category.SECURITY,
+ priority = 5,
+ severity = Severity.INFORMATIONAL,
+ implementation = Implementation(
+ AnnotatedAidlCounter::class.java,
+ Scope.JAVA_FILE_SCOPE
+ ),
+ )
+ }
+}
diff --git a/tools/lint/utils/checks/src/test/java/com/google/android/lint/aidl/AnnotatedAidlCounterTest.kt b/tools/lint/utils/checks/src/test/java/com/google/android/lint/aidl/AnnotatedAidlCounterTest.kt
new file mode 100644
index 0000000..692b7da
--- /dev/null
+++ b/tools/lint/utils/checks/src/test/java/com/google/android/lint/aidl/AnnotatedAidlCounterTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint.aidl
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class AnnotatedAidlCounterTest : LintDetectorTest() {
+ override fun getDetector(): Detector = AnnotatedAidlCounter()
+
+ override fun getIssues(): List<Issue> = listOf(
+ AnnotatedAidlCounter.ISSUE_ANNOTATED_AIDL_COUNTER,
+ )
+
+ override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+ /** No issue scenario */
+
+ fun testDoesNotDetectIssuesCorrectAnnotationOnMethod() {
+ lint().files(java(
+ """
+ package test.pkg;
+ import android.annotation.EnforcePermission;
+ public class TestClass2 extends IFooMethod.Stub {
+ @Override
+ @EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void testMethod() {}
+ }
+ """).indented(),
+ *stubs
+ )
+ .run()
+ .expect("""
+ app: Information: module app => Stat(unannotated=0, enforced=1, notRequired=0) [AnnotatedAidlCounter]
+ 0 errors, 0 warnings
+ """)
+ }
+
+ // A service with permission annotation on the method.
+ private val interfaceIFooMethodStub: TestFile = java(
+ """
+ public interface IFooMethod extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IFooMethod {}
+ @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void testMethod();
+ }
+ """
+ ).indented()
+
+ // A service without any permission annotation.
+ private val interfaceIBarStub: TestFile = java(
+ """
+ public interface IBar extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IBar {
+ @Override
+ public void testMethod() {}
+ }
+ public void testMethod();
+ }
+ """
+ ).indented()
+
+ private val manifestPermissionStub: TestFile = java(
+ """
+ package android.Manifest;
+ class permission {
+ public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
+ }
+ """
+ ).indented()
+
+ private val enforcePermissionAnnotationStub: TestFile = java(
+ """
+ package android.annotation;
+ public @interface EnforcePermission {}
+ """
+ ).indented()
+
+ private val stubs = arrayOf(interfaceIFooMethodStub, interfaceIBarStub,
+ manifestPermissionStub, enforcePermissionAnnotationStub)
+}