diff options
292 files changed, 8626 insertions, 6723 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 2623702f1dc9..599e5cfeeacb 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -12,31 +12,37 @@ // See the License for the specific language governing permissions and // limitations under the License. +aconfig_srcjars = [ + ":android.app.usage.flags-aconfig-java{.generated_srcjars}", + ":android.content.pm.flags-aconfig-java{.generated_srcjars}", + ":android.os.flags-aconfig-java{.generated_srcjars}", + ":android.os.vibrator.flags-aconfig-java{.generated_srcjars}", + ":android.security.flags-aconfig-java{.generated_srcjars}", + ":android.view.flags-aconfig-java{.generated_srcjars}", + ":camera_platform_flags_core_java_lib{.generated_srcjars}", + ":com.android.window.flags.window-aconfig-java{.generated_srcjars}", + ":com.android.hardware.input-aconfig-java{.generated_srcjars}", + ":com.android.text.flags-aconfig-java{.generated_srcjars}", + ":telecom_flags_core_java_lib{.generated_srcjars}", + ":telephony_flags_core_java_lib{.generated_srcjars}", + ":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}", + ":sdk_sandbox_flags_lib{.generated_srcjars}", + ":android.permission.flags-aconfig-java{.generated_srcjars}", +] + +filegroup { + name: "framework-minus-apex-aconfig-srcjars", + srcs: aconfig_srcjars, +} + // Aconfig declarations and libraries for the core framework java_defaults { name: "framework-minus-apex-aconfig-libraries", - // Add java_aconfig_libraries to here to add them to the core framework - srcs: [ - ":android.app.usage.flags-aconfig-java{.generated_srcjars}", - ":android.content.pm.flags-aconfig-java{.generated_srcjars}", - ":android.os.flags-aconfig-java{.generated_srcjars}", - ":android.os.vibrator.flags-aconfig-java{.generated_srcjars}", - ":android.security.flags-aconfig-java{.generated_srcjars}", - ":android.view.flags-aconfig-java{.generated_srcjars}", - ":camera_platform_flags_core_java_lib{.generated_srcjars}", - ":com.android.window.flags.window-aconfig-java{.generated_srcjars}", - ":com.android.hardware.input-aconfig-java{.generated_srcjars}", - ":com.android.text.flags-aconfig-java{.generated_srcjars}", - ":telecom_flags_core_java_lib{.generated_srcjars}", - ":telephony_flags_core_java_lib{.generated_srcjars}", - ":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}", - ":sdk_sandbox_flags_lib{.generated_srcjars}", - ":android.permission.flags-aconfig-java{.generated_srcjars}", - ], + srcs: aconfig_srcjars, // Add aconfig-annotations-lib as a dependency for the optimization libs: ["aconfig-annotations-lib"], } diff --git a/Android.bp b/Android.bp index 57a5a3c6bff1..f1a3af27a633 100644 --- a/Android.bp +++ b/Android.bp @@ -621,6 +621,7 @@ metalava_framework_docs_args = "" + "--api-lint-ignore-prefix org. " + "--error NoSettingsProvider " + "--error UnhiddenSystemApi " + + "--error UnflaggedApi " + "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " + "--hide BroadcastBehavior " + "--hide CallbackInterface " + diff --git a/apex/jobscheduler/framework/java/android/os/WearModeManagerInternal.java b/apex/jobscheduler/framework/java/android/os/WearModeManagerInternal.java index 969975762c91..75838c213eb6 100644 --- a/apex/jobscheduler/framework/java/android/os/WearModeManagerInternal.java +++ b/apex/jobscheduler/framework/java/android/os/WearModeManagerInternal.java @@ -49,13 +49,25 @@ public interface WearModeManagerInternal { String QUICK_DOZE_REQUEST_IDENTIFIER = "quick_doze_request"; /** + * Mode manager off body state identifier. + * + * <p>Unique identifier that can be used as identifier parameter in + * registerInternalStateObserver + * to listen to changes in quick doze request state from mode manager. + * + * TODO(b/288276510): convert to int constant + */ + String OFFBODY_STATE_ID = "off_body"; + + /** * StringDef for Mode manager identifiers. * * @hide */ @Retention(RetentionPolicy.SOURCE) @StringDef({ - QUICK_DOZE_REQUEST_IDENTIFIER + QUICK_DOZE_REQUEST_IDENTIFIER, + OFFBODY_STATE_ID }) @Target(ElementType.TYPE_USE) @interface Identifier { diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index b8596d5a3926..f252a0ba48cf 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -377,7 +377,11 @@ public class DeviceIdleController extends SystemService @GuardedBy("this") private boolean mModeManagerRequestedQuickDoze; @GuardedBy("this") + private boolean mIsOffBody; + @GuardedBy("this") private boolean mForceModeManagerQuickDozeRequest; + @GuardedBy("this") + private boolean mForceModeManagerOffBodyState; /** Time in the elapsed realtime timebase when this listener last received a motion event. */ @GuardedBy("this") @@ -437,6 +441,7 @@ public class DeviceIdleController extends SystemService private static final int ACTIVE_REASON_ALARM = 7; private static final int ACTIVE_REASON_EMERGENCY_CALL = 8; private static final int ACTIVE_REASON_MODE_MANAGER = 9; + private static final int ACTIVE_REASON_ONBODY = 10; @VisibleForTesting static String stateToString(int state) { @@ -837,7 +842,7 @@ public class DeviceIdleController extends SystemService class ModeManagerQuickDozeRequestConsumer implements Consumer<Boolean> { @Override public void accept(Boolean enabled) { - Slog.d(TAG, "Mode manager quick doze request: " + enabled); + Slog.i(TAG, "Mode manager quick doze request: " + enabled); synchronized (DeviceIdleController.this) { if (!mForceModeManagerQuickDozeRequest && mModeManagerRequestedQuickDoze != enabled) { @@ -848,13 +853,46 @@ public class DeviceIdleController extends SystemService } @GuardedBy("DeviceIdleController.this") - public void onModeManagerRequestChangedLocked() { + private void onModeManagerRequestChangedLocked() { // Get into quick doze faster when mode manager requests instead of taking // traditional multi-stage approach. + maybeBecomeActiveOnModeManagerEventsLocked(); updateQuickDozeFlagLocked(); - if (!mModeManagerRequestedQuickDoze && !mBatterySaverEnabled) { - mActiveReason = ACTIVE_REASON_MODE_MANAGER; - becomeActiveLocked("mode_manager", Process.myUid()); + } + } + + @VisibleForTesting + class ModeManagerOffBodyStateConsumer implements Consumer<Boolean> { + @Override + public void accept(Boolean isOffBody) { + Slog.i(TAG, "Offbody event from mode manager: " + isOffBody); + synchronized (DeviceIdleController.this) { + if (!mForceModeManagerOffBodyState && mIsOffBody != isOffBody) { + mIsOffBody = isOffBody; + onModeManagerOffBodyChangedLocked(); + } + } + } + + @GuardedBy("DeviceIdleController.this") + private void onModeManagerOffBodyChangedLocked() { + maybeBecomeActiveOnModeManagerEventsLocked(); + } + } + + @GuardedBy("DeviceIdleController.this") + private void maybeBecomeActiveOnModeManagerEventsLocked() { + synchronized (DeviceIdleController.this) { + if (mQuickDozeActivated) { + // Quick doze is enabled so don't turn the device active. + return; + } + // Fall through when quick doze is not requested. + + if (!mIsOffBody) { + // Quick doze was not requested and device is on body so turn the device active. + mActiveReason = ACTIVE_REASON_ONBODY; + becomeActiveLocked("on_body", Process.myUid()); } } } @@ -864,6 +902,10 @@ public class DeviceIdleController extends SystemService new ModeManagerQuickDozeRequestConsumer(); @VisibleForTesting + final ModeManagerOffBodyStateConsumer mModeManagerOffBodyStateConsumer = + new ModeManagerOffBodyStateConsumer(); + + @VisibleForTesting final class MotionListener extends TriggerEventListener implements SensorEventListener { @@ -2648,6 +2690,12 @@ public class DeviceIdleController extends SystemService WearModeManagerInternal.QUICK_DOZE_REQUEST_IDENTIFIER, AppSchedulingModuleThread.getExecutor(), mModeManagerQuickDozeRequestConsumer); + + modeManagerInternal.addActiveStateChangeListener( + WearModeManagerInternal.OFFBODY_STATE_ID, + AppSchedulingModuleThread.getExecutor(), + mModeManagerOffBodyStateConsumer + ); } } mLocalPowerManager.registerLowPowerModeObserver(ServiceType.QUICK_DOZE, @@ -4463,7 +4511,7 @@ public class DeviceIdleController extends SystemService pw.println( " Resume normal functioning after force-idle or force-inactive or " + "force-modemanager-quickdoze."); - pw.println(" get [light|deep|force|screen|charging|network|offbody|forcebodystate]"); + pw.println(" get [light|deep|force|screen|charging|network|offbody|forceoffbody]"); pw.println(" Retrieve the current given state."); pw.println(" disable [light|deep|all]"); pw.println(" Completely disable device idle mode."); @@ -4500,6 +4548,10 @@ public class DeviceIdleController extends SystemService pw.println(" force-modemanager-quickdoze [true|false]"); pw.println(" Simulate mode manager request to enable (true) or disable (false) " + "quick doze. Mode manager changes will be ignored until unforce is called."); + pw.println(" force-modemanager-offbody [true|false]"); + pw.println(" Force mode manager offbody state, this can be used to simulate " + + "device being off-body (true) or on-body (false). Mode manager changes " + + "will be ignored until unforce is called."); } class Shell extends ShellCommand { @@ -4634,6 +4686,9 @@ public class DeviceIdleController extends SystemService mForceModeManagerQuickDozeRequest = false; pw.println("mForceModeManagerQuickDozeRequest: " + mForceModeManagerQuickDozeRequest); + mForceModeManagerOffBodyState = false; + pw.println("mForceModeManagerOffBodyState: " + + mForceModeManagerOffBodyState); } finally { Binder.restoreCallingIdentity(token); } @@ -4660,6 +4715,8 @@ public class DeviceIdleController extends SystemService case "forcemodemanagerquick": pw.println(mForceModeManagerQuickDozeRequest); break; + case "offbody": pw.println(mIsOffBody); break; + case "forceoffbody": pw.println(mForceModeManagerOffBodyState); break; default: pw.println("Unknown get option: " + arg); break; } } finally { @@ -4982,6 +5039,31 @@ public class DeviceIdleController extends SystemService pw.println("Provide true or false argument after force-modemanager-quickdoze"); return -1; } + } else if ("force-modemanager-offbody".equals(cmd)) { + getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, + null); + String arg = shell.getNextArg(); + + if ("true".equalsIgnoreCase(arg) || "false".equalsIgnoreCase(arg)) { + boolean isOffBody = Boolean.parseBoolean(arg); + + synchronized (DeviceIdleController.this) { + final long token = Binder.clearCallingIdentity(); + try { + mForceModeManagerOffBodyState = true; + pw.println("mForceModeManagerOffBodyState: " + + mForceModeManagerOffBodyState); + mIsOffBody = isOffBody; + pw.println("mIsOffBody: " + mIsOffBody); + mModeManagerOffBodyStateConsumer.onModeManagerOffBodyChangedLocked(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } else { + pw.println("Provide true or false argument after force-modemanager-offbody"); + return -1; + } } else { return shell.handleDefaultCommands(cmd); } @@ -5233,6 +5315,12 @@ public class DeviceIdleController extends SystemService if (mAlarmsActive) { pw.print(" mAlarmsActive="); pw.println(mAlarmsActive); } + if (mConstants.USE_MODE_MANAGER) { + pw.print(" mModeManagerRequestedQuickDoze="); + pw.println(mModeManagerRequestedQuickDoze); + pw.print(" mIsOffBody="); + pw.println(mIsOffBody); + } } } diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp index 2f84df70fc40..8989b10675d3 100644 --- a/api/StubLibraries.bp +++ b/api/StubLibraries.bp @@ -29,11 +29,14 @@ droidstubs { name: "api-stubs-docs-non-updatable", + srcs: [ + ":framework-minus-apex-aconfig-srcjars", + ], defaults: [ "android-non-updatable-stubs-defaults", "module-classpath-stubs-defaults", ], - args: metalava_framework_docs_args + "--error UnflaggedApi ", + args: metalava_framework_docs_args, check_api: { current: { api_file: ":non-updatable-current.txt", @@ -74,8 +77,7 @@ priv_apps_in_stubs = " --show-for-stub-purposes-annotation android.annotation.Sy "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" + "\\)" -test = " --show-annotation android.annotation.TestApi" + - " --hide UnflaggedApi" // TODO(b/297362755): TestApi lint doesn't ignore existing APIs. +test = " --show-annotation android.annotation.TestApi" module_libs = " --show-annotation android.annotation.SystemApi\\(" + "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" + @@ -134,6 +136,7 @@ droidstubs { }, api_lint: { enabled: true, + new_since: ":android.api.test.latest", baseline_file: ":non-updatable-test-lint-baseline.txt", }, }, diff --git a/api/api.go b/api/api.go index 6095a9a781d8..83804c65d81f 100644 --- a/api/api.go +++ b/api/api.go @@ -433,7 +433,7 @@ type bazelCombinedApisAttributes struct { } // combined_apis bp2build converter -func (a *CombinedApis) ConvertWithBp2build(ctx android.TopDownMutatorContext) { +func (a *CombinedApis) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { basePrefix := "non-updatable" scopeToSuffix := map[string]string{ "public": "-current.txt", diff --git a/core/api/current.txt b/core/api/current.txt index a5784a048274..d48685ba6f66 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9681,22 +9681,22 @@ package android.companion.virtual { public final class VirtualDevice implements android.os.Parcelable { method public int describeContents(); method public int getDeviceId(); - method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) @NonNull public int[] getDisplayIds(); + method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @NonNull public int[] getDisplayIds(); method @Nullable public String getName(); method @Nullable public String getPersistentDeviceId(); - method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public boolean hasCustomSensorSupport(); + method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public boolean hasCustomSensorSupport(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDevice> CREATOR; } public final class VirtualDeviceManager { - method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) @Nullable public android.companion.virtual.VirtualDevice getVirtualDevice(int); + method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public android.companion.virtual.VirtualDevice getVirtualDevice(int); method @NonNull public java.util.List<android.companion.virtual.VirtualDevice> getVirtualDevices(); - method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public void registerVirtualDeviceListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener); - method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public void unregisterVirtualDeviceListener(@NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener); + method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public void registerVirtualDeviceListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener); + method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public void unregisterVirtualDeviceListener(@NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener); } - @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public static interface VirtualDeviceManager.VirtualDeviceListener { + @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public static interface VirtualDeviceManager.VirtualDeviceListener { method public default void onVirtualDeviceClosed(int); method public default void onVirtualDeviceCreated(int); } @@ -17653,13 +17653,13 @@ package android.graphics.pdf { package android.graphics.text { public final class LineBreakConfig { - method @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public int getHyphenation(); + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public int getHyphenation(); method public int getLineBreakStyle(); method public int getLineBreakWordStyle(); method @NonNull public android.graphics.text.LineBreakConfig merge(@NonNull android.graphics.text.LineBreakConfig); - field @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public static final int HYPHENATION_DISABLED = 0; // 0x0 - field @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public static final int HYPHENATION_ENABLED = 1; // 0x1 - field @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public static final int HYPHENATION_UNSPECIFIED = -1; // 0xffffffff + field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int HYPHENATION_DISABLED = 0; // 0x0 + field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int HYPHENATION_ENABLED = 1; // 0x1 + field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int HYPHENATION_UNSPECIFIED = -1; // 0xffffffff field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1 field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0 field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2 @@ -17674,7 +17674,7 @@ package android.graphics.text { ctor public LineBreakConfig.Builder(); method @NonNull public android.graphics.text.LineBreakConfig build(); method @NonNull public android.graphics.text.LineBreakConfig.Builder merge(@NonNull android.graphics.text.LineBreakConfig); - method @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) @NonNull public android.graphics.text.LineBreakConfig.Builder setHyphenation(int); + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.graphics.text.LineBreakConfig.Builder setHyphenation(int); method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakStyle(int); method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakWordStyle(int); } @@ -23951,12 +23951,12 @@ package android.media { 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 @FlaggedApi("com.android.media.flags.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 @FlaggedApi("com.android.media.flags.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); @@ -23965,7 +23965,7 @@ package android.media { 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 @FlaggedApi("com.android.media.flags.enable_rlp_callbacks_in_media_router2") public void unregisterRouteListingPreferenceCallback(@NonNull android.media.MediaRouter2.RouteListingPreferenceCallback); method public void unregisterTransferCallback(@NonNull android.media.MediaRouter2.TransferCallback); } @@ -23986,9 +23986,9 @@ package android.media { 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); + @FlaggedApi("com.android.media.flags.enable_rlp_callbacks_in_media_router2") public abstract static class MediaRouter2.RouteListingPreferenceCallback { + ctor @FlaggedApi("com.android.media.flags.enable_rlp_callbacks_in_media_router2") public MediaRouter2.RouteListingPreferenceCallback(); + method @FlaggedApi("com.android.media.flags.enable_rlp_callbacks_in_media_router2") public void onRouteListingPreferenceChanged(@Nullable android.media.RouteListingPreference); } public class MediaRouter2.RoutingController { @@ -32285,7 +32285,7 @@ package android.os { method public static long getNativeHeapFreeSize(); method public static long getNativeHeapSize(); method public static long getPss(); - method @FlaggedApi(Flags.FLAG_REMOVE_APP_PROFILER_PSS_COLLECTION) public static long getRss(); + method @FlaggedApi("android.os.remove_app_profiler_pss_collection") public static long getRss(); method public static String getRuntimeStat(String); method public static java.util.Map<java.lang.String,java.lang.String> getRuntimeStats(); method @Deprecated public static int getThreadAllocCount(); @@ -38657,10 +38657,10 @@ package android.security { } public final class FileIntegrityManager { - method @FlaggedApi(Flags.FLAG_FSVERITY_API) @Nullable public byte[] getFsVerityDigest(@NonNull java.io.File) throws java.io.IOException; + method @FlaggedApi("android.security.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 @FlaggedApi(Flags.FLAG_FSVERITY_API) public void setupFsVerity(@NonNull java.io.File) throws java.io.IOException; + method @FlaggedApi("android.security.fsverity_api") public void setupFsVerity(@NonNull java.io.File) throws java.io.IOException; } public final class KeyChain { @@ -41579,7 +41579,7 @@ package android.telecom { field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10 field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 8192; // 0x2000 field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40 - field @FlaggedApi(Flags.FLAG_VOIP_APP_ACTIONS_SUPPORT) public static final int PROPERTY_IS_TRANSACTIONAL = 32768; // 0x8000 + field @FlaggedApi("com.android.server.telecom.flags.voip_app_actions_support") public static final int PROPERTY_IS_TRANSACTIONAL = 32768; // 0x8000 field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800 field public static final int PROPERTY_RTT = 1024; // 0x400 field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100 @@ -46615,7 +46615,7 @@ package android.text { public static class BoringLayout.Metrics extends android.graphics.Paint.FontMetricsInt { ctor public BoringLayout.Metrics(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @NonNull public android.graphics.RectF getDrawingBoundingBox(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.graphics.RectF getDrawingBoundingBox(); field public int width; } @@ -46800,7 +46800,7 @@ package android.text { public abstract class Layout { ctor protected Layout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @NonNull public android.graphics.RectF computeDrawingBoundingBox(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.graphics.RectF computeDrawingBoundingBox(); method public void draw(android.graphics.Canvas); method public void draw(android.graphics.Canvas, android.graphics.Path, android.graphics.Paint, int); method public void draw(@NonNull android.graphics.Canvas, @Nullable java.util.List<android.graphics.Path>, @Nullable java.util.List<android.graphics.Paint>, @Nullable android.graphics.Path, @Nullable android.graphics.Paint, int); @@ -46809,24 +46809,24 @@ package android.text { method public void fillCharacterBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull float[], @IntRange(from=0) int); method @NonNull public final android.text.Layout.Alignment getAlignment(); method public abstract int getBottomPadding(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public final int getBreakStrategy(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public final int getBreakStrategy(); method public void getCursorPath(int, android.graphics.Path, CharSequence); method public static float getDesiredWidth(CharSequence, android.text.TextPaint); method public static float getDesiredWidth(CharSequence, int, int, android.text.TextPaint); method public abstract int getEllipsisCount(int); method public abstract int getEllipsisStart(int); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @Nullable public final android.text.TextUtils.TruncateAt getEllipsize(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @Nullable public final android.text.TextUtils.TruncateAt getEllipsize(); method @IntRange(from=0) public int getEllipsizedWidth(); method public int getHeight(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public final int getHyphenationFrequency(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public final int getJustificationMode(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @Nullable public final int[] getLeftIndents(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public final int getHyphenationFrequency(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public final int getJustificationMode(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @Nullable public final int[] getLeftIndents(); method public final int getLineAscent(int); method public final int getLineBaseline(int); method public final int getLineBottom(int); method public int getLineBottom(int, boolean); method public int getLineBounds(int, android.graphics.Rect); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig(); method public abstract boolean getLineContainsTab(int); method public abstract int getLineCount(); method public abstract int getLineDescent(int); @@ -46837,13 +46837,13 @@ package android.text { method public float getLineLeft(int); method public float getLineMax(int); method public float getLineRight(int); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public final float getLineSpacingAmount(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public final float getLineSpacingMultiplier(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public final float getLineSpacingAmount(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public final float getLineSpacingMultiplier(); method public abstract int getLineStart(int); method public abstract int getLineTop(int); method public int getLineVisibleEnd(int); method public float getLineWidth(int); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @IntRange(from=1) public final int getMaxLines(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @IntRange(from=1) public final int getMaxLines(); method public int getOffsetForHorizontal(int, float); method public int getOffsetToLeftOf(int); method public int getOffsetToRightOf(int); @@ -46854,19 +46854,19 @@ package android.text { method public final int getParagraphRight(int); method public float getPrimaryHorizontal(int); method @Nullable public int[] getRangeForRect(@NonNull android.graphics.RectF, @NonNull android.text.SegmentFinder, @NonNull android.text.Layout.TextInclusionStrategy); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @Nullable public final int[] getRightIndents(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @Nullable public final int[] getRightIndents(); method public float getSecondaryHorizontal(int); method public void getSelectionPath(int, int, android.graphics.Path); method public final float getSpacingAdd(); method public final float getSpacingMultiplier(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @NonNull public final CharSequence getText(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @NonNull public final android.text.TextDirectionHeuristic getTextDirectionHeuristic(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public final CharSequence getText(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public final android.text.TextDirectionHeuristic getTextDirectionHeuristic(); method public abstract int getTopPadding(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public boolean getUseBoundsForWidth(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public boolean getUseBoundsForWidth(); method @IntRange(from=0) public final int getWidth(); method public final void increaseWidthTo(int); method public boolean isFallbackLineSpacingEnabled(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public final boolean isFontPaddingIncluded(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public final boolean isFontPaddingIncluded(); method public boolean isRtlCharAt(int); method protected final boolean isSpanned(); field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2 @@ -46894,7 +46894,7 @@ package android.text { enum_constant public static final android.text.Layout.Alignment ALIGN_OPPOSITE; } - @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public static final class Layout.Builder { + @FlaggedApi("com.android.text.flags.use_bounds_for_width") public static final class Layout.Builder { ctor public Layout.Builder(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.text.TextPaint, @IntRange(from=0) int); method @NonNull public android.text.Layout build(); method @NonNull public android.text.Layout.Builder setAlignment(@NonNull android.text.Layout.Alignment); @@ -46912,7 +46912,7 @@ package android.text { method @NonNull public android.text.Layout.Builder setMaxLines(@IntRange(from=1) int); method @NonNull public android.text.Layout.Builder setRightIndents(@Nullable int[]); method @NonNull public android.text.Layout.Builder setTextDirectionHeuristic(@NonNull android.text.TextDirectionHeuristic); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) @NonNull public android.text.Layout.Builder setUseBoundsForWidth(boolean); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.Layout.Builder setUseBoundsForWidth(boolean); } public static class Layout.Directions { @@ -47889,13 +47889,13 @@ package android.text.style { method public void writeToParcel(@NonNull android.os.Parcel, int); } - @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public class LineBreakConfigSpan { + @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public class LineBreakConfigSpan { ctor public LineBreakConfigSpan(@NonNull android.graphics.text.LineBreakConfig); method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig(); } - @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public static final class LineBreakConfigSpan.NoHyphenationSpan extends android.text.style.LineBreakConfigSpan { - ctor @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public LineBreakConfigSpan.NoHyphenationSpan(); + @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final class LineBreakConfigSpan.NoHyphenationSpan extends android.text.style.LineBreakConfigSpan { + ctor @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public LineBreakConfigSpan.NoHyphenationSpan(); } public interface LineHeightSpan extends android.text.style.ParagraphStyle android.text.style.WrapTogetherSpan { @@ -50058,7 +50058,7 @@ package android.view { field public static final int VIRTUAL_KEY_RELEASE = 8; // 0x8 } - @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) public class HapticScrollFeedbackProvider implements android.view.ScrollFeedbackProvider { + @FlaggedApi("android.view.flags.scroll_feedback_api") public class HapticScrollFeedbackProvider implements android.view.ScrollFeedbackProvider { ctor public HapticScrollFeedbackProvider(@NonNull android.view.View); method public void onScrollLimit(int, int, int, boolean); method public void onScrollProgress(int, int, int, int); @@ -51230,7 +51230,7 @@ package android.view { method @UiThread public void updatePositionInWindow(); } - @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) public interface ScrollFeedbackProvider { + @FlaggedApi("android.view.flags.scroll_feedback_api") public interface ScrollFeedbackProvider { method public void onScrollLimit(int, int, int, boolean); method public void onScrollProgress(int, int, int, int); method public void onSnapToItem(int, int, int); @@ -52513,7 +52513,7 @@ package android.view { method @Deprecated public static int getEdgeSlop(); method @Deprecated public static int getFadingEdgeLength(); method @Deprecated public static long getGlobalActionKeyTimeout(); - method @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) public int getHapticScrollFeedbackTickInterval(int, int, int); + method @FlaggedApi("android.view.flags.scroll_feedback_api") public int getHapticScrollFeedbackTickInterval(int, int, int); method public static int getJumpTapTimeout(); method public static int getKeyRepeatDelay(); method public static int getKeyRepeatTimeout(); @@ -52553,7 +52553,7 @@ package android.view { method @Deprecated public static int getWindowTouchSlop(); method public static long getZoomControlsTimeout(); method public boolean hasPermanentMenuKey(); - method @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) public boolean isHapticScrollFeedbackEnabled(int, int, int); + method @FlaggedApi("android.view.flags.scroll_feedback_api") public boolean isHapticScrollFeedbackEnabled(int, int, int); method public boolean shouldShowMenuShortcutsWhenKeyboardPresent(); } @@ -59886,7 +59886,7 @@ package android.widget { method public final android.text.method.TransformationMethod getTransformationMethod(); method public android.graphics.Typeface getTypeface(); method public android.text.style.URLSpan[] getUrls(); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public boolean getUseBoundsForWidth(); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public boolean getUseBoundsForWidth(); method public boolean hasSelection(); method public boolean isAllCaps(); method public boolean isCursorVisible(); @@ -60029,7 +60029,7 @@ package android.widget { method public final void setTransformationMethod(android.text.method.TransformationMethod); method public void setTypeface(@Nullable android.graphics.Typeface, int); method public void setTypeface(@Nullable android.graphics.Typeface); - method @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public void setUseBoundsForWidth(boolean); + method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public void setUseBoundsForWidth(boolean); method public void setWidth(int); field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0 field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1 diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt index 6b7910afc347..afb10f5f234a 100644 --- a/core/api/lint-baseline.txt +++ b/core/api/lint-baseline.txt @@ -265,8 +265,6 @@ 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): @@ -321,8 +319,6 @@ UnflaggedApi: android.media.midi.MidiUmpDeviceService#onBind(android.content.Int 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(): @@ -335,8 +331,6 @@ 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: @@ -355,46 +349,10 @@ 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(): @@ -429,24 +387,12 @@ 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): @@ -455,16 +401,10 @@ UnflaggedApi: android.view.HapticScrollFeedbackProvider#onScrollProgress(int, in 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: @@ -515,7 +455,3 @@ UnflaggedApi: android.view.inputmethod.InlineSuggestionsRequest.Builder#setClien 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 a0d38588bc10..163383515548 100644 --- a/core/api/module-lib-lint-baseline.txt +++ b/core/api/module-lib-lint-baseline.txt @@ -35,26 +35,8 @@ SamShouldBeLast: android.media.session.MediaSessionManager#setOnMediaKeyListener SAM-compatible parameters (such as parameter 1, "listener", in android.media.session.MediaSessionManager.setOnMediaKeyListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.media.session.MediaSessionManager#setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, android.os.Handler): SAM-compatible parameters (such as parameter 1, "listener", in android.media.session.MediaSessionManager.setOnVolumeKeyLongPressListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.os.Binder#attachInterface(android.os.IInterface, String): - SAM-compatible parameters (such as parameter 1, "owner", in android.os.Binder.attachInterface) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.os.Binder#linkToDeath(android.os.IBinder.DeathRecipient, int): - SAM-compatible parameters (such as parameter 1, "recipient", in android.os.Binder.linkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.os.Binder#unlinkToDeath(android.os.IBinder.DeathRecipient, int): - SAM-compatible parameters (such as parameter 1, "recipient", in android.os.Binder.unlinkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.os.IBinder#linkToDeath(android.os.IBinder.DeathRecipient, int): - 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: @@ -89,13 +71,7 @@ UnflaggedApi: android.companion.CompanionDeviceManager.OnTransportsChangedListen 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-lint-baseline.txt b/core/api/system-lint-baseline.txt index d62bea86bd06..ee031db50b62 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -21,28 +21,10 @@ ListenerLast: android.telephony.satellite.SatelliteManager#stopSatelliteTransmis Listeners should always be at end of argument list (method `stopSatelliteTransmissionUpdates`) -MissingGetterMatchingBuilder: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallViaAudioProcessing(boolean): - android.telecom.CallScreeningService.CallResponse does not declare a `shouldScreenCallViaAudioProcessing()` method matching method android.telecom.CallScreeningService.CallResponse.Builder.setShouldScreenCallViaAudioProcessing(boolean) -MissingGetterMatchingBuilder: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String): - android.telephony.mbms.DownloadRequest does not declare a `getServiceId()` method matching method android.telephony.mbms.DownloadRequest.Builder.setServiceId(String) - - MissingNullability: android.media.soundtrigger.SoundTriggerDetectionService#onUnbind(android.content.Intent) parameter #0: Missing nullability on parameter `intent` in method `onUnbind` -MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #0: - Missing nullability on parameter `inputId` in method `onEvent` -MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #1: - Missing nullability on parameter `eventType` in method `onEvent` -MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #2: - Missing nullability on parameter `eventArgs` in method `onEvent` MissingNullability: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context) parameter #0: Missing nullability on parameter `base` in method `attachBaseContext` -MissingNullability: android.provider.ContactsContract.MetadataSync#CONTENT_URI: - Missing nullability on field `CONTENT_URI` in class `class android.provider.ContactsContract.MetadataSync` -MissingNullability: android.provider.ContactsContract.MetadataSync#METADATA_AUTHORITY_URI: - Missing nullability on field `METADATA_AUTHORITY_URI` in class `class android.provider.ContactsContract.MetadataSync` -MissingNullability: android.provider.ContactsContract.MetadataSyncState#CONTENT_URI: - Missing nullability on field `CONTENT_URI` in class `class android.provider.ContactsContract.MetadataSyncState` MissingNullability: android.provider.SearchIndexablesProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #0: Missing nullability on parameter `context` in method `attachInfo` MissingNullability: android.provider.SearchIndexablesProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #1: @@ -61,10 +43,6 @@ MissingNullability: android.telephony.NetworkService#onUnbind(android.content.In Missing nullability on parameter `intent` in method `onUnbind` MissingNullability: android.telephony.data.DataService#onUnbind(android.content.Intent) parameter #0: Missing nullability on parameter `intent` in method `onUnbind` -MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String): - Missing nullability on method `setServiceId` return -MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String) parameter #0: - Missing nullability on parameter `serviceId` in method `setServiceId` ProtectedMember: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context): @@ -173,12 +151,6 @@ SamShouldBeLast: android.nfc.NfcAdapter#enableReaderMode(android.app.Activity, a SAM-compatible parameters (such as parameter 2, "callback", in android.nfc.NfcAdapter.enableReaderMode) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.nfc.NfcAdapter#ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler): SAM-compatible parameters (such as parameter 3, "tagRemovedListener", in android.nfc.NfcAdapter.ignore) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.nfc.NfcAdapter#setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity): - SAM-compatible parameters (such as parameter 1, "callback", in android.nfc.NfcAdapter.setBeamPushUrisCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.nfc.NfcAdapter#setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...): - SAM-compatible parameters (such as parameter 1, "callback", in android.nfc.NfcAdapter.setNdefPushMessageCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.nfc.NfcAdapter#setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...): - SAM-compatible parameters (such as parameter 1, "callback", in android.nfc.NfcAdapter.setOnNdefPushCompleteCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.os.Binder#attachInterface(android.os.IInterface, String): SAM-compatible parameters (such as parameter 1, "owner", in android.os.Binder.attachInterface) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.os.Binder#linkToDeath(android.os.IBinder.DeathRecipient, int): @@ -225,1350 +197,32 @@ SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit 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#CAMERA_HEADLESS_SYSTEM_USER: + New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAMERA_HEADLESS_SYSTEM_USER 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.Context#THREAD_NETWORK_SERVICE: + New API must be flagged with @FlaggedApi: field android.content.Context.THREAD_NETWORK_SERVICE 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): @@ -1579,320 +233,6 @@ UnflaggedApi: android.content.pm.PackageManager#EXTRA_REQUEST_PERMISSIONS_DEVICE 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(): @@ -1903,578 +243,22 @@ 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: @@ -2487,8 +271,6 @@ UnflaggedApi: android.service.voice.HotwordTrainingAudio#PARCELABLE_WRITE_RETURN 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(): @@ -2497,10 +279,6 @@ 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: @@ -2513,8 +291,6 @@ UnflaggedApi: android.service.voice.HotwordTrainingAudio.Builder#setAudioFormat( 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: @@ -2537,18 +313,12 @@ 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: @@ -2563,330 +333,10 @@ UnflaggedApi: android.service.voice.HotwordTrainingData.Builder#setTimeoutStage( 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: @@ -2901,18 +351,12 @@ UnflaggedApi: android.telephony.satellite.AntennaDirection#PARCELABLE_WRITE_RETU 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: @@ -2925,16 +369,10 @@ UnflaggedApi: android.telephony.satellite.AntennaPosition#PARCELABLE_WRITE_RETUR 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: @@ -2947,16 +385,10 @@ UnflaggedApi: android.telephony.satellite.PointingInfo#PARCELABLE_WRITE_RETURN_V 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: @@ -2969,20 +401,14 @@ UnflaggedApi: android.telephony.satellite.SatelliteCapabilities#PARCELABLE_WRITE 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: @@ -3037,8 +463,6 @@ UnflaggedApi: android.telephony.satellite.SatelliteManager#NT_RADIO_TECHNOLOGY_P 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: @@ -3057,20 +481,6 @@ UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_DATAGRAM_TR 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: @@ -3085,28 +495,6 @@ UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_MODEM_STATE 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: @@ -3153,14 +541,6 @@ UnflaggedApi: android.telephony.satellite.SatelliteManager#SATELLITE_RESULT_SERV 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>): @@ -3225,141 +605,3 @@ UnflaggedApi: android.telephony.satellite.SatelliteTransmissionUpdateCallback#on 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/api/test-current.txt b/core/api/test-current.txt index a4cc44646341..40c6fa8986f7 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3506,10 +3506,6 @@ package android.view { field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800 } - public static final class MotionEvent.PointerCoords { - method public boolean isResampled(); - } - @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface RemotableViewMethod { method public abstract String asyncImpl() default ""; } diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index 1aaedaba3f79..107be8be42e2 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -1,985 +1,341 @@ // Baseline format: 1.0 -AcronymName: android.app.NotificationChannel#isImportanceLockedByOEM(): - Acronyms should not be capitalized in method names: was `isImportanceLockedByOEM`, should this be `isImportanceLockedByOem`? -AcronymName: android.app.NotificationChannel#setImportanceLockedByOEM(boolean): - Acronyms should not be capitalized in method names: was `setImportanceLockedByOEM`, should this be `setImportanceLockedByOem`? +KotlinKeyword: android.app.Notification#when: + Avoid field names that are Kotlin hard keywords ("when"); see https://android.github.io/kotlin-guides/interop.html#no-hard-keywords -ArrayReturn: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #10: - Method parameter should be Collection<Descriptor> (or subclass) instead of raw array; was `android.media.audiofx.AudioEffect.Descriptor[]` -ArrayReturn: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #11: - Method parameter should be Collection<Descriptor> (or subclass) instead of raw array; was `android.media.audiofx.AudioEffect.Descriptor[]` -ArrayReturn: android.view.Display#getSupportedWideColorGamut(): - Method should return Collection<ColorSpace> (or subclass) instead of raw array; was `android.graphics.ColorSpace[]` -ArrayReturn: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0: - Method parameter should be Collection<View> (or subclass) instead of raw array; was `android.view.View[]` -ArrayReturn: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillOptions(CharSequence[]) parameter #0: - Method parameter should be Collection<CharSequence> (or subclass) instead of raw array; was `java.lang.CharSequence[]` - - -AutoBoxing: android.os.VintfObject#getTargetFrameworkCompatibilityMatrixVersion(): - Must avoid boxed primitives (`java.lang.Long`) - - -BuilderSetStyle: android.os.StrictMode.ThreadPolicy.Builder#detectExplicitGc(): - Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.os.StrictMode.ThreadPolicy.Builder.detectExplicitGc() -BuilderSetStyle: android.os.StrictMode.VmPolicy.Builder#permitIncorrectContextUse(): - Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.os.StrictMode.VmPolicy.Builder.permitIncorrectContextUse() - - -ConcreteCollection: android.content.AutofillOptions#disabledActivities: - Field type is concrete collection (`android.util.ArrayMap`); must be higher-level interface -ConcreteCollection: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill: - Field type is concrete collection (`android.util.ArraySet`); must be higher-level interface -ConcreteCollection: android.content.ContentCaptureOptions#ContentCaptureOptions(int, int, int, int, int, android.util.ArraySet<android.content.ComponentName>) parameter #5: - Parameter type is concrete collection (`android.util.ArraySet`); must be higher-level interface -ConcreteCollection: android.content.ContentCaptureOptions#whitelistedComponents: - Field type is concrete collection (`android.util.ArraySet`); must be higher-level interface -ConcreteCollection: android.database.sqlite.SQLiteDebug.PagerStats#dbStats: - Field type is concrete collection (`java.util.ArrayList`); must be higher-level interface -ConcreteCollection: android.service.autofill.CompositeUserData#getFieldClassificationAlgorithms(): - Return type is concrete collection (`android.util.ArrayMap`); must be higher-level interface -ConcreteCollection: android.service.autofill.CompositeUserData#getFieldClassificationArgs(): - Return type is concrete collection (`android.util.ArrayMap`); must be higher-level interface -ConcreteCollection: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>) parameter #2: - Parameter type is concrete collection (`java.util.ArrayList`); must be higher-level interface -ConcreteCollection: android.service.autofill.UserData#getFieldClassificationAlgorithms(): - Return type is concrete collection (`android.util.ArrayMap`); must be higher-level interface - - -ContextFirst: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1: - Context is distinct, so it must be the first argument (method `get`) - - -EndsWithImpl: android.view.contentcapture.ViewNode.ViewStructureImpl: - Don't expose your implementation details: `ViewStructureImpl` ends with `Impl` - - -Enum: android.view.inspector.InspectableProperty.ValueType: - Enums are discouraged in Android APIs - - -EqualsAndHashCode: android.os.StrictMode.ViolationInfo#hashCode(): - Must override both equals and hashCode; missing one in android.os.StrictMode.ViolationInfo - - -ExecutorRegistration: android.media.audiofx.AudioEffect#setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener): - Registration methods should have overload that accepts delivery Executor: `setParameterListener` -ExecutorRegistration: android.permission.PermissionControllerManager#countPermissionApps(java.util.List<java.lang.String>, int, android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, android.os.Handler): - Registration methods should have overload that accepts delivery Executor: `countPermissionApps` -ExecutorRegistration: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler): - Registration methods should have overload that accepts delivery Executor: `getAppPermissions` -ExecutorRegistration: android.service.watchdog.ExplicitHealthCheckService#setCallback(android.os.RemoteCallback): - Registration methods should have overload that accepts delivery Executor: `setCallback` -ExecutorRegistration: android.window.WindowOrganizer#applySyncTransaction(android.window.WindowContainerTransaction, android.window.WindowContainerTransactionCallback): - Registration methods should have overload that accepts delivery Executor: `applySyncTransaction` - - -ForbiddenSuperClass: android.app.AppDetailsActivity: - AppDetailsActivity should not extend `Activity`. Activity subclasses are impossible to compose. Expose a composable API instead. - - -GenericException: android.service.autofill.CharSequenceTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int): - Methods must not throw generic exceptions (`java.lang.Exception`) -GenericException: android.service.autofill.DateTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int): - Methods must not throw generic exceptions (`java.lang.Exception`) -GenericException: android.service.autofill.ImageTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int): - Methods must not throw generic exceptions (`java.lang.Exception`) - - -GetterSetterNames: android.net.NetworkPolicyManager#getRestrictBackground(): - Symmetric method for `setRestrictBackground` must be named `isRestrictBackground`; was `getRestrictBackground` - - -IntentBuilderName: android.hardware.soundtrigger.KeyphraseEnrollmentInfo#getManageKeyphraseIntent(int, String, java.util.Locale): - Methods creating an Intent should be named `create<Foo>Intent()`, was `getManageKeyphraseIntent` - - -IntentName: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE: - Intent action constant name must be ACTION_FOO: VOICE_INTERACTION_SERVICE -IntentName: android.provider.Telephony.Sms.Intents#SMS_CARRIER_PROVISION_ACTION: - Intent action constant name must be ACTION_FOO: SMS_CARRIER_PROVISION_ACTION - - -KotlinOperator: android.os.PackageTagsList#contains(android.os.PackageTagsList): - Method can be invoked as a "in" operator from Kotlin: `contains` (this is usually desirable; just make sure it makes sense for this type of object) -KotlinOperator: android.util.SparseArrayMap#get(int, K): - Method can be invoked with an indexing operator from Kotlin: `get` (this is usually desirable; just make sure it makes sense for this type of object) - - -ListenerLast: android.permission.PermissionControllerManager#countPermissionApps(java.util.List<java.lang.String>, int, android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, android.os.Handler) parameter #3: - Listeners should always be at end of argument list (method `countPermissionApps`) -ListenerLast: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler) parameter #2: - Listeners should always be at end of argument list (method `getAppPermissions`) - - -ManagerConstructor: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context): - Managers must always be obtained from Context; no direct constructors - - -MinMaxConstant: android.os.UserHandle#MIN_SECONDARY_USER_ID: - If min/max could change in future, make them dynamic methods: android.os.UserHandle#MIN_SECONDARY_USER_ID -MinMaxConstant: android.view.autofill.AutofillManager#MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS: - If min/max could change in future, make them dynamic methods: android.view.autofill.AutofillManager#MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS - - -MissingGetterMatchingBuilder: android.media.VolumeShaper.Configuration.Builder#setOptionFlags(int): - android.media.VolumeShaper.Configuration does not declare a `getOptionFlags()` method matching method android.media.VolumeShaper.Configuration.Builder.setOptionFlags(int) -MissingGetterMatchingBuilder: android.media.audiopolicy.AudioPolicy.Builder#setIsTestFocusPolicy(boolean): - android.media.audiopolicy.AudioPolicy does not declare a `isIsTestFocusPolicy()` method matching method android.media.audiopolicy.AudioPolicy.Builder.setIsTestFocusPolicy(boolean) -MissingGetterMatchingBuilder: android.security.keystore.KeyGenParameterSpec.Builder#setUniqueIdIncluded(boolean): - android.security.keystore.KeyGenParameterSpec does not declare a `isUniqueIdIncluded()` method matching method android.security.keystore.KeyGenParameterSpec.Builder.setUniqueIdIncluded(boolean) -MissingGetterMatchingBuilder: android.telecom.ConnectionRequest.Builder#setIsAdhocConferenceCall(boolean): - android.telecom.ConnectionRequest does not declare a `isIsAdhocConferenceCall()` method matching method android.telecom.ConnectionRequest.Builder.setIsAdhocConferenceCall(boolean) -MissingGetterMatchingBuilder: android.telecom.ConnectionRequest.Builder#setRttPipeFromInCall(android.os.ParcelFileDescriptor): - android.telecom.ConnectionRequest does not declare a `getRttPipeFromInCall()` method matching method android.telecom.ConnectionRequest.Builder.setRttPipeFromInCall(android.os.ParcelFileDescriptor) -MissingGetterMatchingBuilder: android.telecom.ConnectionRequest.Builder#setRttPipeToInCall(android.os.ParcelFileDescriptor): - android.telecom.ConnectionRequest does not declare a `getRttPipeToInCall()` method matching method android.telecom.ConnectionRequest.Builder.setRttPipeToInCall(android.os.ParcelFileDescriptor) -MissingGetterMatchingBuilder: android.telecom.ConnectionRequest.Builder#setShouldShowIncomingCallUi(boolean): - android.telecom.ConnectionRequest does not declare a `shouldShowIncomingCallUi()` method matching method android.telecom.ConnectionRequest.Builder.setShouldShowIncomingCallUi(boolean) -MissingGetterMatchingBuilder: android.view.Display.Mode.Builder#setResolution(int, int): - android.view.Display.Mode does not declare a `getResolution()` method matching method android.view.Display.Mode.Builder.setResolution(int,int) - - -MissingNullability: android.app.Activity#onMovedToDisplay(int, android.content.res.Configuration) parameter #1: - Missing nullability on parameter `config` in method `onMovedToDisplay` -MissingNullability: android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName) parameter #0: - Missing nullability on parameter `activity` in method `alwaysShowUnsupportedCompileSdkWarning` -MissingNullability: android.app.ActivityManager#holdLock(android.os.IBinder, int) parameter #0: - Missing nullability on parameter `token` in method `holdLock` -MissingNullability: android.app.ActivityManager#scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int) parameter #0: - Missing nullability on parameter `packages` in method `scheduleApplicationInfoChanged` -MissingNullability: android.app.ActivityManager.TaskDescription#getIconFilename(): - Missing nullability on method `getIconFilename` return -MissingNullability: android.app.ActivityTaskManager#clearLaunchParamsForPackages(java.util.List<java.lang.String>) parameter #0: - Missing nullability on parameter `packageNames` in method `clearLaunchParamsForPackages` -MissingNullability: android.app.ActivityTaskManager#resizeTask(int, android.graphics.Rect) parameter #1: - Missing nullability on parameter `bounds` in method `resizeTask` -MissingNullability: android.app.ActivityTaskManager#supportsMultiWindow(android.content.Context) parameter #0: - Missing nullability on parameter `context` in method `supportsMultiWindow` -MissingNullability: android.app.ActivityTaskManager#supportsSplitScreenMultiWindow(android.content.Context) parameter #0: - Missing nullability on parameter `context` in method `supportsSplitScreenMultiWindow` MissingNullability: android.app.AppDetailsActivity#onCreate(android.os.Bundle) parameter #0: Missing nullability on parameter `savedInstanceState` in method `onCreate` -MissingNullability: android.app.AppOpsManager#isOperationActive(int, int, String) parameter #2: - Missing nullability on parameter `packageName` in method `isOperationActive` -MissingNullability: android.app.AppOpsManager#opToPermission(int): - Missing nullability on method `opToPermission` return -MissingNullability: android.app.AppOpsManager#permissionToOpCode(String) parameter #0: - Missing nullability on parameter `permission` in method `permissionToOpCode` -MissingNullability: android.app.AppOpsManager#setMode(int, int, String, int) parameter #2: - Missing nullability on parameter `packageName` in method `setMode` -MissingNullability: android.app.NotificationManager#allowAssistantAdjustment(String) parameter #0: - Missing nullability on parameter `capability` in method `allowAssistantAdjustment` -MissingNullability: android.app.NotificationManager#disallowAssistantAdjustment(String) parameter #0: - Missing nullability on parameter `capability` in method `disallowAssistantAdjustment` -MissingNullability: android.app.NotificationManager#getEffectsSuppressor(): - Missing nullability on method `getEffectsSuppressor` return -MissingNullability: android.app.TimePickerDialog#getTimePicker(): - Missing nullability on method `getTimePicker` return -MissingNullability: android.app.WindowConfiguration#compareTo(android.app.WindowConfiguration) parameter #0: - Missing nullability on parameter `that` in method `compareTo` -MissingNullability: android.app.WindowConfiguration#getAppBounds(): - Missing nullability on method `getAppBounds` return -MissingNullability: android.app.WindowConfiguration#getBounds(): - Missing nullability on method `getBounds` return -MissingNullability: android.app.WindowConfiguration#setAppBounds(android.graphics.Rect) parameter #0: - Missing nullability on parameter `rect` in method `setAppBounds` -MissingNullability: android.app.WindowConfiguration#setBounds(android.graphics.Rect) parameter #0: - Missing nullability on parameter `rect` in method `setBounds` -MissingNullability: android.app.WindowConfiguration#setTo(android.app.WindowConfiguration) parameter #0: - Missing nullability on parameter `other` in method `setTo` -MissingNullability: android.app.WindowConfiguration#writeToParcel(android.os.Parcel, int) parameter #0: - Missing nullability on parameter `dest` in method `writeToParcel` -MissingNullability: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle): - Missing nullability on method `getOwnerInstalledCaCerts` return -MissingNullability: android.app.admin.SecurityLog.SecurityEvent#SecurityEvent(long, byte[]) parameter #1: - Missing nullability on parameter `data` in method `SecurityEvent` -MissingNullability: android.app.prediction.AppPredictor#getSessionId(): - Missing nullability on method `getSessionId` return -MissingNullability: android.content.AutofillOptions#forWhitelistingItself(): - Missing nullability on method `forWhitelistingItself` return -MissingNullability: android.content.AutofillOptions#writeToParcel(android.os.Parcel, int) parameter #0: - Missing nullability on parameter `parcel` in method `writeToParcel` -MissingNullability: android.content.ContentCaptureOptions#forWhitelistingItself(): - Missing nullability on method `forWhitelistingItself` return -MissingNullability: android.content.ContentCaptureOptions#writeToParcel(android.os.Parcel, int) parameter #0: - Missing nullability on parameter `parcel` in method `writeToParcel` -MissingNullability: android.content.ContentResolver#getSyncAdapterPackagesForAuthorityAsUser(String, int): - Missing nullability on method `getSyncAdapterPackagesForAuthorityAsUser` return -MissingNullability: android.content.ContentResolver#getSyncAdapterPackagesForAuthorityAsUser(String, int) parameter #0: - Missing nullability on parameter `authority` in method `getSyncAdapterPackagesForAuthorityAsUser` -MissingNullability: android.content.pm.ActivityInfo#isTranslucentOrFloating(android.content.res.TypedArray) parameter #0: - Missing nullability on parameter `attributes` in method `isTranslucentOrFloating` -MissingNullability: android.content.pm.LauncherApps#LauncherApps(android.content.Context) parameter #0: - Missing nullability on parameter `context` in method `LauncherApps` -MissingNullability: android.content.pm.PackageManager#getHoldLockToken(): - Missing nullability on method `getHoldLockToken` return -MissingNullability: android.content.pm.PackageManager#getNamesForUids(int[]) parameter #0: - Missing nullability on parameter `uids` in method `getNamesForUids` -MissingNullability: android.content.pm.PackageManager#holdLock(android.os.IBinder, int) parameter #0: - Missing nullability on parameter `token` in method `holdLock` -MissingNullability: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context) parameter #0: - Missing nullability on parameter `context` in method `ShortcutManager` -MissingNullability: android.content.pm.UserInfo#UserInfo(android.content.pm.UserInfo) parameter #0: - Missing nullability on parameter `orig` in method `UserInfo` -MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int) parameter #1: - Missing nullability on parameter `name` in method `UserInfo` -MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int) parameter #2: - Missing nullability on parameter `iconPath` in method `UserInfo` -MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int, String) parameter #1: - Missing nullability on parameter `name` in method `UserInfo` -MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int, String) parameter #2: - Missing nullability on parameter `iconPath` in method `UserInfo` -MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int, String) parameter #4: - Missing nullability on parameter `userType` in method `UserInfo` -MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, int) parameter #1: - Missing nullability on parameter `name` in method `UserInfo` -MissingNullability: android.content.pm.UserInfo#getUserHandle(): - Missing nullability on method `getUserHandle` return -MissingNullability: android.content.pm.UserInfo#iconPath: - Missing nullability on field `iconPath` in class `class android.content.pm.UserInfo` -MissingNullability: android.content.pm.UserInfo#lastLoggedInFingerprint: - Missing nullability on field `lastLoggedInFingerprint` in class `class android.content.pm.UserInfo` -MissingNullability: android.content.pm.UserInfo#name: - Missing nullability on field `name` in class `class android.content.pm.UserInfo` -MissingNullability: android.content.pm.UserInfo#userType: - Missing nullability on field `userType` in class `class android.content.pm.UserInfo` -MissingNullability: android.content.pm.UserInfo#writeToParcel(android.os.Parcel, int) parameter #0: - Missing nullability on parameter `dest` in method `writeToParcel` -MissingNullability: android.content.res.AssetManager#getOverlayablesToString(String) parameter #0: - Missing nullability on parameter `packageName` in method `getOverlayablesToString` -MissingNullability: android.content.res.Configuration#windowConfiguration: - Missing nullability on field `windowConfiguration` in class `class android.content.res.Configuration` -MissingNullability: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]) parameter #0: - Missing nullability on parameter `printer` in method `dump` -MissingNullability: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]) parameter #1: - Missing nullability on parameter `args` in method `dump` -MissingNullability: android.database.sqlite.SQLiteDebug#getDatabaseInfo(): - Missing nullability on method `getDatabaseInfo` return -MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#DbStats(String, long, long, int, int, int, int) parameter #0: - Missing nullability on parameter `dbName` in method `DbStats` -MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#cache: - Missing nullability on field `cache` in class `class android.database.sqlite.SQLiteDebug.DbStats` -MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#dbName: - Missing nullability on field `dbName` in class `class android.database.sqlite.SQLiteDebug.DbStats` -MissingNullability: android.database.sqlite.SQLiteDebug.PagerStats#dbStats: - Missing nullability on field `dbStats` in class `class android.database.sqlite.SQLiteDebug.PagerStats` -MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #0: - Missing nullability on parameter `db` in method `SQLiteDirectCursorDriver` -MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #1: - Missing nullability on parameter `sql` in method `SQLiteDirectCursorDriver` -MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #2: - Missing nullability on parameter `editTable` in method `SQLiteDirectCursorDriver` -MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #3: - Missing nullability on parameter `cancellationSignal` in method `SQLiteDirectCursorDriver` -MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#cursorRequeried(android.database.Cursor) parameter #0: - Missing nullability on parameter `cursor` in method `cursorRequeried` -MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]): - Missing nullability on method `query` return -MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]) parameter #0: - Missing nullability on parameter `factory` in method `query` -MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]) parameter #1: - Missing nullability on parameter `selectionArgs` in method `query` -MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#setBindArguments(String[]) parameter #0: - Missing nullability on parameter `bindArgs` in method `setBindArguments` -MissingNullability: android.database.sqlite.SQLiteGlobal#getDefaultJournalMode(): - Missing nullability on method `getDefaultJournalMode` return -MissingNullability: android.database.sqlite.SQLiteGlobal#getDefaultSyncMode(): - Missing nullability on method `getDefaultSyncMode` return -MissingNullability: android.database.sqlite.SQLiteGlobal#getWALSyncMode(): - Missing nullability on method `getWALSyncMode` return -MissingNullability: android.graphics.ImageDecoder#createSource(android.content.res.Resources, java.io.InputStream, int) parameter #0: - Missing nullability on parameter `res` in method `createSource` -MissingNullability: android.graphics.drawable.AdaptiveIconDrawable#getSafeZone(): - Missing nullability on method `getSafeZone` return -MissingNullability: android.graphics.drawable.ColorDrawable#getXfermode(): - Missing nullability on method `getXfermode` return -MissingNullability: android.hardware.camera2.CameraManager#getCameraIdListNoLazy(): - Missing nullability on method `getCameraIdListNoLazy` return -MissingNullability: android.hardware.display.AmbientDisplayConfiguration#AmbientDisplayConfiguration(android.content.Context) parameter #0: - Missing nullability on parameter `context` in method `AmbientDisplayConfiguration` -MissingNullability: android.media.AudioAttributes#getSdkUsages(): - Missing nullability on method `getSdkUsages` return -MissingNullability: android.media.AudioManager#getPublicStreamTypes(): - Missing nullability on method `getPublicStreamTypes` return -MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #3: - Missing nullability on parameter `clientFormat` in method `AudioRecordingConfiguration` -MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #4: - Missing nullability on parameter `devFormat` in method `AudioRecordingConfiguration` -MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #6: - Missing nullability on parameter `packageName` in method `AudioRecordingConfiguration` -MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #10: - Missing nullability on parameter `clientEffects` in method `AudioRecordingConfiguration` -MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #11: - Missing nullability on parameter `deviceEffects` in method `AudioRecordingConfiguration` -MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #3: - Missing nullability on parameter `clientFormat` in method `AudioRecordingConfiguration` -MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #4: - Missing nullability on parameter `devFormat` in method `AudioRecordingConfiguration` -MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #6: - Missing nullability on parameter `packageName` in method `AudioRecordingConfiguration` -MissingNullability: android.media.PlaybackParams#setAudioStretchMode(int): - Missing nullability on method `setAudioStretchMode` return -MissingNullability: android.media.audiofx.AudioEffect#EFFECT_TYPE_NULL: - Missing nullability on field `EFFECT_TYPE_NULL` in class `class android.media.audiofx.AudioEffect` -MissingNullability: android.media.audiofx.AudioEffect#byteArrayToInt(byte[]) parameter #0: - Missing nullability on parameter `valueBuf` in method `byteArrayToInt` -MissingNullability: android.media.audiofx.AudioEffect#byteArrayToShort(byte[]) parameter #0: - Missing nullability on parameter `valueBuf` in method `byteArrayToShort` -MissingNullability: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]) parameter #0: - Missing nullability on parameter `param` in method `getParameter` -MissingNullability: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]) parameter #1: - Missing nullability on parameter `value` in method `getParameter` -MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, byte[]) parameter #1: - Missing nullability on parameter `value` in method `getParameter` -MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, int[]) parameter #1: - Missing nullability on parameter `value` in method `getParameter` -MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, short[]) parameter #1: - Missing nullability on parameter `value` in method `getParameter` -MissingNullability: android.media.audiofx.AudioEffect#getParameter(int[], short[]) parameter #0: - Missing nullability on parameter `param` in method `getParameter` -MissingNullability: android.media.audiofx.AudioEffect#getParameter(int[], short[]) parameter #1: - Missing nullability on parameter `value` in method `getParameter` -MissingNullability: android.media.audiofx.AudioEffect#intToByteArray(int): - Missing nullability on method `intToByteArray` return -MissingNullability: android.media.audiofx.AudioEffect#isEffectTypeAvailable(java.util.UUID) parameter #0: - Missing nullability on parameter `type` in method `isEffectTypeAvailable` -MissingNullability: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]) parameter #0: - Missing nullability on parameter `param` in method `setParameter` -MissingNullability: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]) parameter #1: - Missing nullability on parameter `value` in method `setParameter` -MissingNullability: android.media.audiofx.AudioEffect#setParameter(int, byte[]) parameter #1: - Missing nullability on parameter `value` in method `setParameter` -MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], byte[]) parameter #0: - Missing nullability on parameter `param` in method `setParameter` -MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], byte[]) parameter #1: - Missing nullability on parameter `value` in method `setParameter` -MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], int[]) parameter #0: - Missing nullability on parameter `param` in method `setParameter` -MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], int[]) parameter #1: - Missing nullability on parameter `value` in method `setParameter` -MissingNullability: android.media.audiofx.AudioEffect#setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener) parameter #0: - Missing nullability on parameter `listener` in method `setParameterListener` -MissingNullability: android.media.audiofx.AudioEffect#shortToByteArray(short): - Missing nullability on method `shortToByteArray` return -MissingNullability: android.media.audiofx.AudioEffect.Descriptor#Descriptor(android.os.Parcel) parameter #0: - Missing nullability on parameter `in` in method `Descriptor` -MissingNullability: android.media.audiofx.AudioEffect.Descriptor#writeToParcel(android.os.Parcel) parameter #0: - Missing nullability on parameter `dest` in method `writeToParcel` -MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #0: - Missing nullability on parameter `effect` in method `onParameterChange` -MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #2: - Missing nullability on parameter `param` in method `onParameterChange` -MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #3: - Missing nullability on parameter `value` in method `onParameterChange` -MissingNullability: android.os.Build#is64BitAbi(String) parameter #0: - Missing nullability on parameter `abi` in method `is64BitAbi` -MissingNullability: android.os.Build.VERSION#ACTIVE_CODENAMES: - Missing nullability on field `ACTIVE_CODENAMES` in class `class android.os.Build.VERSION` -MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...): - Missing nullability on method `buildPath` return -MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...) parameter #0: - Missing nullability on parameter `base` in method `buildPath` -MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...) parameter #1: - Missing nullability on parameter `segments` in method `buildPath` -MissingNullability: android.os.FileUtils#contains(java.io.File, java.io.File) parameter #0: - Missing nullability on parameter `dir` in method `contains` -MissingNullability: android.os.FileUtils#contains(java.io.File, java.io.File) parameter #1: - Missing nullability on parameter `file` in method `contains` -MissingNullability: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor): - Missing nullability on method `getFile` return -MissingNullability: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor) parameter #0: - Missing nullability on parameter `fd` in method `getFile` -MissingNullability: android.os.StrictMode#setViolationLogger(android.os.StrictMode.ViolationLogger) parameter #0: - Missing nullability on parameter `listener` in method `setViolationLogger` -MissingNullability: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel) parameter #0: - Missing nullability on parameter `in` in method `ViolationInfo` -MissingNullability: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel, boolean) parameter #0: - Missing nullability on parameter `in` in method `ViolationInfo` -MissingNullability: android.os.StrictMode.ViolationInfo#broadcastIntentAction: - Missing nullability on field `broadcastIntentAction` in class `class android.os.StrictMode.ViolationInfo` -MissingNullability: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String) parameter #0: - Missing nullability on parameter `pw` in method `dump` -MissingNullability: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String) parameter #1: - Missing nullability on parameter `prefix` in method `dump` -MissingNullability: android.os.StrictMode.ViolationInfo#getStackTrace(): - Missing nullability on method `getStackTrace` return -MissingNullability: android.os.StrictMode.ViolationInfo#getViolationClass(): - Missing nullability on method `getViolationClass` return -MissingNullability: android.os.StrictMode.ViolationInfo#getViolationDetails(): - Missing nullability on method `getViolationDetails` return -MissingNullability: android.os.StrictMode.ViolationInfo#tags: - Missing nullability on field `tags` in class `class android.os.StrictMode.ViolationInfo` -MissingNullability: android.os.StrictMode.ViolationInfo#writeToParcel(android.os.Parcel, int) parameter #0: - Missing nullability on parameter `dest` in method `writeToParcel` -MissingNullability: android.os.StrictMode.ViolationLogger#log(android.os.StrictMode.ViolationInfo) parameter #0: - Missing nullability on parameter `info` in method `log` -MissingNullability: android.os.VibrationEffect#RINGTONES: - Missing nullability on field `RINGTONES` in class `class android.os.VibrationEffect` -MissingNullability: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #0: - Missing nullability on parameter `uri` in method `get` -MissingNullability: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1: - Missing nullability on parameter `context` in method `get` -MissingNullability: android.os.VibrationEffect#get(int): - Missing nullability on method `get` return -MissingNullability: android.os.VibrationEffect#get(int, boolean): - Missing nullability on method `get` return -MissingNullability: android.os.VintfObject#getHalNamesAndVersions(): - Missing nullability on method `getHalNamesAndVersions` return -MissingNullability: android.os.VintfObject#getSepolicyVersion(): - Missing nullability on method `getSepolicyVersion` return -MissingNullability: android.os.VintfObject#getTargetFrameworkCompatibilityMatrixVersion(): - Missing nullability on method `getTargetFrameworkCompatibilityMatrixVersion` return -MissingNullability: android.os.VintfObject#getVndkSnapshots(): - Missing nullability on method `getVndkSnapshots` return -MissingNullability: android.os.VintfObject#report(): - Missing nullability on method `report` return -MissingNullability: android.os.VintfRuntimeInfo#getCpuInfo(): - Missing nullability on method `getCpuInfo` return -MissingNullability: android.os.VintfRuntimeInfo#getHardwareId(): - Missing nullability on method `getHardwareId` return -MissingNullability: android.os.VintfRuntimeInfo#getKernelVersion(): - Missing nullability on method `getKernelVersion` return -MissingNullability: android.os.VintfRuntimeInfo#getNodeName(): - Missing nullability on method `getNodeName` return -MissingNullability: android.os.VintfRuntimeInfo#getOsName(): - Missing nullability on method `getOsName` return -MissingNullability: android.os.VintfRuntimeInfo#getOsRelease(): - Missing nullability on method `getOsRelease` return -MissingNullability: android.os.VintfRuntimeInfo#getOsVersion(): - Missing nullability on method `getOsVersion` return -MissingNullability: android.os.WorkSource#add(int, String) parameter #1: - Missing nullability on parameter `name` in method `add` -MissingNullability: android.os.health.HealthKeys.Constants#Constants(Class) parameter #0: - Missing nullability on parameter `clazz` in method `Constants` -MissingNullability: android.os.health.HealthKeys.Constants#getDataType(): - Missing nullability on method `getDataType` return -MissingNullability: android.os.health.HealthKeys.Constants#getKeys(int): - Missing nullability on method `getKeys` return -MissingNullability: android.os.health.HealthStats#HealthStats(android.os.Parcel) parameter #0: - Missing nullability on parameter `in` in method `HealthStats` -MissingNullability: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.Parcel) parameter #0: - Missing nullability on parameter `in` in method `HealthStatsParceler` -MissingNullability: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.health.HealthStatsWriter) parameter #0: - Missing nullability on parameter `writer` in method `HealthStatsParceler` -MissingNullability: android.os.health.HealthStatsParceler#getHealthStats(): - Missing nullability on method `getHealthStats` return -MissingNullability: android.os.health.HealthStatsParceler#writeToParcel(android.os.Parcel, int) parameter #0: - Missing nullability on parameter `out` in method `writeToParcel` -MissingNullability: android.os.health.HealthStatsWriter#HealthStatsWriter(android.os.health.HealthKeys.Constants) parameter #0: - Missing nullability on parameter `constants` in method `HealthStatsWriter` -MissingNullability: android.os.health.HealthStatsWriter#addMeasurements(int, String, long) parameter #1: - Missing nullability on parameter `name` in method `addMeasurements` -MissingNullability: android.os.health.HealthStatsWriter#addStats(int, String, android.os.health.HealthStatsWriter) parameter #1: - Missing nullability on parameter `name` in method `addStats` -MissingNullability: android.os.health.HealthStatsWriter#addStats(int, String, android.os.health.HealthStatsWriter) parameter #2: - Missing nullability on parameter `value` in method `addStats` -MissingNullability: android.os.health.HealthStatsWriter#addTimers(int, String, android.os.health.TimerStat) parameter #1: - Missing nullability on parameter `name` in method `addTimers` -MissingNullability: android.os.health.HealthStatsWriter#addTimers(int, String, android.os.health.TimerStat) parameter #2: - Missing nullability on parameter `value` in method `addTimers` -MissingNullability: android.os.health.HealthStatsWriter#flattenToParcel(android.os.Parcel) parameter #0: - Missing nullability on parameter `out` in method `flattenToParcel` -MissingNullability: android.os.storage.StorageVolume#getPath(): - Missing nullability on method `getPath` return -MissingNullability: android.provider.CalendarContract.Calendars#SYNC_WRITABLE_COLUMNS: - Missing nullability on field `SYNC_WRITABLE_COLUMNS` in class `class android.provider.CalendarContract.Calendars` -MissingNullability: android.provider.CalendarContract.Events#SYNC_WRITABLE_COLUMNS: - Missing nullability on field `SYNC_WRITABLE_COLUMNS` in class `class android.provider.CalendarContract.Events` -MissingNullability: android.provider.ContactsContract.RawContactsEntity#CORP_CONTENT_URI: - Missing nullability on field `CORP_CONTENT_URI` in class `class android.provider.ContactsContract.RawContactsEntity` -MissingNullability: android.security.keystore.KeyProtection.Builder#setBoundToSpecificSecureUserId(long): - Missing nullability on method `setBoundToSpecificSecureUserId` return -MissingNullability: android.service.autofill.CompositeUserData#getCategoryIds(): - Missing nullability on method `getCategoryIds` return -MissingNullability: android.service.autofill.CompositeUserData#getDefaultFieldClassificationArgs(): - Missing nullability on method `getDefaultFieldClassificationArgs` return -MissingNullability: android.service.autofill.CompositeUserData#getFieldClassificationAlgorithms(): - Missing nullability on method `getFieldClassificationAlgorithms` return -MissingNullability: android.service.autofill.CompositeUserData#getFieldClassificationArgs(): - Missing nullability on method `getFieldClassificationArgs` return -MissingNullability: android.service.autofill.CompositeUserData#getValues(): - Missing nullability on method `getValues` return -MissingNullability: android.service.autofill.CompositeUserData#writeToParcel(android.os.Parcel, int) parameter #0: - Missing nullability on parameter `parcel` in method `writeToParcel` -MissingNullability: android.service.autofill.UserData#getFieldClassificationAlgorithms(): - Missing nullability on method `getFieldClassificationAlgorithms` return -MissingNullability: android.telecom.Call.Details#getTelecomCallId(): - Missing nullability on method `getTelecomCallId` return -MissingNullability: android.telephony.ServiceState#addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo) parameter #0: - Missing nullability on parameter `nri` in method `addNetworkRegistrationInfo` -MissingNullability: android.telephony.ServiceState#setCellBandwidths(int[]) parameter #0: - Missing nullability on parameter `bandwidths` in method `setCellBandwidths` -MissingNullability: android.telephony.SmsManager#checkSmsShortCodeDestination(String, String) parameter #0: - Missing nullability on parameter `destAddress` in method `checkSmsShortCodeDestination` -MissingNullability: android.telephony.SmsManager#checkSmsShortCodeDestination(String, String) parameter #1: - Missing nullability on parameter `countryIso` in method `checkSmsShortCodeDestination` -MissingNullability: android.telephony.TelephonyManager#HAL_VERSION_UNKNOWN: - Missing nullability on field `HAL_VERSION_UNKNOWN` in class `class android.telephony.TelephonyManager` -MissingNullability: android.telephony.TelephonyManager#HAL_VERSION_UNSUPPORTED: - Missing nullability on field `HAL_VERSION_UNSUPPORTED` in class `class android.telephony.TelephonyManager` -MissingNullability: android.telephony.TelephonyManager#getLine1AlphaTag(): - Missing nullability on method `getLine1AlphaTag` return -MissingNullability: android.telephony.TelephonyManager#getRadioHalVersion(): - Missing nullability on method `getRadioHalVersion` return -MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #0: - Missing nullability on parameter `mccmnc` in method `setCarrierTestOverride` -MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #1: - Missing nullability on parameter `imsi` in method `setCarrierTestOverride` -MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #2: - Missing nullability on parameter `iccid` in method `setCarrierTestOverride` -MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #3: - Missing nullability on parameter `gid1` in method `setCarrierTestOverride` -MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #4: - Missing nullability on parameter `gid2` in method `setCarrierTestOverride` -MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #5: - Missing nullability on parameter `plmn` in method `setCarrierTestOverride` -MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #6: - Missing nullability on parameter `spn` in method `setCarrierTestOverride` -MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #7: - Missing nullability on parameter `carrierPriviledgeRules` in method `setCarrierTestOverride` -MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #8: - Missing nullability on parameter `apn` in method `setCarrierTestOverride` -MissingNullability: android.text.Selection.MemoryTextWatcher#afterTextChanged(android.text.Editable) parameter #0: - Missing nullability on parameter `s` in method `afterTextChanged` -MissingNullability: android.text.Selection.MemoryTextWatcher#beforeTextChanged(CharSequence, int, int, int) parameter #0: - Missing nullability on parameter `s` in method `beforeTextChanged` -MissingNullability: android.text.Selection.MemoryTextWatcher#onTextChanged(CharSequence, int, int, int) parameter #0: - Missing nullability on parameter `s` in method `onTextChanged` -MissingNullability: android.transition.TransitionManager#getTransition(android.transition.Scene): - Missing nullability on method `getTransition` return -MissingNullability: android.transition.TransitionManager#getTransition(android.transition.Scene) parameter #0: - Missing nullability on parameter `scene` in method `getTransition` -MissingNullability: android.util.FeatureFlagUtils#getAllFeatureFlags(): - Missing nullability on method `getAllFeatureFlags` return -MissingNullability: android.util.FeatureFlagUtils#isEnabled(android.content.Context, String) parameter #0: - Missing nullability on parameter `context` in method `isEnabled` -MissingNullability: android.util.FeatureFlagUtils#isEnabled(android.content.Context, String) parameter #1: - Missing nullability on parameter `feature` in method `isEnabled` -MissingNullability: android.util.FeatureFlagUtils#setEnabled(android.content.Context, String, boolean) parameter #0: - Missing nullability on parameter `context` in method `setEnabled` -MissingNullability: android.util.FeatureFlagUtils#setEnabled(android.content.Context, String, boolean) parameter #1: - Missing nullability on parameter `feature` in method `setEnabled` -MissingNullability: android.util.TimeUtils#formatDuration(long): - Missing nullability on method `formatDuration` return -MissingNullability: android.util.proto.EncodedBuffer#dumpBuffers(String) parameter #0: - Missing nullability on parameter `tag` in method `dumpBuffers` -MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #0: - Missing nullability on parameter `tag` in method `dumpByteString` -MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #1: - Missing nullability on parameter `prefix` in method `dumpByteString` -MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #2: - Missing nullability on parameter `buf` in method `dumpByteString` -MissingNullability: android.util.proto.EncodedBuffer#getBytes(int): - Missing nullability on method `getBytes` return -MissingNullability: android.util.proto.EncodedBuffer#getDebugString(): - Missing nullability on method `getDebugString` return -MissingNullability: android.util.proto.EncodedBuffer#writeRawBuffer(byte[]) parameter #0: - Missing nullability on parameter `val` in method `writeRawBuffer` -MissingNullability: android.util.proto.EncodedBuffer#writeRawBuffer(byte[], int, int) parameter #0: - Missing nullability on parameter `val` in method `writeRawBuffer` -MissingNullability: android.util.proto.ProtoParseException#ProtoParseException(String) parameter #0: - Missing nullability on parameter `msg` in method `ProtoParseException` -MissingNullability: android.util.proto.WireTypeMismatchException#WireTypeMismatchException(String) parameter #0: - Missing nullability on parameter `msg` in method `WireTypeMismatchException` -MissingNullability: android.view.Choreographer#postCallback(int, Runnable, Object) parameter #1: - Missing nullability on parameter `action` in method `postCallback` -MissingNullability: android.view.Choreographer#postCallback(int, Runnable, Object) parameter #2: - Missing nullability on parameter `token` in method `postCallback` -MissingNullability: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long) parameter #1: - Missing nullability on parameter `action` in method `postCallbackDelayed` -MissingNullability: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long) parameter #2: - Missing nullability on parameter `token` in method `postCallbackDelayed` -MissingNullability: android.view.Choreographer#removeCallbacks(int, Runnable, Object) parameter #1: - Missing nullability on parameter `action` in method `removeCallbacks` -MissingNullability: android.view.Choreographer#removeCallbacks(int, Runnable, Object) parameter #2: - Missing nullability on parameter `token` in method `removeCallbacks` -MissingNullability: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0: - Missing nullability on parameter `views` in method `sort` -MissingNullability: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #3: - Missing nullability on parameter `root` in method `sort` -MissingNullability: android.view.KeyEvent#actionToString(int): - Missing nullability on method `actionToString` return -MissingNullability: android.view.SurfaceControlViewHost#relayout(android.view.WindowManager.LayoutParams) parameter #0: - Missing nullability on parameter `attrs` in method `relayout` -MissingNullability: android.view.View#getTooltipView(): - Missing nullability on method `getTooltipView` return -MissingNullability: android.view.View#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #0: - Missing nullability on parameter `background` in method `isDefaultFocusHighlightNeeded` -MissingNullability: android.view.View#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #1: - Missing nullability on parameter `foreground` in method `isDefaultFocusHighlightNeeded` -MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #0: - Missing nullability on parameter `tree` in method `startRenderingCommandsCapture` -MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #1: - Missing nullability on parameter `executor` in method `startRenderingCommandsCapture` -MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #2: - Missing nullability on parameter `callback` in method `startRenderingCommandsCapture` -MissingNullability: android.view.WindowManager#holdLock(android.os.IBinder, int) parameter #0: - Missing nullability on parameter `token` in method `holdLock` -MissingNullability: android.view.WindowManager.LayoutParams#accessibilityTitle: - Missing nullability on field `accessibilityTitle` in class `class android.view.WindowManager.LayoutParams` -MissingNullability: android.view.accessibility.AccessibilityNodeInfo#writeToParcelNoRecycle(android.os.Parcel, int) parameter #0: - Missing nullability on parameter `parcel` in method `writeToParcelNoRecycle` -MissingNullability: android.view.accessibility.AccessibilityWindowInfo#setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger) parameter #0: - Missing nullability on parameter `counter` in method `setNumInstancesInUseCounter` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#asyncNewChild(int): - Missing nullability on method `asyncNewChild` return -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getAutofillId(): - Missing nullability on method `getAutofillId` return -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getExtras(): - Missing nullability on method `getExtras` return -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getHint(): - Missing nullability on method `getHint` return -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getNode(): - Missing nullability on method `getNode` return -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getTempRect(): - Missing nullability on method `getTempRect` return -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getText(): - Missing nullability on method `getText` return -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newChild(int): - Missing nullability on method `newChild` return -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newHtmlInfoBuilder(String): - Missing nullability on method `newHtmlInfoBuilder` return -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newHtmlInfoBuilder(String) parameter #0: - Missing nullability on parameter `tagName` in method `newHtmlInfoBuilder` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillHints(String[]) parameter #0: - Missing nullability on parameter `hints` in method `setAutofillHints` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillId(android.view.autofill.AutofillId) parameter #0: - Missing nullability on parameter `id` in method `setAutofillId` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillId(android.view.autofill.AutofillId, int) parameter #0: - Missing nullability on parameter `parentId` in method `setAutofillId` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillOptions(CharSequence[]) parameter #0: - Missing nullability on parameter `options` in method `setAutofillOptions` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillValue(android.view.autofill.AutofillValue) parameter #0: - Missing nullability on parameter `value` in method `setAutofillValue` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setClassName(String) parameter #0: - Missing nullability on parameter `className` in method `setClassName` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setContentDescription(CharSequence) parameter #0: - Missing nullability on parameter `contentDescription` in method `setContentDescription` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHint(CharSequence) parameter #0: - Missing nullability on parameter `hint` in method `setHint` MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHintIdEntry(String) parameter #0: Missing nullability on parameter `entryName` in method `setHintIdEntry` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHtmlInfo(android.view.ViewStructure.HtmlInfo) parameter #0: - Missing nullability on parameter `htmlInfo` in method `setHtmlInfo` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #1: - Missing nullability on parameter `packageName` in method `setId` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #2: - Missing nullability on parameter `typeName` in method `setId` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #3: - Missing nullability on parameter `entryName` in method `setId` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setLocaleList(android.os.LocaleList) parameter #0: - Missing nullability on parameter `localeList` in method `setLocaleList` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setText(CharSequence) parameter #0: - Missing nullability on parameter `text` in method `setText` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setText(CharSequence, int, int) parameter #0: - Missing nullability on parameter `text` in method `setText` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTextLines(int[], int[]) parameter #0: - Missing nullability on parameter `charOffsets` in method `setTextLines` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTextLines(int[], int[]) parameter #1: - Missing nullability on parameter `baselines` in method `setTextLines` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTransformation(android.graphics.Matrix) parameter #0: - Missing nullability on parameter `matrix` in method `setTransformation` -MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setWebDomain(String) parameter #0: - Missing nullability on parameter `domain` in method `setWebDomain` -MissingNullability: android.widget.CalendarView#getBoundsForDate(long, android.graphics.Rect) parameter #1: - Missing nullability on parameter `outBounds` in method `getBoundsForDate` MissingNullability: android.widget.ImageView#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #0: Missing nullability on parameter `background` in method `isDefaultFocusHighlightNeeded` MissingNullability: android.widget.ImageView#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #1: Missing nullability on parameter `foreground` in method `isDefaultFocusHighlightNeeded` -MissingNullability: android.widget.Magnifier#getMagnifierDefaultSize(): - Missing nullability on method `getMagnifierDefaultSize` return -MissingNullability: android.widget.Magnifier#setOnOperationCompleteCallback(android.widget.Magnifier.Callback) parameter #0: - Missing nullability on parameter `callback` in method `setOnOperationCompleteCallback` -MissingNullability: android.widget.NumberPicker#getDisplayedValueForCurrentSelection(): - Missing nullability on method `getDisplayedValueForCurrentSelection` return -MissingNullability: android.widget.PopupMenu#getMenuListView(): - Missing nullability on method `getMenuListView` return -MissingNullability: android.widget.TimePicker#getAmView(): - Missing nullability on method `getAmView` return -MissingNullability: android.widget.TimePicker#getHourView(): - Missing nullability on method `getHourView` return -MissingNullability: android.widget.TimePicker#getMinuteView(): - Missing nullability on method `getMinuteView` return -MissingNullability: android.widget.TimePicker#getPmView(): - Missing nullability on method `getPmView` return - - -MutableBareField: android.content.AutofillOptions#appDisabledExpiration: - Bare field appDisabledExpiration must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.AutofillOptions#augmentedAutofillEnabled: - Bare field augmentedAutofillEnabled must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.AutofillOptions#disabledActivities: - Bare field disabledActivities must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill: - Bare field whitelistedActivitiesForAugmentedAutofill must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#convertedFromPreCreated: - Bare field convertedFromPreCreated must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#creationTime: - Bare field creationTime must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#flags: - Bare field flags must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#guestToRemove: - Bare field guestToRemove must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#iconPath: - Bare field iconPath must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#id: - Bare field id must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#lastLoggedInFingerprint: - Bare field lastLoggedInFingerprint must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#lastLoggedInTime: - Bare field lastLoggedInTime must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#name: - Bare field name must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#partial: - Bare field partial must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#preCreated: - Bare field preCreated must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#profileBadge: - Bare field profileBadge must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#profileGroupId: - Bare field profileGroupId must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#restrictedProfileParentId: - Bare field restrictedProfileParentId must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#serialNumber: - Bare field serialNumber must be marked final, or moved behind accessors if mutable -MutableBareField: android.content.pm.UserInfo#userType: - Bare field userType must be marked final, or moved behind accessors if mutable -MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#cache: - Bare field cache must be marked final, or moved behind accessors if mutable -MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbName: - Bare field dbName must be marked final, or moved behind accessors if mutable -MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbSize: - Bare field dbSize must be marked final, or moved behind accessors if mutable -MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#lookaside: - Bare field lookaside must be marked final, or moved behind accessors if mutable -MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#pageSize: - Bare field pageSize must be marked final, or moved behind accessors if mutable -MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#dbStats: - Bare field dbStats must be marked final, or moved behind accessors if mutable -MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#largestMemAlloc: - Bare field largestMemAlloc must be marked final, or moved behind accessors if mutable -MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#memoryUsed: - Bare field memoryUsed must be marked final, or moved behind accessors if mutable -MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#pageCacheOverflow: - Bare field pageCacheOverflow must be marked final, or moved behind accessors if mutable -MutableBareField: android.os.StrictMode.ViolationInfo#broadcastIntentAction: - Bare field broadcastIntentAction must be marked final, or moved behind accessors if mutable -MutableBareField: android.os.StrictMode.ViolationInfo#durationMillis: - Bare field durationMillis must be marked final, or moved behind accessors if mutable -MutableBareField: android.os.StrictMode.ViolationInfo#numAnimationsRunning: - Bare field numAnimationsRunning must be marked final, or moved behind accessors if mutable -MutableBareField: android.os.StrictMode.ViolationInfo#numInstances: - Bare field numInstances must be marked final, or moved behind accessors if mutable -MutableBareField: android.os.StrictMode.ViolationInfo#tags: - Bare field tags must be marked final, or moved behind accessors if mutable -MutableBareField: android.os.StrictMode.ViolationInfo#violationNumThisLoop: - Bare field violationNumThisLoop must be marked final, or moved behind accessors if mutable -MutableBareField: android.os.StrictMode.ViolationInfo#violationUptimeMillis: - Bare field violationUptimeMillis must be marked final, or moved behind accessors if mutable - - -NoByteOrShort: android.media.audiofx.AudioEffect#byteArrayToShort(byte[]): - Should avoid odd sized primitives; use `int` instead of `short` in method android.media.audiofx.AudioEffect.byteArrayToShort(byte[]) -NoByteOrShort: android.media.audiofx.AudioEffect#setParameter(int, short) parameter #1: - Should avoid odd sized primitives; use `int` instead of `short` in parameter value in android.media.audiofx.AudioEffect.setParameter(int param, short value) -NoByteOrShort: android.media.audiofx.AudioEffect#shortToByteArray(short) parameter #0: - Should avoid odd sized primitives; use `int` instead of `short` in parameter value in android.media.audiofx.AudioEffect.shortToByteArray(short value) -NoByteOrShort: android.util.proto.EncodedBuffer#readRawByte(): - Should avoid odd sized primitives; use `int` instead of `byte` in method android.util.proto.EncodedBuffer.readRawByte() -NoByteOrShort: android.util.proto.EncodedBuffer#writeRawByte(byte) parameter #0: - Should avoid odd sized primitives; use `int` instead of `byte` in parameter val in android.util.proto.EncodedBuffer.writeRawByte(byte val) - - -NoSettingsProvider: android.provider.Settings.Global#APP_OPS_CONSTANTS: - New setting keys are not allowed (Field: APP_OPS_CONSTANTS); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#AUTOMATIC_POWER_SAVE_MODE: - New setting keys are not allowed (Field: AUTOMATIC_POWER_SAVE_MODE); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#BATTERY_SAVER_CONSTANTS: - New setting keys are not allowed (Field: BATTERY_SAVER_CONSTANTS); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD: - New setting keys are not allowed (Field: DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#DYNAMIC_POWER_SAVINGS_ENABLED: - New setting keys are not allowed (Field: DYNAMIC_POWER_SAVINGS_ENABLED); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#HDR_CONVERSION_MODE: - New setting keys are not allowed (Field: HDR_CONVERSION_MODE); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#HDR_FORCE_CONVERSION_TYPE: - New setting keys are not allowed (Field: HDR_FORCE_CONVERSION_TYPE); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#HIDDEN_API_BLACKLIST_EXEMPTIONS: - New setting keys are not allowed (Field: HIDDEN_API_BLACKLIST_EXEMPTIONS); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#HIDDEN_API_POLICY: - New setting keys are not allowed (Field: HIDDEN_API_POLICY); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#HIDE_ERROR_DIALOGS: - New setting keys are not allowed (Field: HIDE_ERROR_DIALOGS); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#LOW_POWER_MODE: - New setting keys are not allowed (Field: LOW_POWER_MODE); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#LOW_POWER_MODE_STICKY: - New setting keys are not allowed (Field: LOW_POWER_MODE_STICKY); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Global#OVERLAY_DISPLAY_DEVICES: - New setting keys are not allowed (Field: OVERLAY_DISPLAY_DEVICES); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED: - New setting keys are not allowed (Field: ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_CAPABILITY: - New setting keys are not allowed (Field: ACCESSIBILITY_MAGNIFICATION_CAPABILITY); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE: - New setting keys are not allowed (Field: ACCESSIBILITY_MAGNIFICATION_MODE); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE: - New setting keys are not allowed (Field: ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_SERVICE: - New setting keys are not allowed (Field: AUTOFILL_SERVICE); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#BIOMETRIC_VIRTUAL_ENABLED: - New setting keys are not allowed (Field: BIOMETRIC_VIRTUAL_ENABLED); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#CONTENT_CAPTURE_ENABLED: - New setting keys are not allowed (Field: CONTENT_CAPTURE_ENABLED); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#DISABLED_PRINT_SERVICES: - New setting keys are not allowed (Field: DISABLED_PRINT_SERVICES); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#ENABLED_VR_LISTENERS: - New setting keys are not allowed (Field: ENABLED_VR_LISTENERS); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#IMMERSIVE_MODE_CONFIRMATIONS: - New setting keys are not allowed (Field: IMMERSIVE_MODE_CONFIRMATIONS); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#NOTIFICATION_BADGING: - New setting keys are not allowed (Field: NOTIFICATION_BADGING); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#POWER_MENU_LOCKED_SHOW_CONTENT: - New setting keys are not allowed (Field: POWER_MENU_LOCKED_SHOW_CONTENT); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#SYNC_PARENT_SOUNDS: - New setting keys are not allowed (Field: SYNC_PARENT_SOUNDS); use getters/setters in relevant manager class -NoSettingsProvider: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE: - New setting keys are not allowed (Field: VOICE_INTERACTION_SERVICE); use getters/setters in relevant manager class - - -OnNameExpected: android.service.notification.ConditionProviderService#isBound(): - If implemented by developer, should follow the on<Something> style; otherwise consider marking final -OnNameExpected: android.service.watchdog.ExplicitHealthCheckService#setCallback(android.os.RemoteCallback): - If implemented by developer, should follow the on<Something> style; otherwise consider marking final - - -PackageLayering: android.util.FeatureFlagUtils: - Method parameter type `android.content.Context` violates package layering: nothing in `package android.util` should depend on `package android.content` - - -ParcelConstructor: android.credentials.ui.ProviderData#ProviderData(android.os.Parcel): - Parcelable inflation is exposed through CREATOR, not raw constructors, in android.credentials.ui.ProviderData -ParcelConstructor: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel): - Parcelable inflation is exposed through CREATOR, not raw constructors, in android.os.StrictMode.ViolationInfo -ParcelConstructor: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.Parcel): - Parcelable inflation is exposed through CREATOR, not raw constructors, in android.os.health.HealthStatsParceler - - -ParcelCreator: android.app.WindowConfiguration: - Parcelable requires a `CREATOR` field; missing in android.app.WindowConfiguration -ParcelCreator: android.service.autofill.InternalOnClickAction: - Parcelable requires a `CREATOR` field; missing in android.service.autofill.InternalOnClickAction -ParcelCreator: android.service.autofill.InternalSanitizer: - Parcelable requires a `CREATOR` field; missing in android.service.autofill.InternalSanitizer -ParcelCreator: android.service.autofill.InternalTransformation: - Parcelable requires a `CREATOR` field; missing in android.service.autofill.InternalTransformation -ParcelCreator: android.service.autofill.InternalValidator: - Parcelable requires a `CREATOR` field; missing in android.service.autofill.InternalValidator - - -ParcelNotFinal: android.app.WindowConfiguration: - Parcelable classes must be final: android.app.WindowConfiguration is not final -ParcelNotFinal: android.content.pm.UserInfo: - Parcelable classes must be final: android.content.pm.UserInfo is not final -ParcelNotFinal: android.os.health.HealthStatsParceler: - Parcelable classes must be final: android.os.health.HealthStatsParceler is not final -ParcelNotFinal: android.service.autofill.InternalOnClickAction: - Parcelable classes must be final: android.service.autofill.InternalOnClickAction is not final -ParcelNotFinal: android.service.autofill.InternalSanitizer: - Parcelable classes must be final: android.service.autofill.InternalSanitizer is not final -ParcelNotFinal: android.service.autofill.InternalTransformation: - Parcelable classes must be final: android.service.autofill.InternalTransformation is not final -ParcelNotFinal: android.service.autofill.InternalValidator: - Parcelable classes must be final: android.service.autofill.InternalValidator is not final ProtectedMember: android.app.AppDetailsActivity#onCreate(android.os.Bundle): Protected methods not allowed; must be public: method android.app.AppDetailsActivity.onCreate(android.os.Bundle)} -ProtectedMember: android.view.View#resetResolvedDrawables(): - Protected methods not allowed; must be public: method android.view.View.resetResolvedDrawables()} ProtectedMember: android.view.ViewGroup#resetResolvedDrawables(): Protected methods not allowed; must be public: method android.view.ViewGroup.resetResolvedDrawables()} -RethrowRemoteException: android.app.ActivityManager#resumeAppSwitches(): - Methods calling system APIs should rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause) - - -SamShouldBeLast: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]): - SAM-compatible parameters (such as parameter 1, "printer", in android.database.sqlite.SQLiteDebug.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]): - SAM-compatible parameters (such as parameter 1, "factory", in android.database.sqlite.SQLiteDirectCursorDriver.query) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String): - SAM-compatible parameters (such as parameter 1, "pw", in android.os.StrictMode.ViolationInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.permission.PermissionControllerManager#countPermissionApps(java.util.List<java.lang.String>, int, android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, android.os.Handler): - SAM-compatible parameters (such as parameter 3, "callback", in android.permission.PermissionControllerManager.countPermissionApps) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler): - SAM-compatible parameters (such as parameter 2, "callback", in android.permission.PermissionControllerManager.getAppPermissions) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.service.autofill.CharSequenceTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int): - SAM-compatible parameters (such as parameter 1, "finder", in android.service.autofill.CharSequenceTransformation.apply) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.service.autofill.DateTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int): - SAM-compatible parameters (such as parameter 1, "finder", in android.service.autofill.DateTransformation.apply) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.service.autofill.ImageTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int): - SAM-compatible parameters (such as parameter 1, "finder", in android.service.autofill.ImageTransformation.apply) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>): - SAM-compatible parameters (such as parameter 1, "finder", in android.service.autofill.InternalTransformation.batchApply) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.view.Choreographer#postCallback(int, Runnable, Object): - SAM-compatible parameters (such as parameter 2, "action", in android.view.Choreographer.postCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long): - SAM-compatible parameters (such as parameter 2, "action", in android.view.Choreographer.postCallbackDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.view.Choreographer#removeCallbacks(int, Runnable, Object): - SAM-compatible parameters (such as parameter 2, "action", in android.view.Choreographer.removeCallbacks) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions - - -StaticUtils: android.os.health.HealthKeys: - Fully-static utility classes must not have constructor -StaticUtils: android.service.autofill.InternalTransformation: - Fully-static utility classes must not have constructor -StaticUtils: android.util.FeatureFlagUtils: - Fully-static utility classes must not have constructor - - -StreamFiles: android.os.Environment#buildPath(java.io.File, java.lang.String...): - Methods accepting `File` should also accept `FileDescriptor` or streams: method android.os.Environment.buildPath(java.io.File,java.lang.String...) -StreamFiles: android.os.FileUtils#contains(java.io.File, java.io.File): - Methods accepting `File` should also accept `FileDescriptor` or streams: method android.os.FileUtils.contains(java.io.File,java.io.File) - - -UseIcu: android.hardware.soundtrigger.KeyphraseEnrollmentInfo#getKeyphraseMetadata(String, java.util.Locale) parameter #1: - Type `java.util.Locale` should be replaced with richer ICU type `android.icu.util.ULocale` -UseIcu: android.hardware.soundtrigger.KeyphraseEnrollmentInfo#getManageKeyphraseIntent(int, String, java.util.Locale) parameter #2: - Type `java.util.Locale` should be replaced with richer ICU type `android.icu.util.ULocale` -UseIcu: android.hardware.soundtrigger.KeyphraseMetadata#supportsLocale(java.util.Locale) parameter #0: - Type `java.util.Locale` should be replaced with richer ICU type `android.icu.util.ULocale` - - -UserHandle: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle): - When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added -UserHandle: android.app.usage.StorageStatsManager#queryCratesForPackage(java.util.UUID, String, android.os.UserHandle): - When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added -UserHandle: android.app.usage.StorageStatsManager#queryCratesForUser(java.util.UUID, android.os.UserHandle): - When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added -UserHandle: android.content.pm.PackageManager#getInstallReason(String, android.os.UserHandle): - When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added - - -UserHandleName: android.content.AutofillOptions: - Classes holding a set of parameters should be called `FooParams`, was `AutofillOptions` -UserHandleName: android.content.ContentCaptureOptions: - Classes holding a set of parameters should be called `FooParams`, was `ContentCaptureOptions` - - -VisiblySynchronized: PsiThisExpression: - Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.getApkPaths() -VisiblySynchronized: android.content.res.AssetManager#getApkPaths(): - Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.getApkPaths() -VisiblySynchronized: android.content.res.AssetManager#getLastResourceResolution(): - Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.getLastResourceResolution() -VisiblySynchronized: android.content.res.AssetManager#getOverlayablesToString(String): - Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.getOverlayablesToString(String) -VisiblySynchronized: android.content.res.AssetManager#setResourceResolutionLoggingEnabled(boolean): - Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.setResourceResolutionLoggingEnabled(boolean) -VisiblySynchronized: android.os.MessageQueue#removeSyncBarrier(int): - Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.os.MessageQueue.removeSyncBarrier(int) +SamShouldBeLast: android.animation.ValueAnimator#ofObject(android.animation.TypeEvaluator, java.lang.Object...): + SAM-compatible parameters (such as parameter 1, "evaluator", in android.animation.ValueAnimator.ofObject) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.Activity#convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions): + SAM-compatible parameters (such as parameter 1, "callback", in android.app.Activity.convertToTranslucent) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int): + SAM-compatible parameters (such as parameter 1, "listener", in android.app.ActivityManager.addOnUidImportanceListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.AlarmManager#set(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler): + SAM-compatible parameters (such as parameter 4, "listener", in android.app.AlarmManager.set) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.AlarmManager#set(int, long, long, long, android.app.AlarmManager.OnAlarmListener, android.os.Handler, android.os.WorkSource): + SAM-compatible parameters (such as parameter 5, "listener", in android.app.AlarmManager.set) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.AlarmManager#setExact(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler): + SAM-compatible parameters (such as parameter 4, "listener", in android.app.AlarmManager.setExact) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.AlarmManager#setWindow(int, long, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler): + SAM-compatible parameters (such as parameter 5, "listener", in android.app.AlarmManager.setWindow) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler): + SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, String): + SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, String, android.os.Bundle): + SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.PendingIntent#send(int, android.app.PendingIntent.OnFinished, android.os.Handler): + SAM-compatible parameters (such as parameter 2, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.UiAutomation#executeAndWaitForEvent(Runnable, android.app.UiAutomation.AccessibilityEventFilter, long): + SAM-compatible parameters (such as parameter 2, "filter", in android.app.UiAutomation.executeAndWaitForEvent) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.WallpaperManager#addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.app.WallpaperManager.addOnColorsChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.ActivityInfo#dump(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ActivityInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.ApplicationInfo#dump(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ApplicationInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.ComponentInfo#dumpBack(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ComponentInfo.dumpBack) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.ComponentInfo#dumpFront(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ComponentInfo.dumpFront) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.PackageItemInfo#dumpBack(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpBack) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.PackageItemInfo#dumpFront(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpFront) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.database.sqlite.SQLiteCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]): + SAM-compatible parameters (such as parameter 1, "factory", in android.database.sqlite.SQLiteCursorDriver.query) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.graphics.drawable.AdaptiveIconDrawable#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long): + SAM-compatible parameters (such as parameter 2, "what", in android.graphics.drawable.AdaptiveIconDrawable.scheduleDrawable) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.graphics.drawable.Drawable#scheduleSelf(Runnable, long): + SAM-compatible parameters (such as parameter 1, "what", in android.graphics.drawable.Drawable.scheduleSelf) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.graphics.drawable.Drawable.Callback#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long): + SAM-compatible parameters (such as parameter 2, "what", in android.graphics.drawable.Drawable.Callback.scheduleDrawable) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.graphics.drawable.LayerDrawable#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long): + SAM-compatible parameters (such as parameter 2, "what", in android.graphics.drawable.LayerDrawable.scheduleDrawable) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioManager#abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes): + SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.abandonAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int): + SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy): + SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int): + SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioRecord#addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioRecord.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioRecord#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioRecord.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioTrack#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioTrack.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioTrack#addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioTrack.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.MediaCas#setEventListener(android.media.MediaCas.EventListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaCas.setEventListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.os.Parcel#createFixedArray(Class<T>, java.util.function.Function<android.os.IBinder,S>, int...): + SAM-compatible parameters (such as parameter 2, "asInterface", in android.os.Parcel.createFixedArray) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, String[], java.security.Principal[], String, int, String): + SAM-compatible parameters (such as parameter 2, "response", in android.security.KeyChain.choosePrivateKeyAlias) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, String[], java.security.Principal[], android.net.Uri, String): + SAM-compatible parameters (such as parameter 2, "response", in android.security.KeyChain.choosePrivateKeyAlias) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.Choreographer#postFrameCallbackDelayed(android.view.Choreographer.FrameCallback, long): + SAM-compatible parameters (such as parameter 1, "callback", in android.view.Choreographer.postFrameCallbackDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.View#postDelayed(Runnable, long): + SAM-compatible parameters (such as parameter 1, "action", in android.view.View.postDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.View#postOnAnimationDelayed(Runnable, long): + SAM-compatible parameters (such as parameter 1, "action", in android.view.View.postOnAnimationDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.View#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long): + SAM-compatible parameters (such as parameter 2, "what", in android.view.View.scheduleDrawable) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.Window#addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.view.Window.addOnFrameMetricsAvailableListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addAccessibilityStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.accessibility.AccessibilityManager#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler): + 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.view.inputmethod.InputMethodInfo#dump(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.view.inputmethod.InputMethodInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions + + +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#START_ACTIVITIES_FROM_SDK_SANDBOX: + New API must be flagged with @FlaggedApi: field android.Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX +UnflaggedApi: android.Manifest.permission#USE_REMOTE_AUTH: + New API must be flagged with @FlaggedApi: field android.Manifest.permission.USE_REMOTE_AUTH +UnflaggedApi: android.app.admin.DevicePolicyIdentifiers#PERMITTED_INPUT_METHODS_POLICY: + New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY +UnflaggedApi: android.app.admin.DevicePolicyIdentifiers#PERSONAL_APPS_SUSPENDED_POLICY: + New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyIdentifiers.PERSONAL_APPS_SUSPENDED_POLICY +UnflaggedApi: android.app.admin.DevicePolicyIdentifiers#SCREEN_CAPTURE_DISABLED_POLICY: + New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY +UnflaggedApi: android.app.admin.DevicePolicyIdentifiers#USB_DATA_SIGNALING_POLICY: + New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyIdentifiers.USB_DATA_SIGNALING_POLICY +UnflaggedApi: android.companion.AssociationInfo.Builder: + New API must be flagged with @FlaggedApi: class android.companion.AssociationInfo.Builder +UnflaggedApi: android.companion.AssociationInfo.Builder#Builder(android.companion.AssociationInfo): + New API must be flagged with @FlaggedApi: constructor android.companion.AssociationInfo.Builder(android.companion.AssociationInfo) +UnflaggedApi: android.companion.AssociationInfo.Builder#Builder(int, int, String): + New API must be flagged with @FlaggedApi: constructor android.companion.AssociationInfo.Builder(int,int,String) +UnflaggedApi: android.companion.AssociationInfo.Builder#build(): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.build() +UnflaggedApi: android.companion.AssociationInfo.Builder#setAssociatedDevice(android.companion.AssociatedDevice): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setAssociatedDevice(android.companion.AssociatedDevice) +UnflaggedApi: android.companion.AssociationInfo.Builder#setDeviceMacAddress(android.net.MacAddress): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setDeviceMacAddress(android.net.MacAddress) +UnflaggedApi: android.companion.AssociationInfo.Builder#setDeviceProfile(String): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setDeviceProfile(String) +UnflaggedApi: android.companion.AssociationInfo.Builder#setDisplayName(CharSequence): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setDisplayName(CharSequence) +UnflaggedApi: android.companion.AssociationInfo.Builder#setLastTimeConnected(long): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setLastTimeConnected(long) +UnflaggedApi: android.companion.AssociationInfo.Builder#setNotifyOnDeviceNearby(boolean): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setNotifyOnDeviceNearby(boolean) +UnflaggedApi: android.companion.AssociationInfo.Builder#setRevoked(boolean): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setRevoked(boolean) +UnflaggedApi: android.companion.AssociationInfo.Builder#setSelfManaged(boolean): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setSelfManaged(boolean) +UnflaggedApi: android.companion.AssociationInfo.Builder#setSystemDataSyncFlags(int): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setSystemDataSyncFlags(int) +UnflaggedApi: android.companion.AssociationInfo.Builder#setTag(String): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setTag(String) +UnflaggedApi: android.companion.AssociationInfo.Builder#setTimeApproved(long): + New API must be flagged with @FlaggedApi: method android.companion.AssociationInfo.Builder.setTimeApproved(long) +UnflaggedApi: android.companion.CompanionDeviceManager#MESSAGE_REQUEST_PING: + New API must be flagged with @FlaggedApi: field android.companion.CompanionDeviceManager.MESSAGE_REQUEST_PING +UnflaggedApi: android.companion.CompanionDeviceManager#enableSecureTransport(boolean): + New API must be flagged with @FlaggedApi: method android.companion.CompanionDeviceManager.enableSecureTransport(boolean) +UnflaggedApi: android.content.AttributionSource#AttributionSource(int, int, String, String, android.os.IBinder, String[], android.content.AttributionSource): + New API must be flagged with @FlaggedApi: constructor android.content.AttributionSource(int,int,String,String,android.os.IBinder,String[],android.content.AttributionSource) +UnflaggedApi: android.content.AttributionSource#AttributionSource(int, int, String, String, android.os.IBinder, String[], int, android.content.AttributionSource): + New API must be flagged with @FlaggedApi: constructor android.content.AttributionSource(int,int,String,String,android.os.IBinder,String[],int,android.content.AttributionSource) +UnflaggedApi: android.content.pm.UserInfo#isCommunalProfile(): + New API must be flagged with @FlaggedApi: method android.content.pm.UserInfo.isCommunalProfile() +UnflaggedApi: android.content.pm.UserInfo#isPrivateProfile(): + New API must be flagged with @FlaggedApi: method android.content.pm.UserInfo.isPrivateProfile() +UnflaggedApi: android.credentials.CredentialProviderInfo#isPrimary(): + New API must be flagged with @FlaggedApi: method android.credentials.CredentialProviderInfo.isPrimary() +UnflaggedApi: android.media.AudioManager#enterAudioFocusFreezeForTest(java.util.List<java.lang.Integer>): + New API must be flagged with @FlaggedApi: method android.media.AudioManager.enterAudioFocusFreezeForTest(java.util.List<java.lang.Integer>) +UnflaggedApi: android.media.AudioManager#exitAudioFocusFreezeForTest(): + New API must be flagged with @FlaggedApi: method android.media.AudioManager.exitAudioFocusFreezeForTest() +UnflaggedApi: android.media.AudioManager#getFocusDuckedUidsForTest(): + New API must be flagged with @FlaggedApi: method android.media.AudioManager.getFocusDuckedUidsForTest() +UnflaggedApi: android.media.AudioManager#getFocusFadeOutDurationForTest(): + New API must be flagged with @FlaggedApi: method android.media.AudioManager.getFocusFadeOutDurationForTest() +UnflaggedApi: android.media.AudioManager#getFocusUnmuteDelayAfterFadeOutForTest(): + New API must be flagged with @FlaggedApi: method android.media.AudioManager.getFocusUnmuteDelayAfterFadeOutForTest() +UnflaggedApi: android.media.RingtoneSelection: + New API must be flagged with @FlaggedApi: class android.media.RingtoneSelection +UnflaggedApi: android.media.RingtoneSelection#DEFAULT_SELECTION_URI_STRING: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.DEFAULT_SELECTION_URI_STRING +UnflaggedApi: android.media.RingtoneSelection#FROM_URI_RINGTONE_SELECTION_ONLY: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.FROM_URI_RINGTONE_SELECTION_ONLY +UnflaggedApi: android.media.RingtoneSelection#FROM_URI_RINGTONE_SELECTION_OR_SOUND: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.FROM_URI_RINGTONE_SELECTION_OR_SOUND +UnflaggedApi: android.media.RingtoneSelection#FROM_URI_RINGTONE_SELECTION_OR_VIBRATION: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.FROM_URI_RINGTONE_SELECTION_OR_VIBRATION +UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_DEFAULT: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_DEFAULT +UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_OFF: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_OFF +UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_URI: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_URI +UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_APPLICATION_PROVIDED: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_APPLICATION_PROVIDED +UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_AUDIO_CHANNEL: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_AUDIO_CHANNEL +UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_DEFAULT: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_DEFAULT +UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_HAPTIC_GENERATOR: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_HAPTIC_GENERATOR +UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_OFF: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_OFF +UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_URI: + New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_URI +UnflaggedApi: android.media.RingtoneSelection#fromUri(android.net.Uri, int): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.fromUri(android.net.Uri,int) +UnflaggedApi: android.media.RingtoneSelection#getSoundSource(): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.getSoundSource() +UnflaggedApi: android.media.RingtoneSelection#getSoundUri(): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.getSoundUri() +UnflaggedApi: android.media.RingtoneSelection#getVibrationSource(): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.getVibrationSource() +UnflaggedApi: android.media.RingtoneSelection#getVibrationUri(): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.getVibrationUri() +UnflaggedApi: android.media.RingtoneSelection#isRingtoneSelectionUri(android.net.Uri): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.isRingtoneSelectionUri(android.net.Uri) +UnflaggedApi: android.media.RingtoneSelection#toUri(): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.toUri() +UnflaggedApi: android.media.RingtoneSelection.Builder: + New API must be flagged with @FlaggedApi: class android.media.RingtoneSelection.Builder +UnflaggedApi: android.media.RingtoneSelection.Builder#Builder(): + New API must be flagged with @FlaggedApi: constructor android.media.RingtoneSelection.Builder() +UnflaggedApi: android.media.RingtoneSelection.Builder#Builder(android.media.RingtoneSelection): + New API must be flagged with @FlaggedApi: constructor android.media.RingtoneSelection.Builder(android.media.RingtoneSelection) +UnflaggedApi: android.media.RingtoneSelection.Builder#build(): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.Builder.build() +UnflaggedApi: android.media.RingtoneSelection.Builder#setSoundSource(android.net.Uri): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.Builder.setSoundSource(android.net.Uri) +UnflaggedApi: android.media.RingtoneSelection.Builder#setSoundSource(int): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.Builder.setSoundSource(int) +UnflaggedApi: android.media.RingtoneSelection.Builder#setVibrationSource(android.net.Uri): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.Builder.setVibrationSource(android.net.Uri) +UnflaggedApi: android.media.RingtoneSelection.Builder#setVibrationSource(int): + New API must be flagged with @FlaggedApi: method android.media.RingtoneSelection.Builder.setVibrationSource(int) +UnflaggedApi: android.media.soundtrigger.SoundTriggerInstrumentation#setInPhoneCallState(boolean): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerInstrumentation.setInPhoneCallState(boolean) +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager#createManagerForModule(android.hardware.soundtrigger.SoundTrigger.ModuleProperties): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.createManagerForModule(android.hardware.soundtrigger.SoundTrigger.ModuleProperties) +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager#createManagerForTestModule(): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.createManagerForTestModule() +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager#listModuleProperties(): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.listModuleProperties() +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager#loadSoundModel(android.hardware.soundtrigger.SoundTrigger.SoundModel): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.loadSoundModel(android.hardware.soundtrigger.SoundTrigger.SoundModel) +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager.Model#getSoundModel(): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.Model.getSoundModel() +UnflaggedApi: android.net.wifi.sharedconnectivity.app.SharedConnectivityManager#getBroadcastReceiver(): + New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.SharedConnectivityManager.getBroadcastReceiver() +UnflaggedApi: android.os.BatteryManager#BATTERY_PLUGGED_ANY: + New API must be flagged with @FlaggedApi: field android.os.BatteryManager.BATTERY_PLUGGED_ANY +UnflaggedApi: android.os.BugreportParams#BUGREPORT_MODE_MAX_VALUE: + New API must be flagged with @FlaggedApi: field android.os.BugreportParams.BUGREPORT_MODE_MAX_VALUE +UnflaggedApi: android.os.PowerManager#isBatterySaverSupported(): + New API must be flagged with @FlaggedApi: method android.os.PowerManager.isBatterySaverSupported() +UnflaggedApi: android.os.UserHandle#USER_CURRENT: + New API must be flagged with @FlaggedApi: field android.os.UserHandle.USER_CURRENT +UnflaggedApi: android.os.UserManager#getAliveUsers(): + New API must be flagged with @FlaggedApi: method android.os.UserManager.getAliveUsers() +UnflaggedApi: android.os.UserManager#getUsers(): + New API must be flagged with @FlaggedApi: method android.os.UserManager.getUsers() +UnflaggedApi: android.os.vibrator.persistence.ParsedVibration: + New API must be flagged with @FlaggedApi: class android.os.vibrator.persistence.ParsedVibration +UnflaggedApi: android.os.vibrator.persistence.ParsedVibration#getVibrationEffects(): + New API must be flagged with @FlaggedApi: method android.os.vibrator.persistence.ParsedVibration.getVibrationEffects() +UnflaggedApi: android.os.vibrator.persistence.ParsedVibration#resolve(android.os.Vibrator): + New API must be flagged with @FlaggedApi: method android.os.vibrator.persistence.ParsedVibration.resolve(android.os.Vibrator) +UnflaggedApi: android.os.vibrator.persistence.VibrationXmlParser: + New API must be flagged with @FlaggedApi: class android.os.vibrator.persistence.VibrationXmlParser +UnflaggedApi: android.os.vibrator.persistence.VibrationXmlParser#parseDocument(java.io.Reader): + New API must be flagged with @FlaggedApi: method android.os.vibrator.persistence.VibrationXmlParser.parseDocument(java.io.Reader) +UnflaggedApi: android.os.vibrator.persistence.VibrationXmlParser#parseVibrationEffect(java.io.Reader): + New API must be flagged with @FlaggedApi: method android.os.vibrator.persistence.VibrationXmlParser.parseVibrationEffect(java.io.Reader) +UnflaggedApi: android.os.vibrator.persistence.VibrationXmlSerializer: + New API must be flagged with @FlaggedApi: class android.os.vibrator.persistence.VibrationXmlSerializer +UnflaggedApi: android.os.vibrator.persistence.VibrationXmlSerializer#serialize(android.os.VibrationEffect, java.io.Writer): + New API must be flagged with @FlaggedApi: method android.os.vibrator.persistence.VibrationXmlSerializer.serialize(android.os.VibrationEffect,java.io.Writer) +UnflaggedApi: android.os.vibrator.persistence.VibrationXmlSerializer.SerializationFailedException: + New API must be flagged with @FlaggedApi: class android.os.vibrator.persistence.VibrationXmlSerializer.SerializationFailedException +UnflaggedApi: android.service.notification.NotificationRankingUpdate: + New API must be flagged with @FlaggedApi: class android.service.notification.NotificationRankingUpdate +UnflaggedApi: android.service.notification.NotificationRankingUpdate#CONTENTS_FILE_DESCRIPTOR: + New API must be flagged with @FlaggedApi: field android.service.notification.NotificationRankingUpdate.CONTENTS_FILE_DESCRIPTOR +UnflaggedApi: android.service.notification.NotificationRankingUpdate#PARCELABLE_WRITE_RETURN_VALUE: + New API must be flagged with @FlaggedApi: field android.service.notification.NotificationRankingUpdate.PARCELABLE_WRITE_RETURN_VALUE +UnflaggedApi: android.service.notification.NotificationRankingUpdate#isFdNotNullAndClosed(): + New API must be flagged with @FlaggedApi: method android.service.notification.NotificationRankingUpdate.isFdNotNullAndClosed() +UnflaggedApi: android.telephony.TelephonyManager#HAL_SERVICE_SATELLITE: + New API must be flagged with @FlaggedApi: field android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE +UnflaggedApi: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities: + New API must be flagged with @FlaggedApi: class android.telephony.ims.feature.MmTelFeature.MmTelCapabilities +UnflaggedApi: android.text.MeasuredParagraph: + New API must be flagged with @FlaggedApi: class android.text.MeasuredParagraph +UnflaggedApi: android.text.MeasuredParagraph#buildForStaticLayoutTest(android.text.TextPaint, android.graphics.text.LineBreakConfig, CharSequence, int, int, android.text.TextDirectionHeuristic, int, boolean, android.text.MeasuredParagraph.StyleRunCallback): + New API must be flagged with @FlaggedApi: method android.text.MeasuredParagraph.buildForStaticLayoutTest(android.text.TextPaint,android.graphics.text.LineBreakConfig,CharSequence,int,int,android.text.TextDirectionHeuristic,int,boolean,android.text.MeasuredParagraph.StyleRunCallback) +UnflaggedApi: android.text.MeasuredParagraph.StyleRunCallback: + New API must be flagged with @FlaggedApi: class android.text.MeasuredParagraph.StyleRunCallback +UnflaggedApi: android.text.MeasuredParagraph.StyleRunCallback#onAppendReplacementRun(android.graphics.Paint, int, float): + New API must be flagged with @FlaggedApi: method android.text.MeasuredParagraph.StyleRunCallback.onAppendReplacementRun(android.graphics.Paint,int,float) +UnflaggedApi: android.text.MeasuredParagraph.StyleRunCallback#onAppendStyleRun(android.graphics.Paint, android.graphics.text.LineBreakConfig, int, boolean): + New API must be flagged with @FlaggedApi: method android.text.MeasuredParagraph.StyleRunCallback.onAppendStyleRun(android.graphics.Paint,android.graphics.text.LineBreakConfig,int,boolean) +UnflaggedApi: android.view.Choreographer#getFrameTimeNanos(): + New API must be flagged with @FlaggedApi: method android.view.Choreographer.getFrameTimeNanos() +UnflaggedApi: android.view.InputDevice#getAssociatedDisplayId(): + New API must be flagged with @FlaggedApi: method android.view.InputDevice.getAssociatedDisplayId() +UnflaggedApi: android.view.InputDevice#getKeyboardLanguageTag(): + New API must be flagged with @FlaggedApi: method android.view.InputDevice.getKeyboardLanguageTag() +UnflaggedApi: android.view.InputDevice#getKeyboardLayoutType(): + New API must be flagged with @FlaggedApi: method android.view.InputDevice.getKeyboardLayoutType() +UnflaggedApi: android.view.MotionEvent.PointerCoords#isResampled(): + New API must be flagged with @FlaggedApi: method android.view.MotionEvent.PointerCoords.isResampled() +UnflaggedApi: android.view.WindowManager#replaceContentOnDisplayWithMirror(int, android.view.Window): + New API must be flagged with @FlaggedApi: method android.view.WindowManager.replaceContentOnDisplayWithMirror(int,android.view.Window) +UnflaggedApi: android.view.WindowManager#replaceContentOnDisplayWithSc(int, android.view.SurfaceControl): + New API must be flagged with @FlaggedApi: method android.view.WindowManager.replaceContentOnDisplayWithSc(int,android.view.SurfaceControl) +UnflaggedApi: android.view.WindowManager.LayoutParams#preferredMaxDisplayRefreshRate: + New API must be flagged with @FlaggedApi: field android.view.WindowManager.LayoutParams.preferredMaxDisplayRefreshRate +UnflaggedApi: android.view.WindowManager.LayoutParams#preferredMinDisplayRefreshRate: + New API must be flagged with @FlaggedApi: field android.view.WindowManager.LayoutParams.preferredMinDisplayRefreshRate +UnflaggedApi: android.view.accessibility.AccessibilityWindowInfo#UNDEFINED_WINDOW_ID: + New API must be flagged with @FlaggedApi: field android.view.accessibility.AccessibilityWindowInfo.UNDEFINED_WINDOW_ID +UnflaggedApi: android.view.animation.AnimationUtils#lockAnimationClock(long, long): + New API must be flagged with @FlaggedApi: method android.view.animation.AnimationUtils.lockAnimationClock(long,long) +UnflaggedApi: android.view.inputmethod.InputMethodManager#getEnabledInputMethodListAsUser(android.os.UserHandle): + New API must be flagged with @FlaggedApi: method android.view.inputmethod.InputMethodManager.getEnabledInputMethodListAsUser(android.os.UserHandle) +UnflaggedApi: android.view.inputmethod.InputMethodManager#getEnabledInputMethodSubtypeListAsUser(String, boolean, android.os.UserHandle): + New API must be flagged with @FlaggedApi: method android.view.inputmethod.InputMethodManager.getEnabledInputMethodSubtypeListAsUser(String,boolean,android.os.UserHandle) +UnflaggedApi: android.view.inputmethod.InputMethodManager#isCurrentRootView(android.view.View): + New API must be flagged with @FlaggedApi: method android.view.inputmethod.InputMethodManager.isCurrentRootView(android.view.View) +UnflaggedApi: android.view.inputmethod.InputMethodManager#isStylusHandwritingAvailableAsUser(android.os.UserHandle): + New API must be flagged with @FlaggedApi: method android.view.inputmethod.InputMethodManager.isStylusHandwritingAvailableAsUser(android.os.UserHandle) +UnflaggedApi: android.view.inputmethod.InsertModeGesture: + New API must be flagged with @FlaggedApi: class android.view.inputmethod.InsertModeGesture +UnflaggedApi: android.window.WindowInfosListenerForTest.WindowInfo#displayId: + New API must be flagged with @FlaggedApi: field android.window.WindowInfosListenerForTest.WindowInfo.displayId +UnflaggedApi: android.window.WindowInfosListenerForTest.WindowInfo#isVisible: + New API must be flagged with @FlaggedApi: field android.window.WindowInfosListenerForTest.WindowInfo.isVisible +UnflaggedApi: android.window.WindowInfosListenerForTest.WindowInfo#transform: + New API must be flagged with @FlaggedApi: field android.window.WindowInfosListenerForTest.WindowInfo.transform diff --git a/core/java/android/app/HomeVisibilityListener.java b/core/java/android/app/HomeVisibilityListener.java index 0b5a5ed100c9..1f5f2e4c8237 100644 --- a/core/java/android/app/HomeVisibilityListener.java +++ b/core/java/android/app/HomeVisibilityListener.java @@ -17,7 +17,6 @@ package android.app; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.SuppressLint; @@ -108,13 +107,12 @@ public abstract class HomeVisibilityListener { if (DBG) { Log.d(TAG, "Task#" + i + ": activity=" + task.topActivity + ", visible=" + task.isVisible() - + ", flg=" + Integer.toHexString(task.baseIntent.getFlags())); + + ", flg=" + Integer.toHexString(task.baseIntent.getFlags()) + + ", type=" + task.getActivityType()); } - if (!task.isVisible() - || (task.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0) { - continue; + if (task.isVisible() && (task.getActivityType() == ACTIVITY_TYPE_HOME)) { + return true; } - return task.getActivityType() == ACTIVITY_TYPE_HOME; } return false; } diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING index 06e1b5bb5fb8..93107cea406e 100644 --- a/core/java/android/app/TEST_MAPPING +++ b/core/java/android/app/TEST_MAPPING @@ -350,21 +350,6 @@ "file_patterns": ["(/|^)ContextImpl.java"] }, { - "name": "CtsWindowManagerDeviceScvh", - "options": [ - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - }, - { - "exclude-annotation": "org.junit.Ignore" - }, - { - "include-filter": "android.content.wm.cts" - } - ], - "file_patterns": ["(/|^)ContextImpl.java"] - }, - { "name": "CtsWindowManagerDeviceWindow", "options": [ { diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 673a8a5edcba..3a9e9bf01f04 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -371,6 +371,13 @@ public class PackageInstaller { "android.content.pm.extra.UNARCHIVE_ALL_USERS"; /** + * A list of warnings that occurred during installation. + * + * @hide + */ + public static final String EXTRA_WARNINGS = "android.content.pm.extra.WARNINGS"; + + /** * Streaming installation pending. * Caller should make sure DataLoader is able to prepare image and reinitiate the operation. * diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index be8b2a20cfb1..65f56f68ed3f 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -486,7 +486,7 @@ public class ServiceInfo extends ComponentInfo * Here is an example: * <pre> * <uses-permission - * android:name="android.permissions.FOREGROUND_SERVICE_SPECIAL_USE" + * android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" * /> * <service * android:name=".MySpecialForegroundService" @@ -506,7 +506,7 @@ public class ServiceInfo extends ComponentInfo * in both platforms. * <pre> * <uses-permission - * android:name="android.permissions.FOREGROUND_SERVICE_SPECIAL_USE" + * android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" * android:maxSdkVersion="last_sdk_version_without_type_foo" * /> * <service diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java index 408869ec76bc..20771af7d26d 100644 --- a/core/java/android/credentials/CredentialManager.java +++ b/core/java/android/credentials/CredentialManager.java @@ -131,15 +131,35 @@ public final class CredentialManager { @Hide public void getCandidateCredentials( @NonNull GetCredentialRequest request, + @NonNull String callingPackage, @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, - @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { + @NonNull OutcomeReceiver<GetCandidateCredentialsResponse, + GetCandidateCredentialsException> callback + ) { requireNonNull(request, "request must not be null"); + requireNonNull(callingPackage, "callingPackage must not be null"); requireNonNull(executor, "executor must not be null"); requireNonNull(callback, "callback must not be null"); if (cancellationSignal != null && cancellationSignal.isCanceled()) { - Log.w(TAG, "getCredential already canceled"); + Log.w(TAG, "getCandidateCredentials already canceled"); + return; + } + + ICancellationSignal cancelRemote = null; + try { + cancelRemote = + mService.getCandidateCredentials( + request, + new GetCandidateCredentialsTransport(executor, callback), + mContext.getOpPackageName()); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + + if (cancellationSignal != null && cancelRemote != null) { + cancellationSignal.setRemote(cancelRemote); } } diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java index 1d649eb92fde..231e4bc4ac75 100644 --- a/core/java/android/credentials/GetCandidateCredentialsResponse.java +++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java @@ -17,9 +17,17 @@ package android.credentials; import android.annotation.Hide; +import android.annotation.NonNull; +import android.credentials.ui.GetCredentialProviderData; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.AnnotationValidations; +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.List; + /** * A list of candidate credentials. * @@ -28,11 +36,34 @@ import android.os.Parcelable; @Hide public final class GetCandidateCredentialsResponse implements Parcelable { // TODO(b/299321990): Add members + + @NonNull + private final List<GetCredentialProviderData> mCandidateProviderDataList; + + /** + * @hide + */ + @Hide + public GetCandidateCredentialsResponse( + List<GetCredentialProviderData> candidateProviderDataList + ) { + Preconditions.checkCollectionNotEmpty( + candidateProviderDataList, + /*valueName=*/ "candidateProviderDataList"); + mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList); + } + protected GetCandidateCredentialsResponse(Parcel in) { + List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>(); + in.readTypedList(candidateProviderDataList, GetCredentialProviderData.CREATOR); + mCandidateProviderDataList = candidateProviderDataList; + + AnnotationValidations.validate(NonNull.class, null, mCandidateProviderDataList); } @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeTypedList(mCandidateProviderDataList); } @Override @@ -41,7 +72,7 @@ public final class GetCandidateCredentialsResponse implements Parcelable { } public static final Creator<GetCandidateCredentialsResponse> CREATOR = - new Creator<GetCandidateCredentialsResponse>() { + new Creator<>() { @Override public GetCandidateCredentialsResponse createFromParcel(Parcel in) { return new GetCandidateCredentialsResponse(in); diff --git a/core/java/android/credentials/ICredentialManager.aidl b/core/java/android/credentials/ICredentialManager.aidl index 42323d66e533..d0815766024a 100644 --- a/core/java/android/credentials/ICredentialManager.aidl +++ b/core/java/android/credentials/ICredentialManager.aidl @@ -47,7 +47,7 @@ interface ICredentialManager { @nullable ICancellationSignal executeCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback, String callingPackage); - @nullable ICancellationSignal getCandidateCredentials(in GetCandidateCredentialsRequest request, in IGetCandidateCredentialsCallback callback, String callingPackage); + @nullable ICancellationSignal getCandidateCredentials(in GetCredentialRequest request, in IGetCandidateCredentialsCallback callback, String callingPackage); @nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage); diff --git a/core/java/android/inputmethodservice/InkWindow.java b/core/java/android/inputmethodservice/InkWindow.java index 24d1c9577f82..1b8d925ec1cd 100644 --- a/core/java/android/inputmethodservice/InkWindow.java +++ b/core/java/android/inputmethodservice/InkWindow.java @@ -104,7 +104,11 @@ final class InkWindow extends PhoneWindow { */ void hide(boolean remove) { if (getDecorView() != null) { - getDecorView().setVisibility(remove ? View.GONE : View.INVISIBLE); + if (remove) { + mWindowManager.removeViewImmediate(getDecorView()); + } else { + getDecorView().setVisibility(View.INVISIBLE); + } } } diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java index 7f6ec5821cb4..cf47786c8821 100644 --- a/core/java/android/inputmethodservice/SoftInputWindow.java +++ b/core/java/android/inputmethodservice/SoftInputWindow.java @@ -16,14 +16,12 @@ package android.inputmethodservice; -import static android.inputmethodservice.SoftInputWindowProto.BOUNDS; import static android.inputmethodservice.SoftInputWindowProto.WINDOW_STATE; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.app.Dialog; -import android.graphics.Rect; import android.os.Debug; import android.os.IBinder; import android.util.Log; @@ -45,7 +43,6 @@ final class SoftInputWindow extends Dialog { private static final String TAG = "SoftInputWindow"; private final KeyEvent.DispatcherState mDispatcherState; - private final Rect mBounds = new Rect(); private final InputMethodService mService; @Retention(SOURCE) @@ -150,22 +147,6 @@ final class SoftInputWindow extends Dialog { } @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - getWindow().getDecorView().getHitRect(mBounds); - - if (ev.isWithinBoundsNoHistory(mBounds.left, mBounds.top, - mBounds.right - 1, mBounds.bottom - 1)) { - return super.dispatchTouchEvent(ev); - } else { - MotionEvent temp = ev.clampNoHistory(mBounds.left, mBounds.top, - mBounds.right - 1, mBounds.bottom - 1); - boolean handled = super.dispatchTouchEvent(temp); - temp.recycle(); - return handled; - } - } - - @Override public void show() { switch (mWindowState) { case WindowState.TOKEN_PENDING: @@ -273,7 +254,6 @@ final class SoftInputWindow extends Dialog { void dumpDebug(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); - mBounds.dumpDebug(proto, BOUNDS); proto.write(WINDOW_STATE, mWindowState); proto.end(token); } diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index f40efc8a2e8f..218d4bb8514f 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -186,6 +186,8 @@ public class Binder implements IBinder { /** * Get the binder transaction observer for this process. * + * TODO(b/299356196): only applies to Java code, not C++/Rust + * * @hide */ public static void setObserver(@Nullable BinderInternal.Observer observer) { @@ -202,6 +204,8 @@ public class Binder implements IBinder { * that require a result must be sent as {@link IBinder#FLAG_ONEWAY} calls * which deliver results through a callback interface. * + * TODO(b/299355525): only applies to Java code, not C++/Rust + * * @hide */ public static void setWarnOnBlocking(boolean warnOnBlocking) { @@ -218,6 +222,8 @@ public class Binder implements IBinder { * interfaces hosted by package that could be upgraded or replaced, * otherwise you risk system instability if that remote interface wedges. * + * TODO(b/299355525): only applies to Java code, not C++/Rust + * * @hide */ public static IBinder allowBlocking(IBinder binder) { @@ -1307,6 +1313,8 @@ public class Binder implements IBinder { int callingUid) { // Make sure the observer won't change while processing a transaction. final BinderInternal.Observer observer = sObserver; + + // TODO(b/299356196): observer should also observe transactions in native code final CallSession callSession = observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null; // Theoretically, we should call transact, which will call onTransact, @@ -1329,7 +1337,7 @@ public class Binder implements IBinder { final boolean tracingEnabled = tagEnabled && transactionTraceName != null; try { - // TODO - this logic should not be in Java - it should be in native + // TODO(b/299356201) - this logic should not be in Java - it should be in native // code in libbinder so that it works for all binder users. final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher; if (heavyHitterWatcher != null && callingUid != -1) { @@ -1340,9 +1348,9 @@ public class Binder implements IBinder { Trace.traceBegin(Trace.TRACE_TAG_AIDL, transactionTraceName); } - // TODO - this logic should not be in Java - it should be in native - // code in libbinder so that it works for all binder users. Further, - // this should not re-use flags. + // TODO(b/299353919) - this logic should not be in Java - it should be + // in native code in libbinder so that it works for all binder users. + // Further, this should not re-use flags. if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0 && callingUid != -1) { AppOpsManager.startNotedAppOpsCollection(callingUid); try { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7e71134f55bb..c19c20c8429d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3596,12 +3596,9 @@ public final class Settings { } Bundle b; - // b/252663068: if we're in system server and the caller did not call + // If we're in system server and the caller did not call // clearCallingIdentity, the read would fail due to mismatched AttributionSources. - // TODO(b/256013480): remove this bypass after fixing the callers in system server. - if (namespace.equals(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER) - && Settings.isInSystemServer() - && Binder.getCallingUid() != Process.myUid()) { + if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) { final long token = Binder.clearCallingIdentity(); try { // Fetch all flags for the namespace at once for caching purposes diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index cfc6f483e4ae..800149cb0a67 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -20,3 +20,11 @@ flag { description: "Feature flag for deprecating .fsv_sig" bug: "277916185" } + +flag { + name: "extend_vb_chain_to_updated_apk" + namespace: "hardware_backed_security" + description: "Use v4 signature and fs-verity to chain verification of allowlisted APKs to Verified Boot" + bug: "277916185" + is_fixed_read_only: true +} diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java index ece069fa0873..c4660c474e57 100644 --- a/core/java/android/util/Patterns.java +++ b/core/java/android/util/Patterns.java @@ -111,7 +111,7 @@ public class Patterns { /** * Regular expression to match all IANA top-level domains. * - * List accurate as of 2015/11/24. List taken from: + * List accurate as of 2023/09/11. List taken from: * http://data.iana.org/TLD/tlds-alpha-by-domain.txt * This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py * @@ -119,121 +119,167 @@ public class Patterns { */ static final String IANA_TOP_LEVEL_DOMAINS = "(?:" - + "(?:aaa|aarp|abb|abbott|abogado|academy|accenture|accountant|accountants|aco|active" - + "|actor|ads|adult|aeg|aero|afl|agency|aig|airforce|airtel|allfinanz|alsace|amica|amsterdam" - + "|android|apartments|app|apple|aquarelle|aramco|archi|army|arpa|arte|asia|associates" - + "|attorney|auction|audio|auto|autos|axa|azure|a[cdefgilmoqrstuwxz])" - + "|(?:band|bank|bar|barcelona|barclaycard|barclays|bargains|bauhaus|bayern|bbc|bbva" - + "|bcn|beats|beer|bentley|berlin|best|bet|bharti|bible|bid|bike|bing|bingo|bio|biz|black" - + "|blackfriday|bloomberg|blue|bms|bmw|bnl|bnpparibas|boats|bom|bond|boo|boots|boutique" - + "|bradesco|bridgestone|broadway|broker|brother|brussels|budapest|build|builders|business" - + "|buzz|bzh|b[abdefghijmnorstvwyz])" - + "|(?:cab|cafe|cal|camera|camp|cancerresearch|canon|capetown|capital|car|caravan|cards" - + "|care|career|careers|cars|cartier|casa|cash|casino|cat|catering|cba|cbn|ceb|center|ceo" - + "|cern|cfa|cfd|chanel|channel|chat|cheap|chloe|christmas|chrome|church|cipriani|cisco" - + "|citic|city|cityeats|claims|cleaning|click|clinic|clothing|cloud|club|clubmed|coach" - + "|codes|coffee|college|cologne|com|commbank|community|company|computer|comsec|condos" - + "|construction|consulting|contractors|cooking|cool|coop|corsica|country|coupons|courses" - + "|credit|creditcard|creditunion|cricket|crown|crs|cruises|csc|cuisinella|cymru|cyou|c[acdfghiklmnoruvwxyz])" - + "|(?:dabur|dad|dance|date|dating|datsun|day|dclk|deals|degree|delivery|dell|delta" - + "|democrat|dental|dentist|desi|design|dev|diamonds|diet|digital|direct|directory|discount" - + "|dnp|docs|dog|doha|domains|doosan|download|drive|durban|dvag|d[ejkmoz])" - + "|(?:earth|eat|edu|education|email|emerck|energy|engineer|engineering|enterprises" - + "|epson|equipment|erni|esq|estate|eurovision|eus|events|everbank|exchange|expert|exposed" - + "|express|e[cegrstu])" - + "|(?:fage|fail|fairwinds|faith|family|fan|fans|farm|fashion|feedback|ferrero|film" - + "|final|finance|financial|firmdale|fish|fishing|fit|fitness|flights|florist|flowers|flsmidth" - + "|fly|foo|football|forex|forsale|forum|foundation|frl|frogans|fund|furniture|futbol|fyi" - + "|f[ijkmor])" - + "|(?:gal|gallery|game|garden|gbiz|gdn|gea|gent|genting|ggee|gift|gifts|gives|giving" - + "|glass|gle|global|globo|gmail|gmo|gmx|gold|goldpoint|golf|goo|goog|google|gop|gov|grainger" - + "|graphics|gratis|green|gripe|group|gucci|guge|guide|guitars|guru|g[abdefghilmnpqrstuwy])" - + "|(?:hamburg|hangout|haus|healthcare|help|here|hermes|hiphop|hitachi|hiv|hockey|holdings" - + "|holiday|homedepot|homes|honda|horse|host|hosting|hoteles|hotmail|house|how|hsbc|hyundai" - + "|h[kmnrtu])" - + "|(?:ibm|icbc|ice|icu|ifm|iinet|immo|immobilien|industries|infiniti|info|ing|ink|institute" - + "|insure|int|international|investments|ipiranga|irish|ist|istanbul|itau|iwc|i[delmnoqrst])" - + "|(?:jaguar|java|jcb|jetzt|jewelry|jlc|jll|jobs|joburg|jprs|juegos|j[emop])" - + "|(?:kaufen|kddi|kia|kim|kinder|kitchen|kiwi|koeln|komatsu|krd|kred|kyoto|k[eghimnprwyz])" - + "|(?:lacaixa|lancaster|land|landrover|lasalle|lat|latrobe|law|lawyer|lds|lease|leclerc" - + "|legal|lexus|lgbt|liaison|lidl|life|lifestyle|lighting|limited|limo|linde|link|live" - + "|lixil|loan|loans|lol|london|lotte|lotto|love|ltd|ltda|lupin|luxe|luxury|l[abcikrstuvy])" - + "|(?:madrid|maif|maison|man|management|mango|market|marketing|markets|marriott|mba" - + "|media|meet|melbourne|meme|memorial|men|menu|meo|miami|microsoft|mil|mini|mma|mobi|moda" - + "|moe|moi|mom|monash|money|montblanc|mormon|mortgage|moscow|motorcycles|mov|movie|movistar" - + "|mtn|mtpc|mtr|museum|mutuelle|m[acdeghklmnopqrstuvwxyz])" - + "|(?:nadex|nagoya|name|navy|nec|net|netbank|network|neustar|new|news|nexus|ngo|nhk" - + "|nico|ninja|nissan|nokia|nra|nrw|ntt|nyc|n[acefgilopruz])" - + "|(?:obi|office|okinawa|omega|one|ong|onl|online|ooo|oracle|orange|org|organic|osaka" - + "|otsuka|ovh|om)" - + "|(?:page|panerai|paris|partners|parts|party|pet|pharmacy|philips|photo|photography" - + "|photos|physio|piaget|pics|pictet|pictures|ping|pink|pizza|place|play|playstation|plumbing" - + "|plus|pohl|poker|porn|post|praxi|press|pro|prod|productions|prof|properties|property" - + "|protection|pub|p[aefghklmnrstwy])" - + "|(?:qpon|quebec|qa)" - + "|(?:racing|realtor|realty|recipes|red|redstone|rehab|reise|reisen|reit|ren|rent|rentals" - + "|repair|report|republican|rest|restaurant|review|reviews|rich|ricoh|rio|rip|rocher|rocks" - + "|rodeo|rsvp|ruhr|run|rwe|ryukyu|r[eosuw])" - + "|(?:saarland|sakura|sale|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|saxo" - + "|sbs|sca|scb|schmidt|scholarships|school|schule|schwarz|science|scor|scot|seat|security" - + "|seek|sener|services|seven|sew|sex|sexy|shiksha|shoes|show|shriram|singles|site|ski" - + "|sky|skype|sncf|soccer|social|software|sohu|solar|solutions|sony|soy|space|spiegel|spreadbetting" - + "|srl|stada|starhub|statoil|stc|stcgroup|stockholm|studio|study|style|sucks|supplies" - + "|supply|support|surf|surgery|suzuki|swatch|swiss|sydney|systems|s[abcdeghijklmnortuvxyz])" - + "|(?:tab|taipei|tatamotors|tatar|tattoo|tax|taxi|team|tech|technology|tel|telefonica" - + "|temasek|tennis|thd|theater|theatre|tickets|tienda|tips|tires|tirol|today|tokyo|tools" - + "|top|toray|toshiba|tours|town|toyota|toys|trade|trading|training|travel|trust|tui|t[cdfghjklmnortvwz])" - + "|(?:ubs|university|uno|uol|u[agksyz])" - + "|(?:vacations|vana|vegas|ventures|versicherung|vet|viajes|video|villas|vin|virgin" - + "|vision|vista|vistaprint|viva|vlaanderen|vodka|vote|voting|voto|voyage|v[aceginu])" - + "|(?:wales|walter|wang|watch|webcam|website|wed|wedding|weir|whoswho|wien|wiki|williamhill" - + "|win|windows|wine|wme|work|works|world|wtc|wtf|w[fs])" - + "|(?:\u03b5\u03bb|\u0431\u0435\u043b|\u0434\u0435\u0442\u0438|\u043a\u043e\u043c|\u043c\u043a\u0434" + + "(?:aaa|aarp|abb|abbott|abbvie|abc|able|abogado|abudhabi|academy|accenture|accountant" + + "|accountants|aco|actor|ads|adult|aeg|aero|aetna|afl|africa|agakhan|agency|aig|airbus" + + "|airforce|airtel|akdn|alibaba|alipay|allfinanz|allstate|ally|alsace|alstom|amazon|americanexpress" + + "|americanfamily|amex|amfam|amica|amsterdam|analytics|android|anquan|anz|aol|apartments" + + "|app|apple|aquarelle|arab|aramco|archi|army|arpa|art|arte|asda|asia|associates|athleta" + + "|attorney|auction|audi|audible|audio|auspost|author|auto|autos|avianca|aws|axa|azure" + + "|a[cdefgilmoqrstuwxz])" + + "|(?:baby|baidu|banamex|bananarepublic|band|bank|bar|barcelona|barclaycard|barclays" + + "|barefoot|bargains|baseball|basketball|bauhaus|bayern|bbc|bbt|bbva|bcg|bcn|beats|beauty" + + "|beer|bentley|berlin|best|bestbuy|bet|bharti|bible|bid|bike|bing|bingo|bio|biz|black" + + "|blackfriday|blockbuster|blog|bloomberg|blue|bms|bmw|bnpparibas|boats|boehringer|bofa" + + "|bom|bond|boo|book|booking|bosch|bostik|boston|bot|boutique|box|bradesco|bridgestone" + + "|broadway|broker|brother|brussels|build|builders|business|buy|buzz|bzh|b[abdefghijmnorstvwyz])" + + "|(?:cab|cafe|cal|call|calvinklein|cam|camera|camp|canon|capetown|capital|capitalone" + + "|car|caravan|cards|care|career|careers|cars|casa|case|cash|casino|cat|catering|catholic" + + "|cba|cbn|cbre|cbs|center|ceo|cern|cfa|cfd|chanel|channel|charity|chase|chat|cheap|chintai" + + "|christmas|chrome|church|cipriani|circle|cisco|citadel|citi|citic|city|cityeats|claims" + + "|cleaning|click|clinic|clinique|clothing|cloud|club|clubmed|coach|codes|coffee|college" + + "|cologne|com|comcast|commbank|community|company|compare|computer|comsec|condos|construction" + + "|consulting|contact|contractors|cooking|cool|coop|corsica|country|coupon|coupons|courses" + + "|cpa|credit|creditcard|creditunion|cricket|crown|crs|cruise|cruises|cuisinella|cymru" + + "|cyou|c[acdfghiklmnoruvwxyz])" + + "|(?:dabur|dad|dance|data|date|dating|datsun|day|dclk|dds|deal|dealer|deals|degree" + + "|delivery|dell|deloitte|delta|democrat|dental|dentist|desi|design|dev|dhl|diamonds|diet" + + "|digital|direct|directory|discount|discover|dish|diy|dnp|docs|doctor|dog|domains|dot" + + "|download|drive|dtv|dubai|dunlop|dupont|durban|dvag|dvr|d[ejkmoz])" + + "|(?:earth|eat|eco|edeka|edu|education|email|emerck|energy|engineer|engineering|enterprises" + + "|epson|equipment|ericsson|erni|esq|estate|etisalat|eurovision|eus|events|exchange|expert" + + "|exposed|express|extraspace|e[cegrstu])" + + "|(?:fage|fail|fairwinds|faith|family|fan|fans|farm|farmers|fashion|fast|fedex|feedback" + + "|ferrari|ferrero|fidelity|fido|film|final|finance|financial|fire|firestone|firmdale" + + "|fish|fishing|fit|fitness|flickr|flights|flir|florist|flowers|fly|foo|food|football" + + "|ford|forex|forsale|forum|foundation|fox|free|fresenius|frl|frogans|frontdoor|frontier" + + "|ftr|fujitsu|fun|fund|furniture|futbol|fyi|f[ijkmor])" + + "|(?:gal|gallery|gallo|gallup|game|games|gap|garden|gay|gbiz|gdn|gea|gent|genting" + + "|george|ggee|gift|gifts|gives|giving|glass|gle|global|globo|gmail|gmbh|gmo|gmx|godaddy" + + "|gold|goldpoint|golf|goo|goodyear|goog|google|gop|got|gov|grainger|graphics|gratis|green" + + "|gripe|grocery|group|guardian|gucci|guge|guide|guitars|guru|g[abdefghilmnpqrstuwy])" + + "|(?:hair|hamburg|hangout|haus|hbo|hdfc|hdfcbank|health|healthcare|help|helsinki|here" + + "|hermes|hiphop|hisamitsu|hitachi|hiv|hkt|hockey|holdings|holiday|homedepot|homegoods" + + "|homes|homesense|honda|horse|hospital|host|hosting|hot|hotels|hotmail|house|how|hsbc" + + "|hughes|hyatt|hyundai|h[kmnrtu])" + + "|(?:ibm|icbc|ice|icu|ieee|ifm|ikano|imamat|imdb|immo|immobilien|inc|industries|infiniti" + + "|info|ing|ink|institute|insurance|insure|int|international|intuit|investments|ipiranga" + + "|irish|ismaili|ist|istanbul|itau|itv|i[delmnoqrst])" + + "|(?:jaguar|java|jcb|jeep|jetzt|jewelry|jio|jll|jmp|jnj|jobs|joburg|jot|joy|jpmorgan" + + "|jprs|juegos|juniper|j[emop])" + + "|(?:kaufen|kddi|kerryhotels|kerrylogistics|kerryproperties|kfh|kia|kids|kim|kinder" + + "|kindle|kitchen|kiwi|koeln|komatsu|kosher|kpmg|kpn|krd|kred|kuokgroup|kyoto|k[eghimnprwyz])" + + "|(?:lacaixa|lamborghini|lamer|lancaster|land|landrover|lanxess|lasalle|lat|latino" + + "|latrobe|law|lawyer|lds|lease|leclerc|lefrak|legal|lego|lexus|lgbt|lidl|life|lifeinsurance" + + "|lifestyle|lighting|like|lilly|limited|limo|lincoln|link|lipsy|live|living|llc|llp|loan" + + "|loans|locker|locus|lol|london|lotte|lotto|love|lpl|lplfinancial|ltd|ltda|lundbeck|luxe" + + "|luxury|l[abcikrstuvy])" + + "|(?:madrid|maif|maison|makeup|man|management|mango|map|market|marketing|markets|marriott" + + "|marshalls|mattel|mba|mckinsey|med|media|meet|melbourne|meme|memorial|men|menu|merckmsd" + + "|miami|microsoft|mil|mini|mint|mit|mitsubishi|mlb|mls|mma|mobi|mobile|moda|moe|moi|mom" + + "|monash|money|monster|mormon|mortgage|moscow|moto|motorcycles|mov|movie|msd|mtn|mtr" + + "|museum|music|m[acdeghklmnopqrstuvwxyz])" + + "|(?:nab|nagoya|name|natura|navy|nba|nec|net|netbank|netflix|network|neustar|new|news" + + "|next|nextdirect|nexus|nfl|ngo|nhk|nico|nike|nikon|ninja|nissan|nissay|nokia|norton" + + "|now|nowruz|nowtv|nra|nrw|ntt|nyc|n[acefgilopruz])" + + "|(?:obi|observer|office|okinawa|olayan|olayangroup|oldnavy|ollo|omega|one|ong|onl" + + "|online|ooo|open|oracle|orange|org|organic|origins|osaka|otsuka|ott|ovh|om)" + + "|(?:page|panasonic|paris|pars|partners|parts|party|pay|pccw|pet|pfizer|pharmacy|phd" + + "|philips|phone|photo|photography|photos|physio|pics|pictet|pictures|pid|pin|ping|pink" + + "|pioneer|pizza|place|play|playstation|plumbing|plus|pnc|pohl|poker|politie|porn|post" + + "|pramerica|praxi|press|prime|pro|prod|productions|prof|progressive|promo|properties" + + "|property|protection|pru|prudential|pub|pwc|p[aefghklmnrstwy])" + + "|(?:qpon|quebec|quest|qa)" + + "|(?:racing|radio|read|realestate|realtor|realty|recipes|red|redstone|redumbrella" + + "|rehab|reise|reisen|reit|reliance|ren|rent|rentals|repair|report|republican|rest|restaurant" + + "|review|reviews|rexroth|rich|richardli|ricoh|ril|rio|rip|rocher|rocks|rodeo|rogers|room" + + "|rsvp|rugby|ruhr|run|rwe|ryukyu|r[eosuw])" + + "|(?:saarland|safe|safety|sakura|sale|salon|samsclub|samsung|sandvik|sandvikcoromant" + + "|sanofi|sap|sarl|sas|save|saxo|sbi|sbs|sca|scb|schaeffler|schmidt|scholarships|school" + + "|schule|schwarz|science|scot|search|seat|secure|security|seek|select|sener|services" + + "|seven|sew|sex|sexy|sfr|shangrila|sharp|shaw|shell|shia|shiksha|shoes|shop|shopping" + + "|shouji|show|showtime|silk|sina|singles|site|ski|skin|sky|skype|sling|smart|smile|sncf" + + "|soccer|social|softbank|software|sohu|solar|solutions|song|sony|soy|spa|space|sport" + + "|spot|srl|stada|staples|star|statebank|statefarm|stc|stcgroup|stockholm|storage|store" + + "|stream|studio|study|style|sucks|supplies|supply|support|surf|surgery|suzuki|swatch" + + "|swiss|sydney|systems|s[abcdeghijklmnorstuvxyz])" + + "|(?:tab|taipei|talk|taobao|target|tatamotors|tatar|tattoo|tax|taxi|tci|tdk|team|tech" + + "|technology|tel|temasek|tennis|teva|thd|theater|theatre|tiaa|tickets|tienda|tips|tires" + + "|tirol|tjmaxx|tjx|tkmaxx|tmall|today|tokyo|tools|top|toray|toshiba|total|tours|town" + + "|toyota|toys|trade|trading|training|travel|travelers|travelersinsurance|trust|trv|tube" + + "|tui|tunes|tushu|tvs|t[cdfghjklmnortvwz])" + + "|(?:ubank|ubs|unicom|university|uno|uol|ups|u[agksyz])" + + "|(?:vacations|vana|vanguard|vegas|ventures|verisign|versicherung|vet|viajes|video" + + "|vig|viking|villas|vin|vip|virgin|visa|vision|viva|vivo|vlaanderen|vodka|volkswagen" + + "|volvo|vote|voting|voto|voyage|v[aceginu])" + + "|(?:wales|walmart|walter|wang|wanggou|watch|watches|weather|weatherchannel|webcam" + + "|weber|website|wed|wedding|weibo|weir|whoswho|wien|wiki|williamhill|win|windows|wine" + + "|winners|wme|wolterskluwer|woodside|work|works|world|wow|wtc|wtf|w[fs])" + + "|(?:\u03b5\u03bb|\u03b5\u03c5|\u0431\u0433|\u0431\u0435\u043b|\u0434\u0435\u0442\u0438" + + "|\u0435\u044e|\u043a\u0430\u0442\u043e\u043b\u0438\u043a|\u043a\u043e\u043c|\u043c\u043a\u0434" + "|\u043c\u043e\u043d|\u043c\u043e\u0441\u043a\u0432\u0430|\u043e\u043d\u043b\u0430\u0439\u043d" + "|\u043e\u0440\u0433|\u0440\u0443\u0441|\u0440\u0444|\u0441\u0430\u0439\u0442|\u0441\u0440\u0431" - + "|\u0443\u043a\u0440|\u049b\u0430\u0437|\u0570\u0561\u0575|\u05e7\u05d5\u05dd|\u0627\u0631\u0627\u0645\u0643\u0648" - + "|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629" - + "|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0627\u06cc\u0631\u0627\u0646" - + "|\u0628\u0627\u0632\u0627\u0631|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633" - + "|\u0633\u0648\u062f\u0627\u0646|\u0633\u0648\u0631\u064a\u0629|\u0634\u0628\u0643\u0629" - + "|\u0639\u0631\u0627\u0642|\u0639\u0645\u0627\u0646|\u0641\u0644\u0633\u0637\u064a\u0646" - + "|\u0642\u0637\u0631|\u0643\u0648\u0645|\u0645\u0635\u0631|\u0645\u0644\u064a\u0633\u064a\u0627" - + "|\u0645\u0648\u0642\u0639|\u0915\u0949\u092e|\u0928\u0947\u091f|\u092d\u093e\u0930\u0924" - + "|\u0938\u0902\u0917\u0920\u0928|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4" - + "|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd" - + "|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e04\u0e2d\u0e21|\u0e44\u0e17\u0e22" - + "|\u10d2\u10d4|\u307f\u3093\u306a|\u30b0\u30fc\u30b0\u30eb|\u30b3\u30e0|\u4e16\u754c" - + "|\u4e2d\u4fe1|\u4e2d\u56fd|\u4e2d\u570b|\u4e2d\u6587\u7f51|\u4f01\u4e1a|\u4f5b\u5c71" - + "|\u4fe1\u606f|\u5065\u5eb7|\u516b\u5366|\u516c\u53f8|\u516c\u76ca|\u53f0\u6e7e|\u53f0\u7063" - + "|\u5546\u57ce|\u5546\u5e97|\u5546\u6807|\u5728\u7ebf|\u5927\u62ff|\u5a31\u4e50|\u5de5\u884c" - + "|\u5e7f\u4e1c|\u6148\u5584|\u6211\u7231\u4f60|\u624b\u673a|\u653f\u52a1|\u653f\u5e9c" - + "|\u65b0\u52a0\u5761|\u65b0\u95fb|\u65f6\u5c1a|\u673a\u6784|\u6de1\u9a6c\u9521|\u6e38\u620f" - + "|\u70b9\u770b|\u79fb\u52a8|\u7ec4\u7ec7\u673a\u6784|\u7f51\u5740|\u7f51\u5e97|\u7f51\u7edc" - + "|\u8c37\u6b4c|\u96c6\u56e2|\u98de\u5229\u6d66|\u9910\u5385|\u9999\u6e2f|\ub2f7\ub137" - + "|\ub2f7\ucef4|\uc0bc\uc131|\ud55c\uad6d|xbox" - + "|xerox|xin|xn\\-\\-11b4c3d|xn\\-\\-1qqw23a|xn\\-\\-30rr7y|xn\\-\\-3bst00m|xn\\-\\-3ds443g" - + "|xn\\-\\-3e0b707e|xn\\-\\-3pxu8k|xn\\-\\-42c2d9a|xn\\-\\-45brj9c|xn\\-\\-45q11c|xn\\-\\-4gbrim" - + "|xn\\-\\-55qw42g|xn\\-\\-55qx5d|xn\\-\\-6frz82g|xn\\-\\-6qq986b3xl|xn\\-\\-80adxhks" - + "|xn\\-\\-80ao21a|xn\\-\\-80asehdb|xn\\-\\-80aswg|xn\\-\\-90a3ac|xn\\-\\-90ais|xn\\-\\-9dbq2a" - + "|xn\\-\\-9et52u|xn\\-\\-b4w605ferd|xn\\-\\-c1avg|xn\\-\\-c2br7g|xn\\-\\-cg4bki|xn\\-\\-clchc0ea0b2g2a9gcd" - + "|xn\\-\\-czr694b|xn\\-\\-czrs0t|xn\\-\\-czru2d|xn\\-\\-d1acj3b|xn\\-\\-d1alf|xn\\-\\-efvy88h" - + "|xn\\-\\-estv75g|xn\\-\\-fhbei|xn\\-\\-fiq228c5hs|xn\\-\\-fiq64b|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s" - + "|xn\\-\\-fjq720a|xn\\-\\-flw351e|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-gecrj9c" - + "|xn\\-\\-h2brj9c|xn\\-\\-hxt814e|xn\\-\\-i1b6b1a6a2e|xn\\-\\-imr513n|xn\\-\\-io0a7i" - + "|xn\\-\\-j1aef|xn\\-\\-j1amh|xn\\-\\-j6w193g|xn\\-\\-kcrx77d1x4a|xn\\-\\-kprw13d|xn\\-\\-kpry57d" + + "|\u0443\u043a\u0440|\u049b\u0430\u0437|\u0570\u0561\u0575|\u05d9\u05e9\u05e8\u05d0\u05dc" + + "|\u05e7\u05d5\u05dd|\u0627\u0628\u0648\u0638\u0628\u064a|\u0627\u062a\u0635\u0627\u0644\u0627\u062a" + + "|\u0627\u0631\u0627\u0645\u0643\u0648|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u0628\u062d\u0631\u064a\u0646" + + "|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629" + + "|\u0627\u0644\u0639\u0644\u064a\u0627\u0646|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a" + + "|\u0627\u06cc\u0631\u0627\u0646|\u0628\u0627\u0631\u062a|\u0628\u0627\u0632\u0627\u0631" + + "|\u0628\u064a\u062a\u0643|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u062f\u0627\u0646" + + "|\u0633\u0648\u0631\u064a\u0629|\u0634\u0628\u0643\u0629|\u0639\u0631\u0627\u0642|\u0639\u0631\u0628" + + "|\u0639\u0645\u0627\u0646|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0643\u0627\u062b\u0648\u0644\u064a\u0643" + + "|\u0643\u0648\u0645|\u0645\u0635\u0631|\u0645\u0644\u064a\u0633\u064a\u0627|\u0645\u0648\u0631\u064a\u062a\u0627\u0646\u064a\u0627" + + "|\u0645\u0648\u0642\u0639|\u0647\u0645\u0631\u0627\u0647|\u067e\u0627\u06a9\u0633\u062a\u0627\u0646" + + "|\u0680\u0627\u0631\u062a|\u0915\u0949\u092e|\u0928\u0947\u091f|\u092d\u093e\u0930\u0924" + + "|\u092d\u093e\u0930\u0924\u092e\u094d|\u092d\u093e\u0930\u094b\u0924|\u0938\u0902\u0917\u0920\u0928" + + "|\u09ac\u09be\u0982\u09b2\u09be|\u09ad\u09be\u09b0\u09a4|\u09ad\u09be\u09f0\u09a4|\u0a2d\u0a3e\u0a30\u0a24" + + "|\u0aad\u0abe\u0ab0\u0aa4|\u0b2d\u0b3e\u0b30\u0b24|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe" + + "|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd" + + "|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0cad\u0cbe\u0cb0\u0ca4|\u0d2d\u0d3e\u0d30\u0d24\u0d02" + + "|\u0dbd\u0d82\u0d9a\u0dcf|\u0e04\u0e2d\u0e21|\u0e44\u0e17\u0e22|\u0ea5\u0eb2\u0ea7|\u10d2\u10d4" + + "|\u307f\u3093\u306a|\u30a2\u30de\u30be\u30f3|\u30af\u30e9\u30a6\u30c9|\u30b0\u30fc\u30b0\u30eb" + + "|\u30b3\u30e0|\u30b9\u30c8\u30a2|\u30bb\u30fc\u30eb|\u30d5\u30a1\u30c3\u30b7\u30e7\u30f3" + + "|\u30dd\u30a4\u30f3\u30c8|\u4e16\u754c|\u4e2d\u4fe1|\u4e2d\u56fd|\u4e2d\u570b|\u4e2d\u6587\u7f51" + + "|\u4e9a\u9a6c\u900a|\u4f01\u4e1a|\u4f5b\u5c71|\u4fe1\u606f|\u5065\u5eb7|\u516b\u5366" + + "|\u516c\u53f8|\u516c\u76ca|\u53f0\u6e7e|\u53f0\u7063|\u5546\u57ce|\u5546\u5e97|\u5546\u6807" + + "|\u5609\u91cc|\u5609\u91cc\u5927\u9152\u5e97|\u5728\u7ebf|\u5927\u62ff|\u5929\u4e3b\u6559" + + "|\u5a31\u4e50|\u5bb6\u96fb|\u5e7f\u4e1c|\u5fae\u535a|\u6148\u5584|\u6211\u7231\u4f60" + + "|\u624b\u673a|\u62db\u8058|\u653f\u52a1|\u653f\u5e9c|\u65b0\u52a0\u5761|\u65b0\u95fb" + + "|\u65f6\u5c1a|\u66f8\u7c4d|\u673a\u6784|\u6de1\u9a6c\u9521|\u6e38\u620f|\u6fb3\u9580" + + "|\u70b9\u770b|\u79fb\u52a8|\u7ec4\u7ec7\u673a\u6784|\u7f51\u5740|\u7f51\u5e97|\u7f51\u7ad9" + + "|\u7f51\u7edc|\u8054\u901a|\u8c37\u6b4c|\u8d2d\u7269|\u901a\u8ca9|\u96c6\u56e2|\u96fb\u8a0a\u76c8\u79d1" + + "|\u98de\u5229\u6d66|\u98df\u54c1|\u9910\u5385|\u9999\u683c\u91cc\u62c9|\u9999\u6e2f" + + "|\ub2f7\ub137|\ub2f7\ucef4|\uc0bc\uc131|\ud55c\uad6d" + + "|xbox|xerox|xfinity|xihuan|xin|xn\\-\\-11b4c3d|xn\\-\\-1ck2e1b|xn\\-\\-1qqw23a|xn\\-\\-2scrj9c" + + "|xn\\-\\-30rr7y|xn\\-\\-3bst00m|xn\\-\\-3ds443g|xn\\-\\-3e0b707e|xn\\-\\-3hcrj9c|xn\\-\\-3pxu8k" + + "|xn\\-\\-42c2d9a|xn\\-\\-45br5cyl|xn\\-\\-45brj9c|xn\\-\\-45q11c|xn\\-\\-4dbrk0ce|xn\\-\\-4gbrim" + + "|xn\\-\\-54b7fta0cc|xn\\-\\-55qw42g|xn\\-\\-55qx5d|xn\\-\\-5su34j936bgsg|xn\\-\\-5tzm5g" + + "|xn\\-\\-6frz82g|xn\\-\\-6qq986b3xl|xn\\-\\-80adxhks|xn\\-\\-80ao21a|xn\\-\\-80aqecdr1a" + + "|xn\\-\\-80asehdb|xn\\-\\-80aswg|xn\\-\\-8y0a063a|xn\\-\\-90a3ac|xn\\-\\-90ae|xn\\-\\-90ais" + + "|xn\\-\\-9dbq2a|xn\\-\\-9et52u|xn\\-\\-9krt00a|xn\\-\\-b4w605ferd|xn\\-\\-bck1b9a5dre4c" + + "|xn\\-\\-c1avg|xn\\-\\-c2br7g|xn\\-\\-cck2b3b|xn\\-\\-cckwcxetd|xn\\-\\-cg4bki|xn\\-\\-clchc0ea0b2g2a9gcd" + + "|xn\\-\\-czr694b|xn\\-\\-czrs0t|xn\\-\\-czru2d|xn\\-\\-d1acj3b|xn\\-\\-d1alf|xn\\-\\-e1a4c" + + "|xn\\-\\-eckvdtc9d|xn\\-\\-efvy88h|xn\\-\\-fct429k|xn\\-\\-fhbei|xn\\-\\-fiq228c5hs" + + "|xn\\-\\-fiq64b|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fjq720a|xn\\-\\-flw351e|xn\\-\\-fpcrj9c3d" + + "|xn\\-\\-fzc2c9e2c|xn\\-\\-fzys8d69uvgm|xn\\-\\-g2xx48c|xn\\-\\-gckr3f0f|xn\\-\\-gecrj9c" + + "|xn\\-\\-gk3at1e|xn\\-\\-h2breg3eve|xn\\-\\-h2brj9c|xn\\-\\-h2brj9c8c|xn\\-\\-hxt814e" + + "|xn\\-\\-i1b6b1a6a2e|xn\\-\\-imr513n|xn\\-\\-io0a7i|xn\\-\\-j1aef|xn\\-\\-j1amh|xn\\-\\-j6w193g" + + "|xn\\-\\-jlq480n2rg|xn\\-\\-jvr189m|xn\\-\\-kcrx77d1x4a|xn\\-\\-kprw13d|xn\\-\\-kpry57d" + "|xn\\-\\-kput3i|xn\\-\\-l1acc|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgb9awbf|xn\\-\\-mgba3a3ejt" - + "|xn\\-\\-mgba3a4f16a|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbab2bd|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e" - + "|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-mgbpl2fh|xn\\-\\-mgbtx2b|xn\\-\\-mgbx4cd0ab" - + "|xn\\-\\-mk1bu44c|xn\\-\\-mxtq1m|xn\\-\\-ngbc5azd|xn\\-\\-node|xn\\-\\-nqv7f|xn\\-\\-nqv7fs00ema" - + "|xn\\-\\-nyqy26a|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1acf|xn\\-\\-p1ai|xn\\-\\-pgbs0dh" - + "|xn\\-\\-pssy2u|xn\\-\\-q9jyb4c|xn\\-\\-qcka1pmc|xn\\-\\-qxam|xn\\-\\-rhqv96g|xn\\-\\-s9brj9c" - + "|xn\\-\\-ses554g|xn\\-\\-t60b56a|xn\\-\\-tckwe|xn\\-\\-unup4y|xn\\-\\-vermgensberater\\-ctb" - + "|xn\\-\\-vermgensberatung\\-pwb|xn\\-\\-vhquv|xn\\-\\-vuq861b|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a" + + "|xn\\-\\-mgba3a4f16a|xn\\-\\-mgba7c0bbn0a|xn\\-\\-mgbaakc7dvf|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbab2bd" + + "|xn\\-\\-mgbah1a3hjkrd|xn\\-\\-mgbai9azgqp6j|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a|xn\\-\\-mgbbh1a71e" + + "|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgbca7dzdo|xn\\-\\-mgbcpq6gpa1a|xn\\-\\-mgberp4a5d4ar|xn\\-\\-mgbgu82a" + + "|xn\\-\\-mgbi4ecexp|xn\\-\\-mgbpl2fh|xn\\-\\-mgbt3dhd|xn\\-\\-mgbtx2b|xn\\-\\-mgbx4cd0ab" + + "|xn\\-\\-mix891f|xn\\-\\-mk1bu44c|xn\\-\\-mxtq1m|xn\\-\\-ngbc5azd|xn\\-\\-ngbe9e0a|xn\\-\\-ngbrx" + + "|xn\\-\\-node|xn\\-\\-nqv7f|xn\\-\\-nqv7fs00ema|xn\\-\\-nyqy26a|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl" + + "|xn\\-\\-otu796d|xn\\-\\-p1acf|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-pssy2u|xn\\-\\-q7ce6a" + + "|xn\\-\\-q9jyb4c|xn\\-\\-qcka1pmc|xn\\-\\-qxa6a|xn\\-\\-qxam|xn\\-\\-rhqv96g|xn\\-\\-rovu88b" + + "|xn\\-\\-rvc1e0am3e|xn\\-\\-s9brj9c|xn\\-\\-ses554g|xn\\-\\-t60b56a|xn\\-\\-tckwe|xn\\-\\-tiq49xqyj" + + "|xn\\-\\-unup4y|xn\\-\\-vermgensberater\\-ctb|xn\\-\\-vermgensberatung\\-pwb|xn\\-\\-vhquv" + + "|xn\\-\\-vuq861b|xn\\-\\-w4r85el8fhu5dnra|xn\\-\\-w4rs40l|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a" + "|xn\\-\\-xhq521b|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-y9a3aq|xn\\-\\-yfro4i67o" - + "|xn\\-\\-ygbi2ammx|xn\\-\\-zfr164b|xperia|xxx|xyz)" - + "|(?:yachts|yamaxun|yandex|yodobashi|yoga|yokohama|youtube|y[et])" - + "|(?:zara|zip|zone|zuerich|z[amw]))"; - + + "|xn\\-\\-ygbi2ammx|xn\\-\\-zfr164b|xxx|xyz)" + + "|(?:yachts|yahoo|yamaxun|yandex|yodobashi|yoga|yokohama|you|youtube|yun|y[et])" + + "|(?:zappos|zara|zero|zip|zone|zuerich|z[amw]))"; /** * Kept for backward compatibility reasons. * diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 776eeda7484e..cdf5eec32fec 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -18,6 +18,7 @@ package android.view; import static android.os.IInputConstants.INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT; import static android.view.Display.DEFAULT_DISPLAY; + import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; @@ -4360,17 +4361,6 @@ public final class MotionEvent extends InputEvent implements Parcelable { public boolean isResampled; /** - * Returns true if this pointer coords object was generated by resampling, rather than from - * an actual input event from the device at this time. - * - * @hide - */ - @TestApi - public boolean isResampled() { - return isResampled; - } - - /** * Clears the contents of this object. * Resets all axes to zero. */ diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 30fd2cfa5f28..4d53b2c6b821 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1584,11 +1584,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ static final int DISABLED = 0x00000020; - /** - * Mask for use with setFlags indicating bits used for indicating whether - * this view is enabled - * {@hide} - */ + /** + * Mask for use with setFlags indicating bits used for indicating whether + * this view is enabled + * {@hide} + */ static final int ENABLED_MASK = 0x00000020; /** @@ -15251,13 +15251,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - /** - * @see #performAccessibilityAction(int, Bundle) - * - * Note: Called from the default {@link AccessibilityDelegate}. - * - * @hide - */ + /** + * @see #performAccessibilityAction(int, Bundle) + * + * Note: Called from the default {@link AccessibilityDelegate}. + * + * @hide + */ @UnsupportedAppUsage public boolean performAccessibilityActionInternal(int action, @Nullable Bundle arguments) { if (isNestedScrollingEnabled() @@ -17391,7 +17391,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); } - /** + /** * Remove the pending click action */ @UnsupportedAppUsage diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index fe515cd3091a..5720fc01abce 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3752,7 +3752,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager && !child.isActivityDeniedForAutofillForUnimportantView()) || (shouldIncludeAllChildrenViewWithAutofillTypeNotNone(afm) && child.getAutofillType() != AUTOFILL_TYPE_NONE) - || shouldIncludeAllChildrenViews(afm)){ + || shouldIncludeAllChildrenViews(afm) + || (child instanceof ViewGroup && child.getVisibility() != View.VISIBLE)) { + // If the child is a ViewGroup object and its visibility is not visible, include + // it as part of the assist structure. The children of these invisible ViewGroup + // objects are parsed and included in the assist structure. When the Autofill + // Provider determines the visibility of these children, it looks at their + // visibility as well as their parent's visibility. Omitting invisible parents + // will lead to the Autofill Provider incorrectly assuming that these children + // of invisible parents are actually visible. list.add(child); } else if (child instanceof ViewGroup) { ((ViewGroup) child).populateChildrenForAutofill(list, flags); @@ -7404,19 +7412,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } target = next; } - if (!childIsHit) { + if (!childIsHit && mFirstHoverTarget != null) { target = mFirstHoverTarget; + final ArrayList<View> preorderedList = buildTouchDispatchChildList(); while (notEmpty && target != null) { final HoverTarget next = target.next; final View hoveredView = target.child; - rect.set(hoveredView.mLeft, hoveredView.mTop, hoveredView.mRight, - hoveredView.mBottom); - matrix.mapRect(rect); - notEmpty = region.op(Math.round(rect.left), Math.round(rect.top), - Math.round(rect.right), Math.round(rect.bottom), Region.Op.DIFFERENCE); + if (!isOnTop(child, hoveredView, preorderedList)) { + rect.set(hoveredView.mLeft, hoveredView.mTop, hoveredView.mRight, + hoveredView.mBottom); + matrix.mapRect(rect); + notEmpty = region.op(Math.round(rect.left), Math.round(rect.top), + Math.round(rect.right), Math.round(rect.bottom), + Region.Op.DIFFERENCE); + } target = next; } + if (preorderedList != null) { + preorderedList.clear(); + } } } else { TouchTarget target = mFirstTouchTarget; @@ -7429,19 +7444,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } target = next; } - if (!childIsHit) { + if (!childIsHit && mFirstTouchTarget != null) { target = mFirstTouchTarget; + final ArrayList<View> preorderedList = buildOrderedChildList(); while (notEmpty && target != null) { final TouchTarget next = target.next; final View touchedView = target.child; - rect.set(touchedView.mLeft, touchedView.mTop, touchedView.mRight, - touchedView.mBottom); - matrix.mapRect(rect); - notEmpty = region.op(Math.round(rect.left), Math.round(rect.top), - Math.round(rect.right), Math.round(rect.bottom), Region.Op.DIFFERENCE); + if (!isOnTop(child, touchedView, preorderedList)) { + rect.set(touchedView.mLeft, touchedView.mTop, touchedView.mRight, + touchedView.mBottom); + matrix.mapRect(rect); + notEmpty = region.op(Math.round(rect.left), Math.round(rect.top), + Math.round(rect.right), Math.round(rect.bottom), + Region.Op.DIFFERENCE); + } target = next; } + if (preorderedList != null) { + preorderedList.clear(); + } } } @@ -7451,6 +7473,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return notEmpty; } + /** + * Return true if the given {@code view} is drawn on top of the {@code otherView}. + * Both the {@code view} and {@code otherView} must be children of this ViewGroup. + * Otherwise, the returned value is meaningless. + */ + private boolean isOnTop(View view, View otherView, ArrayList<View> preorderedList) { + final int childrenCount = mChildrenCount; + final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); + final View[] children = mChildren; + for (int i = childrenCount - 1; i >= 0; i--) { + final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); + if (child == view) { + return true; + } + if (child == otherView) { + return false; + } + } + // Can't find the view and otherView in the children list. Return value is meaningless. + return false; + } private static void applyOpToRegionByBounds(Region region, View view, Region.Op op) { final int[] locationInWindow = new int[2]; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index d191ccdf95a3..ff6165b8a3ba 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -461,6 +461,9 @@ public final class ViewRootImpl implements ViewParent, @NonNull Display mDisplay; final String mBasePackageName; + // If we would like to keep a particular eye on the corresponding package. + final boolean mExtraDisplayListenerLogging; + final int[] mTmpLocation = new int[2]; final TypedValue mTmpValue = new TypedValue(); @@ -1010,6 +1013,8 @@ public final class ViewRootImpl implements ViewParent, mWindowLayout = windowLayout; mDisplay = display; mBasePackageName = context.getBasePackageName(); + final String name = DisplayProperties.debug_vri_package().orElse(null); + mExtraDisplayListenerLogging = !TextUtils.isEmpty(name) && name.equals(mBasePackageName); mThread = Thread.currentThread(); mLocation = new WindowLeaked(null); mLocation.fillInStackTrace(); @@ -1444,6 +1449,10 @@ public final class ViewRootImpl implements ViewParent, // We should update mAttachInfo.mDisplayState after registerDisplayListener // because displayState might be changed before registerDisplayListener. mAttachInfo.mDisplayState = mDisplay.getState(); + if (mExtraDisplayListenerLogging) { + Slog.i(mTag, "(" + mBasePackageName + ") Initial DisplayState: " + + mAttachInfo.mDisplayState, new Throwable()); + } if ((res & WindowManagerGlobal.ADD_FLAG_USE_BLAST) != 0) { mUseBLASTAdapter = true; } @@ -1528,6 +1537,9 @@ public final class ViewRootImpl implements ViewParent, * Register any kind of listeners if setView was success. */ private void registerListeners() { + if (mExtraDisplayListenerLogging) { + Slog.i(mTag, "Register listeners: " + mBasePackageName); + } mAccessibilityManager.addAccessibilityStateChangeListener( mAccessibilityInteractionConnectionManager, mHandler); mAccessibilityManager.addHighTextContrastStateChangeListener( @@ -1553,6 +1565,9 @@ public final class ViewRootImpl implements ViewParent, DisplayManagerGlobal .getInstance() .unregisterDisplayListener(mDisplayListener); + if (mExtraDisplayListenerLogging) { + Slog.w(mTag, "Unregister listeners: " + mBasePackageName, new Throwable()); + } } private void setTag() { @@ -1960,9 +1975,16 @@ public final class ViewRootImpl implements ViewParent, private final DisplayListener mDisplayListener = new DisplayListener() { @Override public void onDisplayChanged(int displayId) { + if (mExtraDisplayListenerLogging) { + Slog.i(mTag, "Received onDisplayChanged - " + mView); + } if (mView != null && mDisplay.getDisplayId() == displayId) { final int oldDisplayState = mAttachInfo.mDisplayState; final int newDisplayState = mDisplay.getState(); + if (mExtraDisplayListenerLogging) { + Slog.i(mTag, "DisplayState - old: " + oldDisplayState + + ", new: " + newDisplayState); + } if (oldDisplayState != newDisplayState) { mAttachInfo.mDisplayState = newDisplayState; pokeDrawLockIfNeeded(); @@ -3995,8 +4017,6 @@ public final class ViewRootImpl implements ViewParent, mWindowFocusChanged = false; hasWindowFocus = mUpcomingWindowFocus; } - // TODO (b/131181940): Make sure this doesn't leak Activity with mActivityConfigCallback - // config changes. if (hasWindowFocus) { mInsetsController.onWindowFocusGained( getFocusedViewOrNull() != null /* hasViewFocused */); diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig index 92d34089cb22..c144289f1a29 100644 --- a/core/java/android/view/inputmethod/flags.aconfig +++ b/core/java/android/view/inputmethod/flags.aconfig @@ -2,7 +2,8 @@ package: "android.view.inputmethod" flag { name: "refactor_insets_controller" - namespace: "inputmethod" + namespace: "input_method" description: "Feature flag for refactoring InsetsController and removing ImeInsetsSourceConsumer" bug: "298172246" + is_fixed_read_only: true }
\ No newline at end of file diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 05063365561f..a0d0656a4e50 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -27,6 +27,7 @@ import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_C import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX; import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY; import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; + import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH; import android.R; @@ -240,7 +241,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastMath; import com.android.internal.util.Preconditions; -import com.android.text.flags.Flags; import libcore.util.EmptyArray; @@ -1634,7 +1634,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (CompatChanges.isChangeEnabled(USE_BOUNDS_FOR_WIDTH)) { - mUseBoundsForWidth = Flags.useBoundsForWidth(); + mUseBoundsForWidth = false; // TODO: Connect to the flag. } else { mUseBoundsForWidth = false; } @@ -14151,7 +14151,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener selectionStart, OffsetMapping.MAP_STRATEGY_CURSOR); final int line = layout.getLineForOffset(offsetTransformed); final float insertionMarkerX = - layout.getPrimaryHorizontal(offsetTransformed) + layout.getPrimaryHorizontal( + offsetTransformed, layout.shouldClampCursor(line)) + viewportToContentHorizontalOffset; final float insertionMarkerTop = layout.getLineTop(line) + viewportToContentVerticalOffset; diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java index 95e9e861bea2..e42193d45949 100644 --- a/core/java/android/window/ScreenCapture.java +++ b/core/java/android/window/ScreenCapture.java @@ -24,7 +24,6 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.os.Build; -import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -35,7 +34,6 @@ import libcore.util.NativeAllocationRegistry; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.ObjIntConsumer; - /** * Handles display and layer captures for the system. * @@ -45,8 +43,6 @@ public class ScreenCapture { private static final String TAG = "ScreenCapture"; private static final int SCREENSHOT_WAIT_TIME_S = 4 * Build.HW_TIMEOUT_MULTIPLIER; - private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs, - long captureListener); private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs, long captureListener); private static native long nativeCreateScreenCaptureListener( @@ -56,37 +52,6 @@ public class ScreenCapture { private static native long getNativeListenerFinalizer(); /** - * @param captureArgs Arguments about how to take the screenshot - * @param captureListener A listener to receive the screenshot callback - * @hide - */ - public static int captureDisplay(@NonNull DisplayCaptureArgs captureArgs, - @NonNull ScreenCaptureListener captureListener) { - return nativeCaptureDisplay(captureArgs, captureListener.mNativeObject); - } - - /** - * Captures all the surfaces in a display and returns a {@link ScreenshotHardwareBuffer} with - * the content. - * - * @hide - */ - public static ScreenshotHardwareBuffer captureDisplay( - DisplayCaptureArgs captureArgs) { - SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener(); - int status = captureDisplay(captureArgs, syncScreenCapture); - if (status != 0) { - return null; - } - - try { - return syncScreenCapture.getBuffer(); - } catch (Exception e) { - return null; - } - } - - /** * Captures a layer and its children and returns a {@link HardwareBuffer} with the content. * * @param layer The root layer to capture. @@ -519,92 +484,6 @@ public class ScreenCapture { } /** - * The arguments class used to make display capture requests. - * - * @hide - * @see #nativeCaptureDisplay(DisplayCaptureArgs, long) - */ - public static class DisplayCaptureArgs extends CaptureArgs { - private final IBinder mDisplayToken; - private final int mWidth; - private final int mHeight; - private final boolean mUseIdentityTransform; - - private DisplayCaptureArgs(Builder builder) { - super(builder); - mDisplayToken = builder.mDisplayToken; - mWidth = builder.mWidth; - mHeight = builder.mHeight; - mUseIdentityTransform = builder.mUseIdentityTransform; - } - - /** - * The Builder class used to construct {@link DisplayCaptureArgs} - */ - public static class Builder extends CaptureArgs.Builder<Builder> { - private IBinder mDisplayToken; - private int mWidth; - private int mHeight; - private boolean mUseIdentityTransform; - - /** - * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder - * remains valid. - */ - public DisplayCaptureArgs build() { - if (mDisplayToken == null) { - throw new IllegalStateException( - "Can't take screenshot with null display token"); - } - return new DisplayCaptureArgs(this); - } - - public Builder(IBinder displayToken) { - setDisplayToken(displayToken); - } - - /** - * The display to take the screenshot of. - */ - public Builder setDisplayToken(IBinder displayToken) { - mDisplayToken = displayToken; - return this; - } - - /** - * Set the desired size of the returned buffer. The raw screen will be scaled down to - * this size - * - * @param width The desired width of the returned buffer. Caller may pass in 0 if no - * scaling is desired. - * @param height The desired height of the returned buffer. Caller may pass in 0 if no - * scaling is desired. - */ - public Builder setSize(int width, int height) { - mWidth = width; - mHeight = height; - return this; - } - - /** - * Replace the rotation transform of the display with the identity transformation while - * taking the screenshot. This ensures the screenshot is taken in the ROTATION_0 - * orientation. Set this value to false if the screenshot should be taken in the - * current screen orientation. - */ - public Builder setUseIdentityTransform(boolean useIdentityTransform) { - mUseIdentityTransform = useIdentityTransform; - return this; - } - - @Override - Builder getThis() { - return this; - } - } - } - - /** * The arguments class used to make layer capture requests. * * @hide @@ -682,7 +561,6 @@ public class ScreenCapture { /** * The object used to receive the results when invoking screen capture requests via - * {@link #captureDisplay(DisplayCaptureArgs, ScreenCaptureListener)} or * {@link #captureLayers(LayerCaptureArgs, ScreenCaptureListener)} * * This listener can only be used for a single call to capture content call. @@ -784,8 +662,7 @@ public class ScreenCapture { /** * Helper class to synchronously get the {@link ScreenshotHardwareBuffer} when calling - * {@link #captureLayers(LayerCaptureArgs, ScreenCaptureListener)} or - * {@link #captureDisplay(DisplayCaptureArgs, ScreenCaptureListener)} + * {@link #captureLayers(LayerCaptureArgs, ScreenCaptureListener)} */ public abstract static class SynchronousScreenCaptureListener extends ScreenCaptureListener { SynchronousScreenCaptureListener(ObjIntConsumer<ScreenshotHardwareBuffer> consumer) { diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java index 451acbe84a60..a88e394c0985 100644 --- a/core/java/android/window/StartingWindowInfo.java +++ b/core/java/android/window/StartingWindowInfo.java @@ -122,7 +122,7 @@ public final class StartingWindowInfo implements Parcelable { TYPE_PARAMETER_PROCESS_RUNNING, TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT, TYPE_PARAMETER_ACTIVITY_CREATED, - TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN, + TYPE_PARAMETER_ALLOW_ICON, TYPE_PARAMETER_ALLOW_HANDLE_SOLID_COLOR_SCREEN, TYPE_PARAMETER_WINDOWLESS, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN @@ -143,7 +143,7 @@ public final class StartingWindowInfo implements Parcelable { /** @hide */ public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010; /** @hide */ - public static final int TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN = 0x00000020; + public static final int TYPE_PARAMETER_ALLOW_ICON = 0x00000020; /** * The parameter which indicates if the activity has finished drawing. * @hide diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 9b5a3f7ea77c..e014ab057653 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -40,6 +40,9 @@ import android.annotation.UiContext; import android.app.ActivityManager; import android.app.KeyguardManager; import android.app.SearchManager; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; @@ -123,6 +126,7 @@ import com.android.internal.view.menu.MenuHelper; import com.android.internal.view.menu.MenuPresenter; import com.android.internal.view.menu.MenuView; import com.android.internal.widget.DecorContentParent; +import com.android.window.flags.Flags; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -162,6 +166,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300; + /** + * Makes navigation bar color transparent by default if the target SDK is + * {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} or above. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + private static final long NAV_BAR_COLOR_DEFAULT_TRANSPARENT = 232195501L; + private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES | (1 << FEATURE_CUSTOM_TITLE) | (1 << FEATURE_CONTENT_TRANSITIONS) | @@ -2525,6 +2537,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mNavigationBarColor = navBarColor == navBarDefaultColor + && !(CompatChanges.isChangeEnabled(NAV_BAR_COLOR_DEFAULT_TRANSPARENT) + && Flags.navBarTransparentByDefault()) && !context.getResources().getBoolean( R.bool.config_navBarDefaultTransparent) ? navBarCompatibleColor diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java index 52ffc984c41e..a513ca535620 100644 --- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java +++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java @@ -21,6 +21,7 @@ import static android.content.res.Resources.ID_NULL; import android.annotation.IdRes; import android.content.Context; +import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; @@ -53,10 +54,13 @@ public class ResolverDrawerLayout extends ViewGroup { private static final String TAG = "ResolverDrawerLayout"; private MetricsLogger mMetricsLogger; + + /** - * Max width of the whole drawer layout + * Max width of the whole drawer layout and its res id */ - private final int mMaxWidth; + private int mMaxWidthResId; + private int mMaxWidth; /** * Max total visible height of views not marked always-show when in the closed/initial state @@ -152,6 +156,7 @@ public class ResolverDrawerLayout extends ViewGroup { final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ResolverDrawerLayout, defStyleAttr, 0); + mMaxWidthResId = a.getResourceId(R.styleable.ResolverDrawerLayout_maxWidth, -1); mMaxWidth = a.getDimensionPixelSize(R.styleable.ResolverDrawerLayout_maxWidth, -1); mMaxCollapsedHeight = a.getDimensionPixelSize( R.styleable.ResolverDrawerLayout_maxCollapsedHeight, 0); @@ -1042,6 +1047,18 @@ public class ResolverDrawerLayout extends ViewGroup { return mAlwaysShowHeight; } + /** + * Max width of the drawer needs to be updated after the configuration is changed. + * For example, foldables have different layout width when the device is folded and unfolded. + */ + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (mMaxWidthResId > 0) { + mMaxWidth = getResources().getDimensionPixelSize(mMaxWidthResId); + } + } + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int width = getWidth(); diff --git a/core/jni/android_window_ScreenCapture.cpp b/core/jni/android_window_ScreenCapture.cpp index bdf7eaa8aace..beb8c9b2d12f 100644 --- a/core/jni/android_window_ScreenCapture.cpp +++ b/core/jni/android_window_ScreenCapture.cpp @@ -50,13 +50,6 @@ static struct { } gCaptureArgsClassInfo; static struct { - jfieldID displayToken; - jfieldID width; - jfieldID height; - jfieldID useIdentityTransform; -} gDisplayCaptureArgsClassInfo; - -static struct { jfieldID layer; jfieldID childrenOnly; } gLayerCaptureArgsClassInfo; @@ -181,39 +174,6 @@ static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs& gCaptureArgsClassInfo.hintForSeamlessTransition); } -static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env, - jobject displayCaptureArgsObject) { - DisplayCaptureArgs captureArgs; - getCaptureArgs(env, displayCaptureArgsObject, captureArgs); - - captureArgs.displayToken = - ibinderForJavaObject(env, - env->GetObjectField(displayCaptureArgsObject, - gDisplayCaptureArgsClassInfo.displayToken)); - captureArgs.width = - env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.width); - captureArgs.height = - env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.height); - captureArgs.useIdentityTransform = - env->GetBooleanField(displayCaptureArgsObject, - gDisplayCaptureArgsClassInfo.useIdentityTransform); - return captureArgs; -} - -static jint nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject, - jlong screenCaptureListenerObject) { - const DisplayCaptureArgs captureArgs = - displayCaptureArgsFromObject(env, displayCaptureArgsObject); - - if (captureArgs.displayToken == nullptr) { - return BAD_VALUE; - } - - sp<gui::IScreenCaptureListener> captureListener = - reinterpret_cast<gui::IScreenCaptureListener*>(screenCaptureListenerObject); - return ScreenshotClient::captureDisplay(captureArgs, captureListener); -} - static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject, jlong screenCaptureListenerObject) { LayerCaptureArgs captureArgs; @@ -283,8 +243,6 @@ static jlong getNativeListenerFinalizer(JNIEnv* env, jclass clazz) { static const JNINativeMethod sScreenCaptureMethods[] = { // clang-format off - {"nativeCaptureDisplay", "(Landroid/window/ScreenCapture$DisplayCaptureArgs;J)I", - (void*)nativeCaptureDisplay }, {"nativeCaptureLayers", "(Landroid/window/ScreenCapture$LayerCaptureArgs;J)I", (void*)nativeCaptureLayers }, {"nativeCreateScreenCaptureListener", "(Ljava/util/function/ObjIntConsumer;)J", @@ -317,17 +275,6 @@ int register_android_window_ScreenCapture(JNIEnv* env) { gCaptureArgsClassInfo.hintForSeamlessTransition = GetFieldIDOrDie(env, captureArgsClazz, "mHintForSeamlessTransition", "Z"); - jclass displayCaptureArgsClazz = - FindClassOrDie(env, "android/window/ScreenCapture$DisplayCaptureArgs"); - gDisplayCaptureArgsClassInfo.displayToken = - GetFieldIDOrDie(env, displayCaptureArgsClazz, "mDisplayToken", "Landroid/os/IBinder;"); - gDisplayCaptureArgsClassInfo.width = - GetFieldIDOrDie(env, displayCaptureArgsClazz, "mWidth", "I"); - gDisplayCaptureArgsClassInfo.height = - GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I"); - gDisplayCaptureArgsClassInfo.useIdentityTransform = - GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z"); - jclass layerCaptureArgsClazz = FindClassOrDie(env, "android/window/ScreenCapture$LayerCaptureArgs"); gLayerCaptureArgsClassInfo.layer = diff --git a/core/proto/android/inputmethodservice/softinputwindow.proto b/core/proto/android/inputmethodservice/softinputwindow.proto index e0ba6bf33567..32d14f0ec263 100644 --- a/core/proto/android/inputmethodservice/softinputwindow.proto +++ b/core/proto/android/inputmethodservice/softinputwindow.proto @@ -27,6 +27,6 @@ message SoftInputWindowProto { reserved 2; // window_type reserved 3; // gravity reserved 4; // takes_focus - optional .android.graphics.RectProto bounds = 5; + reserved 5; // bounds optional int32 window_state = 6; }
\ No newline at end of file diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d09bf4413284..2e2ec5ba52b3 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2814,7 +2814,7 @@ <!-- Base "handwriting slop" value used by ViewConfiguration as a movement threshold where stylus handwriting should begin. --> - <dimen name="config_viewConfigurationHandwritingSlop">4dp</dimen> + <dimen name="config_viewConfigurationHandwritingSlop">2dp</dimen> <!-- Base "hover slop" value used by ViewConfiguration as a movement threshold under which hover is considered "stationary". --> @@ -5451,6 +5451,10 @@ to enroll the other eligible biometric. --> <fraction name="config_biometricNotificationFrrThreshold">25%</fraction> + <!-- Whether to enable the biometric notification for dual-modality device that enrolled a + single biometric and experiences high FRR. --> + <bool name="config_biometricFrrNotificationEnabled">false</bool> + <!-- The component name for the default profile supervisor, which can be set as a profile owner even after user setup is complete. The defined component should be used for supervision purposes only. The component must be part of a system app. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7f1a6f9a88e3..fe1144958c52 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2604,6 +2604,7 @@ <!-- Biometric FRR config --> <java-symbol type="fraction" name="config_biometricNotificationFrrThreshold" /> + <java-symbol type="bool" name="config_biometricFrrNotificationEnabled" /> <!-- Biometric FRR notification messages --> <java-symbol type="string" name="device_unlock_notification_name" /> diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 7f56eb70b153..9cde296b2cab 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -61,11 +61,11 @@ android_test { "testng", "servicestests-utils", "device-time-shell-utils", + "testables", ], libs: [ "android.test.runner", - "testables", "org.apache.http.legacy", "android.test.base", "android.test.mock", diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java index 0e1a6b7e7daa..7c4136d62b8f 100644 --- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java +++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java @@ -35,6 +35,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.After; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -881,6 +882,7 @@ public class DeviceConfigTest { } @Test + @Ignore("b/300174188") public void syncDisabling() throws Exception { Properties properties1 = new Properties.Builder(NAMESPACE) .setString(KEY, VALUE) diff --git a/core/tests/coretests/src/android/service/TEST_MAPPING b/core/tests/coretests/src/android/service/TEST_MAPPING index fbf8a92e031d..7ebda0062335 100644 --- a/core/tests/coretests/src/android/service/TEST_MAPPING +++ b/core/tests/coretests/src/android/service/TEST_MAPPING @@ -1,5 +1,5 @@ { - "postsubmit": [ + "presubmit": [ { "name": "FrameworksCoreTests", "options": [ diff --git a/core/tests/coretests/src/android/service/quicksettings/TileServiceTest.java b/core/tests/coretests/src/android/service/quicksettings/TileServiceTest.java index 322a5532cc4b..04af5d739fc0 100644 --- a/core/tests/coretests/src/android/service/quicksettings/TileServiceTest.java +++ b/core/tests/coretests/src/android/service/quicksettings/TileServiceTest.java @@ -28,26 +28,27 @@ import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) public class TileServiceTest { @Mock private IQSService.Stub mIQSService; + private TestableLooper mTestableLooper; + private IBinder mTileToken; private TileService mTileService; private Tile mTile; @@ -56,6 +57,8 @@ public class TileServiceTest { public void setUp() { MockitoAnnotations.initMocks(this); + mTestableLooper = TestableLooper.get(this); + mTileToken = new Binder(); when(mIQSService.asBinder()).thenCallRealMethod(); when(mIQSService.queryLocalInterface(anyString())).thenReturn(mIQSService); @@ -73,6 +76,7 @@ public class TileServiceTest { when(mIQSService.getTile(mTileToken)).thenThrow(new RemoteException()); IBinder result = mTileService.onBind(intent); + mTestableLooper.processAllMessages(); assertNull(result); } @@ -84,13 +88,12 @@ public class TileServiceTest { when(mIQSService.getTile(mTileToken)).thenReturn(null); IBinder result = mTileService.onBind(intent); + mTestableLooper.processAllMessages(); assertNotNull(result); verify(mIQSService, never()).onStartSuccessful(any()); } - // TODO(b/298075609): Test is disabled due to flakiness. - @Ignore @Test public void testBindSuccessful() throws RemoteException { Intent intent = new Intent(); @@ -99,6 +102,7 @@ public class TileServiceTest { when(mIQSService.getTile(mTileToken)).thenReturn(mTile); IBinder result = mTileService.onBind(intent); + mTestableLooper.processAllMessages(); assertNotNull(result); verify(mIQSService).onStartSuccessful(mTileToken); diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java index 6cea2f3c92bd..dd8f73fd54c4 100644 --- a/core/tests/coretests/src/android/util/PatternsTest.java +++ b/core/tests/coretests/src/android/util/PatternsTest.java @@ -399,7 +399,7 @@ public class PatternsTest extends TestCase { @SmallTest public void testAutoLinkWebUrl_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld() throws Exception { - String url = "thank.you"; + String url = "thank.unknowntld"; assertFalse("Should not match URL that does not start with a protocol and " + "does not contain a known TLD", Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); @@ -422,7 +422,7 @@ public class PatternsTest extends TestCase { @SmallTest public void testAutoLinkWebUrl_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld() throws Exception { - String url = "Thank\u263A.you"; + String url = "Thank\u263A.unknowntld"; assertFalse("Should not match URLs containing emoji and with unknown TLD", Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); } diff --git a/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java b/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java index 60a0a2adbbbe..c210fd631f06 100644 --- a/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java +++ b/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java @@ -90,22 +90,73 @@ public class ViewGroupGetChildLocalHitRegionTest { assertGetChildLocalHitRegionEmpty(R.id.view_cover_top, R.id.view_cover_bottom); } + @Test + public void testGetChildLocalHitRegion_topViewIsNotBlockedByBottomView() { + // In this case, two views overlap with each other and the MotionEvent is injected to the + // bottom view. It verifies that the hit region of the top view won't be blocked by the + // bottom view. + testGetChildLocalHitRegion_topViewIsNotBlockedByBottomView(/* isHover= */ true); + testGetChildLocalHitRegion_topViewIsNotBlockedByBottomView(/* isHover= */ false); + } + + private void testGetChildLocalHitRegion_topViewIsNotBlockedByBottomView(boolean isHover) { + // In this case, two views overlap with each other and the MotionEvent is injected to the + // bottom view. It verifies that the hit region of the top view won't be blocked by the + // bottom view. + mScenarioRule.getScenario().onActivity(activity -> { + View viewTop = activity.findViewById(R.id.view_overlap_top); + View viewBottom = activity.findViewById(R.id.view_overlap_bottom); + + // The viewTop covers the left side of the viewBottom. To avoid the MotionEvent gets + // blocked by viewTop, we inject MotionEvents into viewBottom's right bottom corner. + float x = viewBottom.getWidth() - 1; + float y = viewBottom.getHeight() - 1; + injectMotionEvent(viewBottom, x, y, isHover); + + Matrix actualMatrix = new Matrix(); + Region actualRegion = new Region(0, 0, viewTop.getWidth(), viewTop.getHeight()); + boolean actualNotEmpty = viewTop.getParent() + .getChildLocalHitRegion(viewTop, actualRegion, actualMatrix, isHover); + + int[] windowLocation = new int[2]; + viewTop.getLocationInWindow(windowLocation); + Matrix expectMatrix = new Matrix(); + expectMatrix.preTranslate(-windowLocation[0], -windowLocation[1]); + // Though viewTop and viewBottom overlaps, viewTop's hit region won't be blocked by + // viewBottom. + Region expectRegion = new Region(0, 0, viewTop.getWidth(), viewTop.getHeight()); + + assertThat(actualNotEmpty).isTrue(); + assertThat(actualMatrix).isEqualTo(expectMatrix); + assertThat(actualRegion).isEqualTo(expectRegion); + }); + } + private void injectMotionEvent(View view, boolean isHover) { + float x = view.getWidth() / 2f; + float y = view.getHeight() / 2f; + injectMotionEvent(view, x, y, isHover); + } + + /** + * Inject MotionEvent into the given view, at the given location specified in the view's + * coordinates. + */ + private void injectMotionEvent(View view, float x, float y, boolean isHover) { int[] location = new int[2]; view.getLocationInWindow(location); - float x = location[0] + view.getWidth() / 2f; - float y = location[1] + view.getHeight() / 2f; + float globalX = location[0] + x; + float globalY = location[1] + y; int action = isHover ? MotionEvent.ACTION_HOVER_ENTER : MotionEvent.ACTION_DOWN; MotionEvent motionEvent = MotionEvent.obtain(/* downtime= */ 0, /* eventTime= */ 0, action, - x, y, /* pressure= */ 0, /* size= */ 0, /* metaState= */ 0, + globalX, globalY, /* pressure= */ 0, /* size= */ 0, /* metaState= */ 0, /* xPrecision= */ 1, /* yPrecision= */ 1, /* deviceId= */0, /* edgeFlags= */0); View rootView = view.getRootView(); rootView.dispatchPointerEvent(motionEvent); } - private void assertGetChildLocalHitRegion(int viewId) { assertGetChildLocalHitRegion(viewId, /* isHover= */ true); assertGetChildLocalHitRegion(viewId, /* isHover= */ false); diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index a5ee19e2d068..cdfc4c87d271 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -879,14 +879,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // Skip resolving if the activity is on a pinned TaskFragmentContainer. // TODO(b/243518738): skip resolving for overlay container. - if (container != null) { - final TaskContainer taskContainer = container.getTaskContainer(); - if (taskContainer.isTaskFragmentContainerPinned(container)) { - return true; - } + final TaskContainer taskContainer = container != null ? container.getTaskContainer() : null; + if (container != null && taskContainer != null + && taskContainer.isTaskFragmentContainerPinned(container)) { + return true; } - final TaskContainer taskContainer = container != null ? container.getTaskContainer() : null; if (!isOnReparent && taskContainer != null && taskContainer.getTopNonFinishingTaskFragmentContainer(false /* includePin */) != container) { @@ -895,6 +893,28 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return true; } + // Ensure the top TaskFragments are updated to the right config if activity is resolved + // to a new TaskFragment while pin TF exists. + final boolean handled = resolveActivityToContainerByRule(wct, activity, container, + isOnReparent); + if (handled && taskContainer != null) { + final SplitPinContainer splitPinContainer = taskContainer.getSplitPinContainer(); + if (splitPinContainer != null) { + final TaskFragmentContainer resolvedContainer = getContainerWithActivity(activity); + if (resolvedContainer != null && resolvedContainer.getRunningActivityCount() <= 1) { + updateContainer(wct, splitPinContainer.getSecondaryContainer()); + } + } + } + return handled; + } + + /** + * Resolves the activity to a {@link TaskFragmentContainer} according to the Split-rules. + */ + boolean resolveActivityToContainerByRule(@NonNull WindowContainerTransaction wct, + @NonNull Activity activity, @Nullable TaskFragmentContainer container, + boolean isOnReparent) { /* * We will check the following to see if there is any embedding rule matched: * 1. Whether the new launched activity should always expand. @@ -1301,6 +1321,26 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } } + // Ensure the top TaskFragments are updated to the right config if the intent is resolved + // to a new TaskFragment while pin TF exists. + final TaskFragmentContainer launchingContainer = resolveStartActivityIntentByRule(wct, + taskId, intent, launchingActivity); + if (launchingContainer != null && launchingContainer.getRunningActivityCount() == 0) { + final SplitPinContainer splitPinContainer = + launchingContainer.getTaskContainer().getSplitPinContainer(); + if (splitPinContainer != null) { + updateContainer(wct, splitPinContainer.getSecondaryContainer()); + } + } + return launchingContainer; + } + + /** + * Resolves the intent to a {@link TaskFragmentContainer} according to the Split-rules. + */ + @Nullable + TaskFragmentContainer resolveStartActivityIntentByRule(@NonNull WindowContainerTransaction wct, + int taskId, @NonNull Intent intent, @Nullable Activity launchingActivity) { /* * We will check the following to see if there is any embedding rule matched: * 1. Whether the new activity intent should always expand. diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml index d93e9ba32105..7638132d6562 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml @@ -26,8 +26,8 @@ <ImageButton android:id="@+id/caption_handle" android:layout_width="128dp" - android:layout_height="42dp" - android:paddingVertical="19dp" + android:layout_height="@dimen/desktop_mode_fullscreen_decor_caption_height" + android:paddingVertical="16dp" android:contentDescription="@string/handle_text" android:src="@drawable/decor_handle_dark" tools:tint="@color/desktop_mode_caption_handle_bar_dark" diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index cba86c8b3dcf..7faf3803b11a 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -401,6 +401,12 @@ <!-- Height of button (32dp) + 2 * margin (5dp each). --> <dimen name="freeform_decor_caption_height">42dp</dimen> + <!-- Height of desktop mode caption for freeform tasks. --> + <dimen name="desktop_mode_freeform_decor_caption_height">42dp</dimen> + + <!-- Height of desktop mode caption for fullscreen tasks. --> + <dimen name="desktop_mode_fullscreen_decor_caption_height">36dp</dimen> + <!-- The width of the maximize menu in desktop mode. --> <dimen name="desktop_mode_maximize_menu_width">287dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java index 66e69300f45f..39e3180ffe2a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java @@ -257,8 +257,16 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask return false; } - // Badged bubble image - Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo, b.getIcon()); + Drawable bubbleDrawable = null; + try { + // Badged bubble image + bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo, + b.getIcon()); + } catch (Exception e) { + // If we can't create the icon we'll default to the app icon + Log.w(TAG, "Exception creating icon for the bubble: " + b.getKey()); + } + if (bubbleDrawable == null) { // Default to app icon bubbleDrawable = appIcon; @@ -268,7 +276,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask b.isImportantConversation()); info.badgeBitmap = badgeBitmapInfo.icon; // Raw badge bitmap never includes the important conversation ring - info.rawBadgeBitmap = b.isImportantConversation() // is this needed for bar? + info.rawBadgeBitmap = b.isImportantConversation() ? iconFactory.getBadgeBitmap(badgedIcon, false).icon : badgeBitmapInfo.icon; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index fd23d147b1b7..9f9854e7e244 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -205,6 +205,7 @@ public abstract class WMShellModule { SyncTransactionQueue syncQueue, Transitions transitions, Optional<DesktopTasksController> desktopTasksController, + RecentsTransitionHandler recentsTransitionHandler, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { if (DesktopModeStatus.isEnabled()) { return new DesktopModeWindowDecorViewModel( @@ -218,6 +219,7 @@ public abstract class WMShellModule { syncQueue, transitions, desktopTasksController, + recentsTransitionHandler, rootTaskDisplayAreaOrganizer); } return new CaptionWindowDecorViewModel( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java index 069066e4bd49..2616b8b08bf1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java @@ -34,4 +34,10 @@ public interface RecentTasks { default void getRecentTasks(int maxNum, int flags, int userId, Executor callbackExecutor, Consumer<List<GroupedRecentTaskInfo>> callback) { } + + /** + * Adds the listener to be notified of whether the recent task animation is running. + */ + default void addAnimationStateListener(Executor listenerExecutor, Consumer<Boolean> listener) { + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index 94e1b33dbf58..ccc34389557c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -428,6 +428,21 @@ public class RecentTasksController implements TaskStackListenerCallback, executor.execute(() -> callback.accept(tasks)); }); } + + @Override + public void addAnimationStateListener(Executor executor, Consumer<Boolean> listener) { + mMainExecutor.execute(() -> { + if (mTransitionHandler == null) { + return; + } + mTransitionHandler.addTransitionStateListener(new RecentsTransitionStateListener() { + @Override + public void onAnimationStateChanged(boolean running) { + executor.execute(() -> listener.accept(running)); + } + }); + }); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index 6cd33bc342c8..ead2f9cbd1ad 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -76,6 +76,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { private final RecentTasksController mRecentTasksController; private IApplicationThread mAnimApp = null; private final ArrayList<RecentsController> mControllers = new ArrayList<>(); + private final ArrayList<RecentsTransitionStateListener> mStateListeners = new ArrayList<>(); /** * List of other handlers which might need to mix recents with other things. These are checked @@ -106,6 +107,11 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { mMixers.remove(mixer); } + /** Adds the callback for receiving the state change of transition. */ + public void addTransitionStateListener(RecentsTransitionStateListener listener) { + mStateListeners.add(listener); + } + @VisibleForTesting public IBinder startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options, IApplicationThread appThread, IRecentsAnimationRunner listener) { @@ -128,6 +134,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct, mixedHandler == null ? this : mixedHandler); + for (int i = 0; i < mStateListeners.size(); i++) { + mStateListeners.get(i).onTransitionStarted(transition); + } if (mixer != null) { mixer.setRecentsTransition(transition); } @@ -389,6 +398,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { mTransition = null; mPendingPauseSnapshotsForCancel = null; mControllers.remove(this); + for (int i = 0; i < mStateListeners.size(); i++) { + mStateListeners.get(i).onAnimationStateChanged(false); + } } boolean start(TransitionInfo info, SurfaceControl.Transaction t, @@ -528,6 +540,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { apps.toArray(new RemoteAnimationTarget[apps.size()]), wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]), new Rect(0, 0, 0, 0), new Rect(), b); + for (int i = 0; i < mStateListeners.size(); i++) { + mStateListeners.get(i).onAnimationStateChanged(true); + } } catch (RemoteException e) { Slog.e(TAG, "Error starting recents animation", e); cancel("onAnimationStart() failed"); @@ -581,9 +596,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { final TransitionUtil.LeafTaskFilter leafTaskFilter = new TransitionUtil.LeafTaskFilter(); boolean hasTaskChange = false; - // Walk backwards so that higher z-order changes are recorded *last* in the assorted - // task lists. This way, when the are added, the on-top tasks are drawn on top. - for (int i = info.getChanges().size() - 1; i >= 0; --i) { + for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (taskInfo != null diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java new file mode 100644 index 000000000000..e8733ebd8f03 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java @@ -0,0 +1,30 @@ +/* + * 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.wm.shell.recents; + +import android.os.IBinder; + +/** The listener for the events from {@link RecentsTransitionHandler}. */ +public interface RecentsTransitionStateListener { + + /** Notifies whether the recents animation is running. */ + default void onAnimationStateChanged(boolean running) { + } + + /** Notifies that a recents shell transition has started. */ + default void onTransitionStarted(IBinder transition) {} +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java index 72fc8686f648..6ea6516a96f5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java @@ -30,7 +30,7 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCR import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; -import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN; +import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_ICON; import static android.window.StartingWindowInfo.TYPE_PARAMETER_WINDOWLESS; import android.window.StartingWindowInfo; @@ -52,8 +52,7 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0; final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0; final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0; - final boolean isSolidColorSplashScreen = - (parameter & TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN) != 0; + final boolean allowIcon = (parameter & TYPE_PARAMETER_ALLOW_ICON) != 0; final boolean legacySplashScreen = ((parameter & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN) != 0); final boolean activityDrawn = (parameter & TYPE_PARAMETER_ACTIVITY_DRAWN) != 0; @@ -67,13 +66,13 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor + "processRunning=%b, " + "allowTaskSnapshot=%b, " + "activityCreated=%b, " - + "isSolidColorSplashScreen=%b, " + + "allowIcon=%b, " + "legacySplashScreen=%b, " + "activityDrawn=%b, " + "windowless=%b, " + "topIsHome=%b", newTask, taskSwitch, processRunning, allowTaskSnapshot, activityCreated, - isSolidColorSplashScreen, legacySplashScreen, activityDrawn, windowlessSurface, + allowIcon, legacySplashScreen, activityDrawn, windowlessSurface, topIsHome); if (windowlessSurface) { @@ -81,7 +80,7 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor } if (!topIsHome) { if (!processRunning || newTask || (taskSwitch && !activityCreated)) { - return getSplashscreenType(isSolidColorSplashScreen, legacySplashScreen); + return getSplashscreenType(allowIcon, legacySplashScreen); } } @@ -95,18 +94,18 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor } } if (!activityDrawn && !topIsHome) { - return getSplashscreenType(isSolidColorSplashScreen, legacySplashScreen); + return getSplashscreenType(allowIcon, legacySplashScreen); } } return STARTING_WINDOW_TYPE_NONE; } - private static int getSplashscreenType(boolean solidColorSplashScreen, - boolean legacySplashScreen) { - return solidColorSplashScreen - ? STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN - : legacySplashScreen - ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN + private static int getSplashscreenType(boolean allowIcon, boolean legacySplashScreen) { + if (allowIcon) { + return legacySplashScreen ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN : STARTING_WINDOW_TYPE_SPLASH_SCREEN; + } else { + return STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN; + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index c18973132364..82fc0f49c143 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -18,6 +18,7 @@ package com.android.wm.shell.windowdecor; import android.app.ActivityManager.RunningTaskInfo; import android.app.WindowConfiguration; +import android.app.WindowConfiguration.WindowingMode; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; @@ -114,7 +115,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL mRelayoutParams.reset(); mRelayoutParams.mRunningTaskInfo = taskInfo; mRelayoutParams.mLayoutResId = R.layout.caption_window_decor; - mRelayoutParams.mCaptionHeightId = getCaptionHeightId(); + mRelayoutParams.mCaptionHeightId = getCaptionHeightId(taskInfo.getWindowingMode()); mRelayoutParams.mShadowRadiusId = shadowRadiusID; mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw; @@ -227,7 +228,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL } @Override - int getCaptionHeightId() { + int getCaptionHeightId(@WindowingMode int windowingMode) { return R.dimen.freeform_decor_caption_height; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index b4e181808194..afa2754803f1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; + import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; @@ -73,6 +74,8 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition; import com.android.wm.shell.freeform.FreeformTaskTransitionStarter; +import com.android.wm.shell.recents.RecentsTransitionHandler; +import com.android.wm.shell.recents.RecentsTransitionStateListener; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.KeyguardChangeListener; @@ -102,6 +105,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final DisplayController mDisplayController; private final SyncTransactionQueue mSyncQueue; private final Optional<DesktopTasksController> mDesktopTasksController; + private final RecentsTransitionHandler mRecentsTransitionHandler; private boolean mTransitionDragActive; private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>(); @@ -121,7 +125,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private MoveToDesktopAnimator mMoveToDesktopAnimator; private final Rect mDragToDesktopAnimationStartBounds = new Rect(); - private final DesktopModeKeyguardChangeListener mDesktopModeKeyguardChangeListener; + private final DesktopModeKeyguardChangeListener mDesktopModeKeyguardChangeListener = + new DesktopModeKeyguardChangeListener(); private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; public DesktopModeWindowDecorViewModel( @@ -135,6 +140,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { SyncTransactionQueue syncQueue, Transitions transitions, Optional<DesktopTasksController> desktopTasksController, + RecentsTransitionHandler recentsTransitionHandler, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer ) { this( @@ -148,10 +154,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { syncQueue, transitions, desktopTasksController, + recentsTransitionHandler, new DesktopModeWindowDecoration.Factory(), new InputMonitorFactory(), SurfaceControl.Transaction::new, - new DesktopModeKeyguardChangeListener(), rootTaskDisplayAreaOrganizer); } @@ -167,10 +173,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { SyncTransactionQueue syncQueue, Transitions transitions, Optional<DesktopTasksController> desktopTasksController, + RecentsTransitionHandler recentsTransitionHandler, DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory, InputMonitorFactory inputMonitorFactory, Supplier<SurfaceControl.Transaction> transactionFactory, - DesktopModeKeyguardChangeListener desktopModeKeyguardChangeListener, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { mContext = context; mMainHandler = mainHandler; @@ -182,11 +188,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mSyncQueue = syncQueue; mTransitions = transitions; mDesktopTasksController = desktopTasksController; + mRecentsTransitionHandler = recentsTransitionHandler; mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory; mInputMonitorFactory = inputMonitorFactory; mTransactionFactory = transactionFactory; - mDesktopModeKeyguardChangeListener = desktopModeKeyguardChangeListener; mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; shellInit.addInitCallback(this::onInit, this); @@ -194,6 +200,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private void onInit() { mShellController.addKeyguardChangeListener(mDesktopModeKeyguardChangeListener); + mRecentsTransitionHandler.addTransitionStateListener(new RecentsTransitionStateListener() { + @Override + public void onTransitionStarted(IBinder transition) { + onRecentsTransitionStarted(transition); + } + }); } @Override @@ -319,6 +331,16 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } + private void onRecentsTransitionStarted(IBinder transition) { + // Block relayout on window decorations originating from #onTaskInfoChanges until the + // animation completes to avoid interfering with the transition animation. + for (int i = 0; i < mWindowDecorByTaskId.size(); i++) { + final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.valueAt(i); + decor.incrementRelayoutBlock(); + decor.addTransitionPausingRelayout(transition); + } + } + private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener, DragDetector.MotionEventHandler{ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index dbff20e6026a..84ec6b389c4a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -17,8 +17,10 @@ package com.android.wm.shell.windowdecor; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import android.app.ActivityManager; +import android.app.WindowConfiguration.WindowingMode; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -56,6 +58,7 @@ import com.android.wm.shell.windowdecor.viewholder.DesktopModeWindowDecorationVi import java.util.HashSet; import java.util.Set; +import java.util.function.Supplier; /** * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with @@ -109,7 +112,30 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin Choreographer choreographer, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { - super(context, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorConfig); + this (context, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorConfig, + handler, choreographer, syncQueue, rootTaskDisplayAreaOrganizer, + SurfaceControl.Builder::new, SurfaceControl.Transaction::new, + WindowContainerTransaction::new, new SurfaceControlViewHostFactory() {}); + } + + DesktopModeWindowDecoration( + Context context, + DisplayController displayController, + ShellTaskOrganizer taskOrganizer, + ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl taskSurface, + Configuration windowDecorConfig, + Handler handler, + Choreographer choreographer, + SyncTransactionQueue syncQueue, + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier, + Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier, + Supplier<WindowContainerTransaction> windowContainerTransactionSupplier, + SurfaceControlViewHostFactory surfaceControlViewHostFactory) { + super(context, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorConfig, + surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, + windowContainerTransactionSupplier, surfaceControlViewHostFactory); mHandler = handler; mChoreographer = choreographer; @@ -150,7 +176,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return; } - final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get(); // Use |applyStartTransactionOnDraw| so that the transaction (that applies task crop) is // synced with the buffer transaction (that draws the View). Both will be shown on screen // at the same, whereas applying them independently causes flickering. See b/270202228. @@ -180,13 +206,23 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mRelayoutParams.reset(); mRelayoutParams.mRunningTaskInfo = taskInfo; mRelayoutParams.mLayoutResId = windowDecorLayoutId; - mRelayoutParams.mCaptionHeightId = getCaptionHeightId(); + mRelayoutParams.mCaptionHeightId = getCaptionHeightId(taskInfo.getWindowingMode()); mRelayoutParams.mShadowRadiusId = shadowRadiusID; mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw; - - mRelayoutParams.mWindowDecorConfig = DesktopTasksController.isDesktopDensityOverrideSet() - ? mContext.getResources().getConfiguration() // Use system context - : mTaskInfo.configuration; // Use task configuration + // The configuration used to lay out the window decoration. The system context's config is + // used when the task density has been overridden to a custom density so that the resources + // and views of the decoration aren't affected and match the rest of the System UI, if not + // then just use the task's configuration. A copy is made instead of using the original + // reference so that the configuration isn't mutated on config changes and diff checks can + // be made in WindowDecoration#relayout using the pre/post-relayout configuration. + // See b/301119301. + // TODO(b/301119301): consider moving the config data needed for diffs to relayout params + // instead of using a whole Configuration as a parameter. + final Configuration windowDecorConfig = new Configuration(); + windowDecorConfig.setTo(DesktopTasksController.isDesktopDensityOverrideSet() + ? mContext.getResources().getConfiguration() // Use system context. + : mTaskInfo.configuration); // Use task configuration. + mRelayoutParams.mWindowDecorConfig = windowDecorConfig; mRelayoutParams.mCornerRadius = (int) ScreenDecorationsUtils.getWindowCornerRadius(mContext); @@ -286,7 +322,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final int displayWidth = displayLayout.width(); final int displayHeight = displayLayout.height(); - final int captionHeight = getCaptionHeight(); + final int captionHeight = getCaptionHeight(mTaskInfo.getWindowingMode()); final ImageButton maximizeWindowButton = mResult.mRootView.findViewById(R.id.maximize_window); @@ -442,6 +478,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin @Override void releaseViews() { closeHandleMenu(); + closeMaximizeMenu(); super.releaseViews(); } @@ -545,7 +582,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin super.close(); } - private int getDesktopModeWindowDecorLayoutId(int windowingMode) { + private int getDesktopModeWindowDecorLayoutId(@WindowingMode int windowingMode) { return windowingMode == WINDOWING_MODE_FREEFORM ? R.layout.desktop_mode_app_controls_window_decor : R.layout.desktop_mode_focused_window_decor; @@ -574,7 +611,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin exclusionRegion = new Region(); } exclusionRegion.union(new Rect(0, 0, mResult.mWidth, - getCaptionHeight())); + getCaptionHeight(mTaskInfo.getWindowingMode()))); exclusionRegion.translate(mPositionInParent.x, mPositionInParent.y); return exclusionRegion; } @@ -590,12 +627,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } @Override - int getCaptionHeightId() { - return R.dimen.freeform_decor_caption_height; + int getCaptionHeightId(@WindowingMode int windowingMode) { + return windowingMode == WINDOWING_MODE_FULLSCREEN + ? R.dimen.desktop_mode_fullscreen_decor_caption_height + : R.dimen.desktop_mode_freeform_decor_caption_height; } - private int getCaptionHeight() { - return loadDimensionPixelSize(mContext.getResources(), getCaptionHeightId()); + private int getCaptionHeight(@WindowingMode int windowingMode) { + return loadDimensionPixelSize(mContext.getResources(), getCaptionHeightId(windowingMode)); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index a26927586b61..3c853f188e3a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import android.app.ActivityManager.RunningTaskInfo; +import android.app.WindowConfiguration.WindowingMode; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -196,7 +197,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> final int oldDensityDpi = mWindowDecorConfig.densityDpi; mWindowDecorConfig = params.mWindowDecorConfig != null ? params.mWindowDecorConfig : mTaskInfo.getConfiguration(); - if (oldDensityDpi != mWindowDecorConfig.densityDpi + final int newDensityDpi = mWindowDecorConfig.densityDpi; + if (oldDensityDpi != newDensityDpi || mDisplay == null || mDisplay.getDisplayId() != mTaskInfo.displayId || oldLayoutResId != mLayoutResId) { @@ -336,7 +338,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } } - int getCaptionHeightId() { + int getCaptionHeightId(@WindowingMode int windowingMode) { return Resources.ID_NULL; } @@ -458,7 +460,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * Adds caption inset source to a WCT */ public void addCaptionInset(WindowContainerTransaction wct) { - final int captionHeightId = getCaptionHeightId(); + final int captionHeightId = getCaptionHeightId(mTaskInfo.getWindowingMode()); if (!ViewRootImpl.CAPTION_ON_SHELL || captionHeightId == Resources.ID_NULL) { return; } diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp index 6fd3354700f7..0058d115ce56 100644 --- a/libs/WindowManager/Shell/tests/flicker/Android.bp +++ b/libs/WindowManager/Shell/tests/flicker/Android.bp @@ -119,6 +119,20 @@ java_library { ], } +java_library { + name: "wm-shell-flicker-platinum-tests", + platform_apis: true, + optimize: { + enabled: false, + }, + srcs: [ + ":WMShellFlickerServicePlatinumTests-src", + ], + static_libs: [ + "wm-shell-flicker-utils", + ], +} + java_defaults { name: "WMShellFlickerTestsDefault", manifest: "manifests/AndroidManifest.xml", diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt index 2bd6d5777ff6..03c438f1be86 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt @@ -23,6 +23,7 @@ import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.common.flicker.subject.region.RegionTraceSubject import android.tools.device.helpers.WindowUtils import android.tools.device.traces.parsers.toFlickerComponent import androidx.test.filters.RequiresDevice @@ -128,9 +129,20 @@ class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) : if (tapl.isTablet) { flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) } } else { - // on phones home does not rotate in landscape, PiP enters back to portrait - // orientation so use display bounds from that orientation for assertion - flicker.assertWmVisibleRegion(pipApp) { coversAtMost(portraitDisplayBounds) } + // on phones home screen does not rotate in landscape, PiP enters back to portrait + // orientation - if we go from landscape to portrait it should switch between the bounds + // otherwise it should be the same as tablet (i.e. portrait to portrait) + if (flicker.scenario.isLandscapeOrSeascapeAtStart) { + flicker.assertWmVisibleRegion(pipApp) { + // first check against landscape bounds then against portrait bounds + (coversAtMost(displayBounds).then() as RegionTraceSubject).coversAtMost( + portraitDisplayBounds + ) + } + } else { + // always check against the display bounds which do not change during transition + flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) } + } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt index aa35237b615f..a8f4d0a24c7e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt @@ -31,7 +31,7 @@ import org.junit.runner.RunWith class DismissSplitScreenByGoHomeGesturalNavLandscape : DismissSplitScreenByGoHome(Rotation.ROTATION_90) { - @ExpectedScenarios(["SPLIT_SCREEN_EXIT"]) + @ExpectedScenarios(["APP_CLOSE_TO_HOME"]) // SPLIT_SCREEN_EXIT not yet tagged here (b/301222449) @Test override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt index e195360cdc36..cee9bbfb4aa4 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt @@ -31,7 +31,7 @@ import org.junit.runner.RunWith class DismissSplitScreenByGoHomeGesturalNavPortrait : DismissSplitScreenByGoHome(Rotation.ROTATION_0) { - @ExpectedScenarios(["SPLIT_SCREEN_EXIT"]) + @ExpectedScenarios(["APP_CLOSE_TO_HOME"]) // SPLIT_SCREEN_EXIT not yet tagged here (b/301222449) @Test override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt index e37d806c7a14..b444bad8322e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt @@ -19,10 +19,15 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit +import org.junit.Rule import org.junit.Test open class CopyContentInSplitGesturalNavLandscape : CopyContentInSplit(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt index 2a50912e0a5c..e2ab989af027 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt @@ -19,10 +19,15 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit +import org.junit.Rule import org.junit.Test open class CopyContentInSplitGesturalNavPortrait : CopyContentInSplit(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt index d5da1a8b558c..22b81028dd1d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider +import org.junit.Rule import org.junit.Test open class DismissSplitScreenByDividerGesturalNavLandscape : DismissSplitScreenByDivider(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt index 7fdcb9be62ee..3fb014f9aac9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider +import org.junit.Rule import org.junit.Test open class DismissSplitScreenByDividerGesturalNavPortrait : DismissSplitScreenByDivider(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt index 308e954b86c1..ea1f9426bb81 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome +import org.junit.Rule import org.junit.Test open class DismissSplitScreenByGoHomeGesturalNavLandscape : DismissSplitScreenByGoHome(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt index 39e75bd25a71..8f23a790081d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome +import org.junit.Rule import org.junit.Test open class DismissSplitScreenByGoHomeGesturalNavPortrait : DismissSplitScreenByGoHome(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt index e18da17175c0..b0f39e592744 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt @@ -19,10 +19,15 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize +import org.junit.Rule import org.junit.Test open class DragDividerToResizeGesturalNavLandscape : DragDividerToResize(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt index 00d60e756ffa..6ce874641c6f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt @@ -19,10 +19,15 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize +import org.junit.Rule import org.junit.Test open class DragDividerToResizeGesturalNavPortrait : DragDividerToResize(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt index d7efbc8c0fd4..9f74edf0a79a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps +import org.junit.Rule import org.junit.Test open class EnterSplitScreenByDragFromAllAppsGesturalNavLandscape : EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt index 4eece3f62d10..1e4055e2a50b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps +import org.junit.Rule import org.junit.Test open class EnterSplitScreenByDragFromAllAppsGesturalNavPortrait : EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt index d96b056d8753..c3b8132f4a50 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification +import org.junit.Rule import org.junit.Test open class EnterSplitScreenByDragFromNotificationGesturalNavLandscape : EnterSplitScreenByDragFromNotification(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt index 809b690e0861..7756d048efbb 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification +import org.junit.Rule import org.junit.Test open class EnterSplitScreenByDragFromNotificationGesturalNavPortrait : EnterSplitScreenByDragFromNotification(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt index bbdf2d728494..c72aa5aaeca6 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut +import org.junit.Rule import org.junit.Test open class EnterSplitScreenByDragFromShortcutGesturalNavLandscape : EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt index 5c29fd8fe57e..cc88f27b9045 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut +import org.junit.Rule import org.junit.Test open class EnterSplitScreenByDragFromShortcutGesturalNavPortrait : EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt index a7398ebf56e8..87b38b133357 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar +import org.junit.Rule import org.junit.Test open class EnterSplitScreenByDragFromTaskbarGesturalNavLandscape : EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt index eae88ad4ad09..ca347ed25f08 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar +import org.junit.Rule import org.junit.Test open class EnterSplitScreenByDragFromTaskbarGesturalNavPortrait : EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt index 7e8ee04a28fa..65978192e8e1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview +import org.junit.Rule import org.junit.Test open class EnterSplitScreenFromOverviewGesturalNavLandscape : EnterSplitScreenFromOverview(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt index 9295c330b879..6df31fc9419b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview +import org.junit.Rule import org.junit.Test open class EnterSplitScreenFromOverviewGesturalNavPortrait : EnterSplitScreenFromOverview(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt index 4b59e9fbd866..02596c5f6202 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider +import org.junit.Rule import org.junit.Test open class SwitchAppByDoubleTapDividerGesturalNavLandscape : SwitchAppByDoubleTapDivider(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt index 5ff36d4aabbb..9d579f60eaaa 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider +import org.junit.Rule import org.junit.Test open class SwitchAppByDoubleTapDividerGesturalNavPortrait : SwitchAppByDoubleTapDivider(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt index c0cb7219437b..da853420a705 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp +import org.junit.Rule import org.junit.Test open class SwitchBackToSplitFromAnotherAppGesturalNavLandscape : SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt index 8c140884aa50..1ae2c9eb8a1a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp +import org.junit.Rule import org.junit.Test open class SwitchBackToSplitFromAnotherAppGesturalNavPortrait : SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt index 7b6614b81c11..b1b562577acc 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome +import org.junit.Rule import org.junit.Test open class SwitchBackToSplitFromHomeGesturalNavLandscape : SwitchBackToSplitFromHome(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt index 5df5be9daa8b..08c437eda71c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome +import org.junit.Rule import org.junit.Test open class SwitchBackToSplitFromHomeGesturalNavPortrait : SwitchBackToSplitFromHome(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt index 9d63003bf2a1..efbf86d028ee 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent +import org.junit.Rule import org.junit.Test open class SwitchBackToSplitFromRecentGesturalNavLandscape : SwitchBackToSplitFromRecent(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt index 9fa04b208ad1..f7072fae2e7d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent +import org.junit.Rule import org.junit.Test open class SwitchBackToSplitFromRecentGesturalNavPortrait : SwitchBackToSplitFromRecent(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt index 9386aa2b2cf0..d80d1120017e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs +import org.junit.Rule import org.junit.Test open class SwitchBetweenSplitPairsGesturalNavLandscape : SwitchBetweenSplitPairs(Rotation.ROTATION_90) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt index 5ef21672bfe0..30ec37a41dde 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt @@ -19,11 +19,16 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs +import org.junit.Rule import org.junit.Test open class SwitchBetweenSplitPairsGesturalNavPortrait : SwitchBetweenSplitPairs(Rotation.ROTATION_0) { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt index 9caab9b5182a..1e086d2f5a9b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt @@ -18,13 +18,18 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.BlockJUnit4ClassRunner @RunWith(BlockJUnit4ClassRunner::class) open class UnlockKeyguardToSplitScreenGesturalNavLandscape : UnlockKeyguardToSplitScreen() { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt index bf484e5cef98..932f89217277 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt @@ -18,13 +18,18 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit +import android.tools.device.flicker.rules.FlickerServiceRule import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.BlockJUnit4ClassRunner @RunWith(BlockJUnit4ClassRunner::class) open class UnlockKeyguardToSplitScreenGesturalNavPortrait : UnlockKeyguardToSplitScreen() { + @get:Rule + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + @PlatinumTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt index c433b211b53d..d7b306c3be23 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt @@ -19,6 +19,7 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation import android.tools.common.NavBar import android.tools.common.Rotation +import android.tools.device.flicker.rules.ChangeDisplayOrientationRule import android.tools.device.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice @@ -49,11 +50,13 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) { fun setup() { Assume.assumeTrue(tapl.isTablet) - tapl.setEnableRotation(true) - tapl.setExpectedRotation(rotation.value) - tapl.goHome() + primaryApp.launchViaIntent(wmHelper) + ChangeDisplayOrientationRule.setRotation(rotation) + + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) } @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt index 3f087a5b7ecd..cc982d1ba860 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt @@ -19,6 +19,7 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation import android.tools.common.NavBar import android.tools.common.Rotation +import android.tools.device.flicker.rules.ChangeDisplayOrientationRule import android.tools.device.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice @@ -50,14 +51,16 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) { fun setup() { Assume.assumeTrue(tapl.isTablet) - tapl.setEnableRotation(true) - tapl.setExpectedRotation(rotation.value) - // Send a notification sendNotificationApp.launchViaIntent(wmHelper) sendNotificationApp.postNotification(wmHelper) tapl.goHome() + + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) + primaryApp.launchViaIntent(wmHelper) + ChangeDisplayOrientationRule.setRotation(rotation) } @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt index 767e7b555618..fa12bb869467 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt @@ -19,6 +19,7 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation import android.tools.common.NavBar import android.tools.common.Rotation +import android.tools.device.flicker.rules.ChangeDisplayOrientationRule import android.tools.device.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice @@ -49,12 +50,13 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) { fun setup() { Assume.assumeTrue(tapl.isTablet) - tapl.setEnableRotation(true) - tapl.setExpectedRotation(rotation.value) - tapl.goHome() SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName) primaryApp.launchViaIntent(wmHelper) + ChangeDisplayOrientationRule.setRotation(rotation) + + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) } @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt index 3a6a4a17811b..983653b9b5ca 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt @@ -46,9 +46,6 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) { @Before fun setup() { - tapl.setEnableRotation(true) - tapl.setExpectedRotation(rotation.value) - primaryApp.launchViaIntent(wmHelper) secondaryApp.launchViaIntent(wmHelper) tapl.goHome() @@ -57,6 +54,9 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) { .withAppTransitionIdle() .withHomeActivityVisible() .waitForAndVerify() + + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) } @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt index 6330d33b4be6..068171d2e129 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt @@ -48,11 +48,11 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) { @Before fun setup() { + tapl.workspace.switchToOverview().dismissAllTasks() + tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) - tapl.workspace.switchToOverview().dismissAllTasks() - SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp, rotation) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt index 6ff8c53cbac8..7065846dc653 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt @@ -46,9 +46,10 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) { @Before fun setup() { + tapl.workspace.switchToOverview().dismissAllTasks() + tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) - tapl.workspace.switchToOverview().dismissAllTasks() SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp, rotation) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt index 87e3860a85f8..d53adc08d2ff 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt @@ -108,6 +108,7 @@ object SplitScreenUtils { ) { primaryApp.launchViaIntent(wmHelper) secondaryApp.launchViaIntent(wmHelper) + ChangeDisplayOrientationRule.setRotation(rotation) tapl.goHome() wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify() splitFromOverview(tapl, device, rotation) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java deleted file mode 100644 index d8afe68bac22..000000000000 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.wm.shell.windowdecor; - -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.ActivityManager; -import android.app.WindowConfiguration; -import android.graphics.Rect; -import android.hardware.display.DisplayManager; -import android.hardware.display.VirtualDisplay; -import android.hardware.input.InputManager; -import android.os.Handler; -import android.os.Looper; -import android.view.Choreographer; -import android.view.Display; -import android.view.InputChannel; -import android.view.InputMonitor; -import android.view.SurfaceControl; -import android.view.SurfaceView; - -import androidx.test.filters.SmallTest; - -import com.android.wm.shell.RootTaskDisplayAreaOrganizer; -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.ShellTestCase; -import com.android.wm.shell.TestRunningTaskInfoBuilder; -import com.android.wm.shell.common.DisplayController; -import com.android.wm.shell.common.DisplayLayout; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.desktopmode.DesktopTasksController; -import com.android.wm.shell.sysui.ShellController; -import com.android.wm.shell.sysui.ShellInit; -import com.android.wm.shell.transition.Transitions; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - -/** Tests of {@link DesktopModeWindowDecorViewModel} */ -@SmallTest -public class DesktopModeWindowDecorViewModelTests extends ShellTestCase { - - private static final String TAG = "DesktopModeWindowDecorViewModelTests"; - private static final Rect STABLE_INSETS = new Rect(0, 100, 0, 0); - - @Mock private DesktopModeWindowDecoration mDesktopModeWindowDecoration; - @Mock private DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory; - - @Mock private Handler mMainHandler; - @Mock private Choreographer mMainChoreographer; - @Mock private ShellTaskOrganizer mTaskOrganizer; - @Mock private DisplayController mDisplayController; - @Mock private DisplayLayout mDisplayLayout; - @Mock private SyncTransactionQueue mSyncQueue; - @Mock private DesktopTasksController mDesktopTasksController; - @Mock private InputMonitor mInputMonitor; - @Mock private InputManager mInputManager; - @Mock private Transitions mTransitions; - @Mock private DesktopModeWindowDecorViewModel.InputMonitorFactory mMockInputMonitorFactory; - @Mock private Supplier<SurfaceControl.Transaction> mTransactionFactory; - @Mock private SurfaceControl.Transaction mTransaction; - @Mock private Display mDisplay; - @Mock private ShellController mShellController; - @Mock private ShellInit mShellInit; - @Mock private DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener - mDesktopModeKeyguardChangeListener; - @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; - private final List<InputManager> mMockInputManagers = new ArrayList<>(); - - private DesktopModeWindowDecorViewModel mDesktopModeWindowDecorViewModel; - - @Before - public void setUp() { - mMockInputManagers.add(mInputManager); - - mDesktopModeWindowDecorViewModel = - new DesktopModeWindowDecorViewModel( - mContext, - mMainHandler, - mMainChoreographer, - mShellInit, - mTaskOrganizer, - mDisplayController, - mShellController, - mSyncQueue, - mTransitions, - Optional.of(mDesktopTasksController), - mDesktopModeWindowDecorFactory, - mMockInputMonitorFactory, - mTransactionFactory, - mDesktopModeKeyguardChangeListener, - mRootTaskDisplayAreaOrganizer - ); - - doReturn(mDesktopModeWindowDecoration) - .when(mDesktopModeWindowDecorFactory) - .create(any(), any(), any(), any(), any(), any(), any(), any(), any()); - doReturn(mTransaction).when(mTransactionFactory).get(); - doReturn(mDisplayLayout).when(mDisplayController).getDisplayLayout(anyInt()); - doReturn(STABLE_INSETS).when(mDisplayLayout).stableInsets(); - doNothing().when(mShellController).addKeyguardChangeListener(any()); - - when(mMockInputMonitorFactory.create(any(), any())).thenReturn(mInputMonitor); - // InputChannel cannot be mocked because it passes to InputEventReceiver. - final InputChannel[] inputChannels = InputChannel.openInputChannelPair(TAG); - inputChannels[0].dispose(); - when(mInputMonitor.getInputChannel()).thenReturn(inputChannels[1]); - - mDesktopModeWindowDecoration.mDisplay = mDisplay; - doReturn(Display.DEFAULT_DISPLAY).when(mDisplay).getDisplayId(); - } - - @Test - public void testDeleteCaptionOnChangeTransitionWhenNecessary() throws Exception { - final int taskId = 1; - final ActivityManager.RunningTaskInfo taskInfo = - createTaskInfo(taskId, Display.DEFAULT_DISPLAY, WINDOWING_MODE_FREEFORM); - SurfaceControl surfaceControl = mock(SurfaceControl.class); - runOnMainThread(() -> { - final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); - final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); - - mDesktopModeWindowDecorViewModel.onTaskOpening( - taskInfo, surfaceControl, startT, finishT); - - taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED); - taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); - mDesktopModeWindowDecorViewModel.onTaskChanging( - taskInfo, surfaceControl, startT, finishT); - }); - verify(mDesktopModeWindowDecorFactory) - .create( - mContext, - mDisplayController, - mTaskOrganizer, - taskInfo, - surfaceControl, - mMainHandler, - mMainChoreographer, - mSyncQueue, - mRootTaskDisplayAreaOrganizer); - verify(mDesktopModeWindowDecoration).close(); - } - - @Test - public void testCreateCaptionOnChangeTransitionWhenNecessary() throws Exception { - final int taskId = 1; - final ActivityManager.RunningTaskInfo taskInfo = - createTaskInfo(taskId, Display.DEFAULT_DISPLAY, WINDOWING_MODE_UNDEFINED); - SurfaceControl surfaceControl = mock(SurfaceControl.class); - runOnMainThread(() -> { - final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); - final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); - taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); - - mDesktopModeWindowDecorViewModel.onTaskChanging( - taskInfo, surfaceControl, startT, finishT); - - taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); - taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD); - - mDesktopModeWindowDecorViewModel.onTaskChanging( - taskInfo, surfaceControl, startT, finishT); - }); - verify(mDesktopModeWindowDecorFactory, times(1)) - .create( - mContext, - mDisplayController, - mTaskOrganizer, - taskInfo, - surfaceControl, - mMainHandler, - mMainChoreographer, - mSyncQueue, - mRootTaskDisplayAreaOrganizer); - } - - @Test - public void testCreateAndDisposeEventReceiver() throws Exception { - final int taskId = 1; - final ActivityManager.RunningTaskInfo taskInfo = - createTaskInfo(taskId, Display.DEFAULT_DISPLAY, WINDOWING_MODE_FREEFORM); - taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD); - runOnMainThread(() -> { - SurfaceControl surfaceControl = mock(SurfaceControl.class); - final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); - final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); - - mDesktopModeWindowDecorViewModel.onTaskOpening( - taskInfo, surfaceControl, startT, finishT); - - mDesktopModeWindowDecorViewModel.destroyWindowDecoration(taskInfo); - }); - verify(mMockInputMonitorFactory).create(any(), any()); - verify(mInputMonitor).dispose(); - } - - @Test - public void testEventReceiversOnMultipleDisplays() throws Exception { - runOnMainThread(() -> { - SurfaceView surfaceView = new SurfaceView(mContext); - final DisplayManager mDm = mContext.getSystemService(DisplayManager.class); - final VirtualDisplay secondaryDisplay = mDm.createVirtualDisplay( - "testEventReceiversOnMultipleDisplays", /*width=*/ 400, /*height=*/ 400, - /*densityDpi=*/ 320, surfaceView.getHolder().getSurface(), - DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); - try { - int secondaryDisplayId = secondaryDisplay.getDisplay().getDisplayId(); - - final int taskId = 1; - final ActivityManager.RunningTaskInfo taskInfo = - createTaskInfo(taskId, Display.DEFAULT_DISPLAY, WINDOWING_MODE_FREEFORM); - final ActivityManager.RunningTaskInfo secondTaskInfo = - createTaskInfo(taskId + 1, secondaryDisplayId, WINDOWING_MODE_FREEFORM); - final ActivityManager.RunningTaskInfo thirdTaskInfo = - createTaskInfo(taskId + 2, secondaryDisplayId, WINDOWING_MODE_FREEFORM); - - SurfaceControl surfaceControl = mock(SurfaceControl.class); - final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); - final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); - - mDesktopModeWindowDecorViewModel.onTaskOpening(taskInfo, surfaceControl, startT, - finishT); - mDesktopModeWindowDecorViewModel.onTaskOpening(secondTaskInfo, surfaceControl, - startT, finishT); - mDesktopModeWindowDecorViewModel.onTaskOpening(thirdTaskInfo, surfaceControl, - startT, finishT); - mDesktopModeWindowDecorViewModel.destroyWindowDecoration(thirdTaskInfo); - mDesktopModeWindowDecorViewModel.destroyWindowDecoration(taskInfo); - } finally { - secondaryDisplay.release(); - } - }); - verify(mMockInputMonitorFactory, times(2)).create(any(), any()); - verify(mInputMonitor, times(1)).dispose(); - } - - @Test - public void testCaptionIsNotCreatedWhenKeyguardIsVisible() throws Exception { - doReturn(true).when( - mDesktopModeKeyguardChangeListener).isKeyguardVisibleAndOccluded(); - - final int taskId = 1; - final ActivityManager.RunningTaskInfo taskInfo = - createTaskInfo(taskId, Display.DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN); - taskInfo.isFocused = true; - SurfaceControl surfaceControl = mock(SurfaceControl.class); - runOnMainThread(() -> { - final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); - final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); - - mDesktopModeWindowDecorViewModel.onTaskOpening( - taskInfo, surfaceControl, startT, finishT); - - taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED); - taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); - mDesktopModeWindowDecorViewModel.onTaskChanging( - taskInfo, surfaceControl, startT, finishT); - }); - verify(mDesktopModeWindowDecorFactory, never()) - .create(any(), any(), any(), any(), any(), any(), any(), any(), any()); - } - - private void runOnMainThread(Runnable r) throws Exception { - final Handler mainHandler = new Handler(Looper.getMainLooper()); - final CountDownLatch latch = new CountDownLatch(1); - mainHandler.post(() -> { - r.run(); - latch.countDown(); - }); - latch.await(1, TimeUnit.SECONDS); - } - - private static ActivityManager.RunningTaskInfo createTaskInfo(int taskId, - int displayId, @WindowConfiguration.WindowingMode int windowingMode) { - ActivityManager.RunningTaskInfo taskInfo = - new TestRunningTaskInfoBuilder() - .setDisplayId(displayId) - .setVisible(true) - .build(); - taskInfo.taskId = taskId; - taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode); - return taskInfo; - } -} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt new file mode 100644 index 000000000000..00d70a75837b --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.windowdecor + +import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration +import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD +import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED +import android.graphics.Rect +import android.hardware.display.DisplayManager +import android.hardware.display.VirtualDisplay +import android.os.Handler +import android.os.IBinder +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.view.Choreographer +import android.view.Display.DEFAULT_DISPLAY +import android.view.InputChannel +import android.view.InputMonitor +import android.view.SurfaceControl +import android.view.SurfaceView +import androidx.core.content.getSystemService +import androidx.test.filters.SmallTest +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestRunningTaskInfoBuilder +import com.android.wm.shell.common.DisplayController +import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.common.SyncTransactionQueue +import com.android.wm.shell.desktopmode.DesktopTasksController +import com.android.wm.shell.recents.RecentsTransitionHandler +import com.android.wm.shell.recents.RecentsTransitionStateListener +import com.android.wm.shell.sysui.KeyguardChangeListener +import com.android.wm.shell.sysui.ShellController +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.transition.Transitions +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq +import org.mockito.kotlin.whenever +import java.util.Optional +import java.util.function.Supplier + +/** Tests of [DesktopModeWindowDecorViewModel] */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class DesktopModeWindowDecorViewModelTests : ShellTestCase() { + @Mock private lateinit var mockDesktopModeWindowDecorFactory: + DesktopModeWindowDecoration.Factory + @Mock private lateinit var mockMainHandler: Handler + @Mock private lateinit var mockMainChoreographer: Choreographer + @Mock private lateinit var mockTaskOrganizer: ShellTaskOrganizer + @Mock private lateinit var mockDisplayController: DisplayController + @Mock private lateinit var mockDisplayLayout: DisplayLayout + @Mock private lateinit var mockSyncQueue: SyncTransactionQueue + @Mock private lateinit var mockDesktopTasksController: DesktopTasksController + @Mock private lateinit var mockInputMonitor: InputMonitor + @Mock private lateinit var mockTransitions: Transitions + @Mock private lateinit var mockInputMonitorFactory: + DesktopModeWindowDecorViewModel.InputMonitorFactory + @Mock private lateinit var mockShellController: ShellController + @Mock private lateinit var mockShellExecutor: ShellExecutor + @Mock private lateinit var mockRootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer + @Mock private lateinit var mockRecentsTransitionHandler: RecentsTransitionHandler + + private val transactionFactory = Supplier<SurfaceControl.Transaction> { + SurfaceControl.Transaction() + } + + private lateinit var shellInit: ShellInit + private lateinit var desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel + + @Before + fun setUp() { + shellInit = ShellInit(mockShellExecutor) + desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel( + mContext, + mockMainHandler, + mockMainChoreographer, + shellInit, + mockTaskOrganizer, + mockDisplayController, + mockShellController, + mockSyncQueue, + mockTransitions, + Optional.of(mockDesktopTasksController), + mockRecentsTransitionHandler, + mockDesktopModeWindowDecorFactory, + mockInputMonitorFactory, + transactionFactory, + mockRootTaskDisplayAreaOrganizer + ) + + whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout) + whenever(mockDisplayLayout.stableInsets()).thenReturn(STABLE_INSETS) + whenever(mockInputMonitorFactory.create(any(), any())).thenReturn(mockInputMonitor) + + // InputChannel cannot be mocked because it passes to InputEventReceiver. + val inputChannels = InputChannel.openInputChannelPair(TAG) + inputChannels.first().dispose() + whenever(mockInputMonitor.inputChannel).thenReturn(inputChannels[1]) + + shellInit.init() + } + + @Test + fun testDeleteCaptionOnChangeTransitionWhenNecessary() { + val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM) + val taskSurface = SurfaceControl() + val decoration = setUpMockDecorationForTask(task) + + onTaskOpening(task, taskSurface) + + task.setWindowingMode(WINDOWING_MODE_UNDEFINED) + task.setActivityType(ACTIVITY_TYPE_UNDEFINED) + onTaskChanging(task, taskSurface) + + verify(mockDesktopModeWindowDecorFactory).create( + mContext, + mockDisplayController, + mockTaskOrganizer, + task, + taskSurface, + mockMainHandler, + mockMainChoreographer, + mockSyncQueue, + mockRootTaskDisplayAreaOrganizer + ) + verify(decoration).close() + } + + @Test + fun testCreateCaptionOnChangeTransitionWhenNecessary() { + val task = createTask( + windowingMode = WINDOWING_MODE_UNDEFINED, + activityType = ACTIVITY_TYPE_UNDEFINED + ) + val taskSurface = SurfaceControl() + setUpMockDecorationForTask(task) + + onTaskChanging(task, taskSurface) + verify(mockDesktopModeWindowDecorFactory, never()).create( + mContext, + mockDisplayController, + mockTaskOrganizer, + task, + taskSurface, + mockMainHandler, + mockMainChoreographer, + mockSyncQueue, + mockRootTaskDisplayAreaOrganizer + ) + + task.setWindowingMode(WINDOWING_MODE_FREEFORM) + task.setActivityType(ACTIVITY_TYPE_STANDARD) + onTaskChanging(task, taskSurface) + verify(mockDesktopModeWindowDecorFactory, times(1)).create( + mContext, + mockDisplayController, + mockTaskOrganizer, + task, + taskSurface, + mockMainHandler, + mockMainChoreographer, + mockSyncQueue, + mockRootTaskDisplayAreaOrganizer + ) + } + + @Test + fun testCreateAndDisposeEventReceiver() { + val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM) + setUpMockDecorationForTask(task) + + onTaskOpening(task) + desktopModeWindowDecorViewModel.destroyWindowDecoration(task) + + verify(mockInputMonitorFactory).create(any(), any()) + verify(mockInputMonitor).dispose() + } + + @Test + fun testEventReceiversOnMultipleDisplays() { + val secondaryDisplay = createVirtualDisplay() ?: return + val secondaryDisplayId = secondaryDisplay.display.displayId + val task = createTask(displayId = DEFAULT_DISPLAY, windowingMode = WINDOWING_MODE_FREEFORM) + val secondTask = createTask( + displayId = secondaryDisplayId, + windowingMode = WINDOWING_MODE_FREEFORM + ) + val thirdTask = createTask( + displayId = secondaryDisplayId, + windowingMode = WINDOWING_MODE_FREEFORM + ) + setUpMockDecorationsForTasks(task, secondTask, thirdTask) + + onTaskOpening(task) + onTaskOpening(secondTask) + onTaskOpening(thirdTask) + desktopModeWindowDecorViewModel.destroyWindowDecoration(thirdTask) + desktopModeWindowDecorViewModel.destroyWindowDecoration(task) + secondaryDisplay.release() + + verify(mockInputMonitorFactory, times(2)).create(any(), any()) + verify(mockInputMonitor, times(1)).dispose() + } + + @Test + fun testCaptionIsNotCreatedWhenKeyguardIsVisible() { + val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true) + val keyguardListenerCaptor = argumentCaptor<KeyguardChangeListener>() + verify(mockShellController).addKeyguardChangeListener(keyguardListenerCaptor.capture()) + + keyguardListenerCaptor.firstValue.onKeyguardVisibilityChanged( + true /* visible */, + true /* occluded */, + false /* animatingDismiss */ + ) + onTaskOpening(task) + + task.setWindowingMode(WINDOWING_MODE_UNDEFINED) + task.setWindowingMode(ACTIVITY_TYPE_UNDEFINED) + onTaskChanging(task) + + verify(mockDesktopModeWindowDecorFactory, never()) + .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) + } + + @Test + fun testRelayoutBlockedDuringRecentsTransition() { + val recentsCaptor = argumentCaptor<RecentsTransitionStateListener>() + verify(mockRecentsTransitionHandler).addTransitionStateListener(recentsCaptor.capture()) + + val transition = mock(IBinder::class.java) + val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM) + val decoration = setUpMockDecorationForTask(task) + + // Make sure a window decorations exists first by launching a freeform task. + onTaskOpening(task) + // Now call back when a Recents transition starts. + recentsCaptor.firstValue.onTransitionStarted(transition) + + verify(decoration).incrementRelayoutBlock() + verify(decoration).addTransitionPausingRelayout(transition) + } + + private fun onTaskOpening(task: RunningTaskInfo, leash: SurfaceControl = SurfaceControl()) { + desktopModeWindowDecorViewModel.onTaskOpening( + task, + leash, + SurfaceControl.Transaction(), + SurfaceControl.Transaction() + ) + } + + private fun onTaskChanging(task: RunningTaskInfo, leash: SurfaceControl = SurfaceControl()) { + desktopModeWindowDecorViewModel.onTaskChanging( + task, + leash, + SurfaceControl.Transaction(), + SurfaceControl.Transaction() + ) + } + + private fun createTask( + displayId: Int = DEFAULT_DISPLAY, + @WindowConfiguration.WindowingMode windowingMode: Int, + activityType: Int = ACTIVITY_TYPE_STANDARD, + focused: Boolean = true + ): RunningTaskInfo { + return TestRunningTaskInfoBuilder() + .setDisplayId(displayId) + .setWindowingMode(windowingMode) + .setVisible(true) + .setActivityType(activityType) + .build().apply { + isFocused = focused + } + } + + private fun setUpMockDecorationForTask(task: RunningTaskInfo): DesktopModeWindowDecoration { + val decoration = mock(DesktopModeWindowDecoration::class.java) + whenever(mockDesktopModeWindowDecorFactory.create( + any(), any(), any(), eq(task), any(), any(), any(), any(), any()) + ).thenReturn(decoration) + return decoration + } + + private fun setUpMockDecorationsForTasks(vararg tasks: RunningTaskInfo) { + tasks.forEach { setUpMockDecorationForTask(it) } + } + + private fun createVirtualDisplay(): VirtualDisplay? { + val surfaceView = SurfaceView(mContext) + return mContext.getSystemService<DisplayManager>()?.createVirtualDisplay( + "testEventReceiversOnMultipleDisplays", + /*width=*/ 400, + /*height=*/ 400, + /*densityDpi=*/320, + surfaceView.holder.surface, + DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY + ) + } + + private fun RunningTaskInfo.setWindowingMode(@WindowConfiguration.WindowingMode mode: Int) { + configuration.windowConfiguration.windowingMode = mode + } + + private fun RunningTaskInfo.setActivityType(type: Int) { + configuration.windowConfiguration.activityType = type + } + + companion object { + private const val TAG = "DesktopModeWindowDecorViewModelTests" + private val STABLE_INSETS = Rect(0, 100, 0, 0) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java new file mode 100644 index 000000000000..a2dbab197fb5 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -0,0 +1,132 @@ +/* + * 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.wm.shell.windowdecor; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.res.Configuration; +import android.os.Handler; +import android.testing.AndroidTestingRunner; +import android.view.Choreographer; +import android.view.Display; +import android.view.SurfaceControl; +import android.view.SurfaceControlViewHost; +import android.window.WindowContainerTransaction; + +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.TestRunningTaskInfoBuilder; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.SyncTransactionQueue; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import java.util.function.Supplier; + +/** + * Tests for {@link DesktopModeWindowDecoration}. + * + * Build/Install/Run: + * atest WMShellUnitTests:DesktopModeWindowDecorationTests + */ +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class DesktopModeWindowDecorationTests extends ShellTestCase { + @Mock + private DisplayController mMockDisplayController; + @Mock + private ShellTaskOrganizer mMockShellTaskOrganizer; + @Mock + private Handler mMockHandler; + @Mock + private Choreographer mMockChoreographer; + @Mock + private SyncTransactionQueue mMockSyncQueue; + @Mock + private RootTaskDisplayAreaOrganizer mMockRootTaskDisplayAreaOrganizer; + @Mock + private Supplier<SurfaceControl.Transaction> mMockTransactionSupplier; + @Mock + private SurfaceControl.Transaction mMockTransaction; + @Mock + private SurfaceControl mMockSurfaceControl; + @Mock + private SurfaceControlViewHost mMockSurfaceControlViewHost; + @Mock + private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory; + + private final Configuration mConfiguration = new Configuration(); + + @Before + public void setUp() { + doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory).create( + any(), any(), any()); + doReturn(mMockTransaction).when(mMockTransactionSupplier).get(); + } + + @Test + public void testMenusClosedWhenTaskIsInvisible() { + doReturn(mMockTransaction).when(mMockTransaction).hide(any()); + + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(false /* visible */); + final DesktopModeWindowDecoration spyWindowDecor = + spy(createWindowDecoration(taskInfo)); + + spyWindowDecor.relayout(taskInfo); + + // Menus should close if open before the task being invisible causes relayout to return. + verify(spyWindowDecor).closeHandleMenu(); + verify(spyWindowDecor).closeMaximizeMenu(); + + } + + private DesktopModeWindowDecoration createWindowDecoration( + ActivityManager.RunningTaskInfo taskInfo) { + return new DesktopModeWindowDecoration(mContext, mMockDisplayController, + mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl, mConfiguration, + mMockHandler, mMockChoreographer, mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer, + SurfaceControl.Builder::new, mMockTransactionSupplier, + WindowContainerTransaction::new, mMockSurfaceControlViewHostFactory); + } + + private ActivityManager.RunningTaskInfo createTaskInfo(boolean visible) { + final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = + new ActivityManager.TaskDescription.Builder(); + ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setVisible(visible) + .build(); + taskInfo.realActivity = new ComponentName("com.android.wm.shell.windowdecor", + "DesktopModeWindowDecorationTests"); + taskInfo.baseActivity = new ComponentName("com.android.wm.shell.windowdecor", + "DesktopModeWindowDecorationTests"); + return taskInfo; + + } +} diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 735fc074435d..30d461271c89 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -169,7 +169,8 @@ void CacheManager::trimStaleResources() { return; } mGrContext->flushAndSubmit(); - mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30)); + mGrContext->performDeferredCleanup(std::chrono::seconds(30), + GrPurgeResourceOptions::kAllResources); } void CacheManager::getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage) { diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java index 3b7089030255..f9eaabd800b1 100644 --- a/media/java/android/media/tv/tuner/Lnb.java +++ b/media/java/android/media/tv/tuner/Lnb.java @@ -25,6 +25,8 @@ import android.hardware.tv.tuner.LnbPosition; import android.hardware.tv.tuner.LnbTone; import android.hardware.tv.tuner.LnbVoltage; import android.media.tv.tuner.Tuner.Result; +import android.media.tv.tunerresourcemanager.TunerResourceManager; +import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -147,10 +149,13 @@ public class Lnb implements AutoCloseable { public static final int EVENT_TYPE_LNB_OVERLOAD = LnbEventType.LNB_OVERLOAD; private static final String TAG = "Lnb"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); Map<LnbCallback, Executor> mCallbackMap = new HashMap<LnbCallback, Executor>(); Tuner mOwner; + TunerResourceManager mTunerResourceManager; + int mClientId; private final Object mCallbackLock = new Object(); @@ -174,6 +179,10 @@ public class Lnb implements AutoCloseable { } } setOwner(tuner); + if (mOwner != null) { + mTunerResourceManager = mOwner.getTunerResourceManager(); + mClientId = mOwner.getClientId(); + } } /** @@ -210,6 +219,8 @@ public class Lnb implements AutoCloseable { Objects.requireNonNull(newOwner, "newOwner must not be null"); synchronized (mLock) { mOwner = newOwner; + mTunerResourceManager = newOwner.getTunerResourceManager(); + mClientId = newOwner.getClientId(); } } @@ -317,21 +328,42 @@ public class Lnb implements AutoCloseable { * Releases the LNB instance. */ public void close() { - synchronized (mLock) { - if (mIsClosed) { - return; - } - int res = nativeClose(); - if (res != Tuner.RESULT_SUCCESS) { - TunerUtils.throwExceptionForResult(res, "Failed to close LNB"); - } else { - mIsClosed = true; - if (mOwner != null) { - mOwner.releaseLnb(); - mOwner = null; + acquireTRMSLock("close()"); + try { + synchronized (mLock) { + if (mIsClosed) { + return; + } + int res = nativeClose(); + if (res != Tuner.RESULT_SUCCESS) { + TunerUtils.throwExceptionForResult(res, "Failed to close LNB"); + } else { + mIsClosed = true; + if (mOwner != null) { + mOwner.releaseLnb(); + mOwner = null; + } + mCallbackMap.clear(); } - mCallbackMap.clear(); } + } finally { + releaseTRMSLock(); + } + } + + private void acquireTRMSLock(String functionNameForLog) { + if (DEBUG) { + Log.d(TAG, "ATTEMPT:acquireLock() in " + functionNameForLog + + "for clientId:" + mClientId); + } + if (!mTunerResourceManager.acquireLock(mClientId)) { + Log.e(TAG, "FAILED:acquireLock() in " + functionNameForLog + + " for clientId:" + mClientId + " - this can cause deadlock between" + + " Tuner API calls and onReclaimResources()"); } } + + private void releaseTRMSLock() { + mTunerResourceManager.releaseLock(mClientId); + } } diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index f87e47e0e4df..9924fae26194 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -903,6 +903,9 @@ public class Tuner implements AutoCloseable { } } + /** + * Releases Lnb resource if held. TRMS lock must be acquired prior to calling this function. + */ private void closeLnb() { mLnbLock.lock(); try { @@ -2806,6 +2809,10 @@ public class Tuner implements AutoCloseable { return mClientId; } + /* package */ TunerResourceManager getTunerResourceManager() { + return mTunerResourceManager; + } + private void acquireTRMSLock(String functionNameForLog) { if (DEBUG) { Log.d(TAG, "ATTEMPT:acquireLock() in " + functionNameForLog diff --git a/packages/CredentialManager/Android.bp b/packages/CredentialManager/Android.bp index 233aee29f155..fe26dc3d7feb 100644 --- a/packages/CredentialManager/Android.bp +++ b/packages/CredentialManager/Android.bp @@ -50,46 +50,3 @@ android_app { proguard_compatibility: false, }, } - -android_app { - name: "ClockworkCredentialManager", - defaults: ["platform_app_defaults"], - certificate: "platform", - manifest: "wear/AndroidManifest.xml", - srcs: ["wear/src/**/*.kt"], - resource_dirs: ["wear/res"], - - dex_preopt: { - profile_guided: true, - profile: "wear/profile.txt.prof", - }, - - static_libs: [ - "PlatformComposeCore", - "androidx.activity_activity-compose", - "androidx.appcompat_appcompat", - "androidx.compose.foundation_foundation", - "androidx.compose.foundation_foundation-layout", - "androidx.compose.material_material-icons-core", - "androidx.compose.material_material-icons-extended", - "androidx.compose.ui_ui", - "androidx.core_core-ktx", - "androidx.credentials_credentials", - "androidx.lifecycle_lifecycle-extensions", - "androidx.lifecycle_lifecycle-livedata", - "androidx.lifecycle_lifecycle-runtime-ktx", - "androidx.lifecycle_lifecycle-viewmodel-compose", - "androidx.wear.compose_compose-foundation", - "androidx.wear.compose_compose-material", - "kotlinx-coroutines-core", - ], - - platform_apis: true, - privileged: true, - - kotlincflags: ["-Xjvm-default=all"], - - optimize: { - proguard_compatibility: false, - }, -} diff --git a/packages/CredentialManager/AndroidManifest.xml b/packages/CredentialManager/AndroidManifest.xml index d9ef3a2151ce..a5ccdb6575bb 100644 --- a/packages/CredentialManager/AndroidManifest.xml +++ b/packages/CredentialManager/AndroidManifest.xml @@ -22,6 +22,7 @@ <uses-permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/> + <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" /> <application android:allowBackup="true" diff --git a/packages/CredentialManager/horologist/Android.bp b/packages/CredentialManager/horologist/Android.bp new file mode 100644 index 000000000000..bb324bb8350d --- /dev/null +++ b/packages/CredentialManager/horologist/Android.bp @@ -0,0 +1,27 @@ +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"], +} + +// TODO: ag/24733147 - Remove this project once it is imported. +android_library { + name: "Horologist", + manifest: "AndroidManifest.xml", + srcs: ["src/**/*.kt"], + static_libs: [ + "androidx.compose.foundation_foundation", + "androidx.compose.runtime_runtime", + "androidx.compose.ui_ui", + "androidx.navigation_navigation-compose", + "androidx.lifecycle_lifecycle-extensions", + "androidx.lifecycle_lifecycle-runtime-ktx", + "androidx.lifecycle_lifecycle-viewmodel-compose", + "androidx.wear.compose_compose-foundation", + "androidx.wear.compose_compose-material", + "androidx.wear.compose_compose-navigation", + ], +} diff --git a/packages/CredentialManager/horologist/AndroidManifest.xml b/packages/CredentialManager/horologist/AndroidManifest.xml new file mode 100644 index 000000000000..e386ce2aaddf --- /dev/null +++ b/packages/CredentialManager/horologist/AndroidManifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * Copyright (c) 2023 Google Inc. + * + * 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. + */ +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.horologist"> + + <uses-feature android:name="android.hardware.type.watch" /> + +</manifest> diff --git a/packages/CredentialManager/horologist/src/com/google/android/horologist/annotations/ExperimentalHorologistApi.kt b/packages/CredentialManager/horologist/src/com/google/android/horologist/annotations/ExperimentalHorologistApi.kt new file mode 100644 index 000000000000..ae776056ea4c --- /dev/null +++ b/packages/CredentialManager/horologist/src/com/google/android/horologist/annotations/ExperimentalHorologistApi.kt @@ -0,0 +1,23 @@ +/* + * 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 + * + * https://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.horologist.annotations + +@RequiresOptIn( + message = "Horologist API is experimental. The API may be changed in the future.", +) +@Retention(AnnotationRetention.BINARY) +public annotation class ExperimentalHorologistApi diff --git a/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/layout/ScalingLazyColumnDefaults.kt b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/layout/ScalingLazyColumnDefaults.kt new file mode 100644 index 000000000000..c88bbd8dea8b --- /dev/null +++ b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/layout/ScalingLazyColumnDefaults.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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. + */ + +@file:Suppress("ObjectLiteralToLambda") + +package com.google.android.horologist.compose.layout + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.wear.compose.foundation.lazy.AutoCenteringParams +import androidx.wear.compose.foundation.lazy.ScalingLazyListAnchorType +import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.compose.layout.ScalingLazyColumnState.RotaryMode + +/** + * Default layouts for ScalingLazyColumnState, based on UX guidance. + */ +public object ScalingLazyColumnDefaults { + /** + * Layout the first item, directly under the time text. + * This is positioned from the top of the screen instead of the + * center. + */ + @ExperimentalHorologistApi + public fun belowTimeText( + rotaryMode: RotaryMode = RotaryMode.Scroll, + firstItemIsFullWidth: Boolean = false, + verticalArrangement: Arrangement.Vertical = + Arrangement.spacedBy( + space = 4.dp, + alignment = Alignment.Top, + ), + horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, + contentPadding: PaddingValues = PaddingValues(horizontal = 10.dp), + topPaddingDp: Dp = 32.dp + (if (firstItemIsFullWidth) 20.dp else 0.dp), + ): ScalingLazyColumnState.Factory { + return object : ScalingLazyColumnState.Factory { + @Composable + override fun create(): ScalingLazyColumnState { + val density = LocalDensity.current + val configuration = LocalConfiguration.current + + return remember { + val screenHeightPx = + with(density) { configuration.screenHeightDp.dp.roundToPx() } + val topPaddingPx = with(density) { topPaddingDp.roundToPx() } + val topScreenOffsetPx = screenHeightPx / 2 - topPaddingPx + + ScalingLazyColumnState( + initialScrollPosition = ScalingLazyColumnState.ScrollPosition( + index = 0, + offsetPx = topScreenOffsetPx, + ), + anchorType = ScalingLazyListAnchorType.ItemStart, + rotaryMode = rotaryMode, + verticalArrangement = verticalArrangement, + horizontalAlignment = horizontalAlignment, + contentPadding = contentPadding, + ) + } + } + } + } + + /** + * Layout the item [initialCenterIndex] at [initialCenterOffset] from the + * center of the screen. + */ + @ExperimentalHorologistApi + public fun scalingLazyColumnDefaults( + rotaryMode: RotaryMode = RotaryMode.Scroll, + initialCenterIndex: Int = 1, + initialCenterOffset: Int = 0, + verticalArrangement: Arrangement.Vertical = + Arrangement.spacedBy( + space = 4.dp, + alignment = Alignment.Top, + ), + horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, + contentPadding: PaddingValues = PaddingValues(horizontal = 10.dp), + autoCentering: AutoCenteringParams? = AutoCenteringParams( + initialCenterIndex, + initialCenterOffset, + ), + anchorType: ScalingLazyListAnchorType = ScalingLazyListAnchorType.ItemCenter, + hapticsEnabled: Boolean = true, + reverseLayout: Boolean = false, + ): ScalingLazyColumnState.Factory { + return object : ScalingLazyColumnState.Factory { + @Composable + override fun create(): ScalingLazyColumnState { + return remember { + ScalingLazyColumnState( + initialScrollPosition = ScalingLazyColumnState.ScrollPosition( + index = initialCenterIndex, + offsetPx = initialCenterOffset, + ), + rotaryMode = rotaryMode, + verticalArrangement = verticalArrangement, + horizontalAlignment = horizontalAlignment, + contentPadding = contentPadding, + autoCentering = autoCentering, + anchorType = anchorType, + hapticsEnabled = hapticsEnabled, + reverseLayout = reverseLayout, + ) + } + } + } + } +} diff --git a/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/layout/ScalingLazyColumnState.kt b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/layout/ScalingLazyColumnState.kt new file mode 100644 index 000000000000..3a12b9f9945f --- /dev/null +++ b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/layout/ScalingLazyColumnState.kt @@ -0,0 +1,168 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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. + */ + +@file:Suppress("ObjectLiteralToLambda") +@file:OptIn(ExperimentalHorologistApi::class, ExperimentalWearFoundationApi::class) + +package com.google.android.horologist.compose.layout + +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.ScrollableDefaults +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.wear.compose.foundation.ExperimentalWearFoundationApi +import androidx.wear.compose.foundation.lazy.AutoCenteringParams +import androidx.wear.compose.foundation.lazy.ScalingLazyColumn +import androidx.wear.compose.foundation.lazy.ScalingLazyListAnchorType +import androidx.wear.compose.foundation.lazy.ScalingLazyListScope +import androidx.wear.compose.foundation.lazy.ScalingLazyListState +import androidx.wear.compose.foundation.lazy.ScalingParams +import androidx.wear.compose.foundation.rememberActiveFocusRequester +import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.compose.layout.ScalingLazyColumnState.RotaryMode +import com.google.android.horologist.compose.rotaryinput.rememberDisabledHaptic +import com.google.android.horologist.compose.rotaryinput.rememberRotaryHapticHandler +import com.google.android.horologist.compose.rotaryinput.rotaryWithScroll +import com.google.android.horologist.compose.rotaryinput.rotaryWithSnap +import com.google.android.horologist.compose.rotaryinput.toRotaryScrollAdapter +import androidx.wear.compose.foundation.lazy.ScalingLazyColumnDefaults as WearScalingLazyColumnDefaults + +/** + * A Config and State object wrapping up all configuration for a [ScalingLazyColumn]. + * This allows defaults such as [ScalingLazyColumnDefaults.belowTimeText]. + */ +@ExperimentalHorologistApi +public class ScalingLazyColumnState( + public val initialScrollPosition: ScrollPosition = ScrollPosition(1, 0), + public val autoCentering: AutoCenteringParams? = AutoCenteringParams( + initialScrollPosition.index, + initialScrollPosition.offsetPx, + ), + public val anchorType: ScalingLazyListAnchorType = ScalingLazyListAnchorType.ItemCenter, + public val contentPadding: PaddingValues = PaddingValues(horizontal = 10.dp), + public val rotaryMode: RotaryMode = RotaryMode.Scroll, + public val reverseLayout: Boolean = false, + public val verticalArrangement: Arrangement.Vertical = + Arrangement.spacedBy( + space = 4.dp, + alignment = if (!reverseLayout) Alignment.Top else Alignment.Bottom, + ), + public val horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, + public val flingBehavior: FlingBehavior? = null, + public val userScrollEnabled: Boolean = true, + public val scalingParams: ScalingParams = WearScalingLazyColumnDefaults.scalingParams(), + public val hapticsEnabled: Boolean = true, +) { + private var _state: ScalingLazyListState? = null + public var state: ScalingLazyListState + get() { + if (_state == null) { + _state = ScalingLazyListState( + initialScrollPosition.index, + initialScrollPosition.offsetPx, + ) + } + return _state!! + } + set(value) { + _state = value + } + + public sealed interface RotaryMode { + public object Snap : RotaryMode + public object Scroll : RotaryMode + + @Deprecated( + "Use RotaryMode.Scroll instead", + replaceWith = ReplaceWith("RotaryMode.Scroll"), + ) + public object Fling : RotaryMode + } + + public data class ScrollPosition( + val index: Int, + val offsetPx: Int, + ) + + public fun interface Factory { + @Composable + public fun create(): ScalingLazyColumnState + } +} + +@Composable +public fun rememberColumnState( + factory: ScalingLazyColumnState.Factory = ScalingLazyColumnDefaults.belowTimeText(), +): ScalingLazyColumnState { + val columnState = factory.create() + + columnState.state = rememberSaveable(saver = ScalingLazyListState.Saver) { + columnState.state + } + + return columnState +} + +@ExperimentalHorologistApi +@Composable +public fun ScalingLazyColumn( + columnState: ScalingLazyColumnState, + modifier: Modifier = Modifier, + content: ScalingLazyListScope.() -> Unit, +) { + val focusRequester = rememberActiveFocusRequester() + + val rotaryHaptics = if (columnState.hapticsEnabled) { + rememberRotaryHapticHandler(columnState.state) + } else { + rememberDisabledHaptic() + } + val modifierWithRotary = when (columnState.rotaryMode) { + RotaryMode.Snap -> modifier.rotaryWithSnap( + focusRequester = focusRequester, + rotaryScrollAdapter = columnState.state.toRotaryScrollAdapter(), + reverseDirection = columnState.reverseLayout, + rotaryHaptics = rotaryHaptics, + ) + + else -> modifier.rotaryWithScroll( + focusRequester = focusRequester, + scrollableState = columnState.state, + reverseDirection = columnState.reverseLayout, + rotaryHaptics = rotaryHaptics, + ) + } + + ScalingLazyColumn( + modifier = modifierWithRotary, + state = columnState.state, + contentPadding = columnState.contentPadding, + reverseLayout = columnState.reverseLayout, + verticalArrangement = columnState.verticalArrangement, + horizontalAlignment = columnState.horizontalAlignment, + flingBehavior = columnState.flingBehavior ?: ScrollableDefaults.flingBehavior(), + userScrollEnabled = columnState.userScrollEnabled, + scalingParams = columnState.scalingParams, + anchorType = columnState.anchorType, + autoCentering = columnState.autoCentering, + content = content, + ) +} diff --git a/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/layout/ScrollAway.kt b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/layout/ScrollAway.kt new file mode 100644 index 000000000000..623ae1aad0f0 --- /dev/null +++ b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/layout/ScrollAway.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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.horologist.compose.layout + +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.gestures.ScrollableState +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.State +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.layout.layout +import androidx.compose.ui.platform.LocalDensity +import androidx.wear.compose.foundation.lazy.ScalingLazyListState +import androidx.wear.compose.material.scrollAway +import com.google.android.horologist.compose.navscaffold.ScalingLazyColumnScrollableState + +internal fun Modifier.scrollAway( + scrollState: State<ScrollableState?>, +): Modifier = composed { + when (val state = scrollState.value) { + is ScalingLazyColumnScrollableState -> { + val offsetDp = with(LocalDensity.current) { + state.initialOffsetPx.toDp() + } + this.scrollAway(state.scalingLazyListState, state.initialIndex, offsetDp) + } + is ScalingLazyListState -> this.scrollAway(state) + is LazyListState -> this.scrollAway(state) + is ScrollState -> this.scrollAway(state) + // Disabled + null -> this.hidden() + // Enabled but no scroll state + else -> this + } +} + +internal fun Modifier.hidden(): Modifier = layout { _, _ -> layout(0, 0) {} } diff --git a/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/navscaffold/NavScaffoldViewModel.kt b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/navscaffold/NavScaffoldViewModel.kt new file mode 100644 index 000000000000..14c0ba1290ba --- /dev/null +++ b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/navscaffold/NavScaffoldViewModel.kt @@ -0,0 +1,297 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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. + */ + +@file:OptIn(ExperimentalHorologistApi::class, SavedStateHandleSaveableApi::class) + +package com.google.android.horologist.compose.navscaffold + +import android.os.Bundle +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.gestures.ScrollableState +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi +import androidx.lifecycle.viewmodel.compose.saveable +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavHostController +import androidx.wear.compose.foundation.lazy.ScalingLazyListState +import androidx.wear.compose.material.PositionIndicator +import androidx.wear.compose.material.Scaffold +import androidx.wear.compose.material.TimeText +import androidx.wear.compose.material.Vignette +import androidx.wear.compose.material.VignettePosition +import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.compose.layout.ScalingLazyColumnState +import com.google.android.horologist.compose.navscaffold.NavScaffoldViewModel.PositionIndicatorMode +import com.google.android.horologist.compose.navscaffold.NavScaffoldViewModel.TimeTextMode +import com.google.android.horologist.compose.navscaffold.NavScaffoldViewModel.TimeTextMode.ScrollAway +import com.google.android.horologist.compose.navscaffold.NavScaffoldViewModel.VignetteMode.Off +import com.google.android.horologist.compose.navscaffold.NavScaffoldViewModel.VignetteMode.On +import com.google.android.horologist.compose.navscaffold.NavScaffoldViewModel.VignetteMode.WhenScrollable + +/** + * A ViewModel that backs the WearNavScaffold to allow each composable to interact and effect + * the [Scaffold] positionIndicator, vignette and timeText. + * + * A ViewModel is used to allow the same current instance to be shared between the WearNavScaffold + * and the composable screen via [NavHostController.currentBackStackEntry]. + */ +public open class NavScaffoldViewModel( + private val savedStateHandle: SavedStateHandle, +) : ViewModel() { + internal var initialIndex: Int? = null + internal var initialOffsetPx: Int? = null + internal var scrollType by mutableStateOf<ScrollType?>(null) + + private lateinit var _scrollableState: ScrollableState + + /** + * Returns the scrollable state for this composable or null if the scaffold should + * not consider this element to be scrollable. + */ + public val scrollableState: ScrollableState? + get() = if (scrollType == null || scrollType == ScrollType.None) { + null + } else { + _scrollableState + } + + /** + * The configuration of [Vignette], [WhenScrollable], [Off], [On] and if so whether top and + * bottom. Defaults to on for scrollable screens. + */ + public var vignettePosition: VignetteMode by mutableStateOf(WhenScrollable) + + /** + * The configuration of [TimeText], defaults to [TimeTextMode.ScrollAway] which will move the + * time text above the screen to avoid overlapping with the content moving up. + */ + public var timeTextMode: TimeTextMode by mutableStateOf(ScrollAway) + + /** + * The configuration of [PositionIndicator]. The default is to show a scroll bar while the + * scroll is in progress. + */ + public var positionIndicatorMode: PositionIndicatorMode + by mutableStateOf(PositionIndicatorMode.On) + + internal fun initializeScrollState(scrollStateBuilder: () -> ScrollState): ScrollState { + check(scrollType == null || scrollType == ScrollType.ScrollState) + + if (scrollType == null) { + scrollType = ScrollType.ScrollState + + _scrollableState = savedStateHandle.saveable( + key = "navScaffold.ScrollState", + saver = ScrollState.Saver, + ) { + scrollStateBuilder() + } + } + + return _scrollableState as ScrollState + } + + internal fun initializeScalingLazyListState( + scrollableStateBuilder: () -> ScalingLazyListState, + ): ScalingLazyListState { + check(scrollType == null || scrollType == ScrollType.ScalingLazyColumn) + + if (scrollType == null) { + scrollType = ScrollType.ScalingLazyColumn + + _scrollableState = savedStateHandle.saveable( + key = "navScaffold.ScalingLazyListState", + saver = ScalingLazyListState.Saver, + ) { + scrollableStateBuilder().also { + initialIndex = it.centerItemIndex + initialOffsetPx = it.centerItemScrollOffset + } + } + } + + return _scrollableState as ScalingLazyListState + } + + internal fun initializeScalingLazyListState( + columnState: ScalingLazyColumnState, + ) { + check(scrollType == null || scrollType == ScrollType.ScalingLazyColumn) + + if (scrollType == null) { + scrollType = ScrollType.ScalingLazyColumn + + initialIndex = columnState.initialScrollPosition.index + initialOffsetPx = columnState.initialScrollPosition.offsetPx + + _scrollableState = savedStateHandle.saveable( + key = "navScaffold.ScalingLazyListState", + saver = ScalingLazyListState.Saver, + ) { + columnState.state + } + } + + columnState.state = _scrollableState as ScalingLazyListState + } + + internal fun initializeLazyList( + scrollableStateBuilder: () -> LazyListState, + ): LazyListState { + check(scrollType == null || scrollType == ScrollType.LazyList) + + if (scrollType == null) { + scrollType = ScrollType.LazyList + + _scrollableState = savedStateHandle.saveable( + key = "navScaffold.LazyListState", + saver = LazyListState.Saver, + ) { + scrollableStateBuilder() + } + } + + return _scrollableState as LazyListState + } + + internal enum class ScrollType { + None, ScalingLazyColumn, ScrollState, LazyList + } + + /** + * The configuration of [TimeText], defaults to [ScrollAway] which will move the time text above the + * screen to avoid overlapping with the content moving up. + */ + public enum class TimeTextMode { + On, Off, ScrollAway + } + + /** + * The configuration of [PositionIndicator]. The default is to show a scroll bar while the + * scroll is in progress. + */ + public enum class PositionIndicatorMode { + On, Off + } + + /** + * The configuration of [Vignette], [WhenScrollable], [Off], [On] and if so whether top and + * bottom. Defaults to on for scrollable screens. + */ + public sealed interface VignetteMode { + public object WhenScrollable : VignetteMode + public object Off : VignetteMode + public data class On(val position: VignettePosition) : VignetteMode + } + + internal fun timeTextScrollableState(): ScrollableState? { + return when (timeTextMode) { + ScrollAway -> { + when (this.scrollType) { + ScrollType.ScrollState -> { + this.scrollableState as ScrollState + } + + ScrollType.ScalingLazyColumn -> { + val scalingLazyListState = + this.scrollableState as ScalingLazyListState + + ScalingLazyColumnScrollableState(scalingLazyListState, initialIndex + ?: 1, initialOffsetPx ?: 0) + } + + ScrollType.LazyList -> { + this.scrollableState as LazyListState + } + + else -> { + ScrollState(0) + } + } + } + + TimeTextMode.On -> { + ScrollState(0) + } + + else -> { + null + } + } + } +} + +internal class ScalingLazyColumnScrollableState( + val scalingLazyListState: ScalingLazyListState, + val initialIndex: Int, + val initialOffsetPx: Int, +) : ScrollableState by scalingLazyListState + +/** + * The context items provided to a navigation composable. + * + * The [viewModel] can be used to customise the scaffold behaviour. + */ +public data class ScaffoldContext<T : ScrollableState>( + val backStackEntry: NavBackStackEntry, + val scrollableState: T, + val viewModel: NavScaffoldViewModel, +) { + var timeTextMode: TimeTextMode by viewModel::timeTextMode + + var positionIndicatorMode: PositionIndicatorMode by viewModel::positionIndicatorMode + + val arguments: Bundle? + get() = backStackEntry.arguments +} + +public data class NonScrollableScaffoldContext( + val backStackEntry: NavBackStackEntry, + val viewModel: NavScaffoldViewModel, +) { + var timeTextMode: TimeTextMode by viewModel::timeTextMode + + var positionIndicatorMode: PositionIndicatorMode by viewModel::positionIndicatorMode + + val arguments: Bundle? + get() = backStackEntry.arguments +} + +/** + * The context items provided to a navigation composable. + * + * The [viewModel] can be used to customise the scaffold behaviour. + */ +public data class ScrollableScaffoldContext( + val backStackEntry: NavBackStackEntry, + val columnState: ScalingLazyColumnState, + val viewModel: NavScaffoldViewModel, +) { + val scrollableState: ScalingLazyListState + get() = columnState.state + + var timeTextMode: TimeTextMode by viewModel::timeTextMode + + var positionIndicatorMode: PositionIndicatorMode by viewModel::positionIndicatorMode + + val arguments: Bundle? + get() = backStackEntry.arguments +} diff --git a/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/navscaffold/WearNavScaffold.kt b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/navscaffold/WearNavScaffold.kt new file mode 100644 index 000000000000..315d82263595 --- /dev/null +++ b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/navscaffold/WearNavScaffold.kt @@ -0,0 +1,321 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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. + */ + +@file:OptIn(ExperimentalWearFoundationApi::class) + +package com.google.android.horologist.compose.navscaffold + +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.gestures.ScrollableState +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.key +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NamedNavArgument +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavDeepLink +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.wear.compose.foundation.ExperimentalWearFoundationApi +import androidx.wear.compose.foundation.HierarchicalFocusCoordinator +import androidx.wear.compose.foundation.lazy.ScalingLazyListState +import androidx.wear.compose.material.PositionIndicator +import androidx.wear.compose.material.Scaffold +import androidx.wear.compose.material.TimeText +import androidx.wear.compose.material.Vignette +import androidx.wear.compose.navigation.SwipeDismissableNavHost +import androidx.wear.compose.navigation.SwipeDismissableNavHostState +import androidx.wear.compose.navigation.composable +import androidx.wear.compose.navigation.currentBackStackEntryAsState +import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState +import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults +import com.google.android.horologist.compose.layout.ScalingLazyColumnState +import com.google.android.horologist.compose.layout.scrollAway + +/** + * A Navigation and Scroll aware [Scaffold]. + * + * In addition to [NavGraphBuilder.scrollable], 3 additional extensions are supported + * [scalingLazyColumnComposable], [scrollStateComposable] and + * [lazyListComposable]. + * + * These should be used to build the [ScrollableState] or [FocusRequester] as well as + * configure the behaviour of [TimeText], [PositionIndicator] or [Vignette]. + */ +@Composable +public fun WearNavScaffold( + startDestination: String, + navController: NavHostController, + modifier: Modifier = Modifier, + snackbar: @Composable () -> Unit = {}, + timeText: @Composable (Modifier) -> Unit = { + TimeText( + modifier = it, + ) + }, + state: SwipeDismissableNavHostState = rememberSwipeDismissableNavHostState(), + builder: NavGraphBuilder.() -> Unit, +) { + val currentBackStackEntry: NavBackStackEntry? by navController.currentBackStackEntryAsState() + + val viewModel: NavScaffoldViewModel? = currentBackStackEntry?.let { + viewModel(viewModelStoreOwner = it) + } + + val scrollState: State<ScrollableState?> = remember(viewModel) { + derivedStateOf { + viewModel?.timeTextScrollableState() + } + } + + Scaffold( + modifier = modifier.fillMaxSize(), + timeText = { + timeText(Modifier.scrollAway(scrollState)) + }, + positionIndicator = { + key(currentBackStackEntry?.destination?.route) { + val mode = viewModel?.positionIndicatorMode + + if (mode == NavScaffoldViewModel.PositionIndicatorMode.On) { + NavPositionIndicator(viewModel) + } + } + }, + vignette = { + key(currentBackStackEntry?.destination?.route) { + val vignettePosition = viewModel?.vignettePosition + if (vignettePosition is NavScaffoldViewModel.VignetteMode.On) { + Vignette(vignettePosition = vignettePosition.position) + } + } + }, + ) { + Box { + SwipeDismissableNavHost( + navController = navController, + startDestination = startDestination, + state = state, + ) { + builder() + } + + snackbar() + } + } +} + +@Composable +private fun NavPositionIndicator(viewModel: NavScaffoldViewModel) { + when (viewModel.scrollType) { + NavScaffoldViewModel.ScrollType.ScrollState -> + PositionIndicator( + scrollState = viewModel.scrollableState as ScrollState, + ) + + NavScaffoldViewModel.ScrollType.ScalingLazyColumn -> { + PositionIndicator( + scalingLazyListState = viewModel.scrollableState as ScalingLazyListState, + ) + } + + NavScaffoldViewModel.ScrollType.LazyList -> + PositionIndicator( + lazyListState = viewModel.scrollableState as LazyListState, + ) + + else -> {} + } +} + +/** + * Add a screen to the navigation graph featuring a ScalingLazyColumn. + * + * The scalingLazyListState must be taken from the [ScaffoldContext]. + */ +@Deprecated( + "Use listComposable", +) +public fun NavGraphBuilder.scalingLazyColumnComposable( + route: String, + arguments: List<NamedNavArgument> = emptyList(), + deepLinks: List<NavDeepLink> = emptyList(), + scrollStateBuilder: () -> ScalingLazyListState, + content: @Composable (ScaffoldContext<ScalingLazyListState>) -> Unit, +) { + composable(route, arguments, deepLinks) { + FocusedDestination { + val viewModel: NavScaffoldViewModel = viewModel(it) + + val scrollState = viewModel.initializeScalingLazyListState(scrollStateBuilder) + + content(ScaffoldContext(it, scrollState, viewModel)) + } + } +} + +/** + * Add a screen to the navigation graph featuring a ScalingLazyColumn. + * + * The [ScalingLazyColumnState] must be taken from the [ScrollableScaffoldContext]. + */ +@ExperimentalHorologistApi +public fun NavGraphBuilder.scrollable( + route: String, + arguments: List<NamedNavArgument> = emptyList(), + deepLinks: List<NavDeepLink> = emptyList(), + columnStateFactory: ScalingLazyColumnState.Factory = + ScalingLazyColumnDefaults.belowTimeText(), + content: @Composable (ScrollableScaffoldContext) -> Unit, +) { + this@scrollable.composable(route, arguments, deepLinks) { + FocusedDestination { + val columnState = columnStateFactory.create() + + val viewModel: NavScaffoldViewModel = viewModel(it) + + viewModel.initializeScalingLazyListState(columnState) + + content(ScrollableScaffoldContext(it, columnState, viewModel)) + } + } +} + +/** + * Add a screen to the navigation graph featuring a Scrollable item. + * + * The scrollState must be taken from the [ScaffoldContext]. + */ +public fun NavGraphBuilder.scrollStateComposable( + route: String, + arguments: List<NamedNavArgument> = emptyList(), + deepLinks: List<NavDeepLink> = emptyList(), + scrollStateBuilder: () -> ScrollState = { ScrollState(0) }, + content: @Composable (ScaffoldContext<ScrollState>) -> Unit, +) { + composable(route, arguments, deepLinks) { + FocusedDestination { + val viewModel: NavScaffoldViewModel = viewModel(it) + + val scrollState = viewModel.initializeScrollState(scrollStateBuilder) + + content(ScaffoldContext(it, scrollState, viewModel)) + } + } +} + +/** + * Add a screen to the navigation graph featuring a Lazy list such as LazyColumn. + * + * The scrollState must be taken from the [ScaffoldContext]. + */ +public fun NavGraphBuilder.lazyListComposable( + route: String, + arguments: List<NamedNavArgument> = emptyList(), + deepLinks: List<NavDeepLink> = emptyList(), + lazyListStateBuilder: () -> LazyListState = { LazyListState() }, + content: @Composable (ScaffoldContext<LazyListState>) -> Unit, +) { + composable(route, arguments, deepLinks) { + FocusedDestination { + val viewModel: NavScaffoldViewModel = viewModel(it) + + val scrollState = viewModel.initializeLazyList(lazyListStateBuilder) + + content(ScaffoldContext(it, scrollState, viewModel)) + } + } +} + +/** + * Add non scrolling screen to the navigation graph. The [NavBackStackEntry] and + * [NavScaffoldViewModel] are passed into the [content] block so that + * the Scaffold may be customised, such as disabling TimeText. + */ +@Deprecated( + "Use composable", + ReplaceWith("composable(route, arguments, deepLinks, lazyListStateBuilder, content)"), +) +public fun NavGraphBuilder.wearNavComposable( + route: String, + arguments: List<NamedNavArgument> = emptyList(), + deepLinks: List<NavDeepLink> = emptyList(), + content: @Composable (NavBackStackEntry, NavScaffoldViewModel) -> Unit, +) { + composable(route, arguments, deepLinks) { + FocusedDestination { + val viewModel: NavScaffoldViewModel = viewModel() + + content(it, viewModel) + } + } +} + +/** + * Add non scrolling screen to the navigation graph. The [NavBackStackEntry] and + * [NavScaffoldViewModel] are passed into the [content] block so that + * the Scaffold may be customised, such as disabling TimeText. + */ +@ExperimentalHorologistApi +public fun NavGraphBuilder.composable( + route: String, + arguments: List<NamedNavArgument> = emptyList(), + deepLinks: List<NavDeepLink> = emptyList(), + content: @Composable (NonScrollableScaffoldContext) -> Unit, +) { + this@composable.composable(route, arguments, deepLinks) { + FocusedDestination { + val viewModel: NavScaffoldViewModel = viewModel() + + content(NonScrollableScaffoldContext(it, viewModel)) + } + } +} + +@Composable +internal fun FocusedDestination(content: @Composable () -> Unit) { + val lifecycle = LocalLifecycleOwner.current.lifecycle + val focused = + remember { mutableStateOf(lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) } + + DisposableEffect(lifecycle) { + val listener = LifecycleEventObserver { _, _ -> + focused.value = lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) + } + lifecycle.addObserver(listener) + onDispose { + lifecycle.removeObserver(listener) + } + } + + HierarchicalFocusCoordinator(requiresFocus = { focused.value }) { + content() + } +} diff --git a/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/rotaryinput/Haptics.kt b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/rotaryinput/Haptics.kt new file mode 100644 index 000000000000..c4af4a622b82 --- /dev/null +++ b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/rotaryinput/Haptics.kt @@ -0,0 +1,380 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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. + */ + +@file:OptIn(ExperimentalHorologistApi::class) + +package com.google.android.horologist.compose.rotaryinput + +import android.os.Build +import android.view.HapticFeedbackConstants +import android.view.View +import androidx.compose.foundation.gestures.ScrollableState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalView +import com.google.android.horologist.annotations.ExperimentalHorologistApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.withContext +import kotlin.math.abs + +private const val DEBUG = false + +/** + * Debug logging that can be enabled. + */ +private inline fun debugLog(generateMsg: () -> String) { + if (DEBUG) { + println("RotaryHaptics: ${generateMsg()}") + } +} + +/** + * Throttling events within specified timeframe. Only first and last events will be received. + * For a flow emitting elements 1 to 30, with a 100ms delay between them: + * ``` + * val flow = flow { + * for (i in 1..30) { + * delay(100) + * emit(i) + * } + * } + * ``` + * With timeframe=1000 only those integers will be received: 1, 10, 20, 30 . + */ +internal fun <T> Flow<T>.throttleLatest(timeframe: Long): Flow<T> = + flow { + conflate().collect { + emit(it) + delay(timeframe) + } + } + +/** + * Handles haptics for rotary usage + */ +@ExperimentalHorologistApi +public interface RotaryHapticHandler { + + /** + * Handles haptics when scroll is used + */ + @ExperimentalHorologistApi + public fun handleScrollHaptic(scrollDelta: Float) + + /** + * Handles haptics when scroll with snap is used + */ + @ExperimentalHorologistApi + public fun handleSnapHaptic(scrollDelta: Float) +} + +/** + * Default implementation of [RotaryHapticHandler]. It handles haptic feedback based + * on the [scrollableState], scrolled pixels and [hapticsThresholdPx]. + * Haptic is not fired in this class, instead it's sent to [hapticsChannel] + * where it'll performed later. + * + * @param scrollableState Haptic performed based on this state + * @param hapticsChannel Channel to which haptic events will be sent + * @param hapticsThresholdPx A scroll threshold after which haptic is produced. + */ +public class DefaultRotaryHapticHandler( + private val scrollableState: ScrollableState, + private val hapticsChannel: Channel<RotaryHapticsType>, + private val hapticsThresholdPx: Long = 50, +) : RotaryHapticHandler { + + private var overscrollHapticTriggered = false + private var currScrollPosition = 0f + private var prevHapticsPosition = 0f + + override fun handleScrollHaptic(scrollDelta: Float) { + if ((scrollDelta > 0 && !scrollableState.canScrollForward) || + (scrollDelta < 0 && !scrollableState.canScrollBackward) + ) { + if (!overscrollHapticTriggered) { + trySendHaptic(RotaryHapticsType.ScrollLimit) + overscrollHapticTriggered = true + } + } else { + overscrollHapticTriggered = false + currScrollPosition += scrollDelta + val diff = abs(currScrollPosition - prevHapticsPosition) + + if (diff >= hapticsThresholdPx) { + trySendHaptic(RotaryHapticsType.ScrollTick) + prevHapticsPosition = currScrollPosition + } + } + } + + override fun handleSnapHaptic(scrollDelta: Float) { + if ((scrollDelta > 0 && !scrollableState.canScrollForward) || + (scrollDelta < 0 && !scrollableState.canScrollBackward) + ) { + if (!overscrollHapticTriggered) { + trySendHaptic(RotaryHapticsType.ScrollLimit) + overscrollHapticTriggered = true + } + } else { + overscrollHapticTriggered = false + trySendHaptic(RotaryHapticsType.ScrollItemFocus) + } + } + + private fun trySendHaptic(rotaryHapticsType: RotaryHapticsType) { + // Ok to ignore the ChannelResult because we default to capacity = 2 and DROP_OLDEST + @Suppress("UNUSED_VARIABLE") + val unused = hapticsChannel.trySend(rotaryHapticsType) + } +} + +/** + * Interface for Rotary haptic feedback + */ +@ExperimentalHorologistApi +public interface RotaryHapticFeedback { + @ExperimentalHorologistApi + public fun performHapticFeedback(type: RotaryHapticsType) +} + +/** + * Rotary haptic types + */ +@ExperimentalHorologistApi +@JvmInline +public value class RotaryHapticsType(private val type: Int) { + public companion object { + /** + * A scroll ticking haptic. Similar to texture haptic - performed each time when + * a scrollable content is scrolled by a certain distance + */ + @ExperimentalHorologistApi + public val ScrollTick: RotaryHapticsType = RotaryHapticsType(1) + + /** + * An item focus (snap) haptic. Performed when a scrollable content is snapped + * to a specific item. + */ + @ExperimentalHorologistApi + public val ScrollItemFocus: RotaryHapticsType = RotaryHapticsType(2) + + /** + * A limit(overscroll) haptic. Performed when a list reaches the limit + * (start or end) and can't scroll further + */ + @ExperimentalHorologistApi + public val ScrollLimit: RotaryHapticsType = RotaryHapticsType(3) + } +} + +/** + * Remember disabled haptics handler + */ +@ExperimentalHorologistApi +@Composable +public fun rememberDisabledHaptic(): RotaryHapticHandler = remember { + object : RotaryHapticHandler { + + override fun handleScrollHaptic(scrollDelta: Float) { + // Do nothing + } + + override fun handleSnapHaptic(scrollDelta: Float) { + // Do nothing + } + } +} + +/** + * Remember rotary haptic handler. + * @param scrollableState A scrollableState, used to determine whether the end of the scrollable + * was reached or not. + * @param throttleThresholdMs Throttling events within specified timeframe. + * Only first and last events will be received. Check [throttleLatest] for more info. + * @param hapticsThresholdPx A scroll threshold after which haptic is produced. + * @param hapticsChannel Channel to which haptic events will be sent + * @param rotaryHaptics Interface for Rotary haptic feedback which performs haptics + */ +@ExperimentalHorologistApi +@Composable +public fun rememberRotaryHapticHandler( + scrollableState: ScrollableState, + throttleThresholdMs: Long = 30, + hapticsThresholdPx: Long = 50, + hapticsChannel: Channel<RotaryHapticsType> = rememberHapticChannel(), + rotaryHaptics: RotaryHapticFeedback = rememberDefaultRotaryHapticFeedback(), +): RotaryHapticHandler { + return remember(scrollableState, hapticsChannel, rotaryHaptics) { + DefaultRotaryHapticHandler(scrollableState, hapticsChannel, hapticsThresholdPx) + }.apply { + LaunchedEffect(hapticsChannel) { + hapticsChannel.receiveAsFlow() + .throttleLatest(throttleThresholdMs) + .collect { hapticType -> + // 'withContext' launches performHapticFeedback in a separate thread, + // as otherwise it produces a visible lag (b/219776664) + val currentTime = System.currentTimeMillis() + debugLog { "Haptics started" } + withContext(Dispatchers.Default) { + debugLog { + "Performing haptics, delay: " + + "${System.currentTimeMillis() - currentTime}" + } + rotaryHaptics.performHapticFeedback(hapticType) + } + } + } + } +} + +@Composable +private fun rememberHapticChannel() = + remember { + Channel<RotaryHapticsType>( + capacity = 2, + onBufferOverflow = BufferOverflow.DROP_OLDEST, + ) + } + +@ExperimentalHorologistApi +@Composable +public fun rememberDefaultRotaryHapticFeedback(): RotaryHapticFeedback = + LocalView.current.let { view -> remember { findDeviceSpecificHapticFeedback(view) } } + +internal fun findDeviceSpecificHapticFeedback(view: View): RotaryHapticFeedback = + if (isGooglePixelWatch()) { + PixelWatchRotaryHapticFeedback(view) + } else if (isGalaxyWatchClassic()) { + GalaxyWatchClassicHapticFeedback(view) + } else { + DefaultRotaryHapticFeedback(view) + } + +/** + * Default Rotary implementation for [RotaryHapticFeedback] + */ +@ExperimentalHorologistApi +public class DefaultRotaryHapticFeedback(private val view: View) : RotaryHapticFeedback { + + @ExperimentalHorologistApi + override fun performHapticFeedback( + type: RotaryHapticsType, + ) { + when (type) { + RotaryHapticsType.ScrollItemFocus -> { + view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) + } + + RotaryHapticsType.ScrollTick -> { + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) + } + + RotaryHapticsType.ScrollLimit -> { + view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) + } + } + } +} + +/** + * Implementation of [RotaryHapticFeedback] for Pixel Watch + */ +@ExperimentalHorologistApi +private class PixelWatchRotaryHapticFeedback(private val view: View) : RotaryHapticFeedback { + + @ExperimentalHorologistApi + override fun performHapticFeedback( + type: RotaryHapticsType, + ) { + when (type) { + RotaryHapticsType.ScrollItemFocus -> { + view.performHapticFeedback( + if (Build.VERSION.SDK_INT >= 33) { + ROTARY_SCROLL_ITEM_FOCUS + } else { + WEAR_SCROLL_ITEM_FOCUS + }, + ) + } + + RotaryHapticsType.ScrollTick -> { + view.performHapticFeedback( + if (Build.VERSION.SDK_INT >= 33) ROTARY_SCROLL_TICK else WEAR_SCROLL_TICK, + ) + } + + RotaryHapticsType.ScrollLimit -> { + view.performHapticFeedback( + if (Build.VERSION.SDK_INT >= 33) ROTARY_SCROLL_LIMIT else WEAR_SCROLL_LIMIT, + ) + } + } + } + + private companion object { + // Hidden constants from HapticFeedbackConstants.java specific for Pixel Watch + // API 33 + public const val ROTARY_SCROLL_TICK: Int = 18 + public const val ROTARY_SCROLL_ITEM_FOCUS: Int = 19 + public const val ROTARY_SCROLL_LIMIT: Int = 20 + + // API 30 + public const val WEAR_SCROLL_TICK: Int = 10002 + public const val WEAR_SCROLL_ITEM_FOCUS: Int = 10003 + public const val WEAR_SCROLL_LIMIT: Int = 10003 + } +} + +/** + * Implementation of [RotaryHapticFeedback] for Galaxy Watch 4 Classic + */ +@ExperimentalHorologistApi +private class GalaxyWatchClassicHapticFeedback(private val view: View) : RotaryHapticFeedback { + + @ExperimentalHorologistApi + override fun performHapticFeedback( + type: RotaryHapticsType, + ) { + when (type) { + RotaryHapticsType.ScrollItemFocus -> { + // No haptic for scroll snap ( we have physical bezel) + } + + RotaryHapticsType.ScrollTick -> { + // No haptic for scroll tick ( we have physical bezel) + } + + RotaryHapticsType.ScrollLimit -> { + view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) + } + } + } +} + +private fun isGalaxyWatchClassic(): Boolean = + Build.MODEL.matches("SM-R8[89]5.".toRegex()) + +private fun isGooglePixelWatch(): Boolean = + Build.MODEL.startsWith("Google Pixel Watch") diff --git a/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/rotaryinput/Rotary.kt b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/rotaryinput/Rotary.kt new file mode 100644 index 000000000000..3ca16c1c0d7a --- /dev/null +++ b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/rotaryinput/Rotary.kt @@ -0,0 +1,1301 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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. + */ + +@file:OptIn(ExperimentalHorologistApi::class) + +package com.google.android.horologist.compose.rotaryinput + +import android.view.ViewConfiguration +import androidx.compose.animation.core.AnimationState +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.Easing +import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.SpringSpec +import androidx.compose.animation.core.animateTo +import androidx.compose.animation.core.copy +import androidx.compose.animation.core.spring +import androidx.compose.animation.core.tween +import androidx.compose.foundation.MutatePriority +import androidx.compose.foundation.focusable +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.ScrollableDefaults +import androidx.compose.foundation.gestures.ScrollableState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.input.rotary.onRotaryScrollEvent +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.util.fastSumBy +import androidx.compose.ui.util.lerp +import androidx.wear.compose.foundation.ExperimentalWearFoundationApi +import androidx.wear.compose.foundation.lazy.ScalingLazyListState +import androidx.wear.compose.foundation.rememberActiveFocusRequester +import com.google.android.horologist.annotations.ExperimentalHorologistApi +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.Job +import kotlinx.coroutines.async +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.transformLatest +import kotlin.math.abs +import kotlin.math.absoluteValue +import kotlin.math.sign + +private const val DEBUG = false + +/** + * Debug logging that can be enabled. + */ +private inline fun debugLog(generateMsg: () -> String) { + if (DEBUG) { + println("RotaryScroll: ${generateMsg()}") + } +} + +/** + * A modifier which connects rotary events with scrollable. + * This modifier supports fling. + * + * Fling algorithm: + * - A scroll with RSB/ Bezel happens. + * - If this is a first rotary event after the threshold ( by default 200ms), a new scroll + * session starts by resetting all necessary parameters + * - A delta value is added into VelocityTracker and a new speed is calculated. + * - If the current speed is bigger than the previous one, this value is remembered as + * a latest fling speed with a timestamp + * - After each scroll event a fling countdown starts ( by default 70ms) which + * resets if new scroll event is received + * - If fling countdown is finished - it means that the finger was probably raised from RSB, there will be no other events and probably + * this is the last event during this session. After it a fling is triggered. + * - Fling is stopped when a new scroll event happens + * + * The screen containing the scrollable item should request the focus + * by calling [requestFocus] method + * + * ``` + * LaunchedEffect(Unit) { + * focusRequester.requestFocus() + * } + * ``` + * @param focusRequester Requests the focus for rotary input + * @param scrollableState Scrollable state which will be scrolled while receiving rotary events + * @param flingBehavior Logic describing fling behavior. + * @param rotaryHaptics Class which will handle haptic feedback + * @param reverseDirection Reverse the direction of scrolling. Should be aligned with + * Scrollable `reverseDirection` parameter + */ +@ExperimentalHorologistApi +@Suppress("ComposableModifierFactory") +@Deprecated( + "Use rotaryWithScroll instead", + ReplaceWith( + "this.rotaryWithScroll(scrollableState, focusRequester, " + + "flingBehavior, rotaryHaptics, reverseDirection)", + ), +) +@Composable +public fun Modifier.rotaryWithFling( + focusRequester: FocusRequester, + scrollableState: ScrollableState, + flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), + rotaryHaptics: RotaryHapticHandler = rememberRotaryHapticHandler(scrollableState), + reverseDirection: Boolean = false, +): Modifier = rotaryHandler( + rotaryScrollHandler = RotaryDefaults.rememberFlingHandler(scrollableState, flingBehavior), + reverseDirection = reverseDirection, + rotaryHaptics = rotaryHaptics, +) + .focusRequester(focusRequester) + .focusable() + +/** + * A modifier which connects rotary events with scrollable. + * This modifier supports scroll with fling. + * + * @param scrollableState Scrollable state which will be scrolled while receiving rotary events + * @param focusRequester Requests the focus for rotary input. + * By default comes from [rememberActiveFocusRequester], + * which is used with [HierarchicalFocusCoordinator] + * @param flingBehavior Logic describing fling behavior. If null fling will not happen. + * @param rotaryHaptics Class which will handle haptic feedback + * @param reverseDirection Reverse the direction of scrolling. Should be aligned with + * Scrollable `reverseDirection` parameter + */ +@OptIn(ExperimentalWearFoundationApi::class) +@ExperimentalHorologistApi +@Suppress("ComposableModifierFactory") +@Composable +public fun Modifier.rotaryWithScroll( + scrollableState: ScrollableState, + focusRequester: FocusRequester = rememberActiveFocusRequester(), + flingBehavior: FlingBehavior? = ScrollableDefaults.flingBehavior(), + rotaryHaptics: RotaryHapticHandler = rememberRotaryHapticHandler(scrollableState), + reverseDirection: Boolean = false, +): Modifier = rotaryHandler( + rotaryScrollHandler = RotaryDefaults.rememberFlingHandler(scrollableState, flingBehavior), + reverseDirection = reverseDirection, + rotaryHaptics = rotaryHaptics, +) + .focusRequester(focusRequester) + .focusable() + +/** + * A modifier which connects rotary events with scrollable. + * This modifier supports snap. + * + * @param focusRequester Requests the focus for rotary input. + * By default comes from [rememberActiveFocusRequester], + * which is used with [HierarchicalFocusCoordinator] + * @param rotaryScrollAdapter A connection between scrollable objects and rotary events + * @param rotaryHaptics Class which will handle haptic feedback + * @param reverseDirection Reverse the direction of scrolling. Should be aligned with + * Scrollable `reverseDirection` parameter + */ +@OptIn(ExperimentalWearFoundationApi::class) +@ExperimentalHorologistApi +@Suppress("ComposableModifierFactory") +@Composable +public fun Modifier.rotaryWithSnap( + rotaryScrollAdapter: RotaryScrollAdapter, + focusRequester: FocusRequester = rememberActiveFocusRequester(), + snapParameters: SnapParameters = RotaryDefaults.snapParametersDefault(), + rotaryHaptics: RotaryHapticHandler = + rememberRotaryHapticHandler(rotaryScrollAdapter.scrollableState), + reverseDirection: Boolean = false, +): Modifier = rotaryHandler( + rotaryScrollHandler = + RotaryDefaults.rememberSnapHandler(rotaryScrollAdapter, snapParameters), + reverseDirection = reverseDirection, + rotaryHaptics = rotaryHaptics, +) + .focusRequester(focusRequester) + .focusable() + +/** + * An extension function for creating [RotaryScrollAdapter] from [ScalingLazyListState] + */ +@ExperimentalHorologistApi +public fun ScalingLazyListState.toRotaryScrollAdapter(): RotaryScrollAdapter = + ScalingLazyColumnRotaryScrollAdapter(this) + +/** + * An implementation of rotary scroll adapter for [ScalingLazyColumn] + */ +@ExperimentalHorologistApi +public class ScalingLazyColumnRotaryScrollAdapter( + override val scrollableState: ScalingLazyListState, +) : RotaryScrollAdapter { + + /** + * Calculates an average height of an item by taking an average from visible items height. + */ + override fun averageItemSize(): Float { + val visibleItems = scrollableState.layoutInfo.visibleItemsInfo + return (visibleItems.fastSumBy { it.unadjustedSize } / visibleItems.size).toFloat() + } + + /** + * Current (centred) item index + */ + override fun currentItemIndex(): Int = scrollableState.centerItemIndex + + /** + * An offset from the item centre + */ + override fun currentItemOffset(): Float = scrollableState.centerItemScrollOffset.toFloat() + + /** + * The total count of items in ScalingLazyColumn + */ + override fun totalItemsCount(): Int = scrollableState.layoutInfo.totalItemsCount +} + +/** + * An adapter which connects scrollableState to Rotary + */ +@ExperimentalHorologistApi +public interface RotaryScrollAdapter { + + /** + * A scrollable state. Used for performing scroll when Rotary events received + */ + @ExperimentalHorologistApi + public val scrollableState: ScrollableState + + /** + * Average size of an item. Used for estimating the scrollable distance + */ + @ExperimentalHorologistApi + public fun averageItemSize(): Float + + /** + * A current item index. Used for scrolling + */ + @ExperimentalHorologistApi + public fun currentItemIndex(): Int + + /** + * An offset from the centre or the border of the current item. + */ + @ExperimentalHorologistApi + public fun currentItemOffset(): Float + + /** + * The total count of items in [scrollableState] + */ + @ExperimentalHorologistApi + public fun totalItemsCount(): Int +} + +/** + * Defaults for rotary modifiers + */ +@ExperimentalHorologistApi +public object RotaryDefaults { + + /** + * Handles scroll with fling. + * @param scrollableState Scrollable state which will be scrolled while receiving rotary events + * @param flingBehavior Logic describing Fling behavior. If null - fling will not happen + * @param isLowRes Whether the input is Low-res (a bezel) or high-res(a crown/rsb) + */ + @ExperimentalHorologistApi + @Composable + public fun rememberFlingHandler( + scrollableState: ScrollableState, + flingBehavior: FlingBehavior? = null, + isLowRes: Boolean = isLowResInput(), + ): RotaryScrollHandler { + val viewConfiguration = ViewConfiguration.get(LocalContext.current) + + return remember(scrollableState, flingBehavior, isLowRes) { + debugLog { "isLowRes : $isLowRes" } + fun rotaryFlingBehavior() = flingBehavior?.run { + DefaultRotaryFlingBehavior( + scrollableState, + flingBehavior, + viewConfiguration, + flingTimeframe = + if (isLowRes) lowResFlingTimeframe else highResFlingTimeframe, + ) + } + + fun scrollBehavior() = AnimationScrollBehavior(scrollableState) + + if (isLowRes) { + LowResRotaryScrollHandler( + rotaryFlingBehaviorFactory = { rotaryFlingBehavior() }, + scrollBehaviorFactory = { scrollBehavior() }, + ) + } else { + HighResRotaryScrollHandler( + rotaryFlingBehaviorFactory = { rotaryFlingBehavior() }, + scrollBehaviorFactory = { scrollBehavior() }, + ) + } + } + } + + /** + * Handles scroll with snap + * @param rotaryScrollAdapter A connection between scrollable objects and rotary events + * @param snapParameters Snap parameters + */ + @ExperimentalHorologistApi + @Composable + public fun rememberSnapHandler( + rotaryScrollAdapter: RotaryScrollAdapter, + snapParameters: SnapParameters = snapParametersDefault(), + isLowRes: Boolean = isLowResInput(), + ): RotaryScrollHandler { + return remember(rotaryScrollAdapter, snapParameters) { + if (isLowRes) { + LowResSnapHandler( + snapBehaviourFactory = { + DefaultSnapBehavior(rotaryScrollAdapter, snapParameters) + }, + ) + } else { + HighResSnapHandler( + resistanceFactor = snapParameters.resistanceFactor, + thresholdBehaviorFactory = { + ThresholdBehavior( + rotaryScrollAdapter, + snapParameters.thresholdDivider, + ) + }, + snapBehaviourFactory = { + DefaultSnapBehavior(rotaryScrollAdapter, snapParameters) + }, + scrollBehaviourFactory = { + AnimationScrollBehavior(rotaryScrollAdapter.scrollableState) + }, + ) + } + } + } + + /** + * Returns default [SnapParameters] + */ + @ExperimentalHorologistApi + public fun snapParametersDefault(): SnapParameters = + SnapParameters( + snapOffset = 0, + thresholdDivider = 1.5f, + resistanceFactor = 3f, + ) + + /** + * Returns whether the input is Low-res (a bezel) or high-res(a crown/rsb). + */ + @ExperimentalHorologistApi + @Composable + public fun isLowResInput(): Boolean = LocalContext.current.packageManager + .hasSystemFeature("android.hardware.rotaryencoder.lowres") + + private val lowResFlingTimeframe: Long = 100L + private val highResFlingTimeframe: Long = 30L +} + +/** + * Parameters used for snapping + * + * @param snapOffset an optional offset to be applied when snapping the item. After the snap the + * snapped items offset will be [snapOffset]. + */ +public class SnapParameters( + public val snapOffset: Int, + public val thresholdDivider: Float, + public val resistanceFactor: Float, +) { + /** + * Returns a snapping offset in [Dp] + */ + @Composable + public fun snapOffsetDp(): Dp { + return with(LocalDensity.current) { + snapOffset.toDp() + } + } +} + +/** + * An interface for handling scroll events + */ +@ExperimentalHorologistApi +public interface RotaryScrollHandler { + /** + * Handles scrolling events + * @param coroutineScope A scope for performing async actions + * @param event A scrollable event from rotary input, containing scrollable delta and timestamp + * @param rotaryHaptics + */ + @ExperimentalHorologistApi + public suspend fun handleScrollEvent( + coroutineScope: CoroutineScope, + event: TimestampedDelta, + rotaryHaptics: RotaryHapticHandler, + ) +} + +/** + * An interface for scrolling behavior + */ +@ExperimentalHorologistApi +public interface RotaryScrollBehavior { + /** + * Handles scroll event to [targetValue] + */ + @ExperimentalHorologistApi + public suspend fun handleEvent(targetValue: Float) +} + +/** + * Default implementation of [RotaryFlingBehavior] + */ +@ExperimentalHorologistApi +public class DefaultRotaryFlingBehavior( + private val scrollableState: ScrollableState, + private val flingBehavior: FlingBehavior, + viewConfiguration: ViewConfiguration, + private val flingTimeframe: Long, +) : RotaryFlingBehavior { + + // A time range during which the fling is valid. + // For simplicity it's twice as long as [flingTimeframe] + private val timeRangeToFling = flingTimeframe * 2 + + // A default fling factor for making fling slower + private val flingScaleFactor = 0.7f + + private var previousVelocity = 0f + + private val rotaryVelocityTracker = RotaryVelocityTracker() + + private val minFlingSpeed = viewConfiguration.scaledMinimumFlingVelocity.toFloat() + private val maxFlingSpeed = viewConfiguration.scaledMaximumFlingVelocity.toFloat() + private var latestEventTimestamp: Long = 0 + + private var flingVelocity: Float = 0f + private var flingTimestamp: Long = 0 + + @ExperimentalHorologistApi + override fun startFlingTracking(timestamp: Long) { + rotaryVelocityTracker.start(timestamp) + latestEventTimestamp = timestamp + previousVelocity = 0f + } + + @ExperimentalHorologistApi + override fun observeEvent(timestamp: Long, delta: Float) { + rotaryVelocityTracker.move(timestamp, delta) + latestEventTimestamp = timestamp + } + + @ExperimentalHorologistApi + override suspend fun trackFling(beforeFling: () -> Unit) { + val currentVelocity = rotaryVelocityTracker.velocity + debugLog { "currentVelocity: $currentVelocity" } + + if (abs(currentVelocity) >= abs(previousVelocity)) { + flingTimestamp = latestEventTimestamp + flingVelocity = currentVelocity * flingScaleFactor + } + previousVelocity = currentVelocity + + // Waiting for a fixed amount of time before checking the fling + delay(flingTimeframe) + + // For making a fling 2 criteria should be met: + // 1) no more than + // `rangeToFling` ms should pass between last fling detection + // and the time of last motion event + // 2) flingVelocity should exceed the minFlingSpeed + debugLog { + "Check fling: flingVelocity: $flingVelocity " + + "minFlingSpeed: $minFlingSpeed, maxFlingSpeed: $maxFlingSpeed" + } + if (latestEventTimestamp - flingTimestamp < timeRangeToFling && + abs(flingVelocity) > minFlingSpeed + ) { + // Stops scrollAnimationCoroutine because a fling will be performed + beforeFling() + val velocity = flingVelocity.coerceIn(-maxFlingSpeed, maxFlingSpeed) + scrollableState.scroll(MutatePriority.UserInput) { + with(flingBehavior) { + debugLog { "Flinging with velocity $velocity" } + performFling(velocity) + } + } + } + } +} + +/** + * An interface for flinging with rotary + */ +@ExperimentalHorologistApi +public interface RotaryFlingBehavior { + + /** + * Observing new event within a fling tracking session with new timestamp and delta + */ + @ExperimentalHorologistApi + public fun observeEvent(timestamp: Long, delta: Float) + + /** + * Performing fling if necessary and calling [beforeFling] lambda before it is triggered + */ + @ExperimentalHorologistApi + public suspend fun trackFling(beforeFling: () -> Unit) + + /** + * Starts a new fling tracking session + * with specified timestamp + */ + @ExperimentalHorologistApi + public fun startFlingTracking(timestamp: Long) +} + +/** + * An interface for snapping with rotary + */ +@ExperimentalHorologistApi +public interface RotarySnapBehavior { + + /** + * Preparing snapping. This method should be called before [snapToTargetItem] is called. + * + * Snapping is done for current + [moveForElements] items. + * + * If [sequentialSnap] is true, items are summed up together. + * For example, if [prepareSnapForItems] is called with + * [moveForElements] = 2, 3, 5 -> then the snapping will happen to current + 10 items + * + * If [sequentialSnap] is false, then [moveForElements] are not summed up together. + */ + public fun prepareSnapForItems(moveForElements: Int, sequentialSnap: Boolean) + + /** + * Performs snapping to the closest item. + */ + public suspend fun snapToClosestItem() + + /** + * Returns true if top edge was reached + */ + public fun topEdgeReached(): Boolean + + /** + * Returns true if bottom edge was reached + */ + public fun bottomEdgeReached(): Boolean + + /** + * Performs snapping to the specified in [prepareSnapForItems] element + */ + public suspend fun snapToTargetItem() +} + +/** + * A rotary event object which contains a [timestamp] of the rotary event and a scrolled [delta]. + */ +@ExperimentalHorologistApi +public data class TimestampedDelta(val timestamp: Long, val delta: Float) + +/** Animation implementation of [RotaryScrollBehavior]. + * This class does a smooth animation when the scroll by N pixels is done. + * This animation works well on Rsb(high-res) and Bezel(low-res) devices. + */ +@ExperimentalHorologistApi +public class AnimationScrollBehavior( + private val scrollableState: ScrollableState, +) : RotaryScrollBehavior { + private var sequentialAnimation = false + private var scrollAnimation = AnimationState(0f) + private var prevPosition = 0f + + @ExperimentalHorologistApi + override suspend fun handleEvent(targetValue: Float) { + scrollableState.scroll(MutatePriority.UserInput) { + debugLog { "ScrollAnimation value before start: ${scrollAnimation.value}" } + + scrollAnimation.animateTo( + targetValue, + animationSpec = spring(), + sequentialAnimation = sequentialAnimation, + ) { + val delta = value - prevPosition + debugLog { "Animated by $delta, value: $value" } + scrollBy(delta) + prevPosition = value + sequentialAnimation = value != this.targetValue + } + } + } +} + +/** + * An animated implementation of [RotarySnapBehavior]. Uses animateScrollToItem + * method for snapping to the Nth item + */ +@ExperimentalHorologistApi +public class DefaultSnapBehavior( + private val rotaryScrollAdapter: RotaryScrollAdapter, + private val snapParameters: SnapParameters, +) : RotarySnapBehavior { + private var snapTarget: Int = rotaryScrollAdapter.currentItemIndex() + private var sequentialSnap: Boolean = false + + private var anim = AnimationState(0f) + private var expectedDistance = 0f + + private val defaultStiffness = 200f + private var snapTargetUpdated = true + + @ExperimentalHorologistApi + override fun prepareSnapForItems(moveForElements: Int, sequentialSnap: Boolean) { + this.sequentialSnap = sequentialSnap + if (sequentialSnap) { + snapTarget += moveForElements + } else { + snapTarget = rotaryScrollAdapter.currentItemIndex() + moveForElements + } + snapTargetUpdated = true + snapTarget = snapTarget.coerceIn(0 until rotaryScrollAdapter.totalItemsCount()) + } + + override suspend fun snapToClosestItem() { + // Snapping to the closest item by using performFling method with 0 speed + rotaryScrollAdapter.scrollableState.scroll(MutatePriority.UserInput) { + debugLog { "snap to closest item" } + var prevPosition = 0f + AnimationState(0f).animateTo( + targetValue = -rotaryScrollAdapter.currentItemOffset(), + animationSpec = tween(durationMillis = 100, easing = FastOutSlowInEasing), + ) { + val animDelta = value - prevPosition + scrollBy(animDelta) + prevPosition = value + } + snapTarget = rotaryScrollAdapter.currentItemIndex() + } + } + + override fun topEdgeReached(): Boolean = snapTarget <= 0 + + override fun bottomEdgeReached(): Boolean = + snapTarget >= rotaryScrollAdapter.totalItemsCount() - 1 + + override suspend fun snapToTargetItem() { + if (sequentialSnap) { + anim = anim.copy(0f) + } else { + anim = AnimationState(0f) + } + rotaryScrollAdapter.scrollableState.scroll(MutatePriority.UserInput) { + // If snapTargetUpdated is true - then the target was updated so we + // need to do snap again + while (snapTargetUpdated) { + snapTargetUpdated = false + var latestCenterItem: Int + var continueFirstScroll = true + debugLog { "snapTarget $snapTarget" } + while (continueFirstScroll) { + latestCenterItem = rotaryScrollAdapter.currentItemIndex() + anim = anim.copy(0f) + expectedDistance = expectedDistanceTo(snapTarget, snapParameters.snapOffset) + debugLog { + "expectedDistance = $expectedDistance, " + + "scrollableState.centerItemScrollOffset " + + "${rotaryScrollAdapter.currentItemOffset()}" + } + continueFirstScroll = false + var prevPosition = 0f + + anim.animateTo( + expectedDistance, + animationSpec = SpringSpec( + stiffness = defaultStiffness, + visibilityThreshold = 0.1f, + ), + sequentialAnimation = (anim.velocity != 0f), + ) { + val animDelta = value - prevPosition + debugLog { + "First animation, value:$value, velocity:$velocity, " + + "animDelta:$animDelta" + } + + // Exit animation if snap target was updated + if (snapTargetUpdated) cancelAnimation() + + scrollBy(animDelta) + prevPosition = value + + if (latestCenterItem != rotaryScrollAdapter.currentItemIndex()) { + continueFirstScroll = true + cancelAnimation() + return@animateTo + } + + debugLog { "centerItemIndex = ${rotaryScrollAdapter.currentItemIndex()}" } + if (rotaryScrollAdapter.currentItemIndex() == snapTarget) { + debugLog { "Target is visible. Cancelling first animation" } + debugLog { + "scrollableState.centerItemScrollOffset " + + "${rotaryScrollAdapter.currentItemOffset()}" + } + expectedDistance = -rotaryScrollAdapter.currentItemOffset() + continueFirstScroll = false + cancelAnimation() + return@animateTo + } + } + } + // Exit animation if snap target was updated + if (snapTargetUpdated) continue + + anim = anim.copy(0f) + var prevPosition = 0f + anim.animateTo( + expectedDistance, + animationSpec = SpringSpec( + stiffness = defaultStiffness, + visibilityThreshold = 0.1f, + ), + sequentialAnimation = (anim.velocity != 0f), + ) { + // Exit animation if snap target was updated + if (snapTargetUpdated) cancelAnimation() + + val animDelta = value - prevPosition + debugLog { "Final animation. velocity:$velocity, animDelta:$animDelta" } + scrollBy(animDelta) + prevPosition = value + } + } + } + } + + private fun expectedDistanceTo(index: Int, targetScrollOffset: Int): Float { + val averageSize = rotaryScrollAdapter.averageItemSize() + val indexesDiff = index - rotaryScrollAdapter.currentItemIndex() + debugLog { "Average size $averageSize" } + return (averageSize * indexesDiff) + + targetScrollOffset - rotaryScrollAdapter.currentItemOffset() + } +} + +/** + * A modifier which handles rotary events. + * It accepts ScrollHandler as the input - a class where main logic about how + * scroll should be handled is lying + */ +@ExperimentalHorologistApi +@OptIn(ExperimentalComposeUiApi::class) +public fun Modifier.rotaryHandler( + rotaryScrollHandler: RotaryScrollHandler, + // TODO: batching causes additional delays. Return once it's clear that + // we will use it + /* batchTimeframe: Long = 0L,*/ + reverseDirection: Boolean, + rotaryHaptics: RotaryHapticHandler, +): Modifier = composed { + val channel = rememberTimestampChannel() + val eventsFlow = remember(channel) { channel.receiveAsFlow() } + + composed { + LaunchedEffect(eventsFlow) { + eventsFlow + // TODO: batching causes additional delays. Return once it's clear that + // we will use it + // Do we really need to do this on this level? +// .batchRequestsWithinTimeframe(batchTimeframe) + .collectLatest { + debugLog { + "Scroll event received: " + + "delta:${it.delta}, timestamp:${it.timestamp}" + } + rotaryScrollHandler.handleScrollEvent(this, it, rotaryHaptics) + } + } + this + .onRotaryScrollEvent { + // Okay to ignore the ChannelResult returned from trySend because it is conflated + // (see rememberTimestampChannel()). + @Suppress("UNUSED_VARIABLE") + val unused = channel.trySend( + TimestampedDelta( + it.uptimeMillis, + it.verticalScrollPixels * if (reverseDirection) -1f else 1f, + ), + ) + true + } + } +} + +/** + * Batching requests for scrolling events. This function combines all events together + * (except first) within specified timeframe. Should help with performance on high-res devices. + */ +@ExperimentalHorologistApi +@OptIn(ExperimentalCoroutinesApi::class) +public fun Flow<TimestampedDelta>.batchRequestsWithinTimeframe( + timeframe: Long +): Flow<TimestampedDelta> { + var delta = 0f + var lastTimestamp = -timeframe + return if (timeframe == 0L) { + this + } else { + this.transformLatest { + delta += it.delta + debugLog { "Batching requests. delta:$delta" } + if (lastTimestamp + timeframe <= it.timestamp) { + lastTimestamp = it.timestamp + debugLog { "No events before, delta= $delta" } + emit(TimestampedDelta(it.timestamp, delta)) + } else { + delay(timeframe) + debugLog { "After delay, delta= $delta" } + if (delta > 0f) { + emit(TimestampedDelta(it.timestamp, delta)) + } + } + delta = 0f + } + } +} + +/** + * A scroll handler for RSB(high-res) without snapping and with or without fling + * A list is scrolled by the number of pixels received from the rotary device. + * + * This class is a little bit different from LowResScrollHandler class - it has a filtering + * for events which are coming with wrong sign ( this happens to rsb devices, + * especially at the end of the scroll) + * + * This scroll handler supports fling. It can be set with [RotaryFlingBehavior]. + */ +internal class HighResRotaryScrollHandler( + private val rotaryFlingBehaviorFactory: () -> RotaryFlingBehavior?, + private val scrollBehaviorFactory: () -> RotaryScrollBehavior, + private val hapticsThreshold: Long = 50, +) : RotaryScrollHandler { + + // This constant is specific for high-res devices. Because that input values + // can sometimes come with different sign, we have to filter them in this threshold + private val gestureThresholdTime = 200L + private var scrollJob: Job = CompletableDeferred<Unit>() + private var flingJob: Job = CompletableDeferred<Unit>() + + private var previousScrollEventTime = 0L + private var rotaryScrollDistance = 0f + + private var rotaryFlingBehavior: RotaryFlingBehavior? = rotaryFlingBehaviorFactory() + private var scrollBehavior: RotaryScrollBehavior = scrollBehaviorFactory() + + override suspend fun handleScrollEvent( + coroutineScope: CoroutineScope, + event: TimestampedDelta, + rotaryHaptics: RotaryHapticHandler, + ) { + val time = event.timestamp + val isOppositeScrollValue = isOppositeValueAfterScroll(event.delta) + + if (isNewScrollEvent(time)) { + debugLog { "New scroll event" } + resetTracking(time) + rotaryScrollDistance = event.delta + } else { + // Due to the physics of Rotary side button, some events might come + // with an opposite axis value - either at the start or at the end of the motion. + // We don't want to use these values for fling calculations. + if (!isOppositeScrollValue) { + rotaryFlingBehavior?.observeEvent(event.timestamp, event.delta) + } else { + debugLog { "Opposite value after scroll :${event.delta}" } + } + rotaryScrollDistance += event.delta + } + + scrollJob.cancel() + + rotaryHaptics.handleScrollHaptic(event.delta) + debugLog { "Rotary scroll distance: $rotaryScrollDistance" } + + previousScrollEventTime = time + scrollJob = coroutineScope.async { + scrollBehavior.handleEvent(rotaryScrollDistance) + } + + if (rotaryFlingBehavior != null) { + flingJob.cancel() + flingJob = coroutineScope.async { + rotaryFlingBehavior?.trackFling(beforeFling = { + debugLog { "Calling before fling section" } + scrollJob.cancel() + scrollBehavior = scrollBehaviorFactory() + }) + } + } + } + + private fun isOppositeValueAfterScroll(delta: Float): Boolean = + sign(rotaryScrollDistance) * sign(delta) == -1f && + (abs(delta) < abs(rotaryScrollDistance)) + + private fun isNewScrollEvent(timestamp: Long): Boolean { + val timeDelta = timestamp - previousScrollEventTime + return previousScrollEventTime == 0L || timeDelta > gestureThresholdTime + } + + private fun resetTracking(timestamp: Long) { + scrollBehavior = scrollBehaviorFactory() + rotaryFlingBehavior = rotaryFlingBehaviorFactory() + rotaryFlingBehavior?.startFlingTracking(timestamp) + } +} + +/** + * A scroll handler for Bezel(low-res) without snapping. + * This scroll handler supports fling. It can be set with RotaryFlingBehavior. + */ +internal class LowResRotaryScrollHandler( + private val rotaryFlingBehaviorFactory: () -> RotaryFlingBehavior?, + private val scrollBehaviorFactory: () -> RotaryScrollBehavior, +) : RotaryScrollHandler { + + private val gestureThresholdTime = 200L + private var previousScrollEventTime = 0L + private var rotaryScrollDistance = 0f + + private var scrollJob: Job = CompletableDeferred<Unit>() + private var flingJob: Job = CompletableDeferred<Unit>() + + private var rotaryFlingBehavior: RotaryFlingBehavior? = rotaryFlingBehaviorFactory() + private var scrollBehavior: RotaryScrollBehavior = scrollBehaviorFactory() + + override suspend fun handleScrollEvent( + coroutineScope: CoroutineScope, + event: TimestampedDelta, + rotaryHaptics: RotaryHapticHandler, + ) { + val time = event.timestamp + + if (isNewScrollEvent(time)) { + resetTracking(time) + rotaryScrollDistance = event.delta + } else { + rotaryFlingBehavior?.observeEvent(event.timestamp, event.delta) + rotaryScrollDistance += event.delta + } + + scrollJob.cancel() + flingJob.cancel() + + rotaryHaptics.handleScrollHaptic(event.delta) + debugLog { "Rotary scroll distance: $rotaryScrollDistance" } + + previousScrollEventTime = time + scrollJob = coroutineScope.async { + scrollBehavior.handleEvent(rotaryScrollDistance) + } + + flingJob = coroutineScope.async { + rotaryFlingBehavior?.trackFling( + beforeFling = { + debugLog { "Calling before fling section" } + scrollJob.cancel() + scrollBehavior = scrollBehaviorFactory() + }, + ) + } + } + + private fun isNewScrollEvent(timestamp: Long): Boolean { + val timeDelta = timestamp - previousScrollEventTime + return previousScrollEventTime == 0L || timeDelta > gestureThresholdTime + } + + private fun resetTracking(timestamp: Long) { + scrollBehavior = scrollBehaviorFactory() + debugLog { "Velocity tracker reset" } + rotaryFlingBehavior = rotaryFlingBehaviorFactory() + rotaryFlingBehavior?.startFlingTracking(timestamp) + } +} + +/** + * A scroll handler for RSB(high-res) with snapping and without fling + * Snapping happens after a threshold is reached ( set in [RotarySnapBehavior]) + * + * This scroll handler doesn't support fling. + */ +internal class HighResSnapHandler( + private val resistanceFactor: Float, + private val thresholdBehaviorFactory: () -> ThresholdBehavior, + private val snapBehaviourFactory: () -> RotarySnapBehavior, + private val scrollBehaviourFactory: () -> RotaryScrollBehavior, +) : RotaryScrollHandler { + private val gestureThresholdTime = 200L + private val snapDelay = 100L + private val maxSnapsPerEvent = 2 + + private var scrollJob: Job = CompletableDeferred<Unit>() + private var snapJob: Job = CompletableDeferred<Unit>() + + private var previousScrollEventTime = 0L + private var snapAccumulator = 0f + private var rotaryScrollDistance = 0f + private var scrollInProgress = false + + private var snapBehaviour = snapBehaviourFactory() + private var scrollBehaviour = scrollBehaviourFactory() + private var thresholdBehavior = thresholdBehaviorFactory() + + private val scrollEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 0.5f, 1.0f) + + override suspend fun handleScrollEvent( + coroutineScope: CoroutineScope, + event: TimestampedDelta, + rotaryHaptics: RotaryHapticHandler, + ) { + val time = event.timestamp + + if (isNewScrollEvent(time)) { + debugLog { "New scroll event" } + resetTracking() + snapJob.cancel() + snapBehaviour = snapBehaviourFactory() + scrollBehaviour = scrollBehaviourFactory() + thresholdBehavior = thresholdBehaviorFactory() + thresholdBehavior.startThresholdTracking(time) + snapAccumulator = 0f + rotaryScrollDistance = 0f + } + + if (!isOppositeValueAfterScroll(event.delta)) { + thresholdBehavior.observeEvent(event.timestamp, event.delta) + } else { + debugLog { "Opposite value after scroll :${event.delta}" } + } + + thresholdBehavior.applySmoothing() + val snapThreshold = thresholdBehavior.snapThreshold() + + snapAccumulator += event.delta + if (!snapJob.isActive) { + val resistanceCoeff = + 1 - scrollEasing.transform(rotaryScrollDistance.absoluteValue / snapThreshold) + rotaryScrollDistance += event.delta * resistanceCoeff + } + + debugLog { "Snap accumulator: $snapAccumulator" } + debugLog { "Rotary scroll distance: $rotaryScrollDistance" } + + debugLog { "snapThreshold: $snapThreshold" } + previousScrollEventTime = time + + if (abs(snapAccumulator) > snapThreshold) { + scrollInProgress = false + scrollBehaviour = scrollBehaviourFactory() + scrollJob.cancel() + + val snapDistance = (snapAccumulator / snapThreshold).toInt() + .coerceIn(-maxSnapsPerEvent..maxSnapsPerEvent) + snapAccumulator -= snapThreshold * snapDistance + val sequentialSnap = snapJob.isActive + + debugLog { + "Snap threshold reached: snapDistance:$snapDistance, " + + "sequentialSnap: $sequentialSnap, " + + "snap accumulator remaining: $snapAccumulator" + } + if ((!snapBehaviour.topEdgeReached() && snapDistance < 0) || + (!snapBehaviour.bottomEdgeReached() && snapDistance > 0) + ) { + rotaryHaptics.handleSnapHaptic(event.delta) + } + + snapBehaviour.prepareSnapForItems(snapDistance, sequentialSnap) + if (!snapJob.isActive) { + snapJob.cancel() + snapJob = coroutineScope.async { + debugLog { "Snap started" } + try { + snapBehaviour.snapToTargetItem() + } finally { + debugLog { "Snap called finally" } + } + } + } + rotaryScrollDistance = 0f + } else { + if (!snapJob.isActive) { + scrollJob.cancel() + debugLog { "Scrolling for $rotaryScrollDistance/$resistanceFactor px" } + scrollJob = coroutineScope.async { + scrollBehaviour.handleEvent(rotaryScrollDistance / resistanceFactor) + } + delay(snapDelay) + scrollInProgress = false + scrollBehaviour = scrollBehaviourFactory() + rotaryScrollDistance = 0f + snapAccumulator = 0f + snapBehaviour.prepareSnapForItems(0, false) + + snapJob.cancel() + snapJob = coroutineScope.async { + snapBehaviour.snapToClosestItem() + } + } + } + } + + private fun isOppositeValueAfterScroll(delta: Float): Boolean = + sign(rotaryScrollDistance) * sign(delta) == -1f && + (abs(delta) < abs(rotaryScrollDistance)) + + private fun isNewScrollEvent(timestamp: Long): Boolean { + val timeDelta = timestamp - previousScrollEventTime + return previousScrollEventTime == 0L || timeDelta > gestureThresholdTime + } + + private fun resetTracking() { + scrollInProgress = true + } +} + +/** + * A scroll handler for RSB(high-res) with snapping and without fling + * Snapping happens after a threshold is reached ( set in [RotarySnapBehavior]) + * + * This scroll handler doesn't support fling. + */ +internal class LowResSnapHandler( + private val snapBehaviourFactory: () -> RotarySnapBehavior, +) : RotaryScrollHandler { + private val gestureThresholdTime = 200L + + private var snapJob: Job = CompletableDeferred<Unit>() + + private var previousScrollEventTime = 0L + private var snapAccumulator = 0f + private var scrollInProgress = false + + private var snapBehaviour = snapBehaviourFactory() + + override suspend fun handleScrollEvent( + coroutineScope: CoroutineScope, + event: TimestampedDelta, + rotaryHaptics: RotaryHapticHandler, + ) { + val time = event.timestamp + + if (isNewScrollEvent(time)) { + debugLog { "New scroll event" } + resetTracking() + snapJob.cancel() + snapBehaviour = snapBehaviourFactory() + snapAccumulator = 0f + } + + snapAccumulator += event.delta + + debugLog { "Snap accumulator: $snapAccumulator" } + + previousScrollEventTime = time + + if (abs(snapAccumulator) > 1f) { + scrollInProgress = false + + val snapDistance = sign(snapAccumulator).toInt() + rotaryHaptics.handleSnapHaptic(event.delta) + val sequentialSnap = snapJob.isActive + debugLog { + "Snap threshold reached: snapDistance:$snapDistance, " + + "sequentialSnap: $sequentialSnap, " + + "snap accumulator: $snapAccumulator" + } + + snapBehaviour.prepareSnapForItems(snapDistance, sequentialSnap) + if (!snapJob.isActive) { + snapJob.cancel() + snapJob = coroutineScope.async { + debugLog { "Snap started" } + try { + snapBehaviour.snapToTargetItem() + } finally { + debugLog { "Snap called finally" } + } + } + } + snapAccumulator = 0f + } + } + + private fun isNewScrollEvent(timestamp: Long): Boolean { + val timeDelta = timestamp - previousScrollEventTime + return previousScrollEventTime == 0L || timeDelta > gestureThresholdTime + } + + private fun resetTracking() { + scrollInProgress = true + } +} + +internal class ThresholdBehavior( + private val rotaryScrollAdapter: RotaryScrollAdapter, + private val thresholdDivider: Float, + private val minVelocity: Float = 300f, + private val maxVelocity: Float = 3000f, + private val smoothingConstant: Float = 0.4f, +) { + private val thresholdDividerEasing: Easing = CubicBezierEasing(0.5f, 0.0f, 0.5f, 1.0f) + + private val rotaryVelocityTracker = RotaryVelocityTracker() + + private var smoothedVelocity = 0f + fun startThresholdTracking(time: Long) { + rotaryVelocityTracker.start(time) + smoothedVelocity = 0f + } + + fun observeEvent(timestamp: Long, delta: Float) { + rotaryVelocityTracker.move(timestamp, delta) + } + + fun applySmoothing() { + if (rotaryVelocityTracker.velocity != 0.0f) { + // smooth the velocity + smoothedVelocity = exponentialSmoothing( + currentVelocity = rotaryVelocityTracker.velocity.absoluteValue, + prevVelocity = smoothedVelocity, + smoothingConstant = smoothingConstant, + ) + } + debugLog { "rotaryVelocityTracker velocity: ${rotaryVelocityTracker.velocity}" } + debugLog { "SmoothedVelocity: $smoothedVelocity" } + } + + fun snapThreshold(): Float { + val thresholdDividerFraction = + thresholdDividerEasing.transform( + inverseLerp( + minVelocity, + maxVelocity, + smoothedVelocity, + ), + ) + return rotaryScrollAdapter.averageItemSize() / lerp( + 1f, + thresholdDivider, + thresholdDividerFraction, + ) + } + + private fun exponentialSmoothing( + currentVelocity: Float, + prevVelocity: Float, + smoothingConstant: Float, + ): Float = + smoothingConstant * currentVelocity + (1 - smoothingConstant) * prevVelocity +} + +@Composable +private fun rememberTimestampChannel() = remember { + Channel<TimestampedDelta>(capacity = Channel.CONFLATED) +} + +private fun inverseLerp(start: Float, stop: Float, value: Float): Float { + return ((value - start) / (stop - start)).coerceIn(0f, 1f) +} diff --git a/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/rotaryinput/RotaryVelocityTracker.kt b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/rotaryinput/RotaryVelocityTracker.kt new file mode 100644 index 000000000000..6e627c635425 --- /dev/null +++ b/packages/CredentialManager/horologist/src/com/google/android/horologist/compose/rotaryinput/RotaryVelocityTracker.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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.horologist.compose.rotaryinput + +import androidx.compose.ui.input.pointer.util.VelocityTracker1D + +/** + * A wrapper around VelocityTracker1D to provide support for rotary input. + */ +public class RotaryVelocityTracker { + private var velocityTracker: VelocityTracker1D = VelocityTracker1D(true) + + /** + * Retrieve the last computed velocity. + */ + public val velocity: Float + get() = velocityTracker.calculateVelocity() + + /** + * Start tracking motion. + */ + public fun start(currentTime: Long) { + velocityTracker.resetTracking() + velocityTracker.addDataPoint(currentTime, 0f) + } + + /** + * Continue tracking motion as the input rotates. + */ + public fun move(currentTime: Long, delta: Float) { + velocityTracker.addDataPoint(currentTime, delta) + } + + /** + * Stop tracking motion. + */ + public fun end() { + velocityTracker.resetTracking() + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index 8361877744cf..473d7b6f32df 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -19,6 +19,7 @@ package com.android.credentialmanager import android.app.slice.Slice import android.content.ComponentName import android.content.Context +import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.credentials.Credential.TYPE_PASSWORD_CREDENTIAL import android.credentials.ui.AuthenticationEntry @@ -67,7 +68,7 @@ fun getAppLabel( appPackageName: String ): String? { return try { - val pkgInfo = pm.getPackageInfo(appPackageName, PackageManager.PackageInfoFlags.of(0)) + val pkgInfo = getPackageInfo(pm, appPackageName) val applicationInfo = checkNotNull(pkgInfo.applicationInfo) applicationInfo.loadSafeLabel( pm, 0f, @@ -90,10 +91,7 @@ private fun getServiceLabelAndIcon( // Test data has only package name not component name. // For test data usage only. try { - val pkgInfo = pm.getPackageInfo( - providerFlattenedComponentName, - PackageManager.PackageInfoFlags.of(0) - ) + val pkgInfo = getPackageInfo(pm, providerFlattenedComponentName) val applicationInfo = checkNotNull(pkgInfo.applicationInfo) providerLabel = applicationInfo.loadSafeLabel( @@ -117,10 +115,7 @@ private fun getServiceLabelAndIcon( // Added for mdoc use case where the provider may not need to register a service and // instead only relies on the registration api. try { - val pkgInfo = pm.getPackageInfo( - component.packageName, - PackageManager.PackageInfoFlags.of(0) - ) + val pkgInfo = getPackageInfo(pm, providerFlattenedComponentName) val applicationInfo = checkNotNull(pkgInfo.applicationInfo) providerLabel = applicationInfo.loadSafeLabel( @@ -144,6 +139,19 @@ private fun getServiceLabelAndIcon( } } +private fun getPackageInfo( + pm: PackageManager, + packageName: String +): PackageInfo { + val flags = PackageManager.MATCH_INSTANT + + return pm.getPackageInfo( + packageName, + PackageManager.PackageInfoFlags.of( + (flags).toLong()) + ) +} + /** Utility functions for converting CredentialManager data structures to or from UI formats. */ class GetFlowUtils { companion object { diff --git a/packages/CredentialManager/wear/Android.bp b/packages/CredentialManager/wear/Android.bp new file mode 100644 index 000000000000..639e8d18b306 --- /dev/null +++ b/packages/CredentialManager/wear/Android.bp @@ -0,0 +1,53 @@ +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"], +} + +android_app { + name: "ClockworkCredentialManager", + defaults: ["platform_app_defaults"], + certificate: "platform", + manifest: "AndroidManifest.xml", + srcs: ["src/**/*.kt"], + resource_dirs: ["res"], + + dex_preopt: { + profile_guided: true, + profile: "profile.txt.prof", + }, + + static_libs: [ + "Horologist", + "PlatformComposeCore", + "androidx.activity_activity-compose", + "androidx.appcompat_appcompat", + "androidx.compose.foundation_foundation", + "androidx.compose.foundation_foundation-layout", + "androidx.compose.material_material-icons-core", + "androidx.compose.material_material-icons-extended", + "androidx.compose.runtime_runtime", + "androidx.compose.ui_ui", + "androidx.core_core-ktx", + "androidx.lifecycle_lifecycle-extensions", + "androidx.lifecycle_lifecycle-livedata", + "androidx.lifecycle_lifecycle-runtime-ktx", + "androidx.lifecycle_lifecycle-viewmodel-compose", + "androidx.wear.compose_compose-foundation", + "androidx.wear.compose_compose-material", + "androidx.wear.compose_compose-navigation", + "kotlinx-coroutines-core", + ], + + platform_apis: true, + privileged: true, + + kotlincflags: ["-Xjvm-default=all"], + + optimize: { + proguard_compatibility: false, + }, +} diff --git a/packages/CredentialManager/wear/AndroidManifest.xml b/packages/CredentialManager/wear/AndroidManifest.xml index 001a56ddcb0b..90248734ca7f 100644 --- a/packages/CredentialManager/wear/AndroidManifest.xml +++ b/packages/CredentialManager/wear/AndroidManifest.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <!-- /* - * Copyright (c) 2017 Google Inc. + * Copyright (c) 2023 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.credentialmanager"> + <uses-feature android:name="android.hardware.type.watch" /> + <uses-permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/> @@ -28,17 +30,15 @@ android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:label="@string/app_name" - android:supportsRtl="true" - android:theme="@style/Theme.CredentialSelector"> + android:supportsRtl="true"> <activity - android:name=".CredentialSelectorActivity" + android:name=".ui.CredentialSelectorActivity" android:exported="true" android:permission="android.permission.LAUNCH_CREDENTIAL_SELECTOR" android:launchMode="singleTop" android:label="@string/app_name" - android:excludeFromRecents="true" - android:theme="@style/Theme.CredentialSelector"> + android:excludeFromRecents="true"> </activity> </application> diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/CredentialSelectorActivity.kt index f7b249931871..77fffaa1e04c 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/CredentialSelectorActivity.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,19 +14,29 @@ * limitations under the License. */ +package com.android.credentialmanager.ui + import android.os.Bundle -import androidx.activity.compose.setContent import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.navigation.NavHostController import androidx.wear.compose.material.MaterialTheme -import androidx.wear.compose.material.Text +import androidx.wear.compose.navigation.rememberSwipeDismissableNavController class CredentialSelectorActivity : ComponentActivity() { + + lateinit var navController: NavHostController + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setTheme(android.R.style.Theme_DeviceDefault) + setContent { + navController = rememberSwipeDismissableNavController() + MaterialTheme { - Text("Credential Manager entry point") + WearApp(navController = navController) } } } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/Screen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/Screen.kt new file mode 100644 index 000000000000..ee6ea5e57c19 --- /dev/null +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/Screen.kt @@ -0,0 +1,23 @@ +/* + * 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.0N + * + * 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.credentialmanager.ui + +sealed class Screen( + val route: String, +) { + object Main : Screen("main") +} diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt new file mode 100644 index 000000000000..5ec0c8cd9292 --- /dev/null +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt @@ -0,0 +1,47 @@ +/* + * 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.0N + * + * 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. + */ + +@file:OptIn(ExperimentalHorologistApi::class) + +package com.android.credentialmanager.ui + +import androidx.compose.runtime.Composable +import androidx.navigation.NavHostController +import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState +import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState +import com.android.credentialmanager.ui.screens.MainScreen +import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.compose.navscaffold.WearNavScaffold +import com.google.android.horologist.compose.navscaffold.composable + +@Composable +fun WearApp( + navController: NavHostController +) { + val swipeToDismissBoxState = rememberSwipeToDismissBoxState() + val navHostState = + rememberSwipeDismissableNavHostState(swipeToDismissBoxState = swipeToDismissBoxState) + + WearNavScaffold( + startDestination = Screen.Main.route, + navController = navController, + state = navHostState, + ) { + composable(Screen.Main.route) { + MainScreen() + } + } +} diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/MainScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/MainScreen.kt new file mode 100644 index 000000000000..662d7108ab90 --- /dev/null +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/MainScreen.kt @@ -0,0 +1,30 @@ +/* + * 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.0N + * + * 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.credentialmanager.ui.screens + +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.wear.compose.material.Text + +@Composable +fun MainScreen(modifier: Modifier = Modifier) { + Box(modifier = modifier, contentAlignment = Alignment.Center) { + Text("This is a placeholder for the main screen.") + } +} 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 cfd1a50abb4c..01596d2bc004 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 @@ -45,6 +45,7 @@ import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider import com.android.settingslib.spa.gallery.preference.PreferencePageProvider import com.android.settingslib.spa.gallery.preference.SwitchPreferencePageProvider import com.android.settingslib.spa.gallery.preference.TwoTargetSwitchPreferencePageProvider +import com.android.settingslib.spa.gallery.scaffold.SearchScaffoldPageProvider import com.android.settingslib.spa.gallery.ui.CategoryPageProvider import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider import com.android.settingslib.spa.slice.SpaSliceBroadcastReceiver @@ -94,6 +95,7 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) { SettingsExposedDropdownMenuBoxPageProvider, SettingsExposedDropdownMenuCheckBoxProvider, SettingsTextFieldPasswordPageProvider, + SearchScaffoldPageProvider, ), rootPages = listOf( HomePageProvider.createSettingsPage(), diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt index 6d22e6abf7e3..5ffbe8ba8a26 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt @@ -19,7 +19,7 @@ package com.android.settingslib.spa.gallery.editor import android.os.Bundle import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.tooling.preview.Preview @@ -45,13 +45,13 @@ object SettingsExposedDropdownMenuBoxPageProvider : SettingsPageProvider { @Composable override fun Page(arguments: Bundle?) { - var selectedItem by remember { mutableStateOf("item1") } + var selectedItem by remember { mutableIntStateOf(-1) } val options = listOf("item1", "item2", "item3") RegularScaffold(title = TITLE) { SettingsExposedDropdownMenuBox( label = exposedDropdownMenuBoxLabel, options = options, - selectedOptionText = selectedItem, + selectedOptionIndex = selectedItem, enabled = true, onselectedOptionTextChange = { selectedItem = it }) } 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 6cac2202742a..b339b4482137 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 @@ -41,6 +41,7 @@ import com.android.settingslib.spa.gallery.page.ProgressBarPageProvider import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider import com.android.settingslib.spa.gallery.page.SliderPageProvider import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider +import com.android.settingslib.spa.gallery.scaffold.SearchScaffoldPageProvider import com.android.settingslib.spa.gallery.ui.CategoryPageProvider import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider import com.android.settingslib.spa.widget.scaffold.HomeScaffold @@ -55,6 +56,7 @@ object HomePageProvider : SettingsPageProvider { PreferenceMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), OperateListPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), ArgumentPageProvider.buildInjectEntry("foo")!!.setLink(fromPage = owner).build(), + SearchScaffoldPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), SliderPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), SpinnerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), SettingsPagerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt new file mode 100644 index 000000000000..a1ab35b14749 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt @@ -0,0 +1,56 @@ +/* + * 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.scaffold + +import android.os.Bundle +import androidx.compose.runtime.Composable +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.scaffold.SearchScaffold +import com.android.settingslib.spa.widget.ui.PlaceholderTitle + +private const val TITLE = "Sample SearchScaffold" + +object SearchScaffoldPageProvider : SettingsPageProvider { + override val name = "SearchScaffold" + + private val owner = createSettingsPage() + + fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = owner) + .setUiLayoutFn { + Preference(object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + }) + } + + @Composable + override fun Page(arguments: Bundle?) { + Page() + } +} + +@Composable +private fun Page() { + SearchScaffold(title = TITLE) { bottomPadding, searchQuery -> + PlaceholderTitle("Search query: ${searchQuery.value}") + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt index ec43aab66ee0..0d6c064998ae 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt @@ -41,9 +41,9 @@ import com.android.settingslib.spa.framework.theme.SettingsTheme fun SettingsExposedDropdownMenuBox( label: String, options: List<String>, - selectedOptionText: String, + selectedOptionIndex: Int, enabled: Boolean, - onselectedOptionTextChange: (String) -> Unit, + onselectedOptionTextChange: (Int) -> Unit, ) { var expanded by remember { mutableStateOf(false) } ExposedDropdownMenuBox( @@ -58,8 +58,8 @@ fun SettingsExposedDropdownMenuBox( modifier = Modifier .menuAnchor() .fillMaxWidth(), - value = selectedOptionText, - onValueChange = onselectedOptionTextChange, + value = options.getOrElse(selectedOptionIndex) { "" }, + onValueChange = { }, label = { Text(text = label) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon( @@ -81,7 +81,7 @@ fun SettingsExposedDropdownMenuBox( DropdownMenuItem( text = { Text(option) }, onClick = { - onselectedOptionTextChange(option) + onselectedOptionTextChange(options.indexOf(option)) expanded = false }, contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, @@ -103,7 +103,7 @@ private fun SettingsExposedDropdownMenuBoxsPreview() { SettingsExposedDropdownMenuBox( label = "ExposedDropdownMenuBoxLabel", options = options, - selectedOptionText = item1, + selectedOptionIndex = 0, enabled = true, onselectedOptionTextChange = {}) } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBox.kt index 32600943ac80..a25818553c05 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBox.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuCheckBox.kt @@ -31,6 +31,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -54,7 +55,7 @@ fun SettingsExposedDropdownMenuCheckBox( enabled: Boolean, onSelectedOptionStateChange: () -> Unit, ) { - var dropDownWidth by remember { mutableStateOf(0) } + var dropDownWidth by remember { mutableIntStateOf(0) } var expanded by remember { mutableStateOf(false) } ExposedDropdownMenuBox( expanded = expanded, @@ -104,7 +105,7 @@ fun SettingsExposedDropdownMenuCheckBox( ) } onSelectedOptionStateChange() - }) { + }) { Row( modifier = Modifier .fillMaxHeight() diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt index 09f59457b32d..bc67e4c61ea5 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt @@ -17,6 +17,7 @@ package com.android.settingslib.spa.widget.editor import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -40,13 +41,13 @@ class SettingsExposedDropdownMenuBoxTest { @Test fun exposedDropdownMenuBoxs_displayed() { composeTestRule.setContent { - var selectedItem by remember { mutableStateOf("item1") } + var selectedItem by remember { mutableStateOf(0) } SettingsExposedDropdownMenuBox( label = exposedDropdownMenuBoxLabel, options = options, - selectedOptionText = selectedItem, + selectedOptionIndex = selectedItem, enabled = true, - onselectedOptionTextChange = {selectedItem = it}) + onselectedOptionTextChange = { selectedItem = it }) } composeTestRule.onNodeWithText(exposedDropdownMenuBoxLabel, substring = true) .assertIsDisplayed() @@ -55,13 +56,13 @@ class SettingsExposedDropdownMenuBoxTest { @Test fun exposedDropdownMenuBoxs_expanded() { composeTestRule.setContent { - var selectedItem by remember { mutableStateOf("item1") } + var selectedItem by remember { mutableIntStateOf(0) } SettingsExposedDropdownMenuBox( label = exposedDropdownMenuBoxLabel, options = options, - selectedOptionText = selectedItem, + selectedOptionIndex = selectedItem, enabled = true, - onselectedOptionTextChange = {selectedItem = it}) + onselectedOptionTextChange = { selectedItem = it }) } composeTestRule.onNodeWithText(item2, substring = true) .assertDoesNotExist() @@ -74,13 +75,13 @@ class SettingsExposedDropdownMenuBoxTest { @Test fun exposedDropdownMenuBoxs_valueChanged() { composeTestRule.setContent { - var selectedItem by remember { mutableStateOf("item1") } + var selectedItem by remember { mutableIntStateOf(0) } SettingsExposedDropdownMenuBox( label = exposedDropdownMenuBoxLabel, options = options, - selectedOptionText = selectedItem, + selectedOptionIndex = selectedItem, enabled = true, - onselectedOptionTextChange = {selectedItem = it}) + onselectedOptionTextChange = { selectedItem = it }) } composeTestRule.onNodeWithText(item2, substring = true) .assertDoesNotExist() diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 8dc95f4a5be4..f9ea7735681f 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1254,7 +1254,6 @@ <!-- Summary to show how many devices are connected in wifi hotspot [CHAR LIMIT=NONE] --> <string name="wifi_tether_connected_summary"> {count, plural, - =0 {0 device connected} =1 {1 device connected} other {# devices connected} } diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 77925d6f03cd..608010156fcf 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -203,6 +203,9 @@ android_library { "LowLightDreamLib", "motion_tool_lib", ], + libs: [ + "keepanno-annotations", + ], manifest: "AndroidManifest.xml", javacflags: ["-Adagger.fastInit=enabled"], @@ -466,6 +469,7 @@ android_library { "android.test.runner", "android.test.base", "android.test.mock", + "keepanno-annotations", ], kotlincflags: ["-Xjvm-default=all"], aaptflags: [ @@ -497,6 +501,9 @@ android_app { static_libs: [ "SystemUI-tests-base", ], + libs: [ + "keepanno-annotations", + ], aaptflags: [ "--extra-packages", "com.android.systemui", diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING index cb9e9ee903c5..af6fa86bacf4 100644 --- a/packages/SystemUI/TEST_MAPPING +++ b/packages/SystemUI/TEST_MAPPING @@ -43,7 +43,9 @@ { "exclude-annotation": "android.platform.test.annotations.Postsubmit" } - ] + ], + // The test doesn't run on AOSP Cuttlefish + "keywords": ["internal"] }, { // TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+) @@ -55,7 +57,9 @@ { "exclude-annotation": "androidx.test.filters.FlakyTest" } - ] + ], + // The test doesn't run on AOSP Cuttlefish + "keywords": ["internal"] }, { // Permission indicators @@ -112,10 +116,8 @@ "include-filter": "android.permissionui.cts.CameraMicIndicatorsPermissionTest" } ] - } - ], - "postsubmit": [ - { + }, + { "name": "SystemUIGoogleScreenshotTests", "options": [ { diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index 0c076169eb57..1b56d4a201d9 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -605,12 +605,28 @@ class ActivityLaunchAnimator( object : Controller by delegate { override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { listener?.onLaunchAnimationStart() + + if (DEBUG_LAUNCH_ANIMATION) { + Log.d( + TAG, + "Calling controller.onLaunchAnimationStart(isExpandingFullyAbove=" + + "$isExpandingFullyAbove) [controller=$delegate]" + ) + } delegate.onLaunchAnimationStart(isExpandingFullyAbove) } override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { listener?.onLaunchAnimationEnd() iCallback?.invoke() + + if (DEBUG_LAUNCH_ANIMATION) { + Log.d( + TAG, + "Calling controller.onLaunchAnimationEnd(isExpandingFullyAbove=" + + "$isExpandingFullyAbove) [controller=$delegate]" + ) + } delegate.onLaunchAnimationEnd(isExpandingFullyAbove) } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt index 753672820e28..88944f10eab9 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt @@ -107,6 +107,9 @@ private fun CoroutineScope.animate( reversed: Boolean = false, ) { val fromScene = layoutImpl.state.transitionState.currentScene + val isUserInput = + (layoutImpl.state.transitionState as? TransitionState.Transition)?.isUserInputDriven + ?: false val animationSpec = layoutImpl.transitions.transitionSpec(fromScene, target).spec val visibilityThreshold = @@ -116,9 +119,9 @@ private fun CoroutineScope.animate( val targetProgress = if (reversed) 0f else 1f val transition = if (reversed) { - OneOffTransition(target, fromScene, currentScene = target, animatable) + OneOffTransition(target, fromScene, currentScene = target, isUserInput, animatable) } else { - OneOffTransition(fromScene, target, currentScene = target, animatable) + OneOffTransition(fromScene, target, currentScene = target, isUserInput, animatable) } // Change the current layout state to use this new transition. @@ -139,6 +142,7 @@ private class OneOffTransition( override val fromScene: SceneKey, override val toScene: SceneKey, override val currentScene: SceneKey, + override val isUserInputDriven: Boolean, private val animatable: Animatable<Float, AnimationVector1D>, ) : TransitionState.Transition { override val progress: Float diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt index a625250d1e51..ccdec6ea8c5e 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt @@ -42,6 +42,17 @@ sealed class ObservableTransitionState { val fromScene: SceneKey, val toScene: SceneKey, val progress: Flow<Float>, + + /** + * Whether the transition was originally triggered by user input rather than being + * programmatic. If this value is initially true, it will remain true until the transition + * fully completes, even if the user input that triggered the transition has ended. Any + * sub-transitions launched by this one will inherit this value. For example, if the user + * drags a pointer but does not exceed the threshold required to transition to another + * scene, this value will remain true after the pointer is no longer touching the screen and + * will be true in any transition created to animate back to the original position. + */ + val isUserInputDriven: Boolean, ) : ObservableTransitionState() } @@ -62,6 +73,7 @@ fun SceneTransitionLayoutState.observableTransitionState(): Flow<ObservableTrans fromScene = state.fromScene, toScene = state.toScene, progress = snapshotFlow { state.progress }, + isUserInputDriven = state.isUserInputDriven, ) } } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt index 47e3d5add27b..7a21211c3dde 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt @@ -68,5 +68,8 @@ sealed interface TransitionState { * when flinging quickly during a swipe gesture. */ val progress: Float + + /** Whether the transition was triggered by user input rather than being programmatic. */ + val isUserInputDriven: Boolean } } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt index 2069ebd32b81..790ea0832dbb 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt @@ -137,6 +137,8 @@ private class SwipeTransition(initialScene: Scene) : TransitionState.Transition return offset / distance } + override val isUserInputDriven = true + /** The current offset caused by the drag gesture. */ var dragOffset by mutableFloatStateOf(0f) diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt index cb2607a2845e..2232370f3dc0 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt @@ -122,6 +122,7 @@ class SwipeToSceneTest { assertThat(transition.toScene).isEqualTo(TestScenes.SceneB) assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA) assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth) + assertThat(transition.isUserInputDriven).isTrue() // Release the finger. We should now be animating back to A (currentScene = SceneA) given // that 55dp < positional threshold. @@ -133,6 +134,7 @@ class SwipeToSceneTest { assertThat(transition.toScene).isEqualTo(TestScenes.SceneB) assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA) assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth) + assertThat(transition.isUserInputDriven).isTrue() // Wait for the animation to finish. We should now be in scene A. rule.waitForIdle() @@ -154,6 +156,7 @@ class SwipeToSceneTest { assertThat(transition.toScene).isEqualTo(TestScenes.SceneC) assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA) assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight) + assertThat(transition.isUserInputDriven).isTrue() // Release the finger. We should now be animating to C (currentScene = SceneC) given // that 56dp >= positional threshold. @@ -165,6 +168,7 @@ class SwipeToSceneTest { assertThat(transition.toScene).isEqualTo(TestScenes.SceneC) assertThat(transition.currentScene).isEqualTo(TestScenes.SceneC) assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight) + assertThat(transition.isUserInputDriven).isTrue() // Wait for the animation to finish. We should now be in scene C. rule.waitForIdle() diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt index e06a69bfaa63..5505eaf8fd7e 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt @@ -82,7 +82,7 @@ constructor( ) : ComposableScene { override val key = SceneKey.Bouncer - override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = + override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> = MutableStateFlow( mapOf( UserAction.Back to SceneModel(SceneKey.Lockscreen), diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt index 463253b9fb41..f1da16862220 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt @@ -66,13 +66,13 @@ constructor( ) : ComposableScene { override val key = SceneKey.Lockscreen - override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = + override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> = viewModel.upDestinationSceneKey .map { pageKey -> destinationScenes(up = pageKey) } .stateIn( scope = applicationScope, started = SharingStarted.Eagerly, - initialValue = destinationScenes(up = null) + initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value) ) @Composable diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index 7ac39011d4da..1f9c3e6d1ea1 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -58,13 +58,14 @@ constructor( ) : ComposableScene { override val key = SceneKey.QuickSettings - override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = + private val _destinationScenes = MutableStateFlow<Map<UserAction, SceneModel>>( mapOf( UserAction.Swipe(Direction.UP) to SceneModel(SceneKey.Shade), ) ) .asStateFlow() + override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> = _destinationScenes @Composable override fun SceneScope.Content( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt index 40b0b4a3eaa3..2ee461fca042 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt @@ -38,7 +38,7 @@ import kotlinx.coroutines.flow.asStateFlow class GoneScene @Inject constructor() : ComposableScene { override val key = SceneKey.Gone - override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = + override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> = MutableStateFlow<Map<UserAction, SceneModel>>( mapOf( UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade), 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 6a5a368b3599..ef012660ad71 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 @@ -79,7 +79,7 @@ fun SceneContainer( val currentSceneKey = currentSceneModel.key val currentScene = checkNotNull(sceneByKey[currentSceneKey]) val currentDestinations: Map<UserAction, SceneModel> by - currentScene.destinationScenes().collectAsState() + currentScene.destinationScenes.collectAsState() val state = remember { SceneTransitionLayoutState(currentSceneKey.toTransitionSceneKey()) } val isRibbonEnabled = remember { SystemProperties.getBoolean("flexi.ribbon", false) } @@ -116,7 +116,7 @@ fun SceneContainer( if (sceneKey == currentSceneKey) { currentDestinations } else { - composableScene.destinationScenes().value + composableScene.destinationScenes.value } .map { (userAction, destinationSceneModel) -> toTransitionModels(userAction, destinationSceneModel) @@ -158,6 +158,7 @@ private fun SceneTransitionObservableTransitionState.toModel(): ObservableTransi fromScene = fromScene.toModel().key, toScene = toScene.toModel().key, progress = progress, + isUserInputDriven = isUserInputDriven, ) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index b1056376220f..8832a119dbfd 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -87,7 +87,7 @@ constructor( ) : ComposableScene { override val key = SceneKey.Shade - override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = + override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> = viewModel.upDestinationSceneKey .map { sceneKey -> destinationScenes(up = sceneKey) } .stateIn( diff --git a/packages/SystemUI/proguard_common.flags b/packages/SystemUI/proguard_common.flags index e2d889168516..be1e6554baf1 100644 --- a/packages/SystemUI/proguard_common.flags +++ b/packages/SystemUI/proguard_common.flags @@ -1,8 +1,5 @@ -keep class com.android.systemui.VendorServices -# the `#inject` methods are accessed via reflection to work on ContentProviders --keepclassmembers class * extends com.android.systemui.dagger.SysUIComponent { void inject(***); } - # Needed to ensure callback field references are kept in their respective # owning classes when the downstream callback registrars only store weak refs. # TODO(b/264686688): Handle these cases with more targeted annotations. diff --git a/packages/SystemUI/res/color/notification_overlay_color.xml b/packages/SystemUI/res/color/notification_overlay_color.xml new file mode 100644 index 000000000000..c24bff9c7271 --- /dev/null +++ b/packages/SystemUI/res/color/notification_overlay_color.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:state_pressed="true" android:color="?androidprv:attr/materialColorOnSurface" android:alpha="0.15" /> + <item android:state_hovered="true" android:color="?androidprv:attr/materialColorOnSurface" android:alpha="0.11" /> + <item android:color="@color/transparent" /> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml index 61a8e8e9c6e1..3eaa6180ba1b 100644 --- a/packages/SystemUI/res/drawable/notification_material_bg.xml +++ b/packages/SystemUI/res/drawable/notification_material_bg.xml @@ -15,7 +15,7 @@ ~ limitations under the License --> -<ripple xmlns:android="http://schemas.android.com/apk/res/android" +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:color="?android:attr/colorControlHighlight"> <item> @@ -23,4 +23,9 @@ <solid android:color="?androidprv:attr/colorSurface" /> </shape> </item> -</ripple>
\ No newline at end of file + <item> + <shape> + <solid android:color="@color/notification_overlay_color" /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml index 60a78d6346f1..beb481ae4ffc 100644 --- a/packages/SystemUI/res/layout/combined_qs_header.xml +++ b/packages/SystemUI/res/layout/combined_qs_header.xml @@ -130,6 +130,7 @@ frame when animating QS <-> QQS transition android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="right|center_vertical" + android:gravity="center_vertical" android:paddingStart="@dimen/hover_system_icons_container_padding_start" android:paddingEnd="@dimen/hover_system_icons_container_padding_end" android:paddingTop="@dimen/hover_system_icons_container_padding_top" diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml index f6ce70d4d032..dc560bf2fab7 100644 --- a/packages/SystemUI/res/layout/screen_record_dialog.xml +++ b/packages/SystemUI/res/layout/screen_record_dialog.xml @@ -150,19 +150,6 @@ android:layout_height="match_parent" android:layout_weight="1"/> - <!-- Temporary entrypoint for the partial screensharing used for teamfooding --> - <!-- TODO(b/236838395) remove this and use redesigned dialog --> - <TextView - android:id="@+id/button_app" - android:visibility="gone" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="0" - android:layout_gravity="end" - android:layout_marginEnd="8dp" - android:text="App" - style="@style/Widget.Dialog.Button.BorderButton" /> - <TextView android:id="@+id/button_start" android:layout_width="wrap_content" diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml index 356b36fdbcd6..fa7f9cf06145 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_row.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml @@ -30,12 +30,14 @@ <com.android.systemui.statusbar.notification.row.NotificationBackgroundView android:id="@+id/backgroundNormal" android:layout_width="match_parent" - android:layout_height="match_parent" /> + android:layout_height="match_parent" + android:duplicateParentState="true"/> <com.android.systemui.statusbar.notification.row.NotificationBackgroundView android:id="@+id/backgroundDimmed" android:layout_width="match_parent" - android:layout_height="match_parent" /> + android:layout_height="match_parent" + android:duplicateParentState="true"/> <com.android.systemui.statusbar.notification.row.NotificationContentView android:id="@+id/expanded" diff --git a/packages/SystemUI/res/values-land/bools.xml b/packages/SystemUI/res/values-land/bools.xml new file mode 100644 index 000000000000..e24792dc7dd7 --- /dev/null +++ b/packages/SystemUI/res/values-land/bools.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. +*/ +--> +<resources> + <!-- Only use small clock on lockscreen. + True here because only small clock used on small devices in landscape --> + <bool name="force_small_clock_on_lockscreen">true</bool> +</resources> diff --git a/packages/SystemUI/res/values-sw600dp-land/bools.xml b/packages/SystemUI/res/values-sw600dp-land/bools.xml new file mode 100644 index 000000000000..c4d77e894141 --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp-land/bools.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. +*/ +--> +<resources> + <!-- Only use small clock on lockscreen. + False here because large clock is allowed on large devices in landscape --> + <bool name="force_small_clock_on_lockscreen">false</bool> +</resources> diff --git a/packages/SystemUI/res/values/bools.xml b/packages/SystemUI/res/values/bools.xml index 91d3a88dcc89..39566622a5f4 100644 --- a/packages/SystemUI/res/values/bools.xml +++ b/packages/SystemUI/res/values/bools.xml @@ -59,4 +59,8 @@ True here so bouncers constraints are updated when rotating on small screens --> <bool name="update_bouncer_constraints">true</bool> + + <!-- Only use small clock on lockscreen. + False here because large clock used by default, unless otherwise specified --> + <bool name="force_small_clock_on_lockscreen">false</bool> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index aef8ea6726b9..422b2e1a1d28 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -35,6 +35,7 @@ import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import static android.os.BatteryManager.CHARGING_POLICY_DEFAULT; import static android.os.PowerManager.WAKE_REASON_UNKNOWN; + import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; @@ -4202,7 +4203,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final boolean previousState = mAllowFingerprintOnCurrentOccludingActivity; mAllowFingerprintOnCurrentOccludingActivity = - standardTask.topActivity != null + standardTask != null && standardTask.topActivity != null && !TextUtils.isEmpty(standardTask.topActivity.getPackageName()) && mAllowFingerprintOnOccludingActivitiesFromPackage.contains( standardTask.topActivity.getPackageName()) diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt index 12108b01ab28..b15aaaf9a00e 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt +++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt @@ -25,6 +25,9 @@ import android.content.Intent import android.util.Log import androidx.core.app.AppComponentFactory import com.android.systemui.dagger.ContextComponentHelper +import com.android.systemui.dagger.SysUIComponent +import com.android.tools.r8.keepanno.annotations.KeepTarget +import com.android.tools.r8.keepanno.annotations.UsesReflection import java.lang.reflect.InvocationTargetException import java.util.concurrent.ExecutionException import javax.inject.Inject @@ -88,6 +91,7 @@ abstract class SystemUIAppComponentFactoryBase : AppComponentFactory() { return app } + @UsesReflection(KeepTarget(extendsClassConstant = SysUIComponent::class, methodName = "inject")) override fun instantiateProviderCompat(cl: ClassLoader, className: String): ContentProvider { val contentProvider = super.instantiateProviderCompat(cl, className) if (contentProvider is ContextInitializer) { diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index c9801d77fa43..9fd060255e9b 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -54,6 +54,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; import javax.inject.Inject; @@ -84,6 +85,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon private final SystemClock mClock; private H mBGHandler; + private final Executor mBgExecutor; private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>(); private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>(); private boolean mListening; @@ -153,6 +155,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon public AppOpsControllerImpl( Context context, @Background Looper bgLooper, + @Background Executor bgExecutor, DumpManager dumpManager, AudioManager audioManager, IndividualSensorPrivacyController sensorPrivacyController, @@ -162,6 +165,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon mDispatcher = dispatcher; mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mBGHandler = new H(bgLooper); + mBgExecutor = bgExecutor; final int numOps = OPS.length; for (int i = 0; i < numOps; i++) { mCallbacksByCode.put(OPS[i], new ArraySet<>()); @@ -184,41 +188,43 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon @VisibleForTesting protected void setListening(boolean listening) { mListening = listening; - if (listening) { - // System UI could be restarted while ops are active, so fetch the currently active ops - // once System UI starts listening again. - fetchCurrentActiveOps(); - - mAppOps.startWatchingActive(OPS, this); - mAppOps.startWatchingNoted(OPS, this); - mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler); - mSensorPrivacyController.addCallback(this); - - mMicMuted = mAudioManager.isMicrophoneMute() - || mSensorPrivacyController.isSensorBlocked(MICROPHONE); - mCameraDisabled = mSensorPrivacyController.isSensorBlocked(CAMERA); - - mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged( - mAudioManager.getActiveRecordingConfigurations())); - mDispatcher.registerReceiverWithHandler(this, - new IntentFilter(ACTION_MICROPHONE_MUTE_CHANGED), mBGHandler); - - } else { - mAppOps.stopWatchingActive(this); - mAppOps.stopWatchingNoted(this); - mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback); - mSensorPrivacyController.removeCallback(this); - - mBGHandler.removeCallbacksAndMessages(null); // null removes all - mDispatcher.unregisterReceiver(this); - synchronized (mActiveItems) { - mActiveItems.clear(); - mRecordingsByUid.clear(); - } - synchronized (mNotedItems) { - mNotedItems.clear(); + // Move IPCs to the background. + mBgExecutor.execute(() -> { + if (listening) { + // System UI could be restarted while ops are active, so fetch the currently active + // ops once System UI starts listening again -- see b/294104969. + fetchCurrentActiveOps(); + + mAppOps.startWatchingActive(OPS, this); + mAppOps.startWatchingNoted(OPS, this); + mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler); + mSensorPrivacyController.addCallback(this); + + mMicMuted = mAudioManager.isMicrophoneMute() + || mSensorPrivacyController.isSensorBlocked(MICROPHONE); + mCameraDisabled = mSensorPrivacyController.isSensorBlocked(CAMERA); + + mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged( + mAudioManager.getActiveRecordingConfigurations())); + mDispatcher.registerReceiverWithHandler(this, + new IntentFilter(ACTION_MICROPHONE_MUTE_CHANGED), mBGHandler); + } else { + mAppOps.stopWatchingActive(this); + mAppOps.stopWatchingNoted(this); + mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback); + mSensorPrivacyController.removeCallback(this); + + mBGHandler.removeCallbacksAndMessages(null); // null removes all + mDispatcher.unregisterReceiver(this); + synchronized (mActiveItems) { + mActiveItems.clear(); + mRecordingsByUid.clear(); + } + synchronized (mNotedItems) { + mNotedItems.clear(); + } } - } + }); } private void fetchCurrentActiveOps() { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 7b58b1fe3014..9e5fd5572dbc 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -31,6 +31,7 @@ import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; import com.android.systemui.doze.DozeHost; import com.android.systemui.media.dagger.MediaModule; +import com.android.systemui.navigationbar.NavigationBarControllerModule; import com.android.systemui.navigationbar.gestural.GestureModule; import com.android.systemui.plugins.qs.QSFactory; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -101,6 +102,7 @@ import javax.inject.Named; GestureModule.class, MediaModule.class, MultiUserUtilsModule.class, + NavigationBarControllerModule.class, PowerModule.class, QSModule.class, ReferenceScreenshotModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 3a942bd8203f..58ba3c9c9915 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -89,6 +89,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.connectivity.ConnectivityModule; +import com.android.systemui.statusbar.dagger.StatusBarModule; import com.android.systemui.statusbar.disableflags.dagger.DisableFlagsModule; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.NotifPipelineFlags; @@ -153,71 +154,72 @@ import javax.inject.Named; * may not appreciate that. */ @Module(includes = { - AccessibilityModule.class, - AccessibilityRepositoryModule.class, - AConfigModule.class, - AppOpsModule.class, - AssistModule.class, - AuthenticationModule.class, - BiometricsModule.class, - BouncerViewModule.class, - ClipboardOverlayModule.class, - ClockRegistryModule.class, - CommonRepositoryModule.class, - DisplayModule.class, - ConnectivityModule.class, - CoroutinesModule.class, - DreamModule.class, - ControlsModule.class, - DemoModeModule.class, - DisableFlagsModule.class, - FalsingModule.class, - FlagsModule.class, - SystemPropertiesFlagsModule.class, - FooterActionsModule.class, - KeyboardModule.class, - LetterboxModule.class, - KeyguardBlueprintModule.class, - LogModule.class, - MediaProjectionModule.class, - MediaProjectionTaskSwitcherModule.class, - MotionToolModule.class, - NotificationIconAreaControllerModule.class, - PeopleHubModule.class, - PeopleModule.class, - PluginModule.class, - PolicyModule.class, - PrivacyModule.class, - QRCodeScannerModule.class, - QSFragmentStartableModule.class, - RetailModeModule.class, - ScreenshotModule.class, - SensorModule.class, - SecurityRepositoryModule.class, - ScreenRecordModule.class, - SettingsUtilModule.class, - SmartRepliesInflationModule.class, - SmartspaceModule.class, - StatusBarPipelineModule.class, - StatusBarPolicyModule.class, - StatusBarWindowModule.class, - SysUIConcurrencyModule.class, - SysUIUnfoldModule.class, - TelephonyRepositoryModule.class, - TemporaryDisplayModule.class, - TunerModule.class, - UserModule.class, - UtilModule.class, - NoteTaskModule.class, - WalletModule.class + AccessibilityModule.class, + AccessibilityRepositoryModule.class, + AConfigModule.class, + AppOpsModule.class, + AssistModule.class, + AuthenticationModule.class, + BiometricsModule.class, + BouncerViewModule.class, + ClipboardOverlayModule.class, + ClockRegistryModule.class, + CommonRepositoryModule.class, + ConnectivityModule.class, + ControlsModule.class, + CoroutinesModule.class, + DemoModeModule.class, + DisableFlagsModule.class, + DisplayModule.class, + DreamModule.class, + FalsingModule.class, + FlagsModule.class, + FooterActionsModule.class, + KeyboardModule.class, + KeyguardBlueprintModule.class, + LetterboxModule.class, + LogModule.class, + MediaProjectionModule.class, + MediaProjectionTaskSwitcherModule.class, + MotionToolModule.class, + NotificationIconAreaControllerModule.class, + PeopleHubModule.class, + PeopleModule.class, + PluginModule.class, + PolicyModule.class, + PrivacyModule.class, + QRCodeScannerModule.class, + QSFragmentStartableModule.class, + RetailModeModule.class, + ScreenshotModule.class, + SensorModule.class, + SecurityRepositoryModule.class, + ScreenRecordModule.class, + SettingsUtilModule.class, + SmartRepliesInflationModule.class, + SmartspaceModule.class, + StatusBarModule.class, + StatusBarPipelineModule.class, + StatusBarPolicyModule.class, + StatusBarWindowModule.class, + SystemPropertiesFlagsModule.class, + SysUIConcurrencyModule.class, + SysUIUnfoldModule.class, + TelephonyRepositoryModule.class, + TemporaryDisplayModule.class, + TunerModule.class, + UserModule.class, + UtilModule.class, + NoteTaskModule.class, + WalletModule.class }, subcomponents = { ComplicationComponent.class, - NavigationBarComponent.class, - NotificationRowComponent.class, DozeComponent.class, ExpandableNotificationRowComponent.class, KeyguardBouncerComponent.class, + NavigationBarComponent.class, + NotificationRowComponent.class, NotificationShelfComponent.class, WindowRootViewComponent.class, }) diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index cde389debb92..02575eb8adf4 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -412,16 +412,6 @@ object Flags { val NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS = releasedFlag("new_shade_carrier_group_mobile_icons") - // 700 - dialer/calls - // TODO(b/254512734): Tracking Bug - val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag("ongoing_call_status_bar_chip") - - // TODO(b/254512681): Tracking Bug - val ONGOING_CALL_IN_IMMERSIVE = releasedFlag("ongoing_call_in_immersive") - - // TODO(b/254512753): Tracking Bug - val ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP = releasedFlag("ongoing_call_in_immersive_chip_tap") - // 800 - general visual/theme @JvmField val MONET = resourceBooleanFlag(R.bool.flag_monet, "monet") @@ -773,8 +763,7 @@ object Flags { // TODO(b/285174336): Tracking Bug @JvmField - val USE_REPOS_FOR_BOUNCER_SHOWING = - unreleasedFlag("use_repos_for_bouncer_showing", teamfood = true) + val USE_REPOS_FOR_BOUNCER_SHOWING = releasedFlag("use_repos_for_bouncer_showing") // 3100 - Haptic interactions @@ -790,11 +779,11 @@ object Flags { /** Enable the Compose implementation of the PeopleSpaceActivity. */ @JvmField - val COMPOSE_PEOPLE_SPACE = unreleasedFlag("compose_people_space", teamfood = true) + val COMPOSE_PEOPLE_SPACE = releasedFlag("compose_people_space") /** Enable the Compose implementation of the Quick Settings footer actions. */ @JvmField - val COMPOSE_QS_FOOTER_ACTIONS = unreleasedFlag("compose_qs_footer_actions", teamfood = true) + val COMPOSE_QS_FOOTER_ACTIONS = releasedFlag("compose_qs_footer_actions") /** Enable the share wifi button in Quick Settings internet dialog. */ @JvmField @@ -811,4 +800,9 @@ object Flags { /** Enable showing a dialog when clicking on Quick Settings bluetooth tile. */ @JvmField val BLUETOOTH_QS_TILE_DIALOG = unreleasedFlag("bluetooth_qs_tile_dialog") + + // TODO(b/300995746): Tracking Bug + /** Enable communal hub features. */ + @JvmField + val COMMUNAL_HUB = resourceBooleanFlag(R.bool.config_communalServiceEnabled, "communal_hub") } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index 257006e13201..22bcf0aa2799 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -18,10 +18,8 @@ package com.android.systemui.keyguard import android.content.Context -import android.content.res.Configuration import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import com.android.keyguard.KeyguardStatusView import com.android.keyguard.KeyguardStatusViewController import com.android.keyguard.LockIconView @@ -29,38 +27,21 @@ import com.android.keyguard.LockIconViewController import com.android.keyguard.dagger.KeyguardStatusViewComponent import com.android.systemui.CoreStartable import com.android.systemui.R -import com.android.systemui.communal.ui.adapter.CommunalWidgetViewAdapter -import com.android.systemui.communal.ui.binder.CommunalWidgetViewBinder -import com.android.systemui.communal.ui.viewmodel.CommunalWidgetViewModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor -import com.android.systemui.keyguard.ui.binder.KeyguardAmbientIndicationAreaViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder -import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder -import com.android.systemui.keyguard.ui.binder.KeyguardSettingsViewBinder import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea import com.android.systemui.keyguard.ui.view.KeyguardRootView import com.android.systemui.keyguard.ui.view.layout.KeyguardBlueprintCommandListener -import com.android.systemui.keyguard.ui.viewmodel.KeyguardAmbientIndicationViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsMenuViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel -import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.plugins.FalsingManager import com.android.systemui.shade.NotificationShadeWindowView import com.android.systemui.statusbar.KeyguardIndicationController -import com.android.systemui.statusbar.VibratorHelper -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController -import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer -import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder -import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import javax.inject.Inject @@ -74,30 +55,17 @@ class KeyguardViewConfigurator @Inject constructor( private val keyguardRootView: KeyguardRootView, - private val sharedNotificationContainer: SharedNotificationContainer, private val keyguardRootViewModel: KeyguardRootViewModel, private val keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel, - private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel, - private val keyguardAmbientIndicationViewModel: KeyguardAmbientIndicationViewModel, private val notificationShadeWindowView: NotificationShadeWindowView, private val featureFlags: FeatureFlags, private val indicationController: KeyguardIndicationController, - private val keyguardQuickAffordancesCombinedViewModel: - KeyguardQuickAffordancesCombinedViewModel, - private val falsingManager: FalsingManager, - private val vibratorHelper: VibratorHelper, private val keyguardStateController: KeyguardStateController, - private val keyguardSettingsMenuViewModel: KeyguardSettingsMenuViewModel, - private val activityStarter: ActivityStarter, private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, private val chipbarCoordinator: ChipbarCoordinator, private val keyguardBlueprintCommandListener: KeyguardBlueprintCommandListener, private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel, private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory, - private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor, - private val communalWidgetViewModel: CommunalWidgetViewModel, - private val communalWidgetViewAdapter: CommunalWidgetViewAdapter, - private val notificationStackScrollerLayoutController: NotificationStackScrollLayoutController, private val context: Context, private val keyguardIndicationController: KeyguardIndicationController, private val lockIconViewController: LockIconViewController, @@ -105,10 +73,7 @@ constructor( private var rootViewHandle: DisposableHandle? = null private var indicationAreaHandle: DisposableHandle? = null - private var leftShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null - private var rightShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null - private var ambientIndicationAreaHandle: KeyguardAmbientIndicationAreaViewBinder.Binding? = null - private var settingsPopupMenuHandle: DisposableHandle? = null + var keyguardStatusViewController: KeyguardStatusViewController? = null get() { if (field == null) { @@ -127,52 +92,12 @@ constructor( override fun start() { bindKeyguardRootView() - if (featureFlags.isEnabled(Flags.LAZY_INFLATE_KEYGUARD)) { - keyguardRootView.removeAllViews() - initializeViews() - } else { - val notificationPanel = - notificationShadeWindowView.requireViewById(R.id.notification_panel) as ViewGroup - unbindKeyguardBottomArea(notificationPanel) - bindIndicationArea() - bindLockIconView(notificationPanel) - bindKeyguardStatusView(notificationPanel) - setupNotificationStackScrollLayout(notificationPanel) - bindLeftShortcut() - bindRightShortcut() - bindAmbientIndicationArea() - bindSettingsPopupMenu() - bindCommunalWidgetArea() - } + initializeViews() KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) keyguardBlueprintCommandListener.start() } - fun setupNotificationStackScrollLayout(legacyParent: ViewGroup) { - if (featureFlags.isEnabled(Flags.MIGRATE_NSSL)) { - // This moves the existing NSSL view to a different parent, as the controller is a - // singleton and recreating it has other bad side effects - val nssl = - legacyParent.requireViewById<View>(R.id.notification_stack_scroller).also { - (it.getParent() as ViewGroup).removeView(it) - } - sharedNotificationContainer.addNotificationStackScrollLayout(nssl) - SharedNotificationContainerBinder.bind( - sharedNotificationContainer, - sharedNotificationContainerViewModel, - notificationStackScrollerLayoutController, - ) - } - } - - override fun onConfigurationChanged(newConfig: Configuration?) { - super.onConfigurationChanged(newConfig) - leftShortcutHandle?.onConfigurationChanged() - rightShortcutHandle?.onConfigurationChanged() - ambientIndicationAreaHandle?.onConfigurationChanged() - } - fun bindIndicationArea() { indicationAreaHandle?.dispose() @@ -213,135 +138,6 @@ constructor( ) } - private fun bindLockIconView(legacyParent: ViewGroup) { - if (featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)) { - legacyParent.requireViewById<View>(R.id.lock_icon_view).let { - legacyParent.removeView(it) - } - } else { - keyguardRootView.findViewById<View?>(R.id.lock_icon_view)?.let { - keyguardRootView.removeView(it) - } - legacyParent.requireViewById<LockIconView>(R.id.lock_icon_view).let { - lockIconViewController.setLockIconView(it) - } - } - } - - private fun bindAmbientIndicationArea() { - if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) { - ambientIndicationAreaHandle?.destroy() - ambientIndicationAreaHandle = - KeyguardAmbientIndicationAreaViewBinder.bind( - notificationShadeWindowView, - keyguardAmbientIndicationViewModel, - keyguardRootViewModel, - ) - } else { - keyguardRootView.findViewById<View?>(R.id.ambient_indication_container)?.let { - keyguardRootView.removeView(it) - } - } - } - - private fun bindSettingsPopupMenu() { - if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) { - settingsPopupMenuHandle?.dispose() - settingsPopupMenuHandle = - KeyguardSettingsViewBinder.bind( - keyguardRootView, - keyguardSettingsMenuViewModel, - vibratorHelper, - activityStarter, - ) - } else { - keyguardRootView.findViewById<View?>(R.id.keyguard_settings_button)?.let { - keyguardRootView.removeView(it) - } - } - } - - private fun unbindKeyguardBottomArea(legacyParent: ViewGroup) { - if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) { - legacyParent.requireViewById<View>(R.id.keyguard_bottom_area).let { - legacyParent.removeView(it) - } - } - } - - private fun bindLeftShortcut() { - leftShortcutHandle?.destroy() - if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) { - leftShortcutHandle = - KeyguardQuickAffordanceViewBinder.bind( - keyguardRootView.requireViewById(R.id.start_button), - keyguardQuickAffordancesCombinedViewModel.startButton, - keyguardRootViewModel.alpha, - falsingManager, - vibratorHelper, - ) { - indicationController.showTransientIndication(it) - } - } else { - keyguardRootView.findViewById<View?>(R.id.start_button)?.let { - keyguardRootView.removeView(it) - } - } - } - - private fun bindRightShortcut() { - rightShortcutHandle?.destroy() - if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) { - rightShortcutHandle = - KeyguardQuickAffordanceViewBinder.bind( - keyguardRootView.requireViewById(R.id.end_button), - keyguardQuickAffordancesCombinedViewModel.endButton, - keyguardRootViewModel.alpha, - falsingManager, - vibratorHelper, - ) { - indicationController.showTransientIndication(it) - } - } else { - keyguardRootView.findViewById<View?>(R.id.end_button)?.let { - keyguardRootView.removeView(it) - } - } - } - - fun bindKeyguardStatusView(legacyParent: ViewGroup) { - // At startup, 2 views with the ID `R.id.keyguard_status_view` will be available. - // Disable one of them - if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) { - legacyParent.findViewById<View>(R.id.keyguard_status_view)?.let { - legacyParent.removeView(it) - } - - val keyguardStatusView = keyguardRootView.addStatusView() - val statusViewComponent = keyguardStatusViewComponentFactory.build(keyguardStatusView) - val controller = statusViewComponent.getKeyguardStatusViewController() - controller.init() - keyguardStatusViewController = controller - } else { - keyguardRootView.findViewById<View?>(R.id.keyguard_status_view)?.let { - keyguardRootView.removeView(it) - } - } - } - - private fun bindCommunalWidgetArea() { - if (!featureFlags.isEnabled(Flags.WIDGET_ON_KEYGUARD)) { - return - } - - CommunalWidgetViewBinder.bind( - keyguardRootView, - communalWidgetViewModel, - communalWidgetViewAdapter, - keyguardBlueprintInteractor, - ) - } - /** * Temporary, to allow NotificationPanelViewController to use the same instance while code is * migrated: b/288242803 diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt index af0abdff0c62..5e5caba060ae 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt @@ -34,7 +34,7 @@ import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.withContext @SysUISingleton @@ -58,16 +58,21 @@ constructor( get() = R.drawable.ic_camera override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> - get() = - flowOf( - KeyguardQuickAffordanceConfig.LockScreenState.Visible( - icon = - Icon.Resource( - R.drawable.ic_camera, - ContentDescription.Resource(R.string.accessibility_camera_button) - ) - ) + get() = flow { + emit( + if (isLaunchable()) { + KeyguardQuickAffordanceConfig.LockScreenState.Visible( + icon = + Icon.Resource( + R.drawable.ic_camera, + ContentDescription.Resource(R.string.accessibility_camera_button) + ) + ) + } else { + KeyguardQuickAffordanceConfig.LockScreenState.Hidden + } ) + } override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { return if (isLaunchable()) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt index 5d7a3d432dcb..23f50eaba7e7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt @@ -34,6 +34,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.plugins.ActivityStarter import com.android.systemui.wallet.controller.QuickAccessWalletController +import com.android.systemui.wallet.util.getPaymentCards import javax.inject.Inject import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -60,7 +61,7 @@ constructor( val callback = object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback { override fun onWalletCardsRetrieved(response: GetWalletCardsResponse) { - val hasCards = response?.walletCards?.isNotEmpty() == true + val hasCards = getPaymentCards(response.walletCards)?.isNotEmpty() == true trySendWithFailureLogging( state( isFeatureEnabled = isWalletAvailable(), @@ -135,7 +136,7 @@ constructor( object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback { override fun onWalletCardsRetrieved(response: GetWalletCardsResponse) { continuation.resumeWith( - Result.success(response?.walletCards ?: emptyList()) + Result.success(getPaymentCards(response.walletCards) ?: emptyList()) ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt index a94874176a34..f2b28d964314 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt @@ -19,123 +19,14 @@ package com.android.systemui.keyguard.ui.view import android.content.Context import android.util.AttributeSet -import android.view.LayoutInflater -import android.view.View -import android.widget.ImageView import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.res.ResourcesCompat -import com.android.keyguard.KeyguardStatusView -import com.android.keyguard.LockIconView -import com.android.systemui.R -import com.android.systemui.animation.view.LaunchableImageView /** Provides a container for all keyguard ui content. */ class KeyguardRootView( context: Context, - private val attrs: AttributeSet?, + attrs: AttributeSet?, ) : ConstraintLayout( context, attrs, - ) { - - private var statusView: KeyguardStatusView? = null - - init { - addIndicationTextArea() - addLockIconView() - addAmbientIndicationArea() - addLeftShortcut() - addRightShortcut() - addSettingsPopupMenu() - addStatusView() - } - - private fun addIndicationTextArea() { - val view = KeyguardIndicationArea(context, attrs) - addView(view) - } - - private fun addLockIconView() { - val view = LockIconView(context, attrs).apply { id = R.id.lock_icon_view } - addView(view) - } - - private fun addAmbientIndicationArea() { - LayoutInflater.from(context).inflate(R.layout.ambient_indication, this) - } - - private fun addLeftShortcut() { - val padding = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_padding) - val view = - LaunchableImageView(context, attrs).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) - } - addView(view) - } - - private fun addRightShortcut() { - val padding = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_padding) - val view = - LaunchableImageView(context, attrs).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) - } - addView(view) - } - - private fun addSettingsPopupMenu() { - val view = - LayoutInflater.from(context) - .inflate(R.layout.keyguard_settings_popup_menu, this, false) - .apply { - id = R.id.keyguard_settings_button - visibility = GONE - } - addView(view) - } - - fun addStatusView(): KeyguardStatusView { - // StatusView may need to be rebuilt on config changes. Remove and reinflate - statusView?.let { removeView(it) } - val view = - (LayoutInflater.from(context).inflate(R.layout.keyguard_status_view, this, false) - as KeyguardStatusView) - .apply { - setClipChildren(false) - statusView = this - } - - addView(view) - return view - } -} + ) 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 43bbf69db883..1eeb0172f419 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 @@ -17,10 +17,7 @@ package com.android.systemui.keyguard.ui.view.layout.blueprints -import androidx.constraintlayout.widget.ConstraintLayout import com.android.systemui.dagger.SysUISingleton -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 @@ -54,7 +51,6 @@ constructor( defaultNotificationStackScrollLayoutSection: DefaultNotificationStackScrollLayoutSection, splitShadeGuidelines: SplitShadeGuidelines, aodNotificationIconsSection: AodNotificationIconsSection, - private val featureFlags: FeatureFlags, ) : KeyguardBlueprint { override val id: String = DEFAULT @@ -72,16 +68,6 @@ constructor( aodNotificationIconsSection, ) - override fun replaceViews( - previousBlueprint: KeyguardBlueprint?, - constraintLayout: ConstraintLayout, - bindData: Boolean - ) { - if (featureFlags.isEnabled(Flags.LAZY_INFLATE_KEYGUARD)) { - super.replaceViews(previousBlueprint, constraintLayout, bindData) - } - } - companion object { const val DEFAULT = "default" } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt index 05c932372ccf..cfcbdac4c4e9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt @@ -18,26 +18,39 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.scene.shared.model.SceneKey import javax.inject.Inject -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn /** Models UI state and handles user input for the lockscreen scene. */ @SysUISingleton class LockscreenSceneViewModel @Inject constructor( + @Application applicationScope: CoroutineScope, authenticationInteractor: AuthenticationInteractor, val longPress: KeyguardLongPressViewModel, ) { /** The key of the scene we should switch to when swiping up. */ - val upDestinationSceneKey: Flow<SceneKey> = - authenticationInteractor.isUnlocked.map { isUnlocked -> - if (isUnlocked) { - SceneKey.Gone - } else { - SceneKey.Bouncer - } + val upDestinationSceneKey: StateFlow<SceneKey> = + authenticationInteractor.isUnlocked + .map { isUnlocked -> upDestinationSceneKey(isUnlocked) } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = upDestinationSceneKey(authenticationInteractor.isUnlocked.value), + ) + + private fun upDestinationSceneKey(isUnlocked: Boolean): SceneKey { + return if (isUnlocked) { + SceneKey.Gone + } else { + SceneKey.Bouncer } + } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt index cf64a838c2bf..be487561961c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt @@ -91,7 +91,13 @@ class MediaProjectionAppSelectorActivity( public override fun onCreate(bundle: Bundle?) { lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) - component = componentFactory.create(activity = this, view = this, resultHandler = this) + component = + componentFactory.create( + hostUserHandle = hostUserHandle, + callingPackage = callingPackage, + view = this, + resultHandler = this + ) component.lifecycleObservers.forEach { lifecycle.addObserver(it) } // Create a separate configuration controller for this activity as the configuration @@ -288,6 +294,18 @@ class MediaProjectionAppSelectorActivity( override fun createContentPreviewView(parent: ViewGroup): ViewGroup = recentsViewController.createView(parent) + private val hostUserHandle: UserHandle + get() { + val extras = + intent.extras + ?: error("MediaProjectionAppSelectorActivity should be launched with extras") + return extras.getParcelable(EXTRA_HOST_APP_USER_HANDLE) + ?: error( + "MediaProjectionAppSelectorActivity should be provided with " + + "$EXTRA_HOST_APP_USER_HANDLE extra" + ) + } + companion object { const val TAG = "MediaProjectionAppSelectorActivity" diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt index 11538fadf24e..33d9cc36c9b0 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt @@ -24,7 +24,6 @@ import androidx.lifecycle.DefaultLifecycleObserver import com.android.launcher3.icons.IconFactory import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.media.MediaProjectionAppSelectorActivity -import com.android.systemui.media.MediaProjectionAppSelectorActivity.Companion.EXTRA_HOST_APP_USER_HANDLE import com.android.systemui.media.MediaProjectionPermissionActivity import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerLabelLoader import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader @@ -118,29 +117,8 @@ interface MediaProjectionAppSelectorModule { @Provides @MediaProjectionAppSelector @MediaProjectionAppSelectorScope - fun provideCallerPackageName(activity: MediaProjectionAppSelectorActivity): String? = - activity.callingPackage - - @Provides - @MediaProjectionAppSelector - @MediaProjectionAppSelectorScope - fun bindConfigurationController( - activity: MediaProjectionAppSelectorActivity - ): ConfigurationController = ConfigurationControllerImpl(activity) - - @Provides - @HostUserHandle - @MediaProjectionAppSelectorScope - fun hostUserHandle(activity: MediaProjectionAppSelectorActivity): UserHandle { - val extras = - activity.intent.extras - ?: error("MediaProjectionAppSelectorActivity should be launched with extras") - return extras.getParcelable(EXTRA_HOST_APP_USER_HANDLE) - ?: error( - "MediaProjectionAppSelectorActivity should be provided with " + - "$EXTRA_HOST_APP_USER_HANDLE extra" - ) - } + fun bindConfigurationController(context: Context): ConfigurationController = + ConfigurationControllerImpl(context) @Provides fun bindIconFactory(context: Context): IconFactory = IconFactory.obtain(context) @@ -161,7 +139,8 @@ interface MediaProjectionAppSelectorComponent { interface Factory { /** Create a factory to inject the activity into the graph */ fun create( - @BindsInstance activity: MediaProjectionAppSelectorActivity, + @BindsInstance @HostUserHandle hostUserHandle: UserHandle, + @BindsInstance @MediaProjectionAppSelector callingPackage: String?, @BindsInstance view: MediaProjectionAppSelectorView, @BindsInstance resultHandler: MediaProjectionAppSelectorResultHandler, ): MediaProjectionAppSelectorComponent diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index 5a42028ae83e..a601d7f25b6e 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 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. @@ -16,483 +16,58 @@ package com.android.systemui.navigationbar; -import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; -import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; -import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; -import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG; -import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen; - -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.hardware.display.DisplayManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.RemoteException; -import android.os.Trace; -import android.os.UserHandle; -import android.provider.Settings; -import android.util.Log; -import android.util.SparseArray; -import android.view.Display; -import android.view.IWindowManager; -import android.view.View; -import android.view.WindowManagerGlobal; - -import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.RegisterStatusBarResult; -import com.android.settingslib.applications.InterestingConfigChanges; -import com.android.systemui.Dumpable; -import com.android.systemui.dagger.SysUISingleton; -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.model.SysUiState; -import com.android.systemui.recents.OverviewProxyService; -import com.android.systemui.settings.DisplayTracker; -import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.shared.system.TaskStackChangeListeners; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.phone.AutoHideController; -import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; -import com.android.systemui.statusbar.phone.LightBarController; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.util.settings.SecureSettings; -import com.android.wm.shell.back.BackAnimation; -import com.android.wm.shell.pip.Pip; - -import java.io.PrintWriter; -import java.util.Optional; - -import javax.inject.Inject; +import com.android.systemui.statusbar.phone.BarTransitions; /** A controller to handle navigation bars. */ -@SysUISingleton -public class NavigationBarController implements - ConfigurationController.ConfigurationListener, - NavigationModeController.ModeChangedListener, - Dumpable { - - private static final String TAG = NavigationBarController.class.getSimpleName(); - - private final Context mContext; - private final Handler mHandler; - private final NavigationBarComponent.Factory mNavigationBarComponentFactory; - private FeatureFlags mFeatureFlags; - private final SecureSettings mSecureSettings; - private final DisplayTracker mDisplayTracker; - private final DisplayManager mDisplayManager; - private final TaskbarDelegate mTaskbarDelegate; - private final NavBarHelper mNavBarHelper; - private int mNavMode; - @VisibleForTesting boolean mIsLargeScreen; - - /** A displayId - nav bar maps. */ - @VisibleForTesting - SparseArray<NavigationBar> mNavigationBars = new SparseArray<>(); - - // Tracks config changes that will actually recreate the nav bar - private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( - ActivityInfo.CONFIG_FONT_SCALE - | ActivityInfo.CONFIG_UI_MODE); - - @Inject - public NavigationBarController(Context context, - OverviewProxyService overviewProxyService, - NavigationModeController navigationModeController, - SysUiState sysUiFlagsContainer, - CommandQueue commandQueue, - @Main Handler mainHandler, - ConfigurationController configurationController, - NavBarHelper navBarHelper, - TaskbarDelegate taskbarDelegate, - NavigationBarComponent.Factory navigationBarComponentFactory, - DumpManager dumpManager, - AutoHideController autoHideController, - LightBarController lightBarController, - TaskStackChangeListeners taskStackChangeListeners, - Optional<Pip> pipOptional, - Optional<BackAnimation> backAnimation, - FeatureFlags featureFlags, - SecureSettings secureSettings, - DisplayTracker displayTracker) { - mContext = context; - mHandler = mainHandler; - mNavigationBarComponentFactory = navigationBarComponentFactory; - mFeatureFlags = featureFlags; - mSecureSettings = secureSettings; - mDisplayTracker = displayTracker; - mDisplayManager = mContext.getSystemService(DisplayManager.class); - commandQueue.addCallback(mCommandQueueCallbacks); - configurationController.addCallback(this); - mConfigChanges.applyNewConfig(mContext.getResources()); - mNavMode = navigationModeController.addListener(this); - mNavBarHelper = navBarHelper; - mTaskbarDelegate = taskbarDelegate; - mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService, - navBarHelper, navigationModeController, sysUiFlagsContainer, - dumpManager, autoHideController, lightBarController, pipOptional, - backAnimation.orElse(null), taskStackChangeListeners); - mIsLargeScreen = isLargeScreen(mContext); - dumpManager.registerDumpable(this); - } - - @Override - public void onConfigChanged(Configuration newConfig) { - boolean isOldConfigLargeScreen = mIsLargeScreen; - mIsLargeScreen = isLargeScreen(mContext); - boolean willApplyConfig = mConfigChanges.applyNewConfig(mContext.getResources()); - boolean largeScreenChanged = mIsLargeScreen != isOldConfigLargeScreen; - // TODO(b/243765256): Disable this logging once b/243765256 is fixed. - Log.i(DEBUG_MISSING_GESTURE_TAG, "NavbarController: newConfig=" + newConfig - + " mTaskbarDelegate initialized=" + mTaskbarDelegate.isInitialized() - + " willApplyConfigToNavbars=" + willApplyConfig - + " navBarCount=" + mNavigationBars.size()); - if (mTaskbarDelegate.isInitialized()) { - mTaskbarDelegate.onConfigurationChanged(newConfig); - } - // If we folded/unfolded while in 3 button, show navbar in folded state, hide in unfolded - if (largeScreenChanged && updateNavbarForTaskbar()) { - return; - } - - if (willApplyConfig) { - for (int i = 0; i < mNavigationBars.size(); i++) { - recreateNavigationBar(mNavigationBars.keyAt(i)); - } - } else { - for (int i = 0; i < mNavigationBars.size(); i++) { - mNavigationBars.valueAt(i).onConfigurationChanged(newConfig); - } - } - } - - @Override - public void onNavigationModeChanged(int mode) { - if (mNavMode == mode) { - return; - } - final int oldMode = mNavMode; - mNavMode = mode; - updateAccessibilityButtonModeIfNeeded(); - - mHandler.post(() -> { - // create/destroy nav bar based on nav mode only in unfolded state - if (oldMode != mNavMode) { - updateNavbarForTaskbar(); - } - for (int i = 0; i < mNavigationBars.size(); i++) { - NavigationBar navBar = mNavigationBars.valueAt(i); - if (navBar == null) { - continue; - } - navBar.getView().updateStates(); - } - }); - } - - private void updateAccessibilityButtonModeIfNeeded() { - final int mode = mSecureSettings.getIntForUser( - Settings.Secure.ACCESSIBILITY_BUTTON_MODE, - ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT); - - // ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU is compatible under gestural or non-gestural - // mode, so we don't need to update it. - if (mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) { - return; - } - - // ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR is incompatible under gestural mode. Need to - // force update to ACCESSIBILITY_BUTTON_MODE_GESTURE. - if (QuickStepContract.isGesturalMode(mNavMode) - && mode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR) { - mSecureSettings.putIntForUser( - Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_GESTURE, - UserHandle.USER_CURRENT); - // ACCESSIBILITY_BUTTON_MODE_GESTURE is incompatible under non gestural mode. Need to - // force update to ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR. - } else if (!QuickStepContract.isGesturalMode(mNavMode) - && mode == ACCESSIBILITY_BUTTON_MODE_GESTURE) { - mSecureSettings.putIntForUser( - Settings.Secure.ACCESSIBILITY_BUTTON_MODE, - ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT); - } - } - - private boolean shouldCreateNavBarAndTaskBar(int displayId) { - final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); - - try { - return wms.hasNavigationBar(displayId); - } catch (RemoteException e) { - // Cannot get wms, just return false with warning message. - Log.w(TAG, "Cannot get WindowManager."); - return false; - } - } - - /** @see #initializeTaskbarIfNecessary() */ - private boolean updateNavbarForTaskbar() { - boolean taskbarShown = initializeTaskbarIfNecessary(); - if (!taskbarShown && mNavigationBars.get(mContext.getDisplayId()) == null) { - createNavigationBar(mContext.getDisplay(), null, null); - } - return taskbarShown; - } - - /** @return {@code true} if taskbar is enabled, false otherwise */ - private boolean initializeTaskbarIfNecessary() { - // Enable for large screens or (phone AND flag is set); assuming phone = !mIsLargeScreen - boolean taskbarEnabled = (mIsLargeScreen || mFeatureFlags.isEnabled( - Flags.HIDE_NAVBAR_WINDOW)) && shouldCreateNavBarAndTaskBar(mContext.getDisplayId()); - - if (taskbarEnabled) { - Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary"); - final int displayId = mContext.getDisplayId(); - // Hint to NavBarHelper if we are replacing an existing bar to skip extra work - mNavBarHelper.setTogglingNavbarTaskbar(mNavigationBars.contains(displayId)); - // Remove navigation bar when taskbar is showing - removeNavigationBar(displayId); - mTaskbarDelegate.init(displayId); - mNavBarHelper.setTogglingNavbarTaskbar(false); - Trace.endSection(); - - } else { - mTaskbarDelegate.destroy(); - } - return taskbarEnabled; - } - - private final CommandQueue.Callbacks mCommandQueueCallbacks = new CommandQueue.Callbacks() { - @Override - public void onDisplayRemoved(int displayId) { - removeNavigationBar(displayId); - } - - @Override - public void onDisplayReady(int displayId) { - Display display = mDisplayManager.getDisplay(displayId); - mIsLargeScreen = isLargeScreen(mContext); - createNavigationBar(display, null /* savedState */, null /* result */); - } - - @Override - public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { - final NavigationBar navigationBar = getNavigationBar(displayId); - if (navigationBar != null) { - navigationBar.setNavigationBarLumaSamplingEnabled(enable); - } - } - - @Override - public void showPinningEnterExitToast(boolean entering) { - int displayId = mContext.getDisplayId(); - final NavigationBarView navBarView = getNavigationBarView(displayId); - if (navBarView != null) { - navBarView.showPinningEnterExitToast(entering); - } else if (displayId == mDisplayTracker.getDefaultDisplayId() - && mTaskbarDelegate.isInitialized()) { - mTaskbarDelegate.showPinningEnterExitToast(entering); - } - } - - @Override - public void showPinningEscapeToast() { - int displayId = mContext.getDisplayId(); - final NavigationBarView navBarView = getNavigationBarView(displayId); - if (navBarView != null) { - navBarView.showPinningEscapeToast(); - } else if (displayId == mDisplayTracker.getDefaultDisplayId() - && mTaskbarDelegate.isInitialized()) { - mTaskbarDelegate.showPinningEscapeToast(); - } - } - }; - - /** - * Recreates the navigation bar for the given display. - */ - private void recreateNavigationBar(int displayId) { - // TODO: Improve this flow so that we don't need to create a new nav bar but just - // the view - Bundle savedState = new Bundle(); - NavigationBar bar = mNavigationBars.get(displayId); - if (bar != null) { - bar.onSaveInstanceState(savedState); - } - removeNavigationBar(displayId); - createNavigationBar(mDisplayManager.getDisplay(displayId), savedState, null /* result */); - } - - // TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to - // CarStatusBar because they have their own nav bar. Think about a better way for it. +public interface NavigationBarController { /** * Creates navigation bars when car/status bar initializes. + * <p> + * TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to + * CarStatusBar because they have their own nav bar. Think about a better way for it. * * @param includeDefaultDisplay {@code true} to create navigation bar on default display. */ - public void createNavigationBars(final boolean includeDefaultDisplay, - RegisterStatusBarResult result) { - updateAccessibilityButtonModeIfNeeded(); - - // Don't need to create nav bar on the default display if we initialize TaskBar. - final boolean shouldCreateDefaultNavbar = includeDefaultDisplay - && !initializeTaskbarIfNecessary(); - Display[] displays = mDisplayTracker.getAllDisplays(); - for (Display display : displays) { - if (shouldCreateDefaultNavbar - || display.getDisplayId() != mDisplayTracker.getDefaultDisplayId()) { - createNavigationBar(display, null /* savedState */, result); - } - } - } + void createNavigationBars( + boolean includeDefaultDisplay, + RegisterStatusBarResult result); - /** - * Adds a navigation bar on default display or an external display if the display supports - * system decorations. - * - * @param display the display to add navigation bar on. - */ - @VisibleForTesting - void createNavigationBar(Display display, Bundle savedState, RegisterStatusBarResult result) { - if (display == null) { - return; - } - - final int displayId = display.getDisplayId(); - final boolean isOnDefaultDisplay = displayId == mDisplayTracker.getDefaultDisplayId(); - - if (!shouldCreateNavBarAndTaskBar(displayId)) { - return; - } - - // We may show TaskBar on the default display for large screen device. Don't need to create - // navigation bar for this case. - if (isOnDefaultDisplay && initializeTaskbarIfNecessary()) { - return; - } - - final Context context = isOnDefaultDisplay - ? mContext - : mContext.createDisplayContext(display); - NavigationBarComponent component = mNavigationBarComponentFactory.create( - context, savedState); - NavigationBar navBar = component.getNavigationBar(); - navBar.init(); - mNavigationBars.put(displayId, navBar); - - navBar.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - if (result != null) { - navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken, - result.mImeWindowVis, result.mImeBackDisposition, - result.mShowImeSwitcher); - } - } - - @Override - public void onViewDetachedFromWindow(View v) { - v.removeOnAttachStateChangeListener(this); - } - }); - } - - void removeNavigationBar(int displayId) { - NavigationBar navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.destroyView(); - mNavigationBars.remove(displayId); - } - } + /** Removes the navigation bar for the given display ID. */ + void removeNavigationBar(int displayId); /** @see NavigationBar#checkNavBarModes() */ - public void checkNavBarModes(int displayId) { - NavigationBar navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.checkNavBarModes(); - } - } + void checkNavBarModes(int displayId); /** @see NavigationBar#finishBarAnimations() */ - public void finishBarAnimations(int displayId) { - NavigationBar navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.finishBarAnimations(); - } - } + void finishBarAnimations(int displayId); /** @see NavigationBar#touchAutoDim() */ - public void touchAutoDim(int displayId) { - NavigationBar navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.touchAutoDim(); - } - } + void touchAutoDim(int displayId); /** @see NavigationBar#transitionTo(int, boolean) */ - public void transitionTo(int displayId, @TransitionMode int barMode, boolean animate) { - NavigationBar navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.transitionTo(barMode, animate); - } - } + void transitionTo(int displayId, @BarTransitions.TransitionMode int barMode, boolean animate); /** @see NavigationBar#disableAnimationsDuringHide(long) */ - public void disableAnimationsDuringHide(int displayId, long delay) { - NavigationBar navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.disableAnimationsDuringHide(delay); - } - } + void disableAnimationsDuringHide(int displayId, long delay); /** @return {@link NavigationBarView} on the default display. */ - public @Nullable NavigationBarView getDefaultNavigationBarView() { - return getNavigationBarView(mDisplayTracker.getDefaultDisplayId()); - } + @Nullable + NavigationBarView getDefaultNavigationBarView(); /** * @param displayId the ID of display which Navigation bar is on * @return {@link NavigationBarView} on the display with {@code displayId}. * {@code null} if no navigation bar on that display. */ - public @Nullable NavigationBarView getNavigationBarView(int displayId) { - NavigationBar navBar = getNavigationBar(displayId); - return (navBar == null) ? null : navBar.getView(); - } - - private @Nullable NavigationBar getNavigationBar(int displayId) { - return mNavigationBars.get(displayId); - } + @Nullable + NavigationBarView getNavigationBarView(int displayId); - public boolean isOverviewEnabled(int displayId) { - final NavigationBarView navBarView = getNavigationBarView(displayId); - if (navBarView != null) { - return navBarView.isOverviewEnabled(); - } else { - return mTaskbarDelegate.isOverviewEnabled(); - } - } + boolean isOverviewEnabled(int displayId); /** @return {@link NavigationBar} on the default display. */ @Nullable - public NavigationBar getDefaultNavigationBar() { - return mNavigationBars.get(mDisplayTracker.getDefaultDisplayId()); - } - - @Override - public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { - pw.println("mIsLargeScreen=" + mIsLargeScreen); - pw.println("mNavMode=" + mNavMode); - for (int i = 0; i < mNavigationBars.size(); i++) { - if (i > 0) { - pw.println(); - } - mNavigationBars.valueAt(i).dump(pw); - } - } + NavigationBar getDefaultNavigationBar(); } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerEmptyImpl.kt new file mode 100644 index 000000000000..e73b078a3d88 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerEmptyImpl.kt @@ -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 com.android.systemui.navigationbar + +import com.android.internal.statusbar.RegisterStatusBarResult +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.phone.BarTransitions +import javax.inject.Inject + +/** A no-op version of [NavigationBarController] for variants like Arc and TV. */ +@SysUISingleton +class NavigationBarControllerEmptyImpl @Inject constructor() : NavigationBarController { + override fun createNavigationBars( + includeDefaultDisplay: Boolean, + result: RegisterStatusBarResult?, + ) {} + override fun removeNavigationBar(displayId: Int) {} + override fun checkNavBarModes(displayId: Int) {} + override fun finishBarAnimations(displayId: Int) {} + override fun touchAutoDim(displayId: Int) {} + override fun transitionTo( + displayId: Int, + @BarTransitions.TransitionMode barMode: Int, + animate: Boolean, + ) {} + override fun disableAnimationsDuringHide(displayId: Int, delay: Long) {} + override fun getDefaultNavigationBarView(): NavigationBarView? = null + override fun getNavigationBarView(displayId: Int): NavigationBarView? = null + override fun isOverviewEnabled(displayId: Int) = false + override fun getDefaultNavigationBar(): NavigationBar? = null +} diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java new file mode 100644 index 000000000000..564e984fbce2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java @@ -0,0 +1,490 @@ +/* + * Copyright (C) 2020 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.navigationbar; + +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; +import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG; +import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen; + +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.hardware.display.DisplayManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.RemoteException; +import android.os.Trace; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Log; +import android.util.SparseArray; +import android.view.Display; +import android.view.IWindowManager; +import android.view.View; +import android.view.WindowManagerGlobal; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.statusbar.RegisterStatusBarResult; +import com.android.settingslib.applications.InterestingConfigChanges; +import com.android.systemui.Dumpable; +import com.android.systemui.dagger.SysUISingleton; +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.model.SysUiState; +import com.android.systemui.recents.OverviewProxyService; +import com.android.systemui.settings.DisplayTracker; +import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.shared.system.TaskStackChangeListeners; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; +import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.util.settings.SecureSettings; +import com.android.wm.shell.back.BackAnimation; +import com.android.wm.shell.pip.Pip; + +import java.io.PrintWriter; +import java.util.Optional; + +import javax.inject.Inject; + +@SysUISingleton +public class NavigationBarControllerImpl implements + ConfigurationController.ConfigurationListener, + NavigationModeController.ModeChangedListener, + Dumpable, NavigationBarController { + + private static final String TAG = NavigationBarControllerImpl.class.getSimpleName(); + + private final Context mContext; + private final Handler mHandler; + private final NavigationBarComponent.Factory mNavigationBarComponentFactory; + private FeatureFlags mFeatureFlags; + private final SecureSettings mSecureSettings; + private final DisplayTracker mDisplayTracker; + private final DisplayManager mDisplayManager; + private final TaskbarDelegate mTaskbarDelegate; + private final NavBarHelper mNavBarHelper; + private int mNavMode; + @VisibleForTesting boolean mIsLargeScreen; + + /** A displayId - nav bar maps. */ + @VisibleForTesting + SparseArray<NavigationBar> mNavigationBars = new SparseArray<>(); + + // Tracks config changes that will actually recreate the nav bar + private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( + ActivityInfo.CONFIG_FONT_SCALE + | ActivityInfo.CONFIG_UI_MODE); + + @Inject + public NavigationBarControllerImpl(Context context, + OverviewProxyService overviewProxyService, + NavigationModeController navigationModeController, + SysUiState sysUiFlagsContainer, + CommandQueue commandQueue, + @Main Handler mainHandler, + ConfigurationController configurationController, + NavBarHelper navBarHelper, + TaskbarDelegate taskbarDelegate, + NavigationBarComponent.Factory navigationBarComponentFactory, + DumpManager dumpManager, + AutoHideController autoHideController, + LightBarController lightBarController, + TaskStackChangeListeners taskStackChangeListeners, + Optional<Pip> pipOptional, + Optional<BackAnimation> backAnimation, + FeatureFlags featureFlags, + SecureSettings secureSettings, + DisplayTracker displayTracker) { + mContext = context; + mHandler = mainHandler; + mNavigationBarComponentFactory = navigationBarComponentFactory; + mFeatureFlags = featureFlags; + mSecureSettings = secureSettings; + mDisplayTracker = displayTracker; + mDisplayManager = mContext.getSystemService(DisplayManager.class); + commandQueue.addCallback(mCommandQueueCallbacks); + configurationController.addCallback(this); + mConfigChanges.applyNewConfig(mContext.getResources()); + mNavMode = navigationModeController.addListener(this); + mNavBarHelper = navBarHelper; + mTaskbarDelegate = taskbarDelegate; + mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService, + navBarHelper, navigationModeController, sysUiFlagsContainer, + dumpManager, autoHideController, lightBarController, pipOptional, + backAnimation.orElse(null), taskStackChangeListeners); + mIsLargeScreen = isLargeScreen(mContext); + dumpManager.registerDumpable(this); + } + + @Override + public void onConfigChanged(Configuration newConfig) { + boolean isOldConfigLargeScreen = mIsLargeScreen; + mIsLargeScreen = isLargeScreen(mContext); + boolean willApplyConfig = mConfigChanges.applyNewConfig(mContext.getResources()); + boolean largeScreenChanged = mIsLargeScreen != isOldConfigLargeScreen; + // TODO(b/243765256): Disable this logging once b/243765256 is fixed. + Log.i(DEBUG_MISSING_GESTURE_TAG, "NavbarController: newConfig=" + newConfig + + " mTaskbarDelegate initialized=" + mTaskbarDelegate.isInitialized() + + " willApplyConfigToNavbars=" + willApplyConfig + + " navBarCount=" + mNavigationBars.size()); + if (mTaskbarDelegate.isInitialized()) { + mTaskbarDelegate.onConfigurationChanged(newConfig); + } + // If we folded/unfolded while in 3 button, show navbar in folded state, hide in unfolded + if (largeScreenChanged && updateNavbarForTaskbar()) { + return; + } + + if (willApplyConfig) { + for (int i = 0; i < mNavigationBars.size(); i++) { + recreateNavigationBar(mNavigationBars.keyAt(i)); + } + } else { + for (int i = 0; i < mNavigationBars.size(); i++) { + mNavigationBars.valueAt(i).onConfigurationChanged(newConfig); + } + } + } + + @Override + public void onNavigationModeChanged(int mode) { + if (mNavMode == mode) { + return; + } + final int oldMode = mNavMode; + mNavMode = mode; + updateAccessibilityButtonModeIfNeeded(); + + mHandler.post(() -> { + // create/destroy nav bar based on nav mode only in unfolded state + if (oldMode != mNavMode) { + updateNavbarForTaskbar(); + } + for (int i = 0; i < mNavigationBars.size(); i++) { + NavigationBar navBar = mNavigationBars.valueAt(i); + if (navBar == null) { + continue; + } + navBar.getView().updateStates(); + } + }); + } + + private void updateAccessibilityButtonModeIfNeeded() { + final int mode = mSecureSettings.getIntForUser( + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT); + + // ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU is compatible under gestural or non-gestural + // mode, so we don't need to update it. + if (mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) { + return; + } + + // ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR is incompatible under gestural mode. Need to + // force update to ACCESSIBILITY_BUTTON_MODE_GESTURE. + if (QuickStepContract.isGesturalMode(mNavMode) + && mode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR) { + mSecureSettings.putIntForUser( + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_GESTURE, + UserHandle.USER_CURRENT); + // ACCESSIBILITY_BUTTON_MODE_GESTURE is incompatible under non gestural mode. Need to + // force update to ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR. + } else if (!QuickStepContract.isGesturalMode(mNavMode) + && mode == ACCESSIBILITY_BUTTON_MODE_GESTURE) { + mSecureSettings.putIntForUser( + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT); + } + } + + private boolean shouldCreateNavBarAndTaskBar(int displayId) { + final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); + + try { + return wms.hasNavigationBar(displayId); + } catch (RemoteException e) { + // Cannot get wms, just return false with warning message. + Log.w(TAG, "Cannot get WindowManager."); + return false; + } + } + + /** @see #initializeTaskbarIfNecessary() */ + private boolean updateNavbarForTaskbar() { + boolean taskbarShown = initializeTaskbarIfNecessary(); + if (!taskbarShown && mNavigationBars.get(mContext.getDisplayId()) == null) { + createNavigationBar(mContext.getDisplay(), null, null); + } + return taskbarShown; + } + + /** @return {@code true} if taskbar is enabled, false otherwise */ + private boolean initializeTaskbarIfNecessary() { + // Enable for large screens or (phone AND flag is set); assuming phone = !mIsLargeScreen + boolean taskbarEnabled = (mIsLargeScreen || mFeatureFlags.isEnabled( + Flags.HIDE_NAVBAR_WINDOW)) && shouldCreateNavBarAndTaskBar(mContext.getDisplayId()); + + if (taskbarEnabled) { + Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary"); + final int displayId = mContext.getDisplayId(); + // Hint to NavBarHelper if we are replacing an existing bar to skip extra work + mNavBarHelper.setTogglingNavbarTaskbar(mNavigationBars.contains(displayId)); + // Remove navigation bar when taskbar is showing + removeNavigationBar(displayId); + mTaskbarDelegate.init(displayId); + mNavBarHelper.setTogglingNavbarTaskbar(false); + Trace.endSection(); + + } else { + mTaskbarDelegate.destroy(); + } + return taskbarEnabled; + } + + private final CommandQueue.Callbacks mCommandQueueCallbacks = new CommandQueue.Callbacks() { + @Override + public void onDisplayRemoved(int displayId) { + removeNavigationBar(displayId); + } + + @Override + public void onDisplayReady(int displayId) { + Display display = mDisplayManager.getDisplay(displayId); + mIsLargeScreen = isLargeScreen(mContext); + createNavigationBar(display, null /* savedState */, null /* result */); + } + + @Override + public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { + final NavigationBar navigationBar = getNavigationBar(displayId); + if (navigationBar != null) { + navigationBar.setNavigationBarLumaSamplingEnabled(enable); + } + } + + @Override + public void showPinningEnterExitToast(boolean entering) { + int displayId = mContext.getDisplayId(); + final NavigationBarView navBarView = getNavigationBarView(displayId); + if (navBarView != null) { + navBarView.showPinningEnterExitToast(entering); + } else if (displayId == mDisplayTracker.getDefaultDisplayId() + && mTaskbarDelegate.isInitialized()) { + mTaskbarDelegate.showPinningEnterExitToast(entering); + } + } + + @Override + public void showPinningEscapeToast() { + int displayId = mContext.getDisplayId(); + final NavigationBarView navBarView = getNavigationBarView(displayId); + if (navBarView != null) { + navBarView.showPinningEscapeToast(); + } else if (displayId == mDisplayTracker.getDefaultDisplayId() + && mTaskbarDelegate.isInitialized()) { + mTaskbarDelegate.showPinningEscapeToast(); + } + } + }; + + /** + * Recreates the navigation bar for the given display. + */ + private void recreateNavigationBar(int displayId) { + // TODO: Improve this flow so that we don't need to create a new nav bar but just + // the view + Bundle savedState = new Bundle(); + NavigationBar bar = mNavigationBars.get(displayId); + if (bar != null) { + bar.onSaveInstanceState(savedState); + } + removeNavigationBar(displayId); + createNavigationBar(mDisplayManager.getDisplay(displayId), savedState, null /* result */); + } + + @Override + public void createNavigationBars(final boolean includeDefaultDisplay, + RegisterStatusBarResult result) { + updateAccessibilityButtonModeIfNeeded(); + + // Don't need to create nav bar on the default display if we initialize TaskBar. + final boolean shouldCreateDefaultNavbar = includeDefaultDisplay + && !initializeTaskbarIfNecessary(); + Display[] displays = mDisplayTracker.getAllDisplays(); + for (Display display : displays) { + if (shouldCreateDefaultNavbar + || display.getDisplayId() != mDisplayTracker.getDefaultDisplayId()) { + createNavigationBar(display, null /* savedState */, result); + } + } + } + + /** + * Adds a navigation bar on default display or an external display if the display supports + * system decorations. + * + * @param display the display to add navigation bar on. + */ + @VisibleForTesting + void createNavigationBar(Display display, Bundle savedState, + RegisterStatusBarResult result) { + if (display == null) { + return; + } + + final int displayId = display.getDisplayId(); + final boolean isOnDefaultDisplay = displayId == mDisplayTracker.getDefaultDisplayId(); + + if (!shouldCreateNavBarAndTaskBar(displayId)) { + return; + } + + // We may show TaskBar on the default display for large screen device. Don't need to create + // navigation bar for this case. + if (isOnDefaultDisplay && initializeTaskbarIfNecessary()) { + return; + } + + final Context context = isOnDefaultDisplay + ? mContext + : mContext.createDisplayContext(display); + NavigationBarComponent component = mNavigationBarComponentFactory.create( + context, savedState); + NavigationBar navBar = component.getNavigationBar(); + navBar.init(); + mNavigationBars.put(displayId, navBar); + + navBar.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + if (result != null) { + navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken, + result.mImeWindowVis, result.mImeBackDisposition, + result.mShowImeSwitcher); + } + } + + @Override + public void onViewDetachedFromWindow(View v) { + v.removeOnAttachStateChangeListener(this); + } + }); + } + + @Override + public void removeNavigationBar(int displayId) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.destroyView(); + mNavigationBars.remove(displayId); + } + } + + @Override + public void checkNavBarModes(int displayId) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.checkNavBarModes(); + } + } + + @Override + public void finishBarAnimations(int displayId) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.finishBarAnimations(); + } + } + + @Override + public void touchAutoDim(int displayId) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.touchAutoDim(); + } + } + + @Override + public void transitionTo(int displayId, @TransitionMode int barMode, boolean animate) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.transitionTo(barMode, animate); + } + } + + @Override + public void disableAnimationsDuringHide(int displayId, long delay) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.disableAnimationsDuringHide(delay); + } + } + + @Override + public @Nullable NavigationBarView getDefaultNavigationBarView() { + return getNavigationBarView(mDisplayTracker.getDefaultDisplayId()); + } + + @Override + public @Nullable NavigationBarView getNavigationBarView(int displayId) { + NavigationBar navBar = getNavigationBar(displayId); + return (navBar == null) ? null : navBar.getView(); + } + + private @Nullable NavigationBar getNavigationBar(int displayId) { + return mNavigationBars.get(displayId); + } + + @Override + public boolean isOverviewEnabled(int displayId) { + final NavigationBarView navBarView = getNavigationBarView(displayId); + if (navBarView != null) { + return navBarView.isOverviewEnabled(); + } else { + return mTaskbarDelegate.isOverviewEnabled(); + } + } + + @Override + @Nullable + public NavigationBar getDefaultNavigationBar() { + return mNavigationBars.get(mDisplayTracker.getDefaultDisplayId()); + } + + @Override + public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { + pw.println("mIsLargeScreen=" + mIsLargeScreen); + pw.println("mNavMode=" + mNavMode); + for (int i = 0; i < mNavigationBars.size(); i++) { + if (i > 0) { + pw.println(); + } + mNavigationBars.valueAt(i).dump(pw); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerModule.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerModule.kt new file mode 100644 index 000000000000..448f2803e867 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerModule.kt @@ -0,0 +1,27 @@ +/* + * 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.navigationbar + +import dagger.Binds +import dagger.Module + +/** A module providing an instance of [NavigationBarController]. */ +@Module +abstract class NavigationBarControllerModule { + @Binds + abstract fun navigationBarController(impl: NavigationBarControllerImpl): NavigationBarController +} diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NoopNavigationBarControllerModule.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/NoopNavigationBarControllerModule.kt new file mode 100644 index 000000000000..b59912a0b8be --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NoopNavigationBarControllerModule.kt @@ -0,0 +1,29 @@ +/* + * 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.navigationbar + +import dagger.Binds +import dagger.Module + +/** A module providing a no-op instance of [NavigationBarController]. */ +@Module +abstract class NoopNavigationBarControllerModule { + @Binds + abstract fun navigationBarController( + impl: NavigationBarControllerEmptyImpl + ): NavigationBarController +} diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt index 0842fe0dd764..ea8eb363cc47 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt @@ -321,7 +321,7 @@ constructor( // When switched to a secondary user, the sysUI is still running in the main user, we will // need to update the shortcut in the secondary user. if (user == getCurrentRunningUser()) { - updateNoteTaskAsUserInternal(user) + launchUpdateNoteTaskAsUser(user) } else { // TODO(b/278729185): Replace fire and forget service with a bounded service. val intent = NoteTaskControllerUpdateService.createIntent(context) @@ -330,23 +330,25 @@ constructor( } @InternalNoteTaskApi - fun updateNoteTaskAsUserInternal(user: UserHandle) { - if (!userManager.isUserUnlocked(user)) { - debugLog { "updateNoteTaskAsUserInternal call but user locked: user=$user" } - return - } + fun launchUpdateNoteTaskAsUser(user: UserHandle) { + applicationScope.launch { + if (!userManager.isUserUnlocked(user)) { + debugLog { "updateNoteTaskAsUserInternal call but user locked: user=$user" } + return@launch + } - val packageName = roleManager.getDefaultRoleHolderAsUser(ROLE_NOTES, user) - val hasNotesRoleHolder = isEnabled && !packageName.isNullOrEmpty() + val packageName = roleManager.getDefaultRoleHolderAsUser(ROLE_NOTES, user) + val hasNotesRoleHolder = isEnabled && !packageName.isNullOrEmpty() - setNoteTaskShortcutEnabled(hasNotesRoleHolder, user) + setNoteTaskShortcutEnabled(hasNotesRoleHolder, user) - if (hasNotesRoleHolder) { - shortcutManager.enableShortcuts(listOf(SHORTCUT_ID)) - val updatedShortcut = roleManager.createNoteShortcutInfoAsUser(context, user) - shortcutManager.updateShortcuts(listOf(updatedShortcut)) - } else { - shortcutManager.disableShortcuts(listOf(SHORTCUT_ID)) + if (hasNotesRoleHolder) { + shortcutManager.enableShortcuts(listOf(SHORTCUT_ID)) + val updatedShortcut = roleManager.createNoteShortcutInfoAsUser(context, user) + shortcutManager.updateShortcuts(listOf(updatedShortcut)) + } else { + shortcutManager.disableShortcuts(listOf(SHORTCUT_ID)) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt index 3e352afe3832..486fde14b828 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt @@ -44,7 +44,7 @@ constructor( override fun onCreate() { super.onCreate() // TODO(b/278729185): Replace fire and forget service with a bounded service. - controller.updateNoteTaskAsUserInternal(user) + controller.launchUpdateNoteTaskAsUser(user) stopSelf() } diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt index fe1034a6aa32..338d3ed42f95 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt @@ -23,6 +23,7 @@ import android.os.UserHandle import android.view.KeyEvent import android.view.KeyEvent.KEYCODE_N import android.view.KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL +import android.view.ViewConfiguration import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.dagger.qualifiers.Background @@ -65,12 +66,6 @@ constructor( * [NoteTaskController], ensure custom actions can be triggered (i.e., keyboard shortcut). */ private fun initializeHandleSystemKey() { - val callbacks = - object : CommandQueue.Callbacks { - override fun handleSystemKey(key: KeyEvent) { - key.toNoteTaskEntryPointOrNull()?.let(controller::showNoteTask) - } - } commandQueue.addCallback(callbacks) } @@ -134,15 +129,39 @@ constructor( controller.updateNoteTaskForCurrentUserAndManagedProfiles() } } -} -/** - * Maps a [KeyEvent] to a [NoteTaskEntryPoint]. If the [KeyEvent] does not represent a - * [NoteTaskEntryPoint], returns null. - */ -private fun KeyEvent.toNoteTaskEntryPointOrNull(): NoteTaskEntryPoint? = - when { - keyCode == KEYCODE_STYLUS_BUTTON_TAIL -> TAIL_BUTTON - keyCode == KEYCODE_N && isMetaPressed && isCtrlPressed -> KEYBOARD_SHORTCUT - else -> null + /** + * Tracks a [KeyEvent], and determines if it should trigger an action to show the note task. + * Returns a [NoteTaskEntryPoint] if an action should be taken, and null otherwise. + */ + private fun KeyEvent.toNoteTaskEntryPointOrNull(): NoteTaskEntryPoint? = + when { + keyCode == KEYCODE_STYLUS_BUTTON_TAIL && isTailButtonNotesGesture() -> TAIL_BUTTON + keyCode == KEYCODE_N && isMetaPressed && isCtrlPressed -> KEYBOARD_SHORTCUT + else -> null + } + + private var lastStylusButtonTailUpEventTime: Long = -MULTI_PRESS_TIMEOUT + + /** + * Perform gesture detection for the stylus tail button to make sure we only show the note task + * when there is a single press. Long presses and multi-presses are ignored for now. + */ + private fun KeyEvent.isTailButtonNotesGesture(): Boolean { + if (keyCode != KEYCODE_STYLUS_BUTTON_TAIL || action != KeyEvent.ACTION_UP) { + return false + } + + val isMultiPress = (downTime - lastStylusButtonTailUpEventTime) < MULTI_PRESS_TIMEOUT + val isLongPress = (eventTime - downTime) >= LONG_PRESS_TIMEOUT + lastStylusButtonTailUpEventTime = eventTime + // For now, trigger action immediately on UP of a single press, without waiting for + // the multi-press timeout to expire. + return !isMultiPress && !isLongPress } + + companion object { + val MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout().toLong() + val LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout().toLong() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java index 544e6ad295ff..e382eca17369 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java @@ -20,6 +20,7 @@ import static android.graphics.drawable.Icon.TYPE_URI; import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT; import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE; +import static com.android.systemui.wallet.util.WalletCardUtilsKt.getPaymentCards; import android.content.Intent; import android.content.pm.PackageManager; @@ -210,7 +211,7 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) { Log.i(TAG, "Successfully retrieved wallet cards."); mIsWalletUpdating = false; - List<WalletCard> cards = response.getWalletCards(); + List<WalletCard> cards = getPaymentCards(response.getWalletCards()); if (cards.isEmpty()) { Log.d(TAG, "No wallet cards exist."); mCardViewDrawable = null; diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt index 9a30aa65068c..3927873f8ba8 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt @@ -32,5 +32,16 @@ sealed class ObservableTransitionState { val fromScene: SceneKey, val toScene: SceneKey, val progress: Flow<Float>, + + /** + * Whether the transition was originally triggered by user input rather than being + * programmatic. If this value is initially true, it will remain true until the transition + * fully completes, even if the user input that triggered the transition has ended. Any + * sub-transitions launched by this one will inherit this value. For example, if the user + * drags a pointer but does not exceed the threshold required to transition to another + * scene, this value will remain true after the pointer is no longer touching the screen and + * will be true in any transition created to animate back to the original position. + */ + val isUserInputDriven: Boolean, ) : ObservableTransitionState() } diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt index 31597c1752db..4bc93a8f1ca5 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt @@ -16,9 +16,7 @@ package com.android.systemui.scene.shared.model -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow /** * Defines interface for classes that can describe a "scene". @@ -34,31 +32,26 @@ interface Scene { val key: SceneKey /** - * Returns a mapping between [UserAction] and flows that emit a [SceneModel]. + * The mapping between [UserAction] and destination [SceneModel]s. * - * When the scene framework detects the user action, it starts a transition to the scene - * described by the latest value in the flow that's mapped from that user action. + * When the scene framework detects a user action, if the current scene has a map entry for that + * user action, the framework starts a transition to the scene in the map. * - * Once the [Scene] becomes the current one, the scene framework will invoke this method and set - * up collectors to watch for new values emitted to each of the flows. If a value is added to - * the map at a given [UserAction], the framework will set up user input handling for that - * [UserAction] and, if such a user action is detected, the framework will initiate a transition - * to that [SceneModel]. + * Once the [Scene] becomes the current one, the scene framework will read this property and set + * up a collector to watch for new mapping values. If every map entry provided by the scene, the + * framework will set up user input handling for its [UserAction] and, if such a user action is + * detected, initiate a transition to the specified [SceneModel]. * - * Note that calling this method does _not_ mean that the given user action has occurred. - * Instead, the method is called before any user action/gesture is detected so that the - * framework can decide whether to set up gesture/input detectors/listeners for that type of - * user action. + * Note that reading from this method does _not_ mean that any user action has occurred. + * Instead, the property is read before any user action/gesture is detected so that the + * framework can decide whether to set up gesture/input detectors/listeners in case user actions + * of the given types ever occur. * * Note that a missing value for a specific [UserAction] means that the user action of the given * type is not currently active in the scene and should be ignored by the framework, while the * current scene is this one. - * - * The API is designed such that it's possible to emit ever-changing values for each - * [UserAction] to enable, disable, or change the destination scene of a given user action. */ - fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = - MutableStateFlow(emptyMap<UserAction, SceneModel>()).asStateFlow() + val destinationScenes: StateFlow<Map<UserAction, SceneModel>> } /** Enumerates all scene framework supported user actions. */ diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java index acb6d969e9d2..7a0c087caacf 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java @@ -151,10 +151,9 @@ public class RecordingController return flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING) ? new ScreenRecordPermissionDialog(context, getHostUserHandle(), this, - activityStarter, dialogLaunchAnimator, mUserContextProvider, - onStartRecordingClicked) - : new ScreenRecordDialog(context, this, activityStarter, - mUserContextProvider, flags, dialogLaunchAnimator, onStartRecordingClicked); + activityStarter, mUserContextProvider, onStartRecordingClicked) + : new ScreenRecordDialog(context, this, mUserContextProvider, + onStartRecordingClicked); } /** diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java index 2a21aaa81404..91e3b60a2cf5 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java @@ -18,7 +18,6 @@ package com.android.systemui.screenrecord; import static android.app.Activity.RESULT_OK; -import static com.android.systemui.media.MediaProjectionAppSelectorActivity.EXTRA_CAPTURE_REGION_RESULT_RECEIVER; import static com.android.systemui.media.MediaProjectionAppSelectorActivity.KEY_CAPTURE_TARGET; import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTERNAL; import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC; @@ -28,13 +27,11 @@ import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.NONE; import android.app.Activity; import android.app.PendingIntent; import android.content.Context; -import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.ResultReceiver; import android.view.Gravity; -import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.ArrayAdapter; @@ -45,13 +42,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; import com.android.systemui.R; -import com.android.systemui.animation.ActivityLaunchAnimator; -import com.android.systemui.animation.DialogLaunchAnimator; -import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; -import com.android.systemui.media.MediaProjectionAppSelectorActivity; import com.android.systemui.media.MediaProjectionCaptureTarget; -import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.phone.SystemUIDialog; @@ -71,23 +62,15 @@ public class ScreenRecordDialog extends SystemUIDialog { private final UserContextProvider mUserContextProvider; @Nullable private final Runnable mOnStartRecordingClicked; - private final ActivityStarter mActivityStarter; - private final FeatureFlags mFlags; - private final DialogLaunchAnimator mDialogLaunchAnimator; private Switch mTapsSwitch; private Switch mAudioSwitch; private Spinner mOptions; public ScreenRecordDialog(Context context, RecordingController controller, - ActivityStarter activityStarter, UserContextProvider userContextProvider, - FeatureFlags flags, DialogLaunchAnimator dialogLaunchAnimator, - @Nullable Runnable onStartRecordingClicked) { + UserContextProvider userContextProvider, @Nullable Runnable onStartRecordingClicked) { super(context); mController = controller; mUserContextProvider = userContextProvider; - mActivityStarter = activityStarter; - mDialogLaunchAnimator = dialogLaunchAnimator; - mFlags = flags; mOnStartRecordingClicked = onStartRecordingClicked; } @@ -120,31 +103,6 @@ public class ScreenRecordDialog extends SystemUIDialog { dismiss(); }); - if (mFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)) { - TextView appBtn = findViewById(R.id.button_app); - - appBtn.setVisibility(View.VISIBLE); - appBtn.setOnClickListener(v -> { - Intent intent = new Intent(getContext(), MediaProjectionAppSelectorActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - // We can't start activity for result here so we use result receiver to get - // the selected target to capture - intent.putExtra(EXTRA_CAPTURE_REGION_RESULT_RECEIVER, - new CaptureTargetResultReceiver()); - - ActivityLaunchAnimator.Controller animationController = - mDialogLaunchAnimator.createActivityLaunchController(appBtn); - - if (animationController == null) { - dismiss(); - } - - mActivityStarter.startActivity(intent, /* dismissShade= */ true, - animationController); - }); - } - mAudioSwitch = findViewById(R.id.screenrecord_audio_switch); mTapsSwitch = findViewById(R.id.screenrecord_taps_switch); mOptions = findViewById(R.id.screen_recording_options); diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt index 9c5da1011bc0..56d732eb230b 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt @@ -33,7 +33,6 @@ import android.widget.Spinner import android.widget.Switch import androidx.annotation.LayoutRes import com.android.systemui.R -import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.media.MediaProjectionAppSelectorActivity import com.android.systemui.media.MediaProjectionCaptureTarget import com.android.systemui.plugins.ActivityStarter @@ -45,7 +44,6 @@ class ScreenRecordPermissionDialog( private val hostUserHandle: UserHandle, private val controller: RecordingController, private val activityStarter: ActivityStarter, - private val dialogLaunchAnimator: DialogLaunchAnimator, private val userContextProvider: UserContextProvider, private val onStartRecordingClicked: Runnable? ) : @@ -85,12 +83,7 @@ class ScreenRecordPermissionDialog( MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_USER_HANDLE, hostUserHandle ) - - val animationController = dialogLaunchAnimator.createActivityLaunchController(v!!) - if (animationController == null) { - dismiss() - } - activityStarter.startActivity(intent, /* dismissShade= */ true, animationController) + activityStarter.startActivity(intent, /* dismissShade= */ true) } dismiss() } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index d2e80fc7cf65..a5abf5825dc6 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -586,6 +586,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private boolean mGestureWaitForTouchSlop; private boolean mIgnoreXTouchSlop; private boolean mExpandLatencyTracking; + private boolean mUseExternalTouch = false; + /** * Whether we're waking up and will play the delayed doze animation in * {@link NotificationWakeUpCoordinator}. If so, we'll want to keep the clock centered until the @@ -1404,13 +1406,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump updateViewControllers(userAvatarView, keyguardUserSwitcherView); - if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW) && !mFeatureFlags.isEnabled( - Flags.LAZY_INFLATE_KEYGUARD)) { - attachSplitShadeMediaPlayerContainer( - mKeyguardViewConfigurator.getKeyguardRootView() - .findViewById(R.id.status_view_media_container)); - } - if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) { // Update keyguard bottom area int index = mView.indexOfChild(mKeyguardBottomArea); @@ -1680,6 +1675,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @ClockSize private int computeDesiredClockSize() { + if (shouldForceSmallClock()) { + return SMALL; + } + if (mSplitShadeEnabled) { return computeDesiredClockSizeForSplitShade(); } @@ -1712,6 +1711,13 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump return LARGE; } + private boolean shouldForceSmallClock() { + return mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE) + && !isOnAod() + // True on small landscape screens + && mResources.getBoolean(R.bool.force_small_clock_on_lockscreen); + } + private void updateKeyguardStatusViewAlignment(boolean animate) { boolean shouldBeCentered = shouldKeyguardStatusViewBeCentered(); ConstraintLayout layout; @@ -4121,12 +4127,22 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump /** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */ boolean handleExternalInterceptTouch(MotionEvent event) { - return mTouchHandler.onInterceptTouchEvent(event); + try { + mUseExternalTouch = true; + return mTouchHandler.onInterceptTouchEvent(event); + } finally { + mUseExternalTouch = false; + } } @Override public boolean handleExternalTouch(MotionEvent event) { - return mTouchHandler.onTouchEvent(event); + try { + mUseExternalTouch = true; + return mTouchHandler.onTouchEvent(event); + } finally { + mUseExternalTouch = false; + } } @Override @@ -4713,9 +4729,20 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump public final class TouchHandler implements View.OnTouchListener, Gefingerpoken { private long mLastTouchDownTime = -1L; - /** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */ + /** + * With the shade and lockscreen being separated in the view hierarchy, touch handling now + * originates with the parent window through {@link #handleExternalTouch}. This allows for + * parity with the legacy hierarchy while not undertaking a massive refactoring of touch + * handling. + * + * @see NotificationShadeWindowViewController#didNotificationPanelInterceptEvent + */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { + if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL) && !mUseExternalTouch) { + return false; + } + mShadeLog.logMotionEvent(event, "NPVC onInterceptTouchEvent"); if (mQsController.disallowTouches()) { mShadeLog.logMotionEvent(event, @@ -4868,8 +4895,20 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump return onTouchEvent(event); } + /** + * With the shade and lockscreen being separated in the view hierarchy, touch handling now + * originates with the parent window through {@link #handleExternalTouch}. This allows for + * parity with the legacy hierarchy while not undertaking a massive refactoring of touch + * handling. + * + * @see NotificationShadeWindowViewController#didNotificationPanelInterceptEvent + */ @Override public boolean onTouchEvent(MotionEvent event) { + if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL) && !mUseExternalTouch) { + return false; + } + if (event.getAction() == MotionEvent.ACTION_DOWN) { if (event.getDownTime() == mLastTouchDownTime) { // An issue can occur when swiping down after unlock, where multiple down diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 880ba92123c6..96fae14cec60 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -267,6 +267,9 @@ public class NotificationShadeWindowViewController implements Dumpable { } mView.setLayoutInsetsController(mNotificationInsetsController); mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() { + boolean mUseDragDownHelperForTouch = false; + boolean mLastInterceptWasDragDownHelper = false; + @Override public Boolean handleDispatchTouchEvent(MotionEvent ev) { if (mStatusBarViewController == null) { // Fix for b/192490822 @@ -360,10 +363,8 @@ public class NotificationShadeWindowViewController implements Dumpable { ); // In case we start outside of the view bounds (below the status bar), we need to - // dispatch - // the touch manually as the view system can't accommodate for touches outside of - // the - // regular view bounds. + // dispatch the touch manually as the view system can't accommodate for touches + // outside of the regular view bounds. if (isDown && ev.getY() >= mView.getBottom()) { mExpandingBelowNotch = true; expandingBelowNotch = true; @@ -405,6 +406,15 @@ public class NotificationShadeWindowViewController implements Dumpable { @Override public boolean shouldInterceptTouchEvent(MotionEvent ev) { + boolean intercepted = shouldInterceptTouchEventInternal(ev); + if (intercepted) { + mUseDragDownHelperForTouch = mLastInterceptWasDragDownHelper; + } + return intercepted; + } + + private boolean shouldInterceptTouchEventInternal(MotionEvent ev) { + mLastInterceptWasDragDownHelper = false; if (mStatusBarStateController.isDozing() && !mDozeServiceHost.isPulsing() && !mDockManager.isDocked()) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { @@ -431,19 +441,36 @@ public class NotificationShadeWindowViewController implements Dumpable { } if (mNotificationPanelViewController.isFullyExpanded() - && mDragDownHelper.isDragDownEnabled() && !mService.isBouncerShowing() && !mStatusBarStateController.isDozing()) { - boolean result = mDragDownHelper.onInterceptTouchEvent(ev); - if (result) { - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mShadeLogger.d("NSWVC: drag down helper intercepted"); + if (mDragDownHelper.isDragDownEnabled()) { + // This handles drag down over lockscreen + boolean result = mDragDownHelper.onInterceptTouchEvent(ev); + if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { + if (result) { + mLastInterceptWasDragDownHelper = true; + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mShadeLogger.d("NSWVC: drag down helper intercepted"); + } + } else if (didNotificationPanelInterceptEvent(ev)) { + return true; + } + } else { + if (result) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mShadeLogger.d("NSWVC: drag down helper intercepted"); + } + } + } + return result; + } else { + // This else handles interactions on the full shade while unlocked + if (didNotificationPanelInterceptEvent(ev)) { + return true; } } - return result; - } else { - return false; } + return false; } @Override @@ -451,7 +478,9 @@ public class NotificationShadeWindowViewController implements Dumpable { MotionEvent cancellation = MotionEvent.obtain(ev); cancellation.setAction(MotionEvent.ACTION_CANCEL); mStackScrollLayout.onInterceptTouchEvent(cancellation); - mNotificationPanelViewController.handleExternalInterceptTouch(cancellation); + if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { + mNotificationPanelViewController.handleExternalInterceptTouch(cancellation); + } cancellation.recycle(); } @@ -461,18 +490,27 @@ public class NotificationShadeWindowViewController implements Dumpable { if (mStatusBarStateController.isDozing()) { handled = !mDozeServiceHost.isPulsing(); } - if (mStatusBarKeyguardViewManager.onTouch(ev)) { return true; } - - if (mDragDownHelper.isDragDownEnabled() - || mDragDownHelper.isDraggingDown()) { - // we still want to finish our drag down gesture when locking the screen - return mDragDownHelper.onTouchEvent(ev) || handled; + if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { + if (mLastInterceptWasDragDownHelper && (mDragDownHelper.isDraggingDown())) { + // we still want to finish our drag down gesture when locking the screen + handled |= mDragDownHelper.onTouchEvent(ev) || handled; + } + if (!handled && mNotificationPanelViewController.handleExternalTouch(ev)) { + return true; + } } else { - return handled; + if (mDragDownHelper.isDragDownEnabled() + || mDragDownHelper.isDraggingDown()) { + // we still want to finish our drag down gesture when locking the screen + return mDragDownHelper.onTouchEvent(ev) || handled; + } else { + return handled; + } } + return handled; } @Override @@ -520,6 +558,20 @@ public class NotificationShadeWindowViewController implements Dumpable { mDepthController.onPanelExpansionChanged(currentState); } + private boolean didNotificationPanelInterceptEvent(MotionEvent ev) { + if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { + // Since NotificationStackScrollLayout is now a sibling of notification_panel, we need + // to also ask NotificationPanelViewController directly, in order to process swipe up + // events originating from notifications + if (mNotificationPanelViewController.handleExternalInterceptTouch(ev)) { + mShadeLogger.d("NSWVC: NPVC intercepted"); + return true; + } + } + + return false; + } + public NotificationShadeWindowView getView() { return mView; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt index bdf114efb2b4..3873ac47040d 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt @@ -129,6 +129,9 @@ class NotificationsQSContainerController @Inject constructor( mView.setStackScroller(notificationStackScrollLayoutController.getView()) mView.setMigratingNSSL(featureFlags.isEnabled(Flags.MIGRATE_NSSL)) + if (featureFlags.isEnabled(Flags.QS_CONTAINER_GRAPH_OPTIMIZER)){ + mView.enableGraphOptimization() + } } public override fun onViewAttached() { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java index a4e439b04fc0..292cf8ec1d98 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java @@ -16,6 +16,8 @@ package com.android.systemui.shade; +import static androidx.constraintlayout.core.widgets.Optimizer.OPTIMIZATION_GRAPH; + import android.app.Fragment; import android.content.Context; import android.content.res.Configuration; @@ -24,7 +26,6 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup.MarginLayoutParams; import android.view.WindowInsets; import androidx.annotation.Nullable; @@ -183,6 +184,10 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout mIsMigratingNSSL = isMigrating; } + void enableGraphOptimization() { + setOptimizationLevel(getOptimizationLevel() | OPTIMIZATION_GRAPH); + } + @Override public boolean dispatchTouchEvent(MotionEvent ev) { return TouchLogger.logDispatchTouch("NotificationsQuickSettingsContainer", ev, diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index ff0d78f89e68..d653cb4fa9d7 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -70,6 +70,7 @@ import com.android.systemui.classifier.Classifier; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.media.controls.pipeline.MediaDataManager; @@ -1776,7 +1777,9 @@ public class QuickSettingsController implements Dumpable { // Dragging down on the lockscreen statusbar should prohibit other interactions // immediately, otherwise we'll wait on the touchslop. This is to allow // dragging down to expanded quick settings directly on the lockscreen. - mPanelView.getParent().requestDisallowInterceptTouchEvent(true); + if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { + mPanelView.getParent().requestDisallowInterceptTouchEvent(true); + } } if (mExpansionAnimator != null) { mInitialHeightOnTouch = mExpansionHeight; @@ -1819,7 +1822,9 @@ public class QuickSettingsController implements Dumpable { && Math.abs(h) > Math.abs(x - mInitialTouchX) && shouldQuickSettingsIntercept( mInitialTouchX, mInitialTouchY, h)) { - mPanelView.getParent().requestDisallowInterceptTouchEvent(true); + if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { + mPanelView.getParent().requestDisallowInterceptTouchEvent(true); + } mShadeLog.onQsInterceptMoveQsTrackingEnabled(h); setTracking(true); traceQsJank(true, false); diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt index 9a356ad1fd0b..19a4ee8ef6a0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt @@ -484,11 +484,13 @@ constructor( if (largeScreenActive) { logInstantEvent("Large screen constraints set") header.setTransition(LARGE_SCREEN_HEADER_TRANSITION_ID) + systemIconsHoverContainer.isClickable = true systemIconsHoverContainer.setOnClickListener { shadeCollapseAction?.run() } } else { logInstantEvent("Small screen constraints set") header.setTransition(HEADER_TRANSITION_ID) systemIconsHoverContainer.setOnClickListener(null) + systemIconsHoverContainer.isClickable = false } header.jumpToState(header.startState) updatePosition() diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt index b77b9e488d7e..99189183f82a 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt @@ -59,6 +59,7 @@ constructor( @Application scope: CoroutineScope, disableFlagsRepository: DisableFlagsRepository, sceneContainerFlags: SceneContainerFlags, + // TODO(b/300258424) convert to direct reference instead of provider sceneInteractorProvider: Provider<SceneInteractor>, keyguardRepository: KeyguardRepository, userSetupRepository: UserSetupRepository, @@ -141,15 +142,22 @@ constructor( * if the user's input gesture has ended but a transition they initiated is animating. */ val isUserInteractingWithShade: Flow<Boolean> = - userInteractingFlow(repository.legacyShadeTracking, repository.legacyShadeExpansion) - + if (sceneContainerFlags.isEnabled()) { + sceneBasedInteracting(sceneInteractorProvider.get(), SceneKey.Shade) + } else { + userInteractingFlow(repository.legacyShadeTracking, repository.legacyShadeExpansion) + } /** * Whether the user is expanding or collapsing quick settings with user input. This will be true * even if the user's input gesture has ended but a transition they initiated is still * animating. */ val isUserInteractingWithQs: Flow<Boolean> = - userInteractingFlow(repository.legacyQsTracking, repository.qsExpansion) + if (sceneContainerFlags.isEnabled()) { + sceneBasedInteracting(sceneInteractorProvider.get(), SceneKey.QuickSettings) + } else { + userInteractingFlow(repository.legacyQsTracking, repository.qsExpansion) + } /** * Whether the user is expanding or collapsing either the shade or quick settings with user @@ -158,6 +166,7 @@ constructor( */ val isUserInteracting: Flow<Boolean> = combine(isUserInteractingWithShade, isUserInteractingWithShade) { shade, qs -> shade || qs } + .distinctUntilChanged() /** Emits true if the shade can be expanded from QQS to QS and false otherwise. */ val isExpandToQsEnabled: Flow<Boolean> = @@ -198,6 +207,18 @@ constructor( } .distinctUntilChanged() + fun sceneBasedInteracting(sceneInteractor: SceneInteractor, sceneKey: SceneKey) = + sceneInteractor.transitionState + .map { state -> + when (state) { + is ObservableTransitionState.Idle -> false + is ObservableTransitionState.Transition -> + state.isUserInputDriven && + (state.toScene == sceneKey || state.fromScene == sceneKey) + } + } + .distinctUntilChanged() + /** * Return a flow for whether a user is interacting with an expandable shade component using * tracking and expansion flows. NOTE: expansion must be a `StateFlow` to guarantee that diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 6304c1ea2635..670fb1289357 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -375,15 +375,8 @@ public class CommandQueue extends IStatusBar.Stub implements /** * @see IStatusBar#showTransient(int, int, boolean). */ - default void showTransient(int displayId, @InsetsType int types) { } - - /** - * @see IStatusBar#showTransient(int, int, boolean). - */ default void showTransient(int displayId, @InsetsType int types, - boolean isGestureOnSystemBar) { - showTransient(displayId, types); - } + boolean isGestureOnSystemBar) {} /** * @see IStatusBar#abortTransient(int, int). diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java index 3dfe068e6137..d058d04728ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.dagger; -import android.app.IActivityManager; import android.app.WallpaperManager; import android.content.Context; import android.hardware.display.DisplayManager; @@ -38,7 +37,6 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.media.controls.pipeline.MediaDataManager; -import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.domain.interactor.PowerInteractor; import com.android.systemui.settings.DisplayTracker; @@ -57,12 +55,10 @@ import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.commandline.CommandRegistry; -import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.RemoteInputControllerLogger; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; -import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.phone.CentralSurfacesImpl; import com.android.systemui.statusbar.phone.KeyguardBypassController; @@ -73,23 +69,15 @@ import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl; import com.android.systemui.statusbar.phone.StatusBarIconList; import com.android.systemui.statusbar.phone.StatusBarNotificationPresenterModule; import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback; -import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; -import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallFlags; -import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.RemoteInputUriController; -import com.android.systemui.statusbar.window.StatusBarWindowController; import com.android.systemui.util.concurrency.DelayableExecutor; -import com.android.systemui.util.time.SystemClock; import dagger.Binds; import dagger.Lazy; import dagger.Module; import dagger.Provides; -import java.util.Optional; -import java.util.concurrent.Executor; - /** * This module provides instances needed to construct {@link CentralSurfacesImpl}. These are moved to * this separate from {@link CentralSurfacesModule} module so that components that wish to build @@ -230,51 +218,6 @@ public interface CentralSurfacesDependenciesModule { } /** - */ - @Provides - @SysUISingleton - static OngoingCallController provideOngoingCallController( - Context context, - CommonNotifCollection notifCollection, - SystemClock systemClock, - ActivityStarter activityStarter, - @Main Executor mainExecutor, - IActivityManager iActivityManager, - OngoingCallLogger logger, - DumpManager dumpManager, - StatusBarWindowController statusBarWindowController, - SwipeStatusBarAwayGestureHandler swipeStatusBarAwayGestureHandler, - StatusBarStateController statusBarStateController, - OngoingCallFlags ongoingCallFlags) { - - boolean ongoingCallInImmersiveEnabled = ongoingCallFlags.isInImmersiveEnabled(); - Optional<StatusBarWindowController> windowController = - ongoingCallInImmersiveEnabled - ? Optional.of(statusBarWindowController) - : Optional.empty(); - Optional<SwipeStatusBarAwayGestureHandler> gestureHandler = - ongoingCallInImmersiveEnabled - ? Optional.of(swipeStatusBarAwayGestureHandler) - : Optional.empty(); - OngoingCallController ongoingCallController = - new OngoingCallController( - context, - notifCollection, - ongoingCallFlags, - systemClock, - activityStarter, - mainExecutor, - iActivityManager, - logger, - dumpManager, - windowController, - gestureHandler, - statusBarStateController); - ongoingCallController.init(); - return ongoingCallController; - } - - /** * {@link NotificationPanelViewController} implements two interfaces: * - {@link com.android.systemui.shade.ShadeViewController}, which can be used by any class * needing access to the shade. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt new file mode 100644 index 000000000000..d1464ede2bd5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt @@ -0,0 +1,52 @@ +/* + * 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.statusbar.dagger + +import com.android.systemui.CoreStartable +import com.android.systemui.statusbar.data.repository.StatusBarModeRepository +import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryImpl +import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +/** + * A module for **only** classes related to the status bar **UI element**. This module specifically + * should **not** include: + * - Classes in the `statusbar` package that are unrelated to the status bar UI. + * - Status bar classes that are already provided by other modules + * ([com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule], + * [com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule], etc.). + */ +@Module +abstract class StatusBarModule { + @Binds + abstract fun bindStatusBarModeRepository( + impl: StatusBarModeRepositoryImpl + ): StatusBarModeRepository + + @Binds + @IntoMap + @ClassKey(StatusBarModeRepositoryImpl::class) + abstract fun bindStatusBarModeRepositoryStart(impl: StatusBarModeRepositoryImpl): CoreStartable + + @Binds + @IntoMap + @ClassKey(OngoingCallController::class) + abstract fun bindOngoingCallController(impl: OngoingCallController): CoreStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt new file mode 100644 index 000000000000..1de7a2f2e698 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt @@ -0,0 +1,113 @@ +/* + * 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.statusbar.data.repository + +import android.view.WindowInsets +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.DisplayId +import com.android.systemui.statusbar.CommandQueue +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +/** + * A repository for the current mode of the status bar on the homescreen (translucent, transparent, + * opaque, lights out, hidden, etc.). + * + * Note: These status bar modes are status bar *window* states that are sent to us from + * WindowManager, not determined internally. + */ +interface StatusBarModeRepository { + /** + * True if the status bar window is showing transiently and will disappear soon, and false + * otherwise. ("Otherwise" in this case means the status bar is persistently hidden OR + * persistently shown.) + * + * This behavior is controlled by WindowManager via + * [android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE], *not* calculated + * internally. SysUI merely obeys the behavior sent to us. + */ + val isTransientShown: StateFlow<Boolean> + + /** + * Requests for the status bar to be shown transiently. + * + * TODO(b/277764509): Don't allow [CentralSurfaces] to set the transient mode; have it + * determined internally instead. + */ + fun showTransient() + + /** + * Requests for the status bar to be no longer showing transiently. + * + * TODO(b/277764509): Don't allow [CentralSurfaces] to set the transient mode; have it + * determined internally instead. + */ + fun clearTransient() +} + +@SysUISingleton +class StatusBarModeRepositoryImpl +@Inject +constructor( + @DisplayId thisDisplayId: Int, + private val commandQueue: CommandQueue, +) : StatusBarModeRepository, CoreStartable { + + private val commandQueueCallback = + object : CommandQueue.Callbacks { + override fun showTransient( + displayId: Int, + @WindowInsets.Type.InsetsType types: Int, + isGestureOnSystemBar: Boolean, + ) { + if (isTransientRelevant(displayId, types)) { + _isTransientShown.value = true + } + } + + override fun abortTransient(displayId: Int, @WindowInsets.Type.InsetsType types: Int) { + if (isTransientRelevant(displayId, types)) { + _isTransientShown.value = false + } + } + + private fun isTransientRelevant( + displayId: Int, + @WindowInsets.Type.InsetsType types: Int, + ): Boolean { + return displayId == thisDisplayId && (types and WindowInsets.Type.statusBars() != 0) + } + } + + override fun start() { + commandQueue.addCallback(commandQueueCallback) + } + + private val _isTransientShown = MutableStateFlow(false) + override val isTransientShown: StateFlow<Boolean> = _isTransientShown.asStateFlow() + + override fun showTransient() { + _isTransientShown.value = true + } + + override fun clearTransient() { + _isTransientShown.value = false + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 1b790fdc35c1..cb21291dae1b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -188,12 +188,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView return super.onInterceptTouchEvent(ev); } - /** - * Called by the TouchHandler when this view is tapped. This will be called for actual taps - * only, i.e. taps that have been filtered by the FalsingManager. - */ - public void onTap() {} - /** Sets the last action up time this view was touched. */ public void setLastActionUpTime(long eventTime) { mLastActionUpTime = eventTime; @@ -227,10 +221,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundNormal.setState(getDrawableState()); } - void setRippleAllowed(boolean allowed) { - mBackgroundNormal.setPressedAllowed(allowed); - } - private void updateOutlineAlpha() { float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED; alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java index 028cd18147ab..ded5ee42d855 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java @@ -80,11 +80,7 @@ public class ActivatableNotificationViewController if (ev.getAction() == MotionEvent.ACTION_UP) { // If this is a false tap, capture the even so it doesn't result in a click. - boolean falseTap = mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY); - if (!falseTap && v instanceof ActivatableNotificationView) { - ((ActivatableNotificationView) v).onTap(); - } - return falseTap; + return mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY); } return result; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 7fa955bc75eb..acece33f0b93 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -593,7 +593,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mPublicLayout.updateExpandButtons(true); updateLimits(); updateShelfIconColor(); - updateRippleAllowed(); if (mUpdateSelfBackgroundOnUpdate) { // Because this is triggered by UiMode change which we already propagated to children, // we know that child rows will receive the same event, and will update their own @@ -2570,31 +2569,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf); } } - updateRippleAllowed(); } - private void updateRippleAllowed() { - boolean allowed = isOnKeyguard() - || mEntry.getSbn().getNotification().contentIntent == null; - setRippleAllowed(allowed); - } - - @Override - public void onTap() { - // This notification will expand and animates into the content activity, so we disable the - // ripple. We will restore its value once the tap/click is actually performed. - if (mEntry.getSbn().getNotification().contentIntent != null) { - setRippleAllowed(false); - } - } - - @Override - public boolean performClick() { - // We force-disabled the ripple in onTap. When this method is called, the code drawing the - // ripple will already have been called so we can restore its value now. - updateRippleAllowed(); - return super.performClick(); - } @Override public int getHeightWithoutLockscreenConstraints() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index 647505cea71b..1fd4d12c06ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -32,7 +32,6 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.internal.util.ArrayUtils; import com.android.systemui.Dumpable; import com.android.systemui.R; @@ -59,7 +58,6 @@ public class NotificationBackgroundView extends View implements Dumpable { private int mExpandAnimationWidth = -1; private int mExpandAnimationHeight = -1; private int mDrawableAlpha = 255; - private boolean mIsPressedAllowed; public NotificationBackgroundView(Context context, AttributeSet attrs) { super(context, attrs); @@ -153,9 +151,17 @@ public class NotificationBackgroundView extends View implements Dumpable { public void setTint(int tintColor) { if (tintColor != 0) { - mBackground.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP); + ColorStateList stateList = new ColorStateList(new int[][]{ + new int[]{com.android.internal.R.attr.state_pressed}, + new int[]{com.android.internal.R.attr.state_hovered}, + new int[]{}}, + + new int[]{0, 0, tintColor} + ); + mBackground.setTintMode(PorterDuff.Mode.SRC_ATOP); + mBackground.setTintList(stateList); } else { - mBackground.clearColorFilter(); + mBackground.setTintList(null); } mTintColor = tintColor; invalidate(); @@ -210,10 +216,6 @@ public class NotificationBackgroundView extends View implements Dumpable { public void setState(int[] drawableState) { if (mBackground != null && mBackground.isStateful()) { - if (!mIsPressedAllowed) { - drawableState = ArrayUtils.removeInt(drawableState, - com.android.internal.R.attr.state_pressed); - } mBackground.setState(drawableState); } } @@ -267,9 +269,12 @@ public class NotificationBackgroundView extends View implements Dumpable { return; } if (mBackground instanceof LayerDrawable) { - GradientDrawable gradientDrawable = - (GradientDrawable) ((LayerDrawable) mBackground).getDrawable(0); - gradientDrawable.setCornerRadii(mCornerRadii); + int numberOfLayers = ((LayerDrawable) mBackground).getNumberOfLayers(); + for (int i = 0; i < numberOfLayers; i++) { + GradientDrawable gradientDrawable = + (GradientDrawable) ((LayerDrawable) mBackground).getDrawable(i); + gradientDrawable.setCornerRadii(mCornerRadii); + } } } @@ -295,10 +300,6 @@ public class NotificationBackgroundView extends View implements Dumpable { invalidate(); } - public void setPressedAllowed(boolean allowed) { - mIsPressedAllowed = allowed; - } - @Override public void dump(PrintWriter pw, @NonNull String[] args) { pw.println("mDontModifyCorners: " + mDontModifyCorners); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt index 96547db1283a..0c4ffe218d37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.row import android.content.Context import android.util.AttributeSet import android.view.View -import android.widget.TextView import com.android.internal.widget.ConversationLayout import com.android.internal.widget.ImageFloatingTextView import com.android.internal.widget.MessagingLayout @@ -36,8 +35,6 @@ class PrecomputedTextViewFactory @Inject constructor() : NotifRemoteViewsFactory attrs: AttributeSet ): View? { return when (name) { - TextView::class.java.name, - TextView::class.java.simpleName -> PrecomputedTextView(context, attrs) ImageFloatingTextView::class.java.name -> PrecomputedImageFloatingTextView(context, attrs) MessagingLayout::class.java.name -> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt index 54af1078741c..9a54de1481a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt @@ -82,11 +82,7 @@ private class TouchHandler( } if (ev.action == MotionEvent.ACTION_UP) { // If this is a false tap, capture the even so it doesn't result in a click. - val falseTap: Boolean = falsingManager.isFalseTap(FalsingManager.LOW_PENALTY) - if (!falseTap && v is ActivatableNotificationView) { - v.onTap() - } - return falseTap + return falsingManager.isFalseTap(FalsingManager.LOW_PENALTY) } return result } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt index 688843de06f2..e52d604d7b02 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.stack.ui.view import android.content.Context import android.util.AttributeSet import android.view.View +import androidx.constraintlayout.core.widgets.Optimizer import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet.BOTTOM @@ -45,6 +46,7 @@ class SharedNotificationContainer( private val baseConstraintSet = ConstraintSet() init { + optimizationLevel = optimizationLevel or Optimizer.OPTIMIZATION_GRAPH baseConstraintSet.apply { create(R.id.nssl_guideline, VERTICAL) setGuidelinePercent(R.id.nssl_guideline, 0.5f) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 7d575685dcae..6ed2089a0324 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -306,10 +306,6 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner { @VisibleForTesting void setBarStateForTest(int state); - void showTransientUnchecked(); - - void clearTransient(); - void acquireGestureWakeLock(long time); boolean setAppearance(int appearance); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index ebcfb8adb08d..c9db153ff280 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -36,7 +36,6 @@ import android.util.Log; import android.util.Slog; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; -import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; @@ -192,17 +191,6 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba } @Override - public void abortTransient(int displayId, @InsetsType int types) { - if (displayId != mDisplayId) { - return; - } - if ((types & WindowInsets.Type.statusBars()) == 0) { - return; - } - mCentralSurfaces.clearTransient(); - } - - @Override public void addQsTile(ComponentName tile) { mQSHost.addTile(tile); } @@ -487,17 +475,6 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba } @Override - public void showTransient(int displayId, @InsetsType int types, boolean isGestureOnSystemBar) { - if (displayId != mDisplayId) { - return; - } - if ((types & WindowInsets.Type.statusBars()) == 0) { - return; - } - mCentralSurfaces.showTransientUnchecked(); - } - - @Override public void toggleKeyboardShortcutsMenu(int deviceId) { mCentralSurfaces.resendMessage(new CentralSurfaces.KeyboardShortcutsMessage(deviceId)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt index 5e505f733c93..50d8e99dd798 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt @@ -86,8 +86,6 @@ abstract class CentralSurfacesEmptyImpl : CentralSurfaces { override fun updateNotificationPanelTouchState() {} override fun getRotation() = 0 override fun setBarStateForTest(state: Int) {} - override fun showTransientUnchecked() {} - override fun clearTransient() {} override fun acquireGestureWakeLock(time: Long) {} override fun setAppearance(appearance: Int) = false override fun getBarMode() = 0 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 8d35d39bceea..fe95b230acbe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -207,6 +207,7 @@ import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.core.StatusBarInitializer; +import com.android.systemui.statusbar.data.repository.StatusBarModeRepository; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; @@ -238,6 +239,7 @@ import com.android.systemui.util.DumpUtilsKt; import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.MessageRouter; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.volume.VolumeComponent; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.startingsurface.SplashscreenContentDrawer; @@ -410,6 +412,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final NotificationShadeWindowController mNotificationShadeWindowController; private final StatusBarInitializer mStatusBarInitializer; private final StatusBarWindowController mStatusBarWindowController; + private final StatusBarModeRepository mStatusBarModeRepository; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting DozeServiceHost mDozeServiceHost; @@ -496,8 +499,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */ private @Appearance int mAppearance; - private boolean mTransientShown; - private final DisplayMetrics mDisplayMetrics; // XXX: gesture research @@ -558,6 +559,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final ScrimController mScrimController; protected DozeScrimController mDozeScrimController; private final BackActionInteractor mBackActionInteractor; + private final JavaAdapter mJavaAdapter; private final Executor mUiBgExecutor; protected boolean mDozing; @@ -633,6 +635,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { StatusBarInitializer statusBarInitializer, StatusBarWindowController statusBarWindowController, StatusBarWindowStateController statusBarWindowStateController, + StatusBarModeRepository statusBarModeRepository, KeyguardUpdateMonitor keyguardUpdateMonitor, StatusBarSignalPolicy statusBarSignalPolicy, PulseExpansionHandler pulseExpansionHandler, @@ -651,6 +654,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { DisplayMetrics displayMetrics, MetricsLogger metricsLogger, ShadeLogger shadeLogger, + JavaAdapter javaAdapter, @UiBackground Executor uiBgExecutor, ShadeSurface shadeSurface, NotificationMediaManager notificationMediaManager, @@ -740,6 +744,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mAutoHideController = autoHideController; mStatusBarInitializer = statusBarInitializer; mStatusBarWindowController = statusBarWindowController; + mStatusBarModeRepository = statusBarModeRepository; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mPulseExpansionHandler = pulseExpansionHandler; mWakeUpCoordinator = notificationWakeUpCoordinator; @@ -759,6 +764,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mDisplayMetrics = displayMetrics; mMetricsLogger = metricsLogger; mShadeLogger = shadeLogger; + mJavaAdapter = javaAdapter; mUiBgExecutor = uiBgExecutor; mShadeSurface = shadeSurface; mMediaManager = notificationMediaManager; @@ -934,7 +940,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { setUpPresenter(); if ((result.mTransientBarTypes & WindowInsets.Type.statusBars()) != 0) { - showTransientUnchecked(); + mStatusBarModeRepository.showTransient(); } mCommandQueueCallbacks.onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions, result.mNavbarColorManagedByIme, result.mBehavior, @@ -1184,6 +1190,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mWallpaperController.setRootView(getNotificationShadeWindowView()); mDemoModeController.addCallback(mDemoModeCallback); + mJavaAdapter.alwaysCollectFlow( + mStatusBarModeRepository.isTransientShown(), this::onTransientShownChanged); mCommandQueueCallbacks = mCommandQueueCallbacksLazy.get(); mCommandQueue.addCallback(mCommandQueueCallbacks); @@ -1249,7 +1257,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public void hide() { - clearTransient(); + mStatusBarModeRepository.clearTransient(); } }); @@ -1537,7 +1545,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { return (v, event) -> { mAutoHideController.checkUserAutoHide(event); mRemoteInputManager.checkRemoteInputOutside(event); - mShadeController.onStatusBarTouch(event); + if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { + mShadeController.onStatusBarTouch(event); + } return getNotificationShadeWindowView().onTouchEvent(event); }; } @@ -1716,25 +1726,15 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { return mCommandQueue.panelsEnabled(); } - @Override - public void showTransientUnchecked() { - if (!mTransientShown) { - mTransientShown = true; + private void onTransientShownChanged(boolean transientShown) { + if (transientShown) { mNoAnimationOnNextBarModeChange = true; - maybeUpdateBarMode(); - } - } - - @Override - public void clearTransient() { - if (mTransientShown) { - mTransientShown = false; - maybeUpdateBarMode(); } + maybeUpdateBarMode(); } private void maybeUpdateBarMode() { - final int barMode = barMode(mTransientShown, mAppearance); + final int barMode = barMode(isTransientShown(), mAppearance); if (updateBarMode(barMode)) { mLightBarController.onStatusBarModeChanged(barMode); updateBubblesVisibility(); @@ -2174,10 +2174,16 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // * When phone is unlocked: we still don't want to execute hiding of the keyguard // as the animation could prepare 'fake AOD' interface (without actually // transitioning to keyguard state) and this might reset the view states + // Log for b/290627350 + Log.d(TAG, "!shouldBeKeyguard mStatusBarStateController.isKeyguardRequested() " + + mStatusBarStateController.isKeyguardRequested() + " keyguardForDozing " + + keyguardForDozing + " wakeAndUnlocking " + wakeAndUnlocking + + " isWakingAndOccluded " + isWakingAndOccluded); if (!mScreenOffAnimationController.isKeyguardHideDelayed() // If we're animating occluded, there's an activity launching over the keyguard // UI. Wait to hide it until after the animation concludes. && !mKeyguardViewMediator.isOccludeAnimationPlaying()) { + Log.d(TAG, "hideKeyguardImpl " + forceStateChange); return hideKeyguardImpl(forceStateChange); } } @@ -3149,7 +3155,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // End Extra BaseStatusBarMethods. boolean isTransientShown() { - return mTransientShown; + return mStatusBarModeRepository.isTransientShown().getValue(); } private void updateLightRevealScrimVisibility() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt index 47ab316bb239..5de0d15ee7d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt @@ -62,6 +62,7 @@ constructor( private var keyguardIndicationArea: View? = null private var binding: KeyguardBottomAreaViewBinder.Binding? = null private var lockIconViewController: LockIconViewController? = null + private var isLockscreenLandscapeEnabled: Boolean = false /** Initializes the view. */ @Deprecated("Deprecated as part of b/278057014") @@ -115,15 +116,26 @@ constructor( } } + fun setIsLockscreenLandscapeEnabled(isLockscreenLandscapeEnabled: Boolean) { + this.isLockscreenLandscapeEnabled = isLockscreenLandscapeEnabled + } + override fun onFinishInflate() { super.onFinishInflate() ambientIndicationArea = findViewById(R.id.ambient_indication_container) + keyguardIndicationArea = findViewById(R.id.keyguard_indication_area) } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) binding?.onConfigurationChanged() + if (isLockscreenLandscapeEnabled) { + updateIndicationAreaBottomMargin() + } + } + + private fun updateIndicationAreaBottomMargin() { keyguardIndicationArea?.let { val params = it.layoutParams as FrameLayout.LayoutParams params.bottomMargin = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt index 3942dae7e0c3..0bad47ecb2ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt @@ -16,11 +16,20 @@ package com.android.systemui.statusbar.phone +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags import com.android.systemui.util.ViewController import javax.inject.Inject -class KeyguardBottomAreaViewController @Inject constructor(view: KeyguardBottomAreaView) : +class KeyguardBottomAreaViewController + @Inject constructor(view: KeyguardBottomAreaView, featureFlags: FeatureFlagsClassic) : ViewController<KeyguardBottomAreaView> (view) { + + init { + view.setIsLockscreenLandscapeEnabled( + featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)) + } + override fun onViewAttached() { } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt index b3af91d9fb5b..52e444fb6bb2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt @@ -27,6 +27,7 @@ import android.util.Log import android.view.View import androidx.annotation.VisibleForTesting import com.android.internal.jank.InteractionJankMonitor +import com.android.systemui.CoreStartable import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.animation.ActivityLaunchAnimator @@ -43,7 +44,6 @@ import com.android.systemui.statusbar.policy.CallbackController import com.android.systemui.statusbar.window.StatusBarWindowController import com.android.systemui.util.time.SystemClock import java.io.PrintWriter -import java.util.Optional import java.util.concurrent.Executor import javax.inject.Inject @@ -54,17 +54,16 @@ import javax.inject.Inject class OngoingCallController @Inject constructor( private val context: Context, private val notifCollection: CommonNotifCollection, - private val ongoingCallFlags: OngoingCallFlags, private val systemClock: SystemClock, private val activityStarter: ActivityStarter, @Main private val mainExecutor: Executor, private val iActivityManager: IActivityManager, private val logger: OngoingCallLogger, private val dumpManager: DumpManager, - private val statusBarWindowController: Optional<StatusBarWindowController>, - private val swipeStatusBarAwayGestureHandler: Optional<SwipeStatusBarAwayGestureHandler>, + private val statusBarWindowController: StatusBarWindowController, + private val swipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler, private val statusBarStateController: StatusBarStateController -) : CallbackController<OngoingCallListener>, Dumpable { +) : CallbackController<OngoingCallListener>, Dumpable, CoreStartable { private var isFullscreen: Boolean = false /** Non-null if there's an active call notification. */ private var callNotificationInfo: CallNotificationInfo? = null @@ -120,12 +119,10 @@ class OngoingCallController @Inject constructor( } } - fun init() { + override fun start() { dumpManager.registerDumpable(this) - if (ongoingCallFlags.isStatusBarChipEnabled()) { - notifCollection.addCollectionListener(notifListener) - statusBarStateController.addCallback(statusBarStateListener) - } + notifCollection.addCollectionListener(notifListener) + statusBarStateController.addCallback(statusBarStateListener) } /** @@ -138,7 +135,7 @@ class OngoingCallController @Inject constructor( this.chipView = chipView val backgroundView: OngoingCallBackgroundContainer? = chipView.findViewById(R.id.ongoing_call_chip_background) - backgroundView?.maxHeightFetcher = { statusBarWindowController.get().statusBarHeight } + backgroundView?.maxHeightFetcher = { statusBarWindowController.statusBarHeight } if (hasOngoingCall()) { updateChip() } @@ -197,9 +194,7 @@ class OngoingCallController @Inject constructor( uidObserver.registerWithUid(currentCallNotificationInfo.uid) if (!currentCallNotificationInfo.statusBarSwipedAway) { - statusBarWindowController.ifPresent { - it.setOngoingProcessRequiresStatusBarVisible(true) - } + statusBarWindowController.setOngoingProcessRequiresStatusBarVisible(true) } updateGestureListening() mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) } @@ -217,23 +212,19 @@ class OngoingCallController @Inject constructor( private fun updateChipClickListener() { if (callNotificationInfo == null) { return } - if (isFullscreen && !ongoingCallFlags.isInImmersiveChipTapEnabled()) { - chipView?.setOnClickListener(null) - } else { - val currentChipView = chipView - val backgroundView = - currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background) - val intent = callNotificationInfo?.intent - if (currentChipView != null && backgroundView != null && intent != null) { - currentChipView.setOnClickListener { - logger.logChipClicked() - activityStarter.postStartActivityDismissingKeyguard( - intent, - ActivityLaunchAnimator.Controller.fromView( - backgroundView, - InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP) - ) - } + val currentChipView = chipView + val backgroundView = + currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background) + val intent = callNotificationInfo?.intent + if (currentChipView != null && backgroundView != null && intent != null) { + currentChipView.setOnClickListener { + logger.logChipClicked() + activityStarter.postStartActivityDismissingKeyguard( + intent, + ActivityLaunchAnimator.Controller.fromView( + backgroundView, + InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP) + ) } } } @@ -247,10 +238,10 @@ class OngoingCallController @Inject constructor( if (callNotificationInfo == null || callNotificationInfo?.statusBarSwipedAway == true || !isFullscreen) { - swipeStatusBarAwayGestureHandler.ifPresent { it.removeOnGestureDetectedCallback(TAG) } + swipeStatusBarAwayGestureHandler.removeOnGestureDetectedCallback(TAG) } else { - swipeStatusBarAwayGestureHandler.ifPresent { - it.addOnGestureDetectedCallback(TAG) { _ -> onSwipeAwayGestureDetected() } + swipeStatusBarAwayGestureHandler.addOnGestureDetectedCallback(TAG) { _ -> + onSwipeAwayGestureDetected() } } } @@ -258,8 +249,8 @@ class OngoingCallController @Inject constructor( private fun removeChip() { callNotificationInfo = null tearDownChipView() - statusBarWindowController.ifPresent { it.setOngoingProcessRequiresStatusBarVisible(false) } - swipeStatusBarAwayGestureHandler.ifPresent { it.removeOnGestureDetectedCallback(TAG) } + statusBarWindowController.setOngoingProcessRequiresStatusBarVisible(false) + swipeStatusBarAwayGestureHandler.removeOnGestureDetectedCallback(TAG) mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) } uidObserver.unregister() } @@ -283,12 +274,8 @@ class OngoingCallController @Inject constructor( private fun onSwipeAwayGestureDetected() { if (DEBUG) { Log.d(TAG, "Swipe away gesture detected") } callNotificationInfo = callNotificationInfo?.copy(statusBarSwipedAway = true) - statusBarWindowController.ifPresent { - it.setOngoingProcessRequiresStatusBarVisible(false) - } - swipeStatusBarAwayGestureHandler.ifPresent { - it.removeOnGestureDetectedCallback(TAG) - } + statusBarWindowController.setOngoingProcessRequiresStatusBarVisible(false) + swipeStatusBarAwayGestureHandler.removeOnGestureDetectedCallback(TAG) } private val statusBarStateListener = object : StatusBarStateController.StateListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt deleted file mode 100644 index fcfcb8f7ff31..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2021 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.statusbar.phone.ongoingcall - -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags -import javax.inject.Inject - -@SysUISingleton -class OngoingCallFlags @Inject constructor(private val featureFlags: FeatureFlags) { - - fun isStatusBarChipEnabled(): Boolean = - featureFlags.isEnabled(Flags.ONGOING_CALL_STATUS_BAR_CHIP) - - fun isInImmersiveEnabled(): Boolean = isStatusBarChipEnabled() - && featureFlags.isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE) - - fun isInImmersiveChipTapEnabled(): Boolean = isInImmersiveEnabled() - && featureFlags.isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP) -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java index 81d04d4458c0..6fd0a4db5a14 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java +++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java @@ -16,6 +16,8 @@ package com.android.systemui.wallet.ui; +import static com.android.systemui.wallet.util.WalletCardUtilsKt.getPaymentCards; + import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -47,10 +49,10 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.KeyguardStateController; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** Controller for the wallet card carousel screen. */ public class WalletScreenController implements @@ -126,22 +128,11 @@ public class WalletScreenController implements return; } Log.i(TAG, "Successfully retrieved wallet cards."); - List<WalletCard> walletCards = response.getWalletCards(); - - boolean allUnknown = true; - for (WalletCard card : walletCards) { - if (card.getCardType() != WalletCard.CARD_TYPE_UNKNOWN) { - allUnknown = false; - break; - } - } + List<WalletCard> walletCards = getPaymentCards(response.getWalletCards()); - List<WalletCardViewInfo> paymentCardData = new ArrayList<>(); - for (WalletCard card : walletCards) { - if (allUnknown || card.getCardType() == WalletCard.CARD_TYPE_PAYMENT) { - paymentCardData.add(new QAWalletCardViewInfo(mContext, card)); - } - } + List<WalletCardViewInfo> paymentCardData = walletCards.stream().map( + card -> new QAWalletCardViewInfo(mContext, card) + ).collect(Collectors.toList()); // Get on main thread for UI updates. mHandler.post(() -> { diff --git a/packages/SystemUI/src/com/android/systemui/wallet/util/WalletCardUtils.kt b/packages/SystemUI/src/com/android/systemui/wallet/util/WalletCardUtils.kt new file mode 100644 index 000000000000..077b80bde953 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wallet/util/WalletCardUtils.kt @@ -0,0 +1,34 @@ +/* + * 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.wallet.util + +import android.service.quickaccesswallet.WalletCard + +/** + * Filters wallet cards to only those of [WalletCard.CARD_TYPE_PAYMENT], or returns all cards if + * they are all of [WalletCard.CARD_TYPE_UNKNOWN] (maintaining pre-U behavior). Used by the wallet + * card carousel, quick settings tile, and lock screen. + */ +fun getPaymentCards(walletCards: List<WalletCard>): List<WalletCard> { + val atLeastOneKnownCardType = walletCards.any { it.cardType != WalletCard.CARD_TYPE_UNKNOWN } + + return if (atLeastOneKnownCardType) { + walletCards.filter { it.cardType == WalletCard.CARD_TYPE_PAYMENT } + } else { + walletCards + } +} diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index 6fafcd51bd50..897c4da0fae2 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -61,6 +61,7 @@ import com.android.wm.shell.onehanded.OneHandedEventCallback; import com.android.wm.shell.onehanded.OneHandedTransitionCallback; import com.android.wm.shell.onehanded.OneHandedUiEventLogger; import com.android.wm.shell.pip.Pip; +import com.android.wm.shell.recents.RecentTasks; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.sysui.ShellInterface; @@ -109,6 +110,7 @@ public final class WMShell implements private final Optional<SplitScreen> mSplitScreenOptional; private final Optional<OneHanded> mOneHandedOptional; private final Optional<DesktopMode> mDesktopModeOptional; + private final Optional<RecentTasks> mRecentTasksOptional; private final CommandQueue mCommandQueue; private final ConfigurationController mConfigurationController; @@ -172,6 +174,7 @@ public final class WMShell implements Optional<SplitScreen> splitScreenOptional, Optional<OneHanded> oneHandedOptional, Optional<DesktopMode> desktopMode, + Optional<RecentTasks> recentTasks, CommandQueue commandQueue, ConfigurationController configurationController, KeyguardStateController keyguardStateController, @@ -195,6 +198,7 @@ public final class WMShell implements mSplitScreenOptional = splitScreenOptional; mOneHandedOptional = oneHandedOptional; mDesktopModeOptional = desktopMode; + mRecentTasksOptional = recentTasks; mWakefulnessLifecycle = wakefulnessLifecycle; mUserTracker = userTracker; mDisplayTracker = displayTracker; @@ -220,6 +224,7 @@ public final class WMShell implements mSplitScreenOptional.ifPresent(this::initSplitScreen); mOneHandedOptional.ifPresent(this::initOneHanded); mDesktopModeOptional.ifPresent(this::initDesktopMode); + mRecentTasksOptional.ifPresent(this::initRecentTasks); mNoteTaskInitializer.initialize(); } @@ -351,6 +356,12 @@ public final class WMShell implements }, mSysUiMainExecutor); } + @VisibleForTesting + void initRecentTasks(RecentTasks recentTasks) { + recentTasks.addAnimationStateListener(mSysUiMainExecutor, + mCommandQueue::onRecentsAnimationStateChanged); + } + @Override public boolean isDumpCritical() { // Dump can't be critical because the shell has to dump on the main thread for diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt index decc457dc452..929604bc81b6 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt @@ -810,7 +810,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { ObservableTransitionState.Transition( SceneKey.Lockscreen, SceneKey.Bouncer, - flowOf(.5f) + flowOf(.5f), + false, ) runCurrent() sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason") @@ -822,7 +823,12 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { // keyguard. sceneInteractor.changeScene(SceneModel(SceneKey.Gone, null), "reason") sceneTransitionStateFlow.value = - ObservableTransitionState.Transition(SceneKey.Bouncer, SceneKey.Gone, flowOf(.5f)) + ObservableTransitionState.Transition( + SceneKey.Bouncer, + SceneKey.Gone, + flowOf(.5f), + false + ) runCurrent() sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason") sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone) @@ -834,7 +840,12 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { clearInvocations(viewMediatorCallback) sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer, null), "reason") sceneTransitionStateFlow.value = - ObservableTransitionState.Transition(SceneKey.Gone, SceneKey.Bouncer, flowOf(.5f)) + ObservableTransitionState.Transition( + SceneKey.Gone, + SceneKey.Bouncer, + flowOf(.5f), + false + ) runCurrent() sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason") sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer) @@ -847,7 +858,12 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { underTest.onViewDetached() sceneInteractor.changeScene(SceneModel(SceneKey.Gone, null), "reason") sceneTransitionStateFlow.value = - ObservableTransitionState.Transition(SceneKey.Bouncer, SceneKey.Gone, flowOf(.5f)) + ObservableTransitionState.Transition( + SceneKey.Bouncer, + SceneKey.Gone, + flowOf(.5f), + false + ) runCurrent() sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason") sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone) @@ -860,7 +876,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { ObservableTransitionState.Transition( SceneKey.Gone, SceneKey.Lockscreen, - flowOf(.5f) + flowOf(.5f), + false, ) runCurrent() sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen, null), "reason") @@ -876,7 +893,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { ObservableTransitionState.Transition( SceneKey.Lockscreen, SceneKey.Gone, - flowOf(.5f) + flowOf(.5f), + false, ) runCurrent() sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason") diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java index f9830b124827..0b0410aa1670 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java @@ -59,6 +59,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; +import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; @@ -108,6 +109,7 @@ public class AppOpsControllerTest extends SysuiTestCase { private AppOpsControllerImpl mController; private TestableLooper mTestableLooper; + private final FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock()); private String mExemptedRolePkgName; @@ -139,6 +141,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController = new AppOpsControllerImpl( mContext, mTestableLooper.getLooper(), + mBgExecutor, mDumpManager, mAudioManager, mSensorPrivacyController, @@ -150,6 +153,8 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void testOnlyListenForFewOps() { mController.setListening(true); + mBgExecutor.runAllReady(); + verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsControllerImpl.OPS, mController); verify(mDispatcher, times(1)).registerReceiverWithHandler(eq(mController), any(), any()); verify(mSensorPrivacyController, times(1)).addCallback(mController); @@ -158,6 +163,7 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void testStopListening() { mController.setListening(false); + mBgExecutor.runAllReady(); verify(mAppOpsManager, times(1)).stopWatchingActive(mController); verify(mDispatcher, times(1)).unregisterReceiver(mController); verify(mSensorPrivacyController, times(1)).removeCallback(mController); @@ -169,6 +175,7 @@ public class AppOpsControllerTest extends SysuiTestCase { .thenReturn(List.of()); mController.setListening(true); + mBgExecutor.runAllReady(); assertThat(mController.getActiveAppOps()).isEmpty(); } @@ -186,6 +193,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // WHEN we start listening mController.setListening(true); + mBgExecutor.runAllReady(); // THEN the active list has the op List<AppOpItem> list = mController.getActiveAppOps(); @@ -218,6 +226,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // WHEN we start listening mController.setListening(true); + mBgExecutor.runAllReady(); // THEN the active list has the ops List<AppOpItem> list = mController.getActiveAppOps(); @@ -265,6 +274,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // WHEN we start listening mController.setListening(true); + mBgExecutor.runAllReady(); // THEN the active list has the ops List<AppOpItem> list = mController.getActiveAppOps(); @@ -304,6 +314,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // WHEN we start listening mController.setListening(true); + mBgExecutor.runAllReady(); // THEN the active list has the ops List<AppOpItem> list = mController.getActiveAppOps(); @@ -341,6 +352,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback( new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); // THEN the callback is notified of the current active ops it cares about @@ -366,11 +378,14 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback( new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION}, mCallback); + mBgExecutor.runAllReady(); + mController.onOpActiveChanged( AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); mTestableLooper.processAllMessages(); + verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); } @@ -383,6 +398,7 @@ public class AppOpsControllerTest extends SysuiTestCase { public void addCallback_partialIncludedCode() { mController.addCallback(new int[]{AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, AppOpsManager.OP_FINE_LOCATION}, mCallback); + mBgExecutor.runAllReady(); mController.onOpActiveChanged( AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged( @@ -400,9 +416,12 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void addCallback_notIncludedCode() { mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); + mBgExecutor.runAllReady(); + mController.onOpActiveChanged( AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); + verify(mCallback, never()).onActiveStateChanged( anyInt(), anyInt(), anyString(), anyBoolean()); } @@ -410,7 +429,10 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void removeCallback_sameCode() { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mBgExecutor.runAllReady(); + mController.removeCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mBgExecutor.runAllReady(); mController.onOpActiveChanged( AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); @@ -421,7 +443,10 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void addCallback_notSameCode() { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mBgExecutor.runAllReady(); + mController.removeCallback(new int[]{AppOpsManager.OP_CAMERA}, mCallback); + mBgExecutor.runAllReady(); mController.onOpActiveChanged( AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); @@ -484,6 +509,8 @@ public class AppOpsControllerTest extends SysuiTestCase { assumeFalse(mExemptedRolePkgName == null || mExemptedRolePkgName.equals("")); mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mBgExecutor.runAllReady(); + mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_NON_USER_SENSITIVE, mExemptedRolePkgName, true); @@ -506,6 +533,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.setBGHandler(mMockHandler); mController.setListening(true); + mBgExecutor.runAllReady(); mController.onOpActiveChanged(AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, @@ -513,6 +541,7 @@ public class AppOpsControllerTest extends SysuiTestCase { assertFalse(mController.getActiveAppOps().isEmpty()); mController.setListening(false); + mBgExecutor.runAllReady(); verify(mMockHandler).removeCallbacksAndMessages(null); assertTrue(mController.getActiveAppOps().isEmpty()); @@ -583,6 +612,7 @@ public class AppOpsControllerTest extends SysuiTestCase { TestHandler testHandler = new TestHandler(mTestableLooper.getLooper()); mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); + mBgExecutor.runAllReady(); mController.setBGHandler(testHandler); mController.onOpActiveChanged( @@ -616,6 +646,7 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void testNotedNotRemovedAfterActive() { mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); + mBgExecutor.runAllReady(); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); @@ -645,6 +676,7 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void testNotedAndActiveOnlyOneCall() { mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); + mBgExecutor.runAllReady(); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); @@ -660,6 +692,7 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void testActiveAndNotedOnlyOneCall() { mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); + mBgExecutor.runAllReady(); mController.onOpActiveChanged( AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); @@ -675,6 +708,7 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void testPausedRecordingIsRetrievedOnCreation() { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( @@ -688,6 +722,7 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void testPausedRecordingFilteredOut() { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( @@ -700,6 +735,7 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void testPausedPhoneCallMicrophoneFilteredOut() { mController.addCallback(new int[]{AppOpsManager.OP_PHONE_CALL_MICROPHONE}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( @@ -715,6 +751,7 @@ public class AppOpsControllerTest extends SysuiTestCase { AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA }, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( @@ -751,6 +788,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add callbacks for the micOp and nonMicOp, called for the micOp active state change, // verify the micOp is the only active op returned. mController.addCallback(new int[]{micOp, nonMicOp}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.opToPublicName(micOp), TEST_UID_OTHER, TEST_PACKAGE_NAME, true); @@ -779,6 +817,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add callbacks for the micOp and nonMicOp, called for the micOp active state change, // verify the micOp is the only active op returned. mController.addCallback(new int[]{micOp, nonMicOp}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.opToPublicName(micOp), TEST_UID_OTHER, TEST_PACKAGE_NAME, true); @@ -807,6 +846,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add callbacks for the micOp and nonMicOp, called for the micOp active state change, // verify the micOp is the only active op returned. mController.addCallback(new int[]{micOp, nonMicOp}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.opToPublicName(micOp), TEST_UID_OTHER, TEST_PACKAGE_NAME, true); @@ -835,6 +875,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add callbacks for the micOp and nonMicOp, called for the micOp active state change, // verify the micOp is the only active op returned. mController.addCallback(new int[]{micOp, nonMicOp}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.opToPublicName(micOp), TEST_UID_OTHER, TEST_PACKAGE_NAME, true); @@ -859,6 +900,7 @@ public class AppOpsControllerTest extends SysuiTestCase { public void testCameraFilteredWhenCameraDisabled() { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); @@ -892,6 +934,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback( new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_PHONE_CALL_CAMERA}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OPSTR_PHONE_CALL_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); @@ -922,6 +965,7 @@ public class AppOpsControllerTest extends SysuiTestCase { private void verifyUnPausedSentActive(int micOpCode) { mController.addCallback(new int[]{micOpCode}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged(AppOpsManager.opToPublicName(micOpCode), TEST_UID, TEST_PACKAGE_NAME, true); @@ -936,6 +980,7 @@ public class AppOpsControllerTest extends SysuiTestCase { private void verifyAudioPausedSentInactive(int micOpCode) { mController.addCallback(new int[]{micOpCode}, mCallback); + mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); mController.onOpActiveChanged(AppOpsManager.opToPublicName(micOpCode), TEST_UID_OTHER, TEST_PACKAGE_NAME, true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt index d36e77889810..b9c0b7fe35d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.graphics.drawable.Drawable import android.service.quickaccesswallet.GetWalletCardsResponse import android.service.quickaccesswallet.QuickAccessWalletClient +import android.service.quickaccesswallet.WalletCard import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.R @@ -38,6 +39,7 @@ import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.test.runTest import org.junit.Before @@ -92,6 +94,40 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { } @Test + fun affordance_keyguardShowing_hasNonPaymentCard_modelIsNone() = + runTest(UnconfinedTestDispatcher()) { + setUpState(cardType = WalletCard.CARD_TYPE_NON_PAYMENT) + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + job.cancel() + } + + @Test + fun affordance_keyguardShowing_hasPaymentCard_visibleModel() = + runTest(UnconfinedTestDispatcher()) { + setUpState(cardType = WalletCard.CARD_TYPE_PAYMENT) + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) + + val visibleModel = latest as KeyguardQuickAffordanceConfig.LockScreenState.Visible + assertThat(visibleModel.icon) + .isEqualTo( + Icon.Loaded( + drawable = ICON, + contentDescription = + ContentDescription.Resource( + res = R.string.accessibility_wallet_button, + ), + ) + ) + job.cancel() + } + + @Test fun affordance_walletFeatureNotEnabled_modelIsNone() = runBlockingTest { setUpState(isWalletFeatureAvailable = false) var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null @@ -187,6 +223,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { isWalletServiceAvailable: Boolean = true, isWalletQuerySuccessful: Boolean = true, hasSelectedCard: Boolean = true, + cardType: Int = WalletCard.CARD_TYPE_UNKNOWN ) { val walletClient: QuickAccessWalletClient = mock() whenever(walletClient.tileIcon).thenReturn(ICON) @@ -202,7 +239,19 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { if (isWalletQuerySuccessful) { onWalletCardsRetrieved( if (hasSelectedCard) { - GetWalletCardsResponse(listOf(mock()), 0) + GetWalletCardsResponse( + listOf( + WalletCard.Builder( + /*cardId= */ CARD_ID, + /*cardType= */ cardType, + /*cardImage= */ mock(), + /*contentDescription= */ CARD_DESCRIPTION, + /*pendingIntent= */ mock() + ) + .build() + ), + 0 + ) } else { GetWalletCardsResponse(emptyList(), 0) } @@ -216,5 +265,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { companion object { private val ICON: Drawable = mock() + private const val CARD_ID: String = "Id" + private const val CARD_DESCRIPTION: String = "Description" } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt index 14cdf2f58a7d..90e217f3418c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt @@ -217,6 +217,7 @@ class KeyguardInteractorTest : SysuiTestCase() { fromScene = SceneKey.Gone, toScene = SceneKey.Lockscreen, progress = flowOf(0f), + isUserInputDriven = false, ) runCurrent() assertThat(isAnimate).isFalse() 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 d6b621e55dd7..7f4755df160b 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 @@ -23,8 +23,6 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.keyguard.shared.model.KeyguardBlueprint import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.view.KeyguardRootView @@ -66,8 +64,6 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() { @Mock private lateinit var splitShadeGuidelines: SplitShadeGuidelines @Mock private lateinit var aodNotificationIconsSection: AodNotificationIconsSection - private val featureFlags = FakeFeatureFlags() - @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -84,23 +80,13 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() { defaultNSSLSection, splitShadeGuidelines, aodNotificationIconsSection, - featureFlags, ) - featureFlags.set(Flags.LAZY_INFLATE_KEYGUARD, false) } @Test fun replaceViews() { val constraintLayout = ConstraintLayout(context, null) underTest.replaceViews(null, constraintLayout) - underTest.sections.forEach { verify(it, never()).addViews(constraintLayout) } - } - - @Test - fun replaceViews_lazyInflateFlagOn() { - featureFlags.set(Flags.LAZY_INFLATE_KEYGUARD, true) - val constraintLayout = ConstraintLayout(context, null) - underTest.replaceViews(null, constraintLayout) underTest.sections.forEach { verify(it).addViews(constraintLayout) } } @@ -110,7 +96,6 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() { val someSection = mock(KeyguardSection::class.java) whenever(prevBlueprint.sections) .thenReturn(underTest.sections.minus(defaultLockIconSection).plus(someSection)) - featureFlags.set(Flags.LAZY_INFLATE_KEYGUARD, true) val constraintLayout = ConstraintLayout(context, null) underTest.replaceViews(prevBlueprint, constraintLayout) underTest.sections.minus(defaultLockIconSection).forEach { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt index b30dc9cc67c4..f40ccfde5a92 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt @@ -44,6 +44,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { private val underTest = LockscreenSceneViewModel( + applicationScope = testScope.backgroundScope, authenticationInteractor = authenticationInteractor, longPress = KeyguardLongPressViewModel( diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java index 89405c109224..c835146dd974 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java @@ -74,11 +74,11 @@ import java.util.Optional; @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest -public class NavigationBarControllerTest extends SysuiTestCase { +public class NavigationBarControllerImplTest extends SysuiTestCase { private static final int SECONDARY_DISPLAY = 1; - private NavigationBarController mNavigationBarController; + private NavigationBarControllerImpl mNavigationBarController; private NavigationBar mDefaultNavBar; private NavigationBar mSecondaryNavBar; private StaticMockitoSession mMockitoSession; @@ -95,7 +95,7 @@ public class NavigationBarControllerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mNavigationBarController = spy( - new NavigationBarController(mContext, + new NavigationBarControllerImpl(mContext, mock(OverviewProxyService.class), mock(NavigationModeController.class), mock(SysUiState.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarInflaterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarInflaterViewTest.java index 7369c82e23ba..52d02b631f89 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarInflaterViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarInflaterViewTest.java @@ -33,8 +33,6 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; import com.android.systemui.navigationbar.buttons.ButtonDispatcher; -import com.android.systemui.navigationbar.NavigationBarInflaterView; -import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.recents.OverviewProxyService; import org.junit.After; diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt index 1536c1737de6..b50032fb073b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt @@ -73,6 +73,7 @@ import kotlin.test.assertNotNull import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runCurrent import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -705,12 +706,12 @@ internal class NoteTaskControllerTest : SysuiTestCase() { fun updateNoteTaskAsUser_sameUser_shouldUpdateShortcuts() { val user = UserHandle.CURRENT val controller = spy(createNoteTaskController()) - doNothing().whenever(controller).updateNoteTaskAsUserInternal(any()) + doNothing().whenever(controller).launchUpdateNoteTaskAsUser(any()) whenever(controller.getCurrentRunningUser()).thenReturn(user) controller.updateNoteTaskAsUser(user) - verify(controller).updateNoteTaskAsUserInternal(user) + verify(controller).launchUpdateNoteTaskAsUser(user) verify(context, never()).startServiceAsUser(any(), any()) } @@ -718,12 +719,12 @@ internal class NoteTaskControllerTest : SysuiTestCase() { fun updateNoteTaskAsUser_differentUser_shouldUpdateShortcutsInUserProcess() { val user = UserHandle.CURRENT val controller = spy(createNoteTaskController(isEnabled = true)) - doNothing().whenever(controller).updateNoteTaskAsUserInternal(any()) + doNothing().whenever(controller).launchUpdateNoteTaskAsUser(any()) whenever(controller.getCurrentRunningUser()).thenReturn(UserHandle.SYSTEM) controller.updateNoteTaskAsUser(user) - verify(controller, never()).updateNoteTaskAsUserInternal(any()) + verify(controller, never()).launchUpdateNoteTaskAsUser(any()) val intent = withArgCaptor { verify(context).startServiceAsUser(capture(), eq(user)) } assertThat(intent).hasComponentClass(NoteTaskControllerUpdateService::class.java) } @@ -733,7 +734,8 @@ internal class NoteTaskControllerTest : SysuiTestCase() { @Test fun updateNoteTaskAsUserInternal_withNotesRole_withShortcuts_shouldUpdateShortcuts() { createNoteTaskController(isEnabled = true) - .updateNoteTaskAsUserInternal(userTracker.userHandle) + .launchUpdateNoteTaskAsUser(userTracker.userHandle) + testScope.runCurrent() val actualComponent = argumentCaptor<ComponentName>() verify(context.packageManager) @@ -768,7 +770,8 @@ internal class NoteTaskControllerTest : SysuiTestCase() { .thenReturn(emptyList()) createNoteTaskController(isEnabled = true) - .updateNoteTaskAsUserInternal(userTracker.userHandle) + .launchUpdateNoteTaskAsUser(userTracker.userHandle) + testScope.runCurrent() val argument = argumentCaptor<ComponentName>() verify(context.packageManager) @@ -787,7 +790,8 @@ internal class NoteTaskControllerTest : SysuiTestCase() { @Test fun updateNoteTaskAsUserInternal_flagDisabled_shouldDisableShortcuts() { createNoteTaskController(isEnabled = false) - .updateNoteTaskAsUserInternal(userTracker.userHandle) + .launchUpdateNoteTaskAsUser(userTracker.userHandle) + testScope.runCurrent() val argument = argumentCaptor<ComponentName>() verify(context.packageManager) diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt index 95bb3e0a4538..78330078076c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt @@ -22,6 +22,8 @@ import android.os.UserManager import android.testing.AndroidTestingRunner import android.view.KeyEvent import android.view.KeyEvent.ACTION_DOWN +import android.view.KeyEvent.ACTION_UP +import android.view.KeyEvent.KEYCODE_N import android.view.KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardUpdateMonitor @@ -30,7 +32,6 @@ import com.android.systemui.settings.FakeUserTracker import com.android.systemui.statusbar.CommandQueue import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever @@ -43,7 +44,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.times @@ -66,6 +66,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { private val executor = FakeExecutor(FakeSystemClock()) private val userTracker = FakeUserTracker() + private val handlerCallbacks = mutableListOf<Runnable>() @Before fun setUp() { @@ -74,19 +75,27 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { } private fun createUnderTest( - isEnabled: Boolean, - bubbles: Bubbles?, + isEnabled: Boolean, + bubbles: Bubbles?, ): NoteTaskInitializer = - NoteTaskInitializer( - controller = controller, - commandQueue = commandQueue, - optionalBubbles = Optional.ofNullable(bubbles), - isEnabled = isEnabled, - roleManager = roleManager, - userTracker = userTracker, - keyguardUpdateMonitor = keyguardMonitor, - backgroundExecutor = executor, - ) + NoteTaskInitializer( + controller = controller, + commandQueue = commandQueue, + optionalBubbles = Optional.ofNullable(bubbles), + isEnabled = isEnabled, + roleManager = roleManager, + userTracker = userTracker, + keyguardUpdateMonitor = keyguardMonitor, + backgroundExecutor = executor, + ) + + private fun createKeyEvent( + action: Int, + code: Int, + downTime: Long = 0L, + eventTime: Long = 0L, + metaState: Int = 0 + ): KeyEvent = KeyEvent(downTime, eventTime, action, code, 0 /*repeat*/, metaState) @Test fun initialize_withUserUnlocked() { @@ -120,12 +129,12 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { underTest.initialize() verifyZeroInteractions( - commandQueue, - bubbles, - controller, - roleManager, - userManager, - keyguardMonitor, + commandQueue, + bubbles, + controller, + roleManager, + userManager, + keyguardMonitor, ) } @@ -136,18 +145,23 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { underTest.initialize() verifyZeroInteractions( - commandQueue, - bubbles, - controller, - roleManager, - userManager, - keyguardMonitor, + commandQueue, + bubbles, + controller, + roleManager, + userManager, + keyguardMonitor, ) } @Test fun initialize_handleSystemKey() { - val expectedKeyEvent = KeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL) + val expectedKeyEvent = + createKeyEvent( + ACTION_DOWN, + KEYCODE_N, + metaState = KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON + ) val underTest = createUnderTest(isEnabled = true, bubbles = bubbles) underTest.initialize() val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) } @@ -176,7 +190,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { underTest.initialize() val callback = withArgCaptor { verify(roleManager) - .addOnRoleHoldersChangedListenerAsUser(any(), capture(), eq(UserHandle.ALL)) + .addOnRoleHoldersChangedListenerAsUser(any(), capture(), eq(UserHandle.ALL)) } callback.onRoleHoldersChanged(ROLE_NOTES, userTracker.userHandle) @@ -203,4 +217,60 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { verify(controller, times(2)).updateNoteTaskForCurrentUserAndManagedProfiles() } + + @Test + fun tailButtonGestureDetection_singlePress_shouldShowNoteTaskOnUp() { + val underTest = createUnderTest(isEnabled = true, bubbles = bubbles) + underTest.initialize() + val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) } + + callback.handleSystemKey( + createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 0) + ) + verify(controller, never()).showNoteTask(any()) + + callback.handleSystemKey( + createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 50) + ) + + verify(controller).showNoteTask(any()) + } + + @Test + fun tailButtonGestureDetection_doublePress_shouldNotShowNoteTaskTwice() { + val underTest = createUnderTest(isEnabled = true, bubbles = bubbles) + underTest.initialize() + val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) } + + callback.handleSystemKey( + createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 0) + ) + callback.handleSystemKey( + createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 50) + ) + callback.handleSystemKey( + createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 99, eventTime = 99) + ) + callback.handleSystemKey( + createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 99, eventTime = 150) + ) + + verify(controller, times(1)).showNoteTask(any()) + } + + @Test + fun tailButtonGestureDetection_longPress_shouldNotShowNoteTask() { + val underTest = createUnderTest(isEnabled = true, bubbles = bubbles) + underTest.initialize() + val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) } + + callback.handleSystemKey( + createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 0) + ) + callback.handleSystemKey( + createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 1000) + ) + + verify(controller, never()).showNoteTask(any()) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java index b00ae399af21..dd55baddc2d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java @@ -395,7 +395,7 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { PendingIntent.getActivity(mContext, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE); WalletCard walletCard = new WalletCard.Builder( - CARD_ID, mCardImage, CARD_DESCRIPTION, pendingIntent).build(); + CARD_ID, mCardImage, CARD_DESCRIPTION, pendingIntent).build(); GetWalletCardsResponse response = new GetWalletCardsResponse(Collections.singletonList(walletCard), 0); @@ -410,6 +410,22 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { } @Test + public void testQueryCards_cardDataPayment_updateSideViewDrawable() { + when(mKeyguardStateController.isUnlocked()).thenReturn(true); + setUpWalletCardWithType(/* hasCard =*/ true, WalletCard.CARD_TYPE_PAYMENT); + + assertNotNull(mTile.getState().sideViewCustomDrawable); + } + + @Test + public void testQueryCards_cardDataNonPayment_updateSideViewDrawable() { + when(mKeyguardStateController.isUnlocked()).thenReturn(true); + setUpWalletCardWithType(/* hasCard =*/ true, WalletCard.CARD_TYPE_NON_PAYMENT); + + assertNull(mTile.getState().sideViewCustomDrawable); + } + + @Test public void testQueryCards_noCards_notUpdateSideViewDrawable() { setUpWalletCard(/* hasCard= */ false); @@ -438,6 +454,29 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { verifyZeroInteractions(mQuickAccessWalletClient); } + private WalletCard createWalletCardWithType(Context context, int cardType) { + PendingIntent pendingIntent = + PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE); + return new WalletCard.Builder(CARD_ID, cardType, CARD_IMAGE, CARD_DESCRIPTION, + pendingIntent).build(); + } + + private void setUpWalletCardWithType(boolean hasCard, int cardType) { + GetWalletCardsResponse response = + new GetWalletCardsResponse( + hasCard + ? Collections.singletonList( + createWalletCardWithType(mContext, cardType)) + : Collections.EMPTY_LIST, 0); + + mTile.handleSetListening(true); + + verify(mController).queryWalletCards(mCallbackCaptor.capture()); + + mCallbackCaptor.getValue().onWalletCardsRetrieved(response); + mTestableLooper.processAllMessages(); + } + private void setUpWalletCard(boolean hasCard) { GetWalletCardsResponse response = new GetWalletCardsResponse( diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt index 141fcbb15c0c..2662a10f432e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt @@ -123,6 +123,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { private val lockscreenSceneViewModel = LockscreenSceneViewModel( + applicationScope = testScope.backgroundScope, authenticationInteractor = authenticationInteractor, longPress = KeyguardLongPressViewModel( @@ -432,6 +433,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { fromScene = getCurrentSceneInUi(), toScene = to.key, progress = progressFlow, + isUserInputDriven = false, ) runCurrent() diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt index 181f8a7e3003..ff28d2dbccdd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt @@ -119,6 +119,7 @@ class SceneContainerRepositoryTest : SysuiTestCase() { fromScene = SceneKey.Lockscreen, toScene = SceneKey.Shade, progress = progress, + isUserInputDriven = false, ) assertThat(reflectedTransitionState).isEqualTo(transitionState.value) diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt index ed716a97410f..afc0e6944839 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt @@ -86,6 +86,7 @@ class SceneInteractorTest : SysuiTestCase() { fromScene = SceneKey.Lockscreen, toScene = SceneKey.Shade, progress = progress, + isUserInputDriven = false, ) assertThat(reflectedTransitionState).isEqualTo(transitionState.value) @@ -123,6 +124,7 @@ class SceneInteractorTest : SysuiTestCase() { fromScene = underTest.desiredScene.value.key, toScene = SceneKey.Shade, progress = progress, + isUserInputDriven = false, ) assertThat(transitionTo).isEqualTo(SceneKey.Shade) @@ -158,7 +160,8 @@ class SceneInteractorTest : SysuiTestCase() { ObservableTransitionState.Transition( fromScene = SceneKey.Gone, toScene = SceneKey.Lockscreen, - progress = flowOf(0.5f) + progress = flowOf(0.5f), + isUserInputDriven = false, ) ) val transitioning by @@ -176,7 +179,8 @@ class SceneInteractorTest : SysuiTestCase() { ObservableTransitionState.Transition( fromScene = SceneKey.Shade, toScene = SceneKey.QuickSettings, - progress = flowOf(0.5f) + progress = flowOf(0.5f), + isUserInputDriven = false, ) ) underTest.setTransitionState(transitionState) @@ -192,7 +196,8 @@ class SceneInteractorTest : SysuiTestCase() { ObservableTransitionState.Transition( fromScene = SceneKey.Shade, toScene = SceneKey.Lockscreen, - progress = flowOf(0.5f) + progress = flowOf(0.5f), + isUserInputDriven = false, ) ) val transitioning by @@ -219,7 +224,8 @@ class SceneInteractorTest : SysuiTestCase() { ObservableTransitionState.Transition( fromScene = SceneKey.Shade, toScene = SceneKey.Lockscreen, - progress = flowOf(0.5f) + progress = flowOf(0.5f), + isUserInputDriven = false, ) assertThat(transitioning).isTrue() diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index 145629a65f68..16fdf8e40ed1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -109,6 +109,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fromScene = SceneKey.Gone, toScene = SceneKey.Shade, progress = flowOf(0.5f), + isUserInputDriven = false, ) assertThat(isVisible).isTrue() sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason") @@ -121,6 +122,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fromScene = SceneKey.Shade, toScene = SceneKey.Gone, progress = flowOf(0.5f), + isUserInputDriven = false, ) assertThat(isVisible).isTrue() sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone), "reason") diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt index 17ee3a1cc906..f6195aa9c3f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt @@ -78,8 +78,8 @@ internal class SceneContainerFlagsTest( @JvmStatic fun testCases() = buildList { repeat(4) { combination -> - val isComposeAvailable = combination and 0b100 != 0 - val areAllFlagsSet = combination and 0b001 != 0 + val isComposeAvailable = combination and 0b10 != 0 + val areAllFlagsSet = combination and 0b01 != 0 val expectedEnabled = isComposeAvailable && areAllFlagsSet diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt deleted file mode 100644 index 03d944475da8..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.screenrecord - -import android.testing.AndroidTestingRunner -import android.testing.TestableLooper -import android.view.View -import androidx.test.filters.SmallTest -import com.android.systemui.R -import com.android.systemui.SysuiTestCase -import com.android.systemui.animation.DialogLaunchAnimator -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags -import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.settings.UserContextProvider -import com.google.common.truth.Truth.assertThat -import org.junit.After -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.MockitoAnnotations -import org.mockito.Mockito.`when` as whenever - -@SmallTest -@RunWith(AndroidTestingRunner::class) -@TestableLooper.RunWithLooper(setAsMainLooper = true) -class ScreenRecordDialogTest : SysuiTestCase() { - - @Mock - private lateinit var starter: ActivityStarter - @Mock - private lateinit var controller: RecordingController - @Mock - private lateinit var userContextProvider: UserContextProvider - @Mock - private lateinit var flags: FeatureFlags - @Mock - private lateinit var dialogLaunchAnimator: DialogLaunchAnimator - @Mock - private lateinit var onStartRecordingClicked: Runnable - - private lateinit var dialog: ScreenRecordDialog - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - - dialog = ScreenRecordDialog( - context, controller, starter, userContextProvider, flags, dialogLaunchAnimator, - onStartRecordingClicked - ) - } - - @After - fun teardown() { - if (::dialog.isInitialized) { - dialog.dismiss() - } - } - - @Test - fun testShowDialog_partialScreenSharingDisabled_appButtonIsNotVisible() { - whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(false) - - dialog.show() - - val visibility = dialog.requireViewById<View>(R.id.button_app).visibility - assertThat(visibility).isEqualTo(View.GONE) - } - - @Test - fun testShowDialog_partialScreenSharingEnabled_appButtonIsVisible() { - whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true) - - dialog.show() - - val visibility = dialog.requireViewById<View>(R.id.button_app).visibility - assertThat(visibility).isEqualTo(View.VISIBLE) - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt index ad6909d71ddd..a6c25be1e6a5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt @@ -24,7 +24,6 @@ import android.widget.Spinner import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase -import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.plugins.ActivityStarter @@ -36,8 +35,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) @@ -48,7 +47,6 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() { @Mock private lateinit var controller: RecordingController @Mock private lateinit var userContextProvider: UserContextProvider @Mock private lateinit var flags: FeatureFlags - @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator @Mock private lateinit var onStartRecordingClicked: Runnable private lateinit var dialog: ScreenRecordPermissionDialog @@ -63,7 +61,6 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() { UserHandle.of(0), controller, starter, - dialogLaunchAnimator, userContextProvider, onStartRecordingClicked ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index 6dadd4c3dca9..8be817839fcc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -16,7 +16,6 @@ package com.android.systemui.shade; -import static com.android.keyguard.FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED; import static com.android.keyguard.KeyguardClockSwitch.LARGE; import static com.android.keyguard.KeyguardClockSwitch.SMALL; import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED; @@ -59,6 +58,7 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.FaceAuthApiRequestReason; import com.android.systemui.DejankUtils; import com.android.systemui.R; +import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.shared.model.WakeSleepReason; import com.android.systemui.keyguard.shared.model.WakefulnessModel; import com.android.systemui.keyguard.shared.model.WakefulnessState; @@ -834,6 +834,42 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test + public void switchesToBigClockInSplitShadeOn_landFlagOn_ForceSmallClock() { + when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(false); + mStatusBarStateController.setState(KEYGUARD); + enableSplitShade(/* enabled= */ false); + mNotificationPanelViewController.setDozing(false, false); + when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)).thenReturn(true); + when(mResources.getBoolean(R.bool.force_small_clock_on_lockscreen)).thenReturn(true); + when(mMediaDataManager.hasActiveMedia()).thenReturn(false); + when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + clearInvocations(mKeyguardStatusViewController); + + enableSplitShade(/* enabled= */ true); + mNotificationPanelViewController.updateResources(); + + verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate */ false); + } + + @Test + public void switchesToBigClockInSplitShadeOn_landFlagOff_DontForceSmallClock() { + when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(false); + mStatusBarStateController.setState(KEYGUARD); + enableSplitShade(/* enabled= */ false); + mNotificationPanelViewController.setDozing(false, false); + when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)).thenReturn(false); + when(mResources.getBoolean(R.bool.force_small_clock_on_lockscreen)).thenReturn(true); + when(mMediaDataManager.hasActiveMedia()).thenReturn(false); + when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + clearInvocations(mKeyguardStatusViewController); + + enableSplitShade(/* enabled= */ true); + mNotificationPanelViewController.updateResources(); + + verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ false); + } + + @Test public void testDisplaysSmallClockOnLockscreenInSplitShadeWhenMediaIsPlaying() { mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); @@ -1064,7 +1100,18 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0); verify(mUpdateMonitor, never()).requestFaceAuth(anyString()); + } + + @Test + public void nsslFlagEnabled_allowOnlyExternalTouches() { + when(mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)).thenReturn(true); + + // This sets the dozing state that is read when onMiddleClicked is eventually invoked. + mTouchHandler.onTouch(mock(View.class), mDownMotionEvent); + verify(mQsController, never()).disallowTouches(); + mNotificationPanelViewController.handleExternalInterceptTouch(mDownMotionEvent); + verify(mQsController).disallowTouches(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 39fe4989260e..3da5f6a4b7c0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -48,6 +48,7 @@ import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransition import com.android.systemui.log.BouncerLogger import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler +import com.android.systemui.statusbar.DragDownHelper import com.android.systemui.statusbar.LockscreenShadeTransitionController import com.android.systemui.statusbar.NotificationInsetsController import com.android.systemui.statusbar.NotificationShadeDepthController @@ -124,6 +125,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider> @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor + @Mock lateinit var dragDownHelper: DragDownHelper @Mock lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel @Mock lateinit var keyEventInteractor: KeyEventInteractor @@ -137,6 +139,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { private lateinit var testScope: TestScope + private lateinit var featureFlags: FakeFeatureFlags + @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -150,12 +154,13 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition) .thenReturn(emptyFlow<TransitionStep>()) - val featureFlags = FakeFeatureFlags() + featureFlags = FakeFeatureFlags() featureFlags.set(Flags.TRACKPAD_GESTURE_COMMON, true) featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false) featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true) featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false) + featureFlags.set(Flags.MIGRATE_NSSL, false) testScope = TestScope() fakeClock = FakeSystemClock() @@ -206,6 +211,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { keyEventInteractor, ) underTest.setupExpandedStatusBar() + underTest.setDragDownHelper(dragDownHelper) interactionEventHandlerCaptor = ArgumentCaptor.forClass(InteractionEventHandler::class.java) verify(view).setInteractionEventHandler(interactionEventHandlerCaptor.capture()) @@ -347,9 +353,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { testScope.runTest { // GIVEN touch dispatcher in a state that returns true underTest.setStatusBarViewController(phoneStatusBarViewController) - whenever(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn( - true - ) + whenever(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) + .thenReturn(true) assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue() // WHEN launch animation is running for 2 seconds @@ -381,6 +386,32 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { } @Test + fun shouldInterceptTouchEvent_notificationPanelViewControllerShouldIntercept() { + // GIVEN not dozing + whenever(sysuiStatusBarStateController.isDozing()).thenReturn(false) + // AND alternate bouncer doesn't want the touch + whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT)) + .thenReturn(false) + // AND the lock icon doesn't want the touch + whenever(lockIconViewController.onInterceptTouchEvent(DOWN_EVENT)).thenReturn(false) + // AND the notification panel can accept touches + whenever(notificationPanelViewController.isFullyExpanded()).thenReturn(true) + whenever(dragDownHelper.isDragDownEnabled).thenReturn(true) + whenever(centralSurfaces.isBouncerShowing()).thenReturn(false) + + // AND the drag down helper doesn't want the touch (to pull the shade down) + whenever(dragDownHelper.onInterceptTouchEvent(DOWN_EVENT)).thenReturn(false) + + featureFlags.set(Flags.MIGRATE_NSSL, true) + + // WHEN asked if should intercept touch + interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT) + + // Verify that NPVC gets a chance to use the touch + verify(notificationPanelViewController).handleExternalInterceptTouch(DOWN_EVENT) + } + + @Test fun testGetKeyguardMessageArea() = testScope.runTest { underTest.keyguardMessageArea diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt index 3031658d3bcc..04c4b45251f2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -164,6 +164,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true) featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false) + featureFlags.set(Flags.MIGRATE_NSSL, false) testScope = TestScope() controller = NotificationShadeWindowViewController( diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt index 36cf1d96b891..e9e6d31ff214 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt @@ -101,7 +101,11 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) fakeSystemClock = FakeSystemClock() delayableExecutor = FakeExecutor(fakeSystemClock) - featureFlags = FakeFeatureFlags().apply { set(Flags.MIGRATE_NSSL, false) } + featureFlags = + FakeFeatureFlags().apply { + set(Flags.MIGRATE_NSSL, false) + set(Flags.QS_CONTAINER_GRAPH_OPTIMIZER, false) + } mContext.ensureTestableResources() whenever(view.context).thenReturn(mContext) whenever(view.resources).thenReturn(mContext.resources) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt index 090bee2c772e..6801f2fb7394 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt @@ -100,7 +100,11 @@ class NotificationsQSContainerControllerTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) fakeSystemClock = FakeSystemClock() delayableExecutor = FakeExecutor(fakeSystemClock) - featureFlags = FakeFeatureFlags().apply { set(Flags.MIGRATE_NSSL, true) } + featureFlags = + FakeFeatureFlags().apply { + set(Flags.MIGRATE_NSSL, true) + set(Flags.QS_CONTAINER_GRAPH_OPTIMIZER, true) + } mContext.ensureTestableResources() whenever(view.context).thenReturn(mContext) whenever(view.resources).thenReturn(mContext.resources) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt index d4b69fad6097..342b1c5b1ad2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt @@ -623,6 +623,7 @@ class ShadeInteractorTest : SysuiTestCase() { fromScene = SceneKey.Lockscreen, toScene = key, progress = progress, + isUserInputDriven = false, ) ) sceneInteractor.setTransitionState(transitionState) @@ -659,6 +660,7 @@ class ShadeInteractorTest : SysuiTestCase() { fromScene = key, toScene = SceneKey.Lockscreen, progress = progress, + isUserInputDriven = false, ) ) sceneInteractor.setTransitionState(transitionState) @@ -694,6 +696,7 @@ class ShadeInteractorTest : SysuiTestCase() { fromScene = SceneKey.Lockscreen, toScene = SceneKey.Shade, progress = progress, + isUserInputDriven = false, ) ) sceneInteractor.setTransitionState(transitionState) @@ -936,4 +939,192 @@ class ShadeInteractorTest : SysuiTestCase() { // THEN user is not interacting assertThat(actual).isFalse() } + @Test + fun userInteracting_idle() = + testScope.runTest() { + // GIVEN an interacting flow based on transitions to and from a scene + val key = SceneKey.Shade + val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key) + val interacting by collectLastValue(interactingFlow) + + // WHEN transition state is idle + val transitionState = + MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) + sceneInteractor.setTransitionState(transitionState) + + // THEN interacting is false + assertThat(interacting).isFalse() + } + + @Test + fun userInteracting_transitioning_toScene_programmatic() = + testScope.runTest() { + // GIVEN an interacting flow based on transitions to and from a scene + val key = SceneKey.QuickSettings + val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key) + val interacting by collectLastValue(interactingFlow) + + // WHEN transition state is starting to move to the scene + val progress = MutableStateFlow(0f) + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = SceneKey.Lockscreen, + toScene = key, + progress = progress, + isUserInputDriven = false, + ) + ) + sceneInteractor.setTransitionState(transitionState) + + // THEN interacting is false + assertThat(interacting).isFalse() + + // WHEN transition state is partially to the scene + progress.value = .4f + + // THEN interacting is false + assertThat(interacting).isFalse() + + // WHEN transition completes + progress.value = 1f + + // THEN interacting is false + assertThat(interacting).isFalse() + } + + @Test + fun userInteracting_transitioning_toScene_userInputDriven() = + testScope.runTest() { + // GIVEN an interacting flow based on transitions to and from a scene + val key = SceneKey.QuickSettings + val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key) + val interacting by collectLastValue(interactingFlow) + + // WHEN transition state is starting to move to the scene + val progress = MutableStateFlow(0f) + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = SceneKey.Lockscreen, + toScene = key, + progress = progress, + isUserInputDriven = true, + ) + ) + sceneInteractor.setTransitionState(transitionState) + + // THEN interacting is true + assertThat(interacting).isTrue() + + // WHEN transition state is partially to the scene + progress.value = .4f + + // THEN interacting is true + assertThat(interacting).isTrue() + + // WHEN transition completes + progress.value = 1f + + // THEN interacting is true + assertThat(interacting).isTrue() + } + + @Test + fun userInteracting_transitioning_fromScene_programmatic() = + testScope.runTest() { + // GIVEN an interacting flow based on transitions to and from a scene + val key = SceneKey.QuickSettings + val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key) + val interacting by collectLastValue(interactingFlow) + + // WHEN transition state is starting to move to the scene + val progress = MutableStateFlow(0f) + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = key, + toScene = SceneKey.Lockscreen, + progress = progress, + isUserInputDriven = false, + ) + ) + sceneInteractor.setTransitionState(transitionState) + + // THEN interacting is false + assertThat(interacting).isFalse() + + // WHEN transition state is partially to the scene + progress.value = .4f + + // THEN interacting is false + assertThat(interacting).isFalse() + + // WHEN transition completes + progress.value = 1f + + // THEN interacting is false + assertThat(interacting).isFalse() + } + + @Test + fun userInteracting_transitioning_fromScene_userInputDriven() = + testScope.runTest() { + // GIVEN an interacting flow based on transitions to and from a scene + val key = SceneKey.QuickSettings + val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key) + val interacting by collectLastValue(interactingFlow) + + // WHEN transition state is starting to move to the scene + val progress = MutableStateFlow(0f) + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = key, + toScene = SceneKey.Lockscreen, + progress = progress, + isUserInputDriven = true, + ) + ) + sceneInteractor.setTransitionState(transitionState) + + // THEN interacting is true + assertThat(interacting).isTrue() + + // WHEN transition state is partially to the scene + progress.value = .4f + + // THEN interacting is true + assertThat(interacting).isTrue() + + // WHEN transition completes + progress.value = 1f + + // THEN interacting is true + assertThat(interacting).isTrue() + } + + @Test + fun userInteracting_transitioning_toAndFromDifferentScenes() = + testScope.runTest() { + // GIVEN an interacting flow based on transitions to and from a scene + val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, SceneKey.Shade) + val interacting by collectLastValue(interactingFlow) + + // WHEN transition state is starting to between different scenes + val progress = MutableStateFlow(0f) + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = SceneKey.Lockscreen, + toScene = SceneKey.QuickSettings, + progress = progress, + isUserInputDriven = true, + ) + ) + sceneInteractor.setTransitionState(transitionState) + + // THEN interacting is false + assertThat(interacting).isFalse() + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt index a09e844c739f..0925858d740d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt @@ -83,7 +83,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { ObservableTransitionState.Transition( fromScene = SceneKey.Shade, toScene = SceneKey.QuickSettings, - progress = MutableStateFlow(0.5f) + progress = MutableStateFlow(0.5f), + isUserInputDriven = false, ) ) ) @@ -100,7 +101,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { ObservableTransitionState.Transition( fromScene = SceneKey.QuickSettings, toScene = SceneKey.Shade, - progress = MutableStateFlow(0.5f) + progress = MutableStateFlow(0.5f), + isUserInputDriven = false, ) ) ) @@ -117,7 +119,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { ObservableTransitionState.Transition( fromScene = SceneKey.Gone, toScene = SceneKey.Shade, - progress = MutableStateFlow(0.5f) + progress = MutableStateFlow(0.5f), + isUserInputDriven = false, ) ) ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java index 88d853e244e0..8f06e636b479 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java @@ -181,29 +181,30 @@ public class PluginInstanceTest extends SysuiTestCase { String ACTION = "testAction"; } - public void assertInstances(Integer allocated, Integer created) { - // Run the garbage collector to finalize and deallocate outstanding - // instances. Since the GC doesn't always appear to want to run - // completely when we ask, we ask it 10 times in a short loop. - for (int i = 0; i < 10; i++) { + private void assertInstances(int allocated, int created) { + // If there are more than the expected number of allocated instances, then we run the + // garbage collector to finalize and deallocate any outstanding non-referenced instances. + // Since the GC doesn't always appear to want to run completely when we ask, we do this up + // to 10 times before failing the test. + for (int i = 0; mCounter.getAllocatedInstances() > allocated && i < 10; i++) { System.runFinalization(); System.gc(); } - mCounter.assertInstances(allocated, created); + assertEquals(allocated, mCounter.getAllocatedInstances()); + assertEquals(created, mCounter.getCreatedInstances()); } public static class RefCounter { public final AtomicInteger mAllocatedInstances = new AtomicInteger(); public final AtomicInteger mCreatedInstances = new AtomicInteger(); - public void assertInstances(Integer allocated, Integer created) { - if (allocated != null) { - assertEquals(allocated.intValue(), mAllocatedInstances.get()); - } - if (created != null) { - assertEquals(created.intValue(), mCreatedInstances.get()); - } + public int getAllocatedInstances() { + return mAllocatedInstances.get(); + } + + public int getCreatedInstances() { + return mCreatedInstances.get(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt new file mode 100644 index 000000000000..bc62e5cf6ad9 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt @@ -0,0 +1,30 @@ +/* + * 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.statusbar.data.repository + +import kotlinx.coroutines.flow.MutableStateFlow + +class FakeStatusBarModeRepository : StatusBarModeRepository { + override val isTransientShown = MutableStateFlow(false) + + override fun showTransient() { + isTransientShown.value = true + } + override fun clearTransient() { + isTransientShown.value = false + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt new file mode 100644 index 000000000000..fa018fdc2bb1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt @@ -0,0 +1,183 @@ +/* + * 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.statusbar.data.repository + +import android.view.WindowInsets +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.mockito.Mockito.verify + +@SmallTest +class StatusBarModeRepositoryImplTest : SysuiTestCase() { + private val commandQueue = mock<CommandQueue>() + + private val underTest = + StatusBarModeRepositoryImpl( + DISPLAY_ID, + commandQueue, + ) + .apply { this.start() } + + private val commandQueueCallback: CommandQueue.Callbacks + get() { + val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>() + verify(commandQueue).addCallback(callbackCaptor.capture()) + return callbackCaptor.value + } + + @Test + fun isTransientShown_commandQueueShow_wrongDisplayId_notUpdated() { + commandQueueCallback.showTransient( + DISPLAY_ID + 1, + WindowInsets.Type.statusBars(), + /* isGestureOnSystemBar= */ false, + ) + + assertThat(underTest.isTransientShown.value).isFalse() + } + + @Test + fun isTransientShown_commandQueueShow_notStatusBarType_notUpdated() { + commandQueueCallback.showTransient( + DISPLAY_ID, + WindowInsets.Type.navigationBars(), + /* isGestureOnSystemBar= */ false, + ) + + assertThat(underTest.isTransientShown.value).isFalse() + } + + @Test + fun isTransientShown_commandQueueShow_true() { + commandQueueCallback.showTransient( + DISPLAY_ID, + WindowInsets.Type.statusBars(), + /* isGestureOnSystemBar= */ false, + ) + + assertThat(underTest.isTransientShown.value).isTrue() + } + + @Test + fun isTransientShown_commandQueueShow_statusBarAndOtherTypes_true() { + commandQueueCallback.showTransient( + DISPLAY_ID, + WindowInsets.Type.statusBars().or(WindowInsets.Type.navigationBars()), + /* isGestureOnSystemBar= */ false, + ) + + assertThat(underTest.isTransientShown.value).isTrue() + } + + @Test + fun isTransientShown_commandQueueAbort_wrongDisplayId_notUpdated() { + // Start as true + commandQueueCallback.showTransient( + DISPLAY_ID, + WindowInsets.Type.statusBars(), + /* isGestureOnSystemBar= */ false, + ) + assertThat(underTest.isTransientShown.value).isTrue() + + // GIVEN the wrong display ID + commandQueueCallback.abortTransient(DISPLAY_ID + 1, WindowInsets.Type.statusBars()) + + // THEN the old value remains + assertThat(underTest.isTransientShown.value).isTrue() + } + + @Test + fun isTransientShown_commandQueueAbort_notStatusBarType_notUpdated() { + // Start as true + commandQueueCallback.showTransient( + DISPLAY_ID, + WindowInsets.Type.statusBars(), + /* isGestureOnSystemBar= */ false, + ) + assertThat(underTest.isTransientShown.value).isTrue() + + // GIVEN the wrong type + commandQueueCallback.abortTransient(DISPLAY_ID, WindowInsets.Type.navigationBars()) + + // THEN the old value remains + assertThat(underTest.isTransientShown.value).isTrue() + } + + @Test + fun isTransientShown_commandQueueAbort_false() { + // Start as true + commandQueueCallback.showTransient( + DISPLAY_ID, + WindowInsets.Type.statusBars(), + /* isGestureOnSystemBar= */ false, + ) + assertThat(underTest.isTransientShown.value).isTrue() + + commandQueueCallback.abortTransient(DISPLAY_ID, WindowInsets.Type.statusBars()) + + assertThat(underTest.isTransientShown.value).isFalse() + } + + @Test + fun isTransientShown_commandQueueAbort_statusBarAndOtherTypes_false() { + // Start as true + commandQueueCallback.showTransient( + DISPLAY_ID, + WindowInsets.Type.statusBars(), + /* isGestureOnSystemBar= */ false, + ) + assertThat(underTest.isTransientShown.value).isTrue() + + commandQueueCallback.abortTransient( + DISPLAY_ID, + WindowInsets.Type.statusBars().or(WindowInsets.Type.captionBar()), + ) + + assertThat(underTest.isTransientShown.value).isFalse() + } + + @Test + fun isTransientShown_showTransient_true() { + underTest.showTransient() + + assertThat(underTest.isTransientShown.value).isTrue() + } + + @Test + fun isTransientShown_clearTransient_false() { + // Start as true + commandQueueCallback.showTransient( + DISPLAY_ID, + WindowInsets.Type.statusBars(), + /* isGestureOnSystemBar= */ false, + ) + assertThat(underTest.isTransientShown.value).isTrue() + + underTest.clearTransient() + + assertThat(underTest.isTransientShown.value).isFalse() + } + + private companion object { + const val DISPLAY_ID = 5 + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index b3f5ea26f9f4..56062162bce6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -180,7 +180,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); - mFeatureFlags.set(Flags.USE_REPOS_FOR_BOUNCER_SHOWING, false); + mFeatureFlags.set(Flags.USE_REPOS_FOR_BOUNCER_SHOWING, true); when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper); when(mKeyguardTransitionRepo.getTransitions()).thenReturn(emptyFlow()); 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 6b944aed9368..26c0fd695b95 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 @@ -82,6 +82,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.TestScopeProvider; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.InitController; import com.android.systemui.R; @@ -145,6 +146,7 @@ import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.core.StatusBarInitializer; +import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationActivityStarter; @@ -177,6 +179,7 @@ import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.MessageRouterImpl; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.volume.VolumeComponent; import com.android.wm.shell.bubbles.Bubbles; @@ -452,6 +455,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { emptySet()), mStatusBarWindowController, mStatusBarWindowStateController, + new FakeStatusBarModeRepository(), mKeyguardUpdateMonitor, mStatusBarSignalPolicy, mPulseExpansionHandler, @@ -470,6 +474,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { new DisplayMetrics(), mMetricsLogger, mShadeLogger, + new JavaAdapter(TestScopeProvider.getTestScope()), mUiBgExecutor, mNotificationPanelViewController, mNotificationMediaManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt index 711e4ac937cc..6430856291b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt @@ -84,7 +84,6 @@ class OngoingCallControllerTest : SysuiTestCase() { private lateinit var controller: OngoingCallController private lateinit var notifCollectionListener: NotifCollectionListener - @Mock private lateinit var mockOngoingCallFlags: OngoingCallFlags @Mock private lateinit var mockSwipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler @Mock private lateinit var mockOngoingCallListener: OngoingCallListener @@ -103,24 +102,22 @@ class OngoingCallControllerTest : SysuiTestCase() { } MockitoAnnotations.initMocks(this) - `when`(mockOngoingCallFlags.isStatusBarChipEnabled()).thenReturn(true) val notificationCollection = mock(CommonNotifCollection::class.java) controller = OngoingCallController( context, notificationCollection, - mockOngoingCallFlags, clock, mockActivityStarter, mainExecutor, mockIActivityManager, OngoingCallLogger(uiEventLoggerFake), DumpManager(), - Optional.of(mockStatusBarWindowController), - Optional.of(mockSwipeStatusBarAwayGestureHandler), + mockStatusBarWindowController, + mockSwipeStatusBarAwayGestureHandler, mockStatusBarStateController, ) - controller.init() + controller.start() controller.addCallback(mockOngoingCallListener) controller.setChipView(chipView) @@ -494,42 +491,7 @@ class OngoingCallControllerTest : SysuiTestCase() { } @Test - fun fullscreenIsTrue_thenCallNotificationAdded_chipNotClickable() { - `when`(mockOngoingCallFlags.isInImmersiveChipTapEnabled()).thenReturn(false) - - getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true) - notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) - - assertThat(chipView.hasOnClickListeners()).isFalse() - } - - @Test - fun callNotificationAdded_thenFullscreenIsTrue_chipNotClickable() { - `when`(mockOngoingCallFlags.isInImmersiveChipTapEnabled()).thenReturn(false) - - notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) - getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true) - - assertThat(chipView.hasOnClickListeners()).isFalse() - } - - @Test - fun fullscreenChangesToFalse_chipClickable() { - `when`(mockOngoingCallFlags.isInImmersiveChipTapEnabled()).thenReturn(false) - - notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) - // First, update to true - getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true) - // Then, update to false - getStateListener().onFullscreenStateChanged(/* isFullscreen= */ false) - - assertThat(chipView.hasOnClickListeners()).isTrue() - } - - @Test - fun fullscreenIsTrue_butChipClickInImmersiveEnabled_chipClickable() { - `when`(mockOngoingCallFlags.isInImmersiveChipTapEnabled()).thenReturn(true) - + fun fullscreenIsTrue_chipStillClickable() { notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java index 692af6a9a37b..c1d11aa1eb89 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java @@ -459,7 +459,7 @@ public class WalletScreenControllerTest extends SysuiTestCase { WalletCard.CARD_TYPE_UNKNOWN), createWalletCardWithType(mContext, WalletCard.CARD_TYPE_PAYMENT), createWalletCardWithType(mContext, WalletCard.CARD_TYPE_NON_PAYMENT) - ); + ); GetWalletCardsResponse response = new GetWalletCardsResponse(walletCardList, 0); mController.onWalletCardsRetrieved(response); mTestableLooper.processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt new file mode 100644 index 000000000000..e46c1f554dd6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt @@ -0,0 +1,73 @@ +/* + * 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.wallet.util + +import android.service.quickaccesswallet.WalletCard +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +/** Test class for WalletCardUtils */ +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +@SmallTest +class WalletCardUtilsTest : SysuiTestCase() { + + private val paymentCard = createWalletCardWithType(WalletCard.CARD_TYPE_PAYMENT) + private val nonPaymentCard = createWalletCardWithType(WalletCard.CARD_TYPE_NON_PAYMENT) + private val unknownCard = createWalletCardWithType(WalletCard.CARD_TYPE_UNKNOWN) + + @Test + fun paymentCards_cardTypesAllUnknown_getsAllCards() { + val walletCardList = + mutableListOf( + createWalletCardWithType(WalletCard.CARD_TYPE_UNKNOWN), + createWalletCardWithType(WalletCard.CARD_TYPE_UNKNOWN), + createWalletCardWithType(WalletCard.CARD_TYPE_UNKNOWN) + ) + + assertThat(walletCardList).isEqualTo(getPaymentCards(walletCardList)) + } + + @Test + fun paymentCards_cardTypesDifferent_onlyGetsPayment() { + val walletCardList = mutableListOf(paymentCard, nonPaymentCard, unknownCard) + + assertThat(getPaymentCards(walletCardList)).isEqualTo(mutableListOf(paymentCard)) + } + + private fun createWalletCardWithType(cardType: Int): WalletCard { + return WalletCard.Builder( + /*cardId= */ CARD_ID, + /*cardType= */ cardType, + /*cardImage= */ mock(), + /*contentDescription= */ CARD_DESCRIPTION, + /*pendingIntent= */ mock() + ) + .build() + } + + companion object { + private const val CARD_ID: String = "ID" + private const val CARD_DESCRIPTION: String = "Description" + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java index ef0adbb91a63..d2c8aea5988f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java @@ -41,6 +41,7 @@ import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.onehanded.OneHandedEventCallback; import com.android.wm.shell.onehanded.OneHandedTransitionCallback; import com.android.wm.shell.pip.Pip; +import com.android.wm.shell.recents.RecentTasks; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.sysui.ShellInterface; @@ -79,6 +80,7 @@ public class WMShellTest extends SysuiTestCase { @Mock ShellExecutor mSysUiMainExecutor; @Mock NoteTaskInitializer mNoteTaskInitializer; @Mock DesktopMode mDesktopMode; + @Mock RecentTasks mRecentTasks; @Before public void setUp() { @@ -91,6 +93,7 @@ public class WMShellTest extends SysuiTestCase { Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mDesktopMode), + Optional.of(mRecentTasks), mCommandQueue, mConfigurationController, mKeyguardStateController, @@ -129,4 +132,10 @@ public class WMShellTest extends SysuiTestCase { any(DesktopModeTaskRepository.VisibleTasksListener.class), any(Executor.class)); } + + @Test + public void initRecentTasks_registersListener() { + mWMShell.initRecentTasks(mRecentTasks); + verify(mRecentTasks).addAnimationStateListener(any(Executor.class), any()); + } } diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 838aae8a83c0..cd879083927f 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -112,7 +112,14 @@ public abstract class PackageManagerInternal { */ public static final int INTEGRITY_VERIFICATION_REJECT = 0; - /** Observer called whenever the list of packages changes */ + /** + * Observer called whenever the list of packages changes. + * + * @deprecated please use {@link com.android.internal.content.PackageMonitor} instead. + * PackageMonitor covers more installation and uninstallation corner cases than + * PackageListObserver. + */ + @Deprecated public interface PackageListObserver { /** A package was added to the system. */ default void onPackageAdded(@NonNull String packageName, int uid) {} @@ -723,7 +730,12 @@ public abstract class PackageManagerInternal { * notified if a package is updated. * <p>The package list will not be updated automatically as packages are * installed / uninstalled. Any changes must be handled within the observer. + * + * @deprecated please use {@link com.android.internal.content.PackageMonitor} instead. + * PackageMonitor covers more installation and uninstallation corner cases than + * PackageListObserver. */ + @Deprecated public abstract @NonNull PackageList getPackageList(@Nullable PackageListObserver observer); /** @@ -733,7 +745,12 @@ public abstract class PackageManagerInternal { * <p>Does nothing if the observer isn't currently registered. * <p>Observers are notified asynchronously and it's possible for an observer to be * invoked after its been removed. + * + * @deprecated please use {@link com.android.internal.content.PackageMonitor} instead. + * PackageMonitor covers more installation and uninstallation corner cases than + * PackageListObserver. */ + @Deprecated public abstract void removePackageListObserver(@NonNull PackageListObserver observer); /** diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 93fe0c9c18c3..553b08501925 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -97,6 +97,11 @@ import static android.os.Process.SYSTEM_UID; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_BG_LAUNCH; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_DELEGATE; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NONE; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_START_FOREGROUND_SERVICE; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_START_SERVICE; import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED; import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER; import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT; @@ -122,6 +127,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.Manifest; +import android.Manifest.permission; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -901,7 +907,10 @@ public final class ActiveServices { showFgsBgRestrictedNotificationLocked(r); logFGSStateChangeLocked(r, FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, - 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN); + 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, callingUid)) { throw new ForegroundServiceStartNotAllowedException(msg); } @@ -2066,6 +2075,7 @@ public final class ActiveServices { boolean alreadyStartedOp = false; boolean stopProcStatsOp = false; + final boolean origFgRequired = r.fgRequired; if (r.fgRequired) { if (DEBUG_SERVICE || DEBUG_BACKGROUND_CHECK) { Slog.i(TAG, "Service called startForeground() as required: " + r); @@ -2117,6 +2127,9 @@ public final class ActiveServices { // Whether to extend the SHORT_SERVICE time out. boolean extendShortServiceTimeout = false; + // Whether setFgsRestrictionLocked() is called in here. Only used for logging. + boolean fgsRestrictionRecalculated = false; + int fgsTypeCheckCode = FGS_TYPE_POLICY_CHECK_UNKNOWN; if (!ignoreForeground) { if (foregroundServiceType == FOREGROUND_SERVICE_TYPE_SHORT_SERVICE @@ -2182,6 +2195,7 @@ public final class ActiveServices { r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); + fgsRestrictionRecalculated = true; if (!r.isFgsAllowedStart()) { Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: " + " BFSL DENIED."); @@ -2246,6 +2260,7 @@ public final class ActiveServices { r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); + fgsRestrictionRecalculated = true; final String temp = "startForegroundDelayMs:" + delayMs; if (r.mInfoAllowStartForeground != null) { r.mInfoAllowStartForeground += "; " + temp; @@ -2266,6 +2281,25 @@ public final class ActiveServices { r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); + fgsRestrictionRecalculated = true; + } + + // When startForeground() is called on a bound service, without having + // it started (i.e. no Context.startService() or startForegroundService() was + // called.) + // called on it, then we probably didn't call setFgsRestrictionLocked() + // in startService(). If fgsRestrictionRecalculated is false, then we + // didn't call setFgsRestrictionLocked() here either. + // + // In this situation, we call setFgsRestrictionLocked() with + // forBoundFgs = false, so we'd set the FGS allowed reason to the + // by-bindings fields, so we can put it in the log, without affecting the + // logic. + if (!fgsRestrictionRecalculated && !r.startRequested) { + setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), + r.appInfo.uid, r.intent.getIntent(), r, r.userId, + BackgroundStartPrivileges.NONE, + false /* isBindService */, true /* forBoundFgs */); } // If the foreground service is not started from TOP process, do not allow it to @@ -2291,7 +2325,10 @@ public final class ActiveServices { ignoreForeground = true; logFGSStateChangeLocked(r, FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, - 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN); + 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, r.appInfo.uid)) { throw new ForegroundServiceStartNotAllowedException(msg); @@ -2331,7 +2368,10 @@ public final class ActiveServices { if (fgsTypeResult.second != null) { logFGSStateChangeLocked(r, FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, - 0, FGS_STOP_REASON_UNKNOWN, fgsTypeResult.first); + 0, FGS_STOP_REASON_UNKNOWN, fgsTypeResult.first, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); throw fgsTypeResult.second; } } @@ -2403,9 +2443,24 @@ public final class ActiveServices { AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); registerAppOpCallbackLocked(r); mAm.updateForegroundServiceUsageStats(r.name, r.userId, true); + + int fgsStartApi = FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NONE; + if (r.startRequested) { + if (origFgRequired) { + fgsStartApi = + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_START_FOREGROUND_SERVICE; + } else { + fgsStartApi = + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_START_SERVICE; + } + } + logFGSStateChangeLocked(r, FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER, - 0, FGS_STOP_REASON_UNKNOWN, fgsTypeCheckCode); + 0, FGS_STOP_REASON_UNKNOWN, fgsTypeCheckCode, + fgsStartApi, + fgsRestrictionRecalculated + ); synchronized (mFGSLogger) { mFGSLogger.logForegroundServiceStart(r.appInfo.uid, 0, r); } @@ -2499,7 +2554,10 @@ public final class ActiveServices { r.mFgsExitTime > r.mFgsEnterTime ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0, FGS_STOP_REASON_STOP_FOREGROUND, - FGS_TYPE_POLICY_CHECK_UNKNOWN); + FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); synchronized (mFGSLogger) { mFGSLogger.logForegroundServiceStop(r.appInfo.uid, r); @@ -3338,7 +3396,10 @@ public final class ActiveServices { FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT, nowUptime > sr.mFgsEnterTime ? (int) (nowUptime - sr.mFgsEnterTime) : 0, FGS_STOP_REASON_UNKNOWN, - FGS_TYPE_POLICY_CHECK_UNKNOWN); + FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); try { sr.app.getThread().scheduleTimeoutService(sr, sr.getShortFgsInfo().getStartId()); } catch (RemoteException e) { @@ -5705,7 +5766,10 @@ public final class ActiveServices { r.mFgsExitTime > r.mFgsEnterTime ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0, FGS_STOP_REASON_STOP_SERVICE, - FGS_TYPE_POLICY_CHECK_UNKNOWN); + FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); synchronized (mFGSLogger) { mFGSLogger.logForegroundServiceStop(r.appInfo.uid, r); } @@ -7452,6 +7516,13 @@ public final class ActiveServices { } } + private void setFgsRestrictionLocked(String callingPackage, + int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId, + BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) { + setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId, + backgroundStartPrivileges, isBindService, /*forBoundFgs*/ false); + } + /** * There are two FGS restrictions: * In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground @@ -7463,11 +7534,14 @@ public final class ActiveServices { * @param intent intent to start/bind service. * @param r the service to start. * @param isBindService True if it's called from bindService(). + * @param forBoundFgs set to true if it's called from Service.startForeground() for a + * service that's not started but bound. * @return true if allow, false otherwise. */ private void setFgsRestrictionLocked(String callingPackage, int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId, - BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) { + BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService, + boolean forBoundFgs) { @ReasonCode int allowWIU; @ReasonCode int allowStart; @@ -7511,9 +7585,19 @@ public final class ActiveServices { r.mAllowWIUInBindService = allowWIU; r.mAllowStartInBindService = allowStart; } else { - r.mAllowWhileInUsePermissionInFgsReasonNoBinding = allowWIU; - r.mAllowStartForegroundNoBinding = allowStart; - + if (!forBoundFgs) { + // This is for "normal" situation. + r.mAllowWhileInUsePermissionInFgsReasonNoBinding = allowWIU; + r.mAllowStartForegroundNoBinding = allowStart; + } else { + // This logic is only for logging, so we only update the "by-binding" fields. + if (r.mAllowWIUByBindings == REASON_DENIED) { + r.mAllowWIUByBindings = allowWIU; + } + if (r.mAllowStartByBindings == REASON_DENIED) { + r.mAllowStartByBindings = allowStart; + } + } // Also do a binding client check, unless called from bindService(). if (r.mAllowWIUByBindings == REASON_DENIED) { r.mAllowWIUByBindings = @@ -8137,7 +8221,10 @@ public final class ActiveServices { */ private void logFGSStateChangeLocked(ServiceRecord r, int state, int durationMs, @FgsStopReason int fgsStopReason, - @ForegroundServicePolicyCheckCode int fgsTypeCheckCode) { + @ForegroundServicePolicyCheckCode int fgsTypeCheckCode, + int fgsStartApi, // from ForegroundServiceStateChanged.FgsStartApi + boolean fgsRestrictionRecalculated + ) { if (!ActivityManagerUtils.shouldSamplePackageForAtom( r.packageName, mAm.mConstants.mFgsAtomSampleRate)) { return; @@ -8194,7 +8281,9 @@ public final class ActiveServices { r.mAllowWIUByBindings, r.mAllowStartForegroundNoBinding, r.mAllowStartInBindService, - r.mAllowStartByBindings); + r.mAllowStartByBindings, + fgsStartApi, + fgsRestrictionRecalculated); int event = 0; if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) { @@ -8373,7 +8462,10 @@ public final class ActiveServices { } logFGSStateChangeLocked(r, FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER, - 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN); + 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_DELEGATE, + false /* fgsRestrictionRecalculated */ + ); // Notify the caller. if (connection != null) { mAm.mHandler.post(() -> { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 50be1288ded9..cbc9ff16e6de 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -16843,7 +16843,7 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i = 0; i < N; i++) { PendingTempAllowlist ptw = list[i]; mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid, - ptw.duration, ptw.type, true, ptw.reasonCode, ptw.tag, + ptw.duration, ptw.type, false, ptw.reasonCode, ptw.tag, ptw.callingUid); } } diff --git a/services/core/java/com/android/server/am/AnrTimer.java b/services/core/java/com/android/server/am/AnrTimer.java index cd6f009a4106..378a38602211 100644 --- a/services/core/java/com/android/server/am/AnrTimer.java +++ b/services/core/java/com/android/server/am/AnrTimer.java @@ -38,11 +38,13 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.Keep; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.ProcessCpuTracker; +import com.android.internal.util.RingBuffer; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; @@ -75,7 +77,7 @@ import java.util.concurrent.atomic.AtomicInteger; * * @hide */ -abstract class AnrTimer<V> { +class AnrTimer<V> { /** * The log tag. @@ -139,6 +141,8 @@ abstract class AnrTimer<V> { final String tag; /** A partial stack that localizes the caller of the operation. */ final StackTraceElement[] stack; + /** The date, in local time, the error was created. */ + final String date; Error(@NonNull String issue, @NonNull String operation, @NonNull String tag, @NonNull StackTraceElement[] stack, @NonNull String arg) { @@ -147,21 +151,17 @@ abstract class AnrTimer<V> { this.tag = tag; this.stack = stack; this.arg = arg; + this.date = new Date().toString(); } } /** * A list of errors detected during processing. Errors correspond to "timer not found" * conditions. The stack trace identifies the source of the call. The list is - * first-in/first-out, and the size is limited to MAX_SAVED_ERROR_COUNT. + * first-in/first-out, and the size is limited to 20. */ @GuardedBy("sErrors") - private static final ArrayList<Error> sErrors = new ArrayList<>(); - - /** - * The maximum number of errors that are saved in the sErrors list. - */ - private static final int MAX_SAVED_ERROR_COUNT = 20; + private static final RingBuffer<Error> sErrors = new RingBuffer<>(Error.class, 20); /** * A record of a single anr timer. The pid and uid are retained for reference but they do not @@ -420,7 +420,7 @@ abstract class AnrTimer<V> { if (extension > 0) { post(t, extension); } else { - onExpiredLocked(t, now()); + onExpiredLocked(t); } } return true; @@ -706,7 +706,7 @@ abstract class AnrTimer<V> { * The notifier that a timer has fired. The timer is not modified. */ @GuardedBy("mLock") - private void onExpiredLocked(@NonNull Timer timer, long when) { + private void onExpiredLocked(@NonNull Timer timer) { if (DEBUG) report(timer, "expire"); traceBegin(timer, "expired"); mHandler.sendMessage(Message.obtain(mHandler, mWhat, timer.arg)); @@ -757,12 +757,7 @@ abstract class AnrTimer<V> { // This should be enough to isolate the location of the call. StackTraceElement[] location = Arrays.copyOfRange(s, 6, 9); synchronized (sErrors) { - // Ensure the error list does not grow beyond the limit. - while (sErrors.size() >= MAX_SAVED_ERROR_COUNT) { - sErrors.remove(0); - } - // Add the new error to the list. - sErrors.add(new Error(errorMsg, operation, mLabel, location, what)); + sErrors.append(new Error(errorMsg, operation, mLabel, location, what)); } if (DEBUG) Log.w(TAG, operation + " " + errorMsg + " " + mLabel + " timer " + what); mTotalErrors++; @@ -790,6 +785,7 @@ abstract class AnrTimer<V> { private static void dump(IndentingPrintWriter ipw, int seq, Error err) { ipw.format("%2d: op:%s tag:%s issue:%s arg:%s\n", seq, err.operation, err.tag, err.issue, err.arg); + ipw.format(" date:%s\n", err.date); ipw.increaseIndent(); for (int i = 0; i < err.stack.length; i++) { ipw.println(" " + err.stack[i].toString()); @@ -801,15 +797,15 @@ abstract class AnrTimer<V> { * Dump all errors to the output stream. */ private static void dumpErrors(IndentingPrintWriter ipw) { - ArrayList<Error> errors; + Error errors[]; synchronized (sErrors) { if (sErrors.size() == 0) return; - errors = (ArrayList<Error>) sErrors.clone(); + errors = sErrors.toArray(); } ipw.println("Errors"); ipw.increaseIndent(); - for (int i = 0; i < errors.size(); i++) { - dump(ipw, i, errors.get(i)); + for (int i = 0; i < errors.length; i++) { + if (errors[i] != null) dump(ipw, i, errors[i]); } ipw.decreaseIndent(); } diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index c35a3b2474aa..5d31d1545b8d 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -1347,8 +1347,8 @@ class BroadcastProcessQueue { * Set the timeout flag to indicate that an ANR timer has been started. A value of true means a * timer is running; a value of false means there is no timer running. */ - void setTimeoutScheduled(boolean timeoutStarted) { - mTimeoutScheduled = timeoutStarted; + void setTimeoutScheduled(boolean timeoutScheduled) { + mTimeoutScheduled = timeoutScheduled; } /** diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 6a41628601b4..a3dac6dc3404 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -1183,7 +1183,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } private class BroadcastAnrTimer extends AnrTimer<BroadcastProcessQueue> { - BroadcastAnrTimer(Handler handler) { + BroadcastAnrTimer(@NonNull Handler handler) { super(Objects.requireNonNull(handler), MSG_DELIVERY_TIMEOUT, "BROADCAST_TIMEOUT", true); } diff --git a/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java index f6859d1f027e..e0a71d46641a 100644 --- a/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java +++ b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java @@ -27,6 +27,8 @@ import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_PHONE_CALL import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_USB; import static android.os.Process.INVALID_UID; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA; + import android.annotation.IntDef; import android.app.ActivityManager; import android.app.ActivityManager.ForegroundServiceApiType; @@ -520,7 +522,10 @@ public class ForegroundServiceTypeLoggerModule { r.mAllowWIUByBindings, r.mAllowStartForegroundNoBinding, r.mAllowStartInBindService, - r.mAllowStartByBindings); + r.mAllowStartByBindings, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false + ); } /** @@ -578,7 +583,10 @@ public class ForegroundServiceTypeLoggerModule { 0, 0, 0, - 0); + 0, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false + ); } /** diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 60af280614e2..e08fdd65ad94 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -1437,6 +1437,7 @@ public class AudioDeviceInventory { } }); new MediaMetrics.Item(mMetricsId + "disconnectA2dp") + .set(MediaMetrics.Property.EVENT, "disconnectA2dp") .record(); if (toRemove.size() > 0) { final int delay = checkSendBecomingNoisyIntentInt( @@ -1459,6 +1460,7 @@ public class AudioDeviceInventory { } }); new MediaMetrics.Item(mMetricsId + "disconnectA2dpSink") + .set(MediaMetrics.Property.EVENT, "disconnectA2dpSink") .record(); toRemove.stream().forEach(deviceAddress -> makeA2dpSrcUnavailable(deviceAddress)); } @@ -1474,6 +1476,7 @@ public class AudioDeviceInventory { } }); new MediaMetrics.Item(mMetricsId + "disconnectHearingAid") + .set(MediaMetrics.Property.EVENT, "disconnectHearingAid") .record(); if (toRemove.size() > 0) { final int delay = checkSendBecomingNoisyIntentInt( @@ -1531,6 +1534,7 @@ public class AudioDeviceInventory { } }); new MediaMetrics.Item(mMetricsId + "disconnectLeAudio") + .set(MediaMetrics.Property.EVENT, "disconnectLeAudio") .record(); if (toRemove.size() > 0) { final int delay = checkSendBecomingNoisyIntentInt(device, diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java index 6edbfb7752a1..4df25811cc99 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java @@ -57,6 +57,7 @@ public class AuthenticationStatsCollector { @NonNull private final FaceManager mFaceManager; @NonNull private final FingerprintManager mFingerprintManager; + private final boolean mEnabled; private final float mThreshold; private final int mModality; @@ -80,6 +81,7 @@ public class AuthenticationStatsCollector { public AuthenticationStatsCollector(@NonNull Context context, int modality, @NonNull BiometricNotification biometricNotification) { mContext = context; + mEnabled = context.getResources().getBoolean(R.bool.config_biometricFrrNotificationEnabled); mThreshold = context.getResources() .getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1); mUserAuthenticationStatsMap = new HashMap<>(); @@ -110,6 +112,11 @@ public class AuthenticationStatsCollector { /** Update total authentication and rejected attempts. */ public void authenticate(int userId, boolean authenticated) { + // Don't collect data if the feature is disabled. + if (!mEnabled) { + return; + } + // Don't collect data for single-modality devices or user has both biometrics enrolled. if (isSingleModalityDevice() || (hasEnrolledFace(userId) && hasEnrolledFingerprint(userId))) { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 540ddd235e8c..df45001b7086 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -119,6 +119,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.DeviceConfigInterface; import android.provider.Settings; +import android.sysprop.DisplayProperties; import android.text.TextUtils; import android.util.ArraySet; import android.util.EventLog; @@ -488,6 +489,9 @@ public final class DisplayManagerService extends SystemService { private boolean mBootCompleted = false; + // If we would like to keep a particular eye on a package, we can set the package name. + private final boolean mExtraDisplayEventLogging; + private final BroadcastReceiver mIdleModeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -571,6 +575,8 @@ public final class DisplayManagerService extends SystemService { mOverlayProperties = SurfaceControl.getOverlaySupport(); mSystemReady = false; mConfigParameterProvider = new DeviceConfigParameterProvider(DeviceConfigInterface.REAL); + final String name = DisplayProperties.debug_vri_package().orElse(null); + mExtraDisplayEventLogging = !TextUtils.isEmpty(name); } public void setupSchedulerPolicies() { @@ -2919,9 +2925,10 @@ public final class DisplayManagerService extends SystemService { // Delivers display event notifications to callbacks. private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids, @DisplayEvent int event) { - if (DEBUG) { + if (DEBUG || mExtraDisplayEventLogging) { Slog.d(TAG, "Delivering display event: displayId=" - + displayId + ", event=" + event); + + displayId + ", event=" + event + + (uids != null ? ", uids=" + uids : "")); } // Grab the lock and copy the callbacks. diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 0cfdaf26cc1c..10b6052bec69 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -195,8 +195,12 @@ public class RecoverableKeyStoreManager { mApplicationKeyStorage = applicationKeyStorage; mTestCertHelper = testOnlyInsecureCertificateHelper; mCleanupManager = cleanupManager; - // Clears data for removed users. - mCleanupManager.verifyKnownUsers(); + try { + // Clears data for removed users. + mCleanupManager.verifyKnownUsers(); + } catch (Exception e) { + Log.e(TAG, "Failed to verify known users", e); + } try { mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mDatabase); } catch (NoSuchAlgorithmException e) { diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java index b015a72a653e..d2e980b7e355 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java @@ -39,6 +39,7 @@ import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.util.FrameworkStatsLog; +import java.time.Duration; import java.util.ArrayList; import java.util.Objects; @@ -497,6 +498,7 @@ interface NotificationRecordLogger { final boolean is_non_dismissible; final int fsi_state; final boolean is_locked; + final int age_in_minutes; @DurationMillisLong long post_duration_millis; // Not final; calculated at the end. NotificationReported(NotificationRecordPair p, @@ -541,6 +543,9 @@ interface NotificationRecordLogger { hasFullScreenIntent, hasFsiRequestedButDeniedFlag, eventType); this.is_locked = p.r.isLocked(); + + this.age_in_minutes = NotificationRecordLogger.getAgeInMinutes( + p.r.getSbn().getPostTime(), p.r.getSbn().getNotification().when); } } @@ -601,4 +606,13 @@ interface NotificationRecordLogger { } return FrameworkStatsLog.NOTIFICATION_REPORTED__FSI_STATE__NO_FSI; } + + /** + * @param postTimeMs time (in {@link System#currentTimeMillis} time) the notification was posted + * @param whenMs A timestamp related to this notification, in milliseconds since the epoch. + * @return difference in duration as an integer in minutes + */ + static int getAgeInMinutes(long postTimeMs, long whenMs) { + return (int) Duration.ofMillis(postTimeMs - whenMs).toMinutes(); + } } diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java index 9da0e98c1775..fc0a7764963e 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java @@ -77,7 +77,8 @@ class NotificationRecordLoggerImpl implements NotificationRecordLogger { notificationReported.is_non_dismissible, notificationReported.post_duration_millis, notificationReported.fsi_state, - notificationReported.is_locked); + notificationReported.is_locked, + notificationReported.age_in_minutes); } @Override diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java index 85c140c67949..e14f7c09770f 100644 --- a/services/core/java/com/android/server/notification/PermissionHelper.java +++ b/services/core/java/com/android/server/notification/PermissionHelper.java @@ -16,7 +16,6 @@ package com.android.server.notification; -import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.content.pm.PackageManager.GET_PERMISSIONS; @@ -203,7 +202,6 @@ public final class PermissionHelper { Context.DEVICE_ID_DEFAULT, userId, TAG); } int flagMask = FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED; - flagMask = userSet || !grant ? flagMask | FLAG_PERMISSION_GRANTED_BY_DEFAULT : flagMask; if (userSet) { mPermManager.updatePermissionFlags(packageName, NOTIFICATION_PERMISSION, flagMask, FLAG_PERMISSION_USER_SET, true, Context.DEVICE_ID_DEFAULT, userId); diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index ff347acdfd96..a4ee3c8287c5 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -22,6 +22,8 @@ import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.os.Process.INVALID_UID; +import static com.android.server.art.model.DexoptResult.DexContainerFileDexoptResult; +import static com.android.server.art.model.DexoptResult.PackageDexoptResult; import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY; import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP; import static com.android.server.pm.PackageManagerService.TAG; @@ -57,6 +59,7 @@ import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashSet; import java.util.List; final class InstallRequest { @@ -148,6 +151,9 @@ final class InstallRequest { @NonNull private int[] mUpdateBroadcastInstantUserIds = EMPTY_INT_ARRAY; + @NonNull + private ArrayList<String> mWarnings = new ArrayList<>(); + // New install InstallRequest(InstallingSession params) { mUserId = params.getUser().getIdentifier(); @@ -658,6 +664,11 @@ final class InstallRequest { return mUpdateBroadcastInstantUserIds; } + @NonNull + public ArrayList<String> getWarnings() { + return mWarnings; + } + public void setScanFlags(int scanFlags) { mScanFlags = scanFlags; } @@ -855,6 +866,10 @@ final class InstallRequest { } } + public void addWarning(@NonNull String warning) { + mWarnings.add(warning); + } + public void onPrepareStarted() { if (mPackageMetrics != null) { mPackageMetrics.onStepStarted(PackageMetrics.STEP_PREPARE); @@ -904,22 +919,37 @@ final class InstallRequest { } public void onDexoptFinished(DexoptResult dexoptResult) { - if (mPackageMetrics == null) { - return; - } - mDexoptStatus = dexoptResult.getFinalStatus(); - if (mDexoptStatus != DexoptResult.DEXOPT_PERFORMED) { - return; + // Only report external profile warnings when installing from adb. The goal is to warn app + // developers if they have provided bad external profiles, so it's not beneficial to report + // those warnings in the normal app install workflow. + if (isInstallFromAdb()) { + var externalProfileErrors = new LinkedHashSet<String>(); + for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) { + for (DexContainerFileDexoptResult fileResult : + packageResult.getDexContainerFileDexoptResults()) { + externalProfileErrors.addAll(fileResult.getExternalProfileErrors()); + } + } + if (!externalProfileErrors.isEmpty()) { + addWarning("Error occurred during dexopt when processing external profiles:\n " + + String.join("\n ", externalProfileErrors)); + } } - long durationMillis = 0; - for (DexoptResult.PackageDexoptResult packageResult : - dexoptResult.getPackageDexoptResults()) { - for (DexoptResult.DexContainerFileDexoptResult fileResult : - packageResult.getDexContainerFileDexoptResults()) { - durationMillis += fileResult.getDex2oatWallTimeMillis(); + + // Report dexopt metrics. + if (mPackageMetrics != null) { + mDexoptStatus = dexoptResult.getFinalStatus(); + if (mDexoptStatus == DexoptResult.DEXOPT_PERFORMED) { + long durationMillis = 0; + for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) { + for (DexContainerFileDexoptResult fileResult : + packageResult.getDexContainerFileDexoptResults()) { + durationMillis += fileResult.getDex2oatWallTimeMillis(); + } + } + mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis); } } - mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis); } public void onInstallCompleted() { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 512d338b0b48..d699baa0d9ab 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -5138,6 +5138,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (!TextUtils.isEmpty(existing)) { fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing); } + ArrayList<String> warnings = extras.getStringArrayList(PackageInstaller.EXTRA_WARNINGS); + if (!ArrayUtils.isEmpty(warnings)) { + fillIn.putStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS, warnings); + } } try { final BroadcastOptions options = BroadcastOptions.makeBasic(); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 864ed323697c..700fae953ead 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1433,6 +1433,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService break; } } + if (!request.getWarnings().isEmpty()) { + extras.putStringArrayList(PackageInstaller.EXTRA_WARNINGS, request.getWarnings()); + } return extras; } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 1b30c4b82d82..72a737084526 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -4397,10 +4397,21 @@ class PackageManagerShellCommand extends ShellCommand { session.commit(receiver.getIntentSender()); if (!session.isStaged()) { final Intent result = receiver.getResult(); - final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, - PackageInstaller.STATUS_FAILURE); + int status = result.getIntExtra( + PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); + List<String> warnings = + result.getStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS); if (status == PackageInstaller.STATUS_SUCCESS) { - if (logSuccess) { + if (!ArrayUtils.isEmpty(warnings)) { + // Don't start the output string with "Success" because that will make adb + // treat this as a success. + for (String warning : warnings) { + pw.println("Warning: " + warning); + } + // Treat warnings as failure to draw app developers' attention. + status = PackageInstaller.STATUS_FAILURE; + pw.println("Completed with warning(s)"); + } else if (logSuccess) { pw.println("Success"); } } else { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 4d38239973d7..b420acdc0850 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4773,7 +4773,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY: case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY: case KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL: { - if (down && mStylusButtonsEnabled) { + if (mStylusButtonsEnabled) { sendSystemKeyToStatusBarAsync(event); } result &= ~ACTION_PASS_TO_USER; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 216369bf56b4..5fec50e29a9c 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -580,7 +580,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A IBinder mRequestedLaunchingTaskFragmentToken; // Tracking splash screen status from previous activity - boolean mSplashScreenStyleSolidColor = false; + boolean mAllowIconSplashScreen = true; boolean mPauseSchedulePendingForPip = false; @@ -2408,8 +2408,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @VisibleForTesting boolean addStartingWindow(String pkg, int resolvedTheme, ActivityRecord from, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, - boolean activityCreated, boolean isSimple, - boolean activityAllDrawn) { + boolean activityCreated, boolean allowIcon, boolean activityAllDrawn) { // If the display is frozen, we won't do anything until the actual window is // displayed so there is no reason to put in the starting window. if (!okToDisplay()) { @@ -2444,8 +2443,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final int typeParameter = StartingSurfaceController .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning, - allowTaskSnapshot, activityCreated, isSimple, useLegacy, activityAllDrawn, - type, packageName, mUserId); + allowTaskSnapshot, activityCreated, allowIcon, useLegacy, + activityAllDrawn, type, packageName, mUserId); if (type == STARTING_WINDOW_TYPE_SNAPSHOT) { if (isActivityTypeHome()) { @@ -6747,7 +6746,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void onFirstWindowDrawn(WindowState win) { firstWindowDrawn = true; // stop tracking - mSplashScreenStyleSolidColor = true; + mAllowIconSplashScreen = false; if (mStartingWindow != null) { ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s" @@ -6796,7 +6795,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void onStartingWindowDrawn() { boolean wasTaskVisible = false; if (task != null) { - mSplashScreenStyleSolidColor = true; + mAllowIconSplashScreen = false; wasTaskVisible = !setTaskHasBeenVisible(); } @@ -7319,52 +7318,69 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } return false; } - private boolean shouldUseSolidColorSplashScreen(ActivityRecord sourceRecord, + + /** + * Checks whether an icon splash screen can be used in the starting window based on the + * preference in the {@code options} and this activity's theme, giving higher priority to the + * {@code options}'s preference. + * + * When no preference is specified, a default behaviour is defined: + * - if the activity is started from the home or shell app, an icon can be used + * - if the activity is started from SystemUI, an icon should not be used + * - if there is a launching activity, use its preference + * - if none of the above is met, only use an icon when the activity is started for the first + * time from a System app + * + * The returned value is sent to WmShell, which will make the final decision on what splash + * screen type will be used. + * + * @return true if an icon can be used in the splash screen + * false when an icon should not be used in the splash screen + */ + private boolean canUseIconSplashScreen(ActivityRecord sourceRecord, boolean startActivity, ActivityOptions options, int resolvedTheme) { if (sourceRecord == null && !startActivity) { - // Use simple style if this activity is not top activity. This could happen when adding - // a splash screen window to the warm start activity which is re-create because top is - // finishing. + // Shouldn't use an icon if this activity is not top activity. This could happen when + // adding a splash screen window to the warm start activity which is re-create because + // top is finishing. final ActivityRecord above = task.getActivityAbove(this); if (above != null) { - return true; + return false; } } // setSplashScreenStyle decide in priority of windowSplashScreenBehavior. - if (options != null) { - final int optionsStyle = options.getSplashScreenStyle(); - if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR) { - return true; - } else if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_ICON + final int optionsStyle = options != null ? options.getSplashScreenStyle() : + SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED; + if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR) { + return false; + } else if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_ICON || isIconStylePreferred(resolvedTheme)) { - return false; + return true; + } + + // Choose the default behavior when neither the ActivityRecord nor the activity theme have + // specified a splash screen style. + + if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME || launchedFromUid == Process.SHELL_UID) { + return true; + } else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) { + return false; + } else { + // Need to check sourceRecord in case this activity is launched from a service or a + // trampoline activity. + if (sourceRecord == null) { + sourceRecord = searchCandidateLaunchingActivity(); } - // Choose the default behavior for Launcher and SystemUI when the SplashScreen style is - // not specified in the ActivityOptions. - if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME - || launchedFromUid == Process.SHELL_UID) { - return false; - } else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) { - return true; + + if (sourceRecord != null) { + return sourceRecord.mAllowIconSplashScreen; } - } else if (isIconStylePreferred(resolvedTheme)) { - return false; - } - if (sourceRecord == null) { - sourceRecord = searchCandidateLaunchingActivity(); - } - if (sourceRecord != null && !sourceRecord.isActivityTypeHome()) { - return sourceRecord.mSplashScreenStyleSolidColor; + // Use an icon if the activity was launched from System for the first start. + // Otherwise, can't use an icon splash screen. + return mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEM && startActivity; } - - // If this activity was launched from Launcher or System for first start, never use a - // solid color splash screen. - // Need to check sourceRecord before in case this activity is launched from service. - return !startActivity || !(mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEM - || mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME - || launchedFromUid == Process.SHELL_UID); } private int getSplashscreenTheme(ActivityOptions options) { @@ -7427,7 +7443,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final int resolvedTheme = evaluateStartingWindowTheme(prev, packageName, theme, splashScreenTheme); - mSplashScreenStyleSolidColor = shouldUseSolidColorSplashScreen(sourceRecord, startActivity, + mAllowIconSplashScreen = canUseIconSplashScreen(sourceRecord, startActivity, startOptions, resolvedTheme); final boolean activityCreated = @@ -7439,7 +7455,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean scheduled = addStartingWindow(packageName, resolvedTheme, prev, newTask || newSingleActivity, taskSwitch, processRunning, - allowTaskSnapshot(), activityCreated, mSplashScreenStyleSolidColor, allDrawn); + allowTaskSnapshot(), activityCreated, mAllowIconSplashScreen, allDrawn); if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) { Slog.d(TAG, "Scheduled starting window for " + this); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 9c9c63f33903..f38f6b0e4fa0 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1843,8 +1843,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { RemoteCallback navigationObserver, BackAnimationAdapter adapter) { mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS, "startBackNavigation()"); - - return mBackNavigationController.startBackNavigation(navigationObserver, adapter); + final long origId = Binder.clearCallingIdentity(); + try { + return mBackNavigationController.startBackNavigation(navigationObserver, adapter); + } finally { + Binder.restoreCallingIdentity(origId); + } } /** diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index e523119ee9a0..9bfc5534ef45 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -795,17 +795,13 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { return false; } - // Try pausing the existing resumed activity in the same TaskFragment if any. - final TaskFragment taskFragment = r.getTaskFragment(); - if (taskFragment != null && taskFragment.getResumedActivity() != null) { - if (taskFragment.startPausing(mUserLeaving, false /* uiSleeping */, r, "realStart")) { - return false; - } + // Try pausing the existing resumed activity in the Task if any. + final Task task = r.getTask(); + if (task.pauseActivityIfNeeded(r, "realStart")) { + return false; } - final Task task = r.getTask(); final Task rootTask = task.getRootTask(); - beginDeferResume(); // The LaunchActivityItem also contains process configuration, so the configuration change // from WindowProcessController#setProcess can be deferred. The major reason is that if diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 3639e1b9cb47..d2d6552a0c9c 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -661,6 +661,10 @@ final class LetterboxUiController { @ScreenOrientation int overrideOrientationIfNeeded(@ScreenOrientation int candidate) { if (shouldApplyUserFullscreenOverride()) { + Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for " + + mActivityRecord + " is overridden to " + + screenOrientationToString(SCREEN_ORIENTATION_USER) + + " by user aspect ratio settings."); return SCREEN_ORIENTATION_USER; } @@ -668,6 +672,14 @@ final class LetterboxUiController { // orientation. candidate = mActivityRecord.mWmService.mapOrientationRequest(candidate); + if (shouldApplyUserMinAspectRatioOverride() && !isFixedOrientation(candidate)) { + Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for " + + mActivityRecord + " is overridden to " + + screenOrientationToString(SCREEN_ORIENTATION_PORTRAIT) + + " by user aspect ratio settings."); + return SCREEN_ORIENTATION_PORTRAIT; + } + if (FALSE.equals(mBooleanPropertyAllowOrientationOverride)) { return candidate; } diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index a55c232990cf..a0517bebca6d 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -19,12 +19,12 @@ package com.android.server.wm; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_DRAWN; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_HANDLE_SOLID_COLOR_SCREEN; +import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_ICON; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT; import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; -import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SNAPSHOT; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SPLASH_SCREEN; @@ -102,7 +102,7 @@ public class StartingSurfaceController { static int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, - boolean isSolidColor, boolean useLegacy, boolean activityDrawn, int startingWindowType, + boolean allowIcon, boolean useLegacy, boolean activityDrawn, int startingWindowType, String packageName, int userId) { int parameter = 0; if (newTask) { @@ -120,8 +120,8 @@ public class StartingSurfaceController { if (activityCreated || startingWindowType == STARTING_WINDOW_TYPE_SNAPSHOT) { parameter |= TYPE_PARAMETER_ACTIVITY_CREATED; } - if (isSolidColor) { - parameter |= TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN; + if (allowIcon) { + parameter |= TYPE_PARAMETER_ALLOW_ICON; } if (useLegacy) { parameter |= TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index de197a164d10..b4b8a74d0d1b 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1262,6 +1262,37 @@ class Task extends TaskFragment { return null; } + boolean pauseActivityIfNeeded(@Nullable ActivityRecord resuming, @NonNull String reason) { + if (!isLeafTask()) { + return false; + } + + final int[] someActivityPaused = {0}; + // Check if the direct child resumed activity in the leaf task needed to be paused if + // the leaf task is not a leaf task fragment. + if (!isLeafTaskFragment()) { + final ActivityRecord top = topRunningActivity(); + final ActivityRecord resumedActivity = getResumedActivity(); + if (resumedActivity != null && top.getTaskFragment() != this) { + // Pausing the resumed activity because it is occluded by other task fragment. + if (startPausing(false /* uiSleeping*/, resuming, reason)) { + someActivityPaused[0]++; + } + } + } + + forAllLeafTaskFragments((taskFrag) -> { + final ActivityRecord resumedActivity = taskFrag.getResumedActivity(); + if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) { + if (taskFrag.startPausing(false /* uiSleeping*/, resuming, reason)) { + someActivityPaused[0]++; + } + } + }, true /* traverseTopToBottom */); + + return someActivityPaused[0] > 0; + } + void updateTaskMovement(boolean toTop, boolean toBottom, int position) { EventLogTags.writeWmTaskMoved(mTaskId, getRootTaskId(), getDisplayId(), toTop ? 1 : 0, position); diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 9af12ad6e766..ae794a89480a 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1271,27 +1271,9 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { boolean pauseBackTasks(ActivityRecord resuming) { final int[] someActivityPaused = {0}; forAllLeafTasks(leafTask -> { - // Check if the direct child resumed activity in the leaf task needed to be paused if - // the leaf task is not a leaf task fragment. - if (!leafTask.isLeafTaskFragment()) { - final ActivityRecord top = topRunningActivity(); - final ActivityRecord resumedActivity = leafTask.getResumedActivity(); - if (resumedActivity != null && top.getTaskFragment() != leafTask) { - // Pausing the resumed activity because it is occluded by other task fragment. - if (leafTask.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) { - someActivityPaused[0]++; - } - } + if (leafTask.pauseActivityIfNeeded(resuming, "pauseBackTasks")) { + someActivityPaused[0]++; } - - leafTask.forAllLeafTaskFragments((taskFrag) -> { - final ActivityRecord resumedActivity = taskFrag.getResumedActivity(); - if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) { - if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) { - someActivityPaused[0]++; - } - } - }, true /* traverseTopToBottom */); }, true /* traverseTopToBottom */); return someActivityPaused[0] > 0; } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 881fdec4549e..bbafa25eac5b 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1614,13 +1614,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } - // Take task snapshots before the animation so that we can capture IME before it gets - // transferred. If transition is transient, IME won't be moved during the transition and - // the tasks are still live, so we take the snapshot at the end of the transition instead. - if (mTransientLaunches == null) { - mController.mSnapshotController.onTransactionReady(mType, mTargets); - } - // This is non-null only if display has changes. It handles the visible windows that don't // need to be participated in the transition. for (int i = 0; i < mTargetDisplays.size(); ++i) { @@ -1671,6 +1664,16 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { reportStartReasonsToLogger(); + // Take snapshots for closing tasks/activities before the animation finished but after + // dispatching onTransitionReady, so IME (if there is) can be captured together and the + // time spent on snapshot won't delay the start of animation. Note that if this transition + // is transient (mTransientLaunches != null), the snapshot will be captured at the end of + // the transition, because IME won't move be moved during the transition and the tasks are + // still live. + if (mTransientLaunches == null) { + mController.mSnapshotController.onTransactionReady(mType, mTargets); + } + // Since we created root-leash but no longer reference it from core, release it now info.releaseAnimSurfaces(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 561848e8dbfa..8fe104c23312 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2493,6 +2493,14 @@ public class WindowManagerService extends IWindowManager.Stub outInsetsState.set(win.getCompatInsetsState(), true /* copySources */); } + // TODO (b/298562855): Remove this after identifying the reason why the frame is empty. + if (win.mAttrs.providedInsets != null && win.getFrame().isEmpty()) { + Slog.w(TAG, "Empty frame of " + win + + " configChanged=" + configChanged + + " frame=" + win.getFrame().toShortString() + + " attrs=" + attrs); + } + ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b", win, focusMayChange); diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 82d39d6c6982..a4adf5866f3d 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -35,7 +35,7 @@ import android.credentials.CreateCredentialException; import android.credentials.CreateCredentialRequest; import android.credentials.CredentialOption; import android.credentials.CredentialProviderInfo; -import android.credentials.GetCandidateCredentialsRequest; +import android.credentials.GetCandidateCredentialsException; import android.credentials.GetCredentialException; import android.credentials.GetCredentialRequest; import android.credentials.IClearCredentialStateCallback; @@ -303,9 +303,9 @@ public final class CredentialManagerService ComponentName compName = ComponentName.unflattenFromString(serviceName); if (compName == null) { Slog.w( - TAG, - "Primary provider component name unflatten from string error: " - + serviceName); + TAG, + "Primary provider component name unflatten from string error: " + + serviceName); continue; } services.add(compName); @@ -474,13 +474,55 @@ public final class CredentialManagerService final class CredentialManagerServiceStub extends ICredentialManager.Stub { @Override public ICancellationSignal getCandidateCredentials( - GetCandidateCredentialsRequest request, + GetCredentialRequest request, IGetCandidateCredentialsCallback callback, final String callingPackage) { Slog.i(TAG, "starting getCandidateCredentials with callingPackage: " + callingPackage); - // TODO(): Implement - return CancellationSignal.createTransport(); + ICancellationSignal cancelTransport = CancellationSignal.createTransport(); + + final int userId = UserHandle.getCallingUserId(); + final int callingUid = Binder.getCallingUid(); + + // New request session, scoped for this request only. + final GetCandidateRequestSession session = + new GetCandidateRequestSession( + getContext(), + mSessionManager, + mLock, + userId, + callingUid, + callback, + request, + constructCallingAppInfo(callingPackage, userId, request.getOrigin()), + getEnabledProvidersForUser(userId), + CancellationSignal.fromTransport(cancelTransport) + ); + addSessionLocked(userId, session); + + List<ProviderSession> providerSessions = + initiateProviderSessions( + session, + request.getCredentialOptions().stream() + .map(CredentialOption::getType) + .collect(Collectors.toList())); + + if (providerSessions.isEmpty()) { + try { + callback.onError( + GetCandidateCredentialsException.TYPE_NO_CREDENTIAL, + "No credentials available on this device."); + } catch (RemoteException e) { + Slog.i( + TAG, + "Issue invoking onError on IGetCredentialCallback " + + "callback: " + + e.getMessage()); + } + } + + invokeProviderSessions(providerSessions); + return cancelTransport; } @Override @@ -737,7 +779,7 @@ public final class CredentialManagerService @Override public void setEnabledProviders( - List<String> primaryProviders, List<String> providers, int userId, + List<String> primaryProviders, List<String> providers, int userId, ISetEnabledProvidersCallback callback) { final int callingUid = Binder.getCallingUid(); if (!hasWriteSecureSettingsPermission()) { @@ -862,9 +904,9 @@ public final class CredentialManagerService ApiName.GET_CREDENTIAL_PROVIDER_SERVICES, ApiStatus.SUCCESS, callingUid); return CredentialProviderInfoFactory - .getCredentialProviderServices( - mContext, userId, providerFilter, getEnabledProvidersForUser(userId), - getPrimaryProvidersForUserId(mContext, userId)); + .getCredentialProviderServices( + mContext, userId, providerFilter, getEnabledProvidersForUser(userId), + getPrimaryProvidersForUserId(mContext, userId)); } @@ -894,13 +936,14 @@ public final class CredentialManagerService private Set<ComponentName> getEnabledProvidersForUser(int userId) { final int resolvedUserId = ActivityManager.handleIncomingUser( - Binder.getCallingPid(), Binder.getCallingUid(), - userId, false, false, - "getEnabledProvidersForUser", null); + Binder.getCallingPid(), Binder.getCallingUid(), + userId, false, false, + "getEnabledProvidersForUser", null); Set<ComponentName> enabledProviders = new HashSet<>(); String directValue = Settings.Secure.getStringForUser( - mContext.getContentResolver(), Settings.Secure.CREDENTIAL_SERVICE, resolvedUserId); + mContext.getContentResolver(), Settings.Secure.CREDENTIAL_SERVICE, + resolvedUserId); if (!TextUtils.isEmpty(directValue)) { String[] components = directValue.split(":"); diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java new file mode 100644 index 000000000000..6d9b7e824e28 --- /dev/null +++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.credentials; + +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; +import android.credentials.CredentialProviderInfo; +import android.credentials.GetCandidateCredentialsException; +import android.credentials.GetCandidateCredentialsResponse; +import android.credentials.GetCredentialRequest; +import android.credentials.IGetCandidateCredentialsCallback; +import android.credentials.ui.GetCredentialProviderData; +import android.credentials.ui.ProviderData; +import android.credentials.ui.RequestInfo; +import android.os.CancellationSignal; +import android.os.RemoteException; +import android.service.credentials.CallingAppInfo; +import android.util.Slog; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Central session for a single getCandidateCredentials request. This class listens to the + * responses from providers, and updates the provider(s) state. + */ +public class GetCandidateRequestSession extends RequestSession<GetCredentialRequest, + IGetCandidateCredentialsCallback, GetCandidateCredentialsResponse> + implements ProviderSession.ProviderInternalCallback<GetCandidateCredentialsResponse> { + private static final String TAG = "GetCandidateRequestSession"; + + public GetCandidateRequestSession( + Context context, SessionLifetime sessionCallback, + Object lock, int userId, int callingUid, + IGetCandidateCredentialsCallback callback, GetCredentialRequest request, + CallingAppInfo callingAppInfo, Set<ComponentName> enabledProviders, + CancellationSignal cancellationSignal) { + super(context, sessionCallback, lock, userId, callingUid, request, callback, + RequestInfo.TYPE_GET, callingAppInfo, enabledProviders, + cancellationSignal, 0L); + } + + /** + * Creates a new provider session, and adds it list of providers that are contributing to + * this session. + * + * @return the provider session created within this request session, for the given provider + * info. + */ + @Override + @Nullable + public ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo, + RemoteCredentialService remoteCredentialService) { + ProviderGetSession providerGetCandidateSessions = ProviderGetSession + .createNewSession(mContext, mUserId, providerInfo, + this, remoteCredentialService); + if (providerGetCandidateSessions != null) { + Slog.d(TAG, "In startProviderSession - provider session created and " + + "being added for: " + providerInfo.getComponentName()); + mProviders.put(providerGetCandidateSessions.getComponentName().flattenToString(), + providerGetCandidateSessions); + } + return providerGetCandidateSessions; + } + + /** + * Even though there is no UI involved, this is called when all providers are ready + * in our current flow. Eventually can completely separate UI and non UI flows. + */ + @Override + protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { + if (providerDataList == null || providerDataList.isEmpty()) { + respondToClientWithErrorAndFinish( + GetCandidateCredentialsException.TYPE_NO_CREDENTIAL, + "No credentials found"); + return; + } + + List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>(); + for (ProviderData providerData : providerDataList) { + candidateProviderDataList.add((GetCredentialProviderData) (providerData)); + } + respondToClientWithResponseAndFinish(new GetCandidateCredentialsResponse( + candidateProviderDataList)); + } + + @Override + protected void invokeClientCallbackSuccess(GetCandidateCredentialsResponse response) + throws RemoteException { + mClientCallback.onResponse(response); + } + + @Override + protected void invokeClientCallbackError(String errorType, String errorMsg) + throws RemoteException { + mClientCallback.onError(errorType, errorMsg); + } + + @Override + public void onFinalErrorReceived(ComponentName componentName, String errorType, + String message) { + // Not applicable for session without UI + } + + @Override + public void onUiCancellation(boolean isUserCancellation) { + // Not applicable for session without UI + } + + @Override + public void onUiSelectorInvocationFailure() { + // Not applicable for session without UI + } + + @Override + public void onProviderStatusChanged(ProviderSession.Status status, + ComponentName componentName, ProviderSession.CredentialsSource source) { + Slog.d(TAG, "in onStatusChanged with status: " + status + ", and source: " + source); + + // For any other status, we check if all providers are done and then invoke UI if needed + if (!isAnyProviderPending()) { + // If all provider responses have been received, we can either need the UI, + // or we need to respond with error. The only other case is the entry being + // selected after the UI has been invoked which has a separate code path. + if (isUiInvocationNeeded()) { + Slog.d(TAG, "in onProviderStatusChanged - isUiInvocationNeeded"); + getProviderDataAndInitiateUi(); + } else { + respondToClientWithErrorAndFinish( + GetCandidateCredentialsException.TYPE_NO_CREDENTIAL, + "No credentials available"); + } + } + } + + @Override + public void onFinalResponseReceived(ComponentName componentName, + GetCandidateCredentialsResponse response) { + // Not applicable for session without UI + } +} diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index 3c1432a320e7..3eb6718c0a95 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -119,6 +119,42 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential return null; } + /** Creates a new provider session to be used by the request session. */ + @Nullable + public static ProviderGetSession createNewSession( + Context context, + @UserIdInt int userId, + CredentialProviderInfo providerInfo, + GetCandidateRequestSession getRequestSession, + RemoteCredentialService remoteCredentialService) { + android.credentials.GetCredentialRequest filteredRequest = + filterOptions(providerInfo.getCapabilities(), + getRequestSession.mClientRequest, + providerInfo); + if (filteredRequest != null) { + Map<String, CredentialOption> beginGetOptionToCredentialOptionMap = + new HashMap<>(); + return new ProviderGetSession( + context, + providerInfo, + getRequestSession, + userId, + remoteCredentialService, + constructQueryPhaseRequest( + filteredRequest, getRequestSession.mClientAppInfo, + getRequestSession.mClientRequest.alwaysSendAppInfoToProvider(), + beginGetOptionToCredentialOptionMap), + filteredRequest, + getRequestSession.mClientAppInfo, + beginGetOptionToCredentialOptionMap, + getRequestSession.mHybridService + ); + } + Slog.i(TAG, "Unable to create provider session for: " + + providerInfo.getComponentName()); + return null; + } + private static BeginGetCredentialRequest constructQueryPhaseRequest( android.credentials.GetCredentialRequest filteredRequest, CallingAppInfo callingAppInfo, @@ -192,7 +228,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential public ProviderGetSession(Context context, CredentialProviderInfo info, - ProviderInternalCallback<GetCredentialResponse> callbacks, + ProviderInternalCallback callbacks, int userId, RemoteCredentialService remoteCredentialService, BeginGetCredentialRequest beginGetRequest, android.credentials.GetCredentialRequest completeGetRequest, diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt index 827960062983..1e052c037b3c 100644 --- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt +++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt @@ -1753,10 +1753,19 @@ class PermissionService( } override fun addOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) { + context.enforceCallingOrSelfPermission( + Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS, "addOnPermissionsChangeListener" + ) + onPermissionsChangeListeners.addListener(listener) } override fun removeOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) { + context.enforceCallingOrSelfPermission( + Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS, + "removeOnPermissionsChangeListener" + ) + onPermissionsChangeListeners.removeListener(listener) } diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt index 3ab25479686d..3cf57a3cf57a 100644 --- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt +++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt @@ -1445,6 +1445,192 @@ class AppIdPermissionPolicyTest { .isEqualTo(expectedNewFlags) } + @Test + fun testOnPackageAdded_runtimeExistingImplicitPermissions_sourceFlagsNotInherited() { + val oldImplicitPermissionFlags = PermissionFlags.USER_FIXED + testInheritImplicitPermissionStates( + implicitPermissionFlags = oldImplicitPermissionFlags, + isNewInstallAndNewPermission = false + ) + + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = oldImplicitPermissionFlags or PermissionFlags.IMPLICIT_GRANTED or + PermissionFlags.APP_OP_REVOKED + assertWithMessage( + "After onPackageAdded() is called for a package that requests a permission that is" + + " implicit, existing and runtime, it should not inherit the runtime flags from" + + " the source permission. Hence the actual permission flags $actualFlags should" + + " match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + @Test + fun testOnPackageAdded_nonRuntimeNewImplicitPermissions_sourceFlagsNotInherited() { + testInheritImplicitPermissionStates( + implicitPermissionProtectionLevel = PermissionInfo.PROTECTION_NORMAL + ) + + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = PermissionFlags.INSTALL_GRANTED + assertWithMessage( + "After onPackageAdded() is called for a package that requests a permission that is" + + " implicit, new and non-runtime, it should not inherit the runtime flags from" + + " the source permission. Hence the actual permission flags $actualFlags should" + + " match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + @Test + fun testOnPackageAdded_runtimeNewImplicitPermissions_sourceFlagsInherited() { + val sourceRuntimeFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET + testInheritImplicitPermissionStates(sourceRuntimeFlags = sourceRuntimeFlags) + + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = sourceRuntimeFlags or PermissionFlags.IMPLICIT_GRANTED or + PermissionFlags.IMPLICIT + assertWithMessage( + "After onPackageAdded() is called for a package that requests a permission that is" + + " implicit, new and runtime, it should inherit the runtime flags from" + + " the source permission. Hence the actual permission flags $actualFlags should" + + " match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + @Test + fun testOnPackageAdded_grantingNewFromRevokeImplicitPermissions_onlySourceFlagsInherited() { + val sourceRuntimeFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET + testInheritImplicitPermissionStates( + implicitPermissionFlags = PermissionFlags.POLICY_FIXED, + sourceRuntimeFlags = sourceRuntimeFlags, + isAnySourcePermissionNonRuntime = false + ) + + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = sourceRuntimeFlags or PermissionFlags.IMPLICIT + assertWithMessage( + "After onPackageAdded() is called for a package that requests a permission that is" + + " implicit, existing, runtime and revoked, it should only inherit runtime flags" + + " from source permission. Hence the actual permission flags $actualFlags should" + + " match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + /** + * If it's a media implicit permission (one of RETAIN_IMPLICIT_FLAGS_PERMISSIONS), we want to + * remove the IMPLICIT flag so that they will be granted when they are no longer implicit. + * (instead of revoking it) + */ + @Test + fun testOnPackageAdded_mediaImplicitPermissions_getsImplicitFlagRemoved() { + val sourceRuntimeFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET + testInheritImplicitPermissionStates( + implicitPermissionName = PERMISSION_ACCESS_MEDIA_LOCATION, + sourceRuntimeFlags = sourceRuntimeFlags + ) + + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_ACCESS_MEDIA_LOCATION) + val expectedNewFlags = sourceRuntimeFlags or PermissionFlags.IMPLICIT_GRANTED + assertWithMessage( + "After onPackageAdded() is called for a package that requests a media permission that" + + " is implicit, new and runtime, it should inherit the runtime flags from" + + " the source permission and have the IMPLICIT flag removed. Hence the actual" + + " permission flags $actualFlags should match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + private fun testInheritImplicitPermissionStates( + implicitPermissionName: String = PERMISSION_NAME_0, + implicitPermissionFlags: Int = 0, + implicitPermissionProtectionLevel: Int = PermissionInfo.PROTECTION_DANGEROUS, + sourceRuntimeFlags: Int = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET, + isAnySourcePermissionNonRuntime: Boolean = true, + isNewInstallAndNewPermission: Boolean = true + ) { + val implicitPermission = mockParsedPermission( + implicitPermissionName, + PACKAGE_NAME_0, + protectionLevel = implicitPermissionProtectionLevel, + ) + // For source from non-runtime in order to grant by implicit + val sourcePermission1 = mockParsedPermission( + PERMISSION_NAME_1, + PACKAGE_NAME_0, + protectionLevel = if (isAnySourcePermissionNonRuntime) { + PermissionInfo.PROTECTION_NORMAL + } else { + PermissionInfo.PROTECTION_DANGEROUS + } + ) + // For inheriting runtime flags + val sourcePermission2 = mockParsedPermission( + PERMISSION_NAME_2, + PACKAGE_NAME_0, + protectionLevel = PermissionInfo.PROTECTION_DANGEROUS, + ) + val permissionOwnerPackageState = mockPackageState( + APP_ID_0, + mockAndroidPackage( + PACKAGE_NAME_0, + permissions = listOf(implicitPermission, sourcePermission1, sourcePermission2) + ) + ) + val installedPackageState = mockPackageState( + APP_ID_1, + mockAndroidPackage( + PACKAGE_NAME_1, + requestedPermissions = setOf( + implicitPermissionName, + PERMISSION_NAME_1, + PERMISSION_NAME_2 + ), + implicitPermissions = setOf(implicitPermissionName) + ) + ) + oldState.mutateExternalState().setImplicitToSourcePermissions( + MutableIndexedMap<String, IndexedListSet<String>>().apply { + put(implicitPermissionName, MutableIndexedListSet<String>().apply { + add(PERMISSION_NAME_1) + add(PERMISSION_NAME_2) + }) + } + ) + addPackageState(permissionOwnerPackageState) + addPermission(implicitPermission) + addPermission(sourcePermission1) + addPermission(sourcePermission2) + if (!isNewInstallAndNewPermission) { + addPackageState(installedPackageState) + setPermissionFlags(APP_ID_1, USER_ID_0, implicitPermissionName, implicitPermissionFlags) + } + setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_2, sourceRuntimeFlags) + + mutateState { + if (isNewInstallAndNewPermission) { + addPackageState(installedPackageState) + setPermissionFlags( + APP_ID_1, + USER_ID_0, + implicitPermissionName, + implicitPermissionFlags, + newState + ) + } + with(appIdPermissionPolicy) { + onPackageAdded(installedPackageState) + } + } + } + /** * Setup simple package states for testing evaluatePermissionState(). * permissionOwnerPackageState is definer of permissionName with APP_ID_0. @@ -1734,6 +1920,7 @@ class AppIdPermissionPolicyTest { private const val PERMISSION_NAME_0 = "permissionName0" private const val PERMISSION_NAME_1 = "permissionName1" + private const val PERMISSION_NAME_2 = "permissionName2" private const val PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE private const val PERMISSION_POST_NOTIFICATIONS = @@ -1742,6 +1929,8 @@ class AppIdPermissionPolicyTest { Manifest.permission.BLUETOOTH_CONNECT private const val PERMISSION_ACCESS_BACKGROUND_LOCATION = Manifest.permission.ACCESS_BACKGROUND_LOCATION + private const val PERMISSION_ACCESS_MEDIA_LOCATION = + Manifest.permission.ACCESS_MEDIA_LOCATION private const val USER_ID_0 = 0 } diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index 525bfd75269b..5b1508b8393b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -16,7 +16,6 @@ package com.android.server; import static androidx.test.InstrumentationRegistry.getContext; - import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -42,7 +41,6 @@ import static com.android.server.DeviceIdleController.STATE_QUICK_DOZE_DELAY; import static com.android.server.DeviceIdleController.STATE_SENSING; import static com.android.server.DeviceIdleController.lightStateToString; import static com.android.server.DeviceIdleController.stateToString; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -2418,7 +2416,7 @@ public class DeviceIdleControllerTest { } @Test - public void testModeManager_NoModeManagerLocalService_AddListenerNotCalled() { + public void testModeManager_NoModeManagerLocalService_AddQuickDozeListenerNotCalled() { mConstants.USE_MODE_MANAGER = true; doReturn(null) .when(() -> LocalServices.getService(WearModeManagerInternal.class)); @@ -2430,6 +2428,33 @@ public class DeviceIdleControllerTest { } @Test + public void testModeManager_NoModeManagerLocalService_AddOffBodyListenerNotCalled() { + mConstants.USE_MODE_MANAGER = true; + doReturn(null) + .when(() -> LocalServices.getService(WearModeManagerInternal.class)); + cleanupDeviceIdleController(); + setupDeviceIdleController(); + verify(mWearModeManagerInternal, never()).addActiveStateChangeListener( + eq(WearModeManagerInternal.OFFBODY_STATE_ID), any(), + eq(mDeviceIdleController.mModeManagerOffBodyStateConsumer)); + } + + @Test + public void testModeManager_USEMODEMANAGERIsFalse_AddListenerNotCalled() { + mConstants.USE_MODE_MANAGER = false; + doReturn(new Object()) + .when(() -> LocalServices.getService(WearModeManagerInternal.class)); + cleanupDeviceIdleController(); + setupDeviceIdleController(); + verify(mWearModeManagerInternal, never()).addActiveStateChangeListener( + eq(WearModeManagerInternal.OFFBODY_STATE_ID), any(), + eq(mDeviceIdleController.mModeManagerOffBodyStateConsumer)); + verify(mWearModeManagerInternal, never()).addActiveStateChangeListener( + eq(WearModeManagerInternal.QUICK_DOZE_REQUEST_IDENTIFIER), any(), + eq(mDeviceIdleController.mModeManagerQuickDozeRequestConsumer)); + } + + @Test public void testModeManager_NoBatterySaver_QuickDoze() { mConstants.USE_MODE_MANAGER = true; PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled( @@ -2469,6 +2494,102 @@ public class DeviceIdleControllerTest { assertTrue(mDeviceIdleController.isQuickDozeEnabled()); } + @Test + public void testModeManager_QuickDozeRequestedBatterySaverEnabledOnBody_QuickDozeEnabled() { + mConstants.USE_MODE_MANAGER = true; + PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled( + true).build(); + when(mPowerManagerInternal.getLowPowerState(anyInt())) + .thenReturn(powerSaveState); + cleanupDeviceIdleController(); + setupDeviceIdleController(); + + mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(false); + mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true); + + assertTrue(mDeviceIdleController.isQuickDozeEnabled()); + } + + @Test + public void testModeManager_QuickDozeRequestedBatterySaverEnabledOffBody_QuickDozeEnabled() { + mConstants.USE_MODE_MANAGER = true; + PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled( + true).build(); + when(mPowerManagerInternal.getLowPowerState(anyInt())) + .thenReturn(powerSaveState); + cleanupDeviceIdleController(); + setupDeviceIdleController(); + + mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(true); + mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true); + + assertTrue(mDeviceIdleController.isQuickDozeEnabled()); + } + + @Test + public void testModeManager_QuickDozeRequestedBatterySaverDisabledOnBody_QuickDozeEnabled() { + mConstants.USE_MODE_MANAGER = true; + PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled( + false).build(); + when(mPowerManagerInternal.getLowPowerState(anyInt())) + .thenReturn(powerSaveState); + cleanupDeviceIdleController(); + setupDeviceIdleController(); + + mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(false); + mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true); + + assertTrue(mDeviceIdleController.isQuickDozeEnabled()); + } + + @Test + public void testModeManager_QuickDozeRequestedBatterySaverDisabledOffBody_QuickDozeEnabled() { + mConstants.USE_MODE_MANAGER = true; + PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled( + false).build(); + when(mPowerManagerInternal.getLowPowerState(anyInt())) + .thenReturn(powerSaveState); + cleanupDeviceIdleController(); + setupDeviceIdleController(); + + mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(true); + mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true); + + assertTrue(mDeviceIdleController.isQuickDozeEnabled()); + } + + @Test + public void testModeManager_QuickDozeNotRequestedBatterySaverEnabledOnBody_QuickDozeEnabled() { + mConstants.USE_MODE_MANAGER = true; + PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled( + true).build(); + when(mPowerManagerInternal.getLowPowerState(anyInt())) + .thenReturn(powerSaveState); + cleanupDeviceIdleController(); + setupDeviceIdleController(); + + mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(false); + mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(false); + + assertTrue(mDeviceIdleController.isQuickDozeEnabled()); + } + + @Test + public void testModeManager_QuickDozeNotRequestedBatterySaverEnabledOffBody_QuickDozeEnabled() { + mConstants.USE_MODE_MANAGER = true; + PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled( + true).build(); + when(mPowerManagerInternal.getLowPowerState(anyInt())) + .thenReturn(powerSaveState); + cleanupDeviceIdleController(); + setupDeviceIdleController(); + + mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(true); + mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(false); + + assertTrue(mDeviceIdleController.isQuickDozeEnabled()); + } + private void enterDeepState(int state) { switch (state) { case STATE_ACTIVE: 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 a11a8f53c2cb..d2e83e9b0708 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java @@ -87,6 +87,8 @@ public class AuthenticationStatsCollectorTest { public void setUp() { when(mContext.getResources()).thenReturn(mResources); + when(mResources.getBoolean(eq(R.bool.config_biometricFrrNotificationEnabled))) + .thenReturn(true); when(mResources.getFraction(eq(R.fraction.config_biometricNotificationFrrThreshold), anyInt(), anyInt())).thenReturn(FRR_THRESHOLD); @@ -110,7 +112,6 @@ public class AuthenticationStatsCollectorTest { 0 /* modality */, mBiometricNotification); } - @Test public void authenticate_authenticationSucceeded_mapShouldBeUpdated() { // Assert that the user doesn't exist in the map initially. @@ -342,4 +343,32 @@ public class AuthenticationStatsCollectorTest { // Assert that notification count has been updated. assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(1); } + + @Test + public void authenticate_featureDisabled_mapMustNotBeUpdated() { + // Disable the feature. + when(mResources.getBoolean(eq(R.bool.config_biometricFrrNotificationEnabled))) + .thenReturn(false); + AuthenticationStatsCollector authenticationStatsCollector = + new AuthenticationStatsCollector(mContext, 0 /* modality */, + mBiometricNotification); + + authenticationStatsCollector.setAuthenticationStatsForUser(USER_ID_1, + new AuthenticationStats(USER_ID_1, 500 /* totalAttempts */, + 400 /* rejectedAttempts */, 0 /* enrollmentNotifications */, + 0 /* modality */)); + + authenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */); + + // Assert that no notification should be sent. + verify(mBiometricNotification, never()).sendFaceEnrollNotification(any()); + verify(mBiometricNotification, never()).sendFpEnrollNotification(any()); + // Assert that data hasn't been updated. + AuthenticationStats authenticationStats = authenticationStatsCollector + .getAuthenticationStatsForUser(USER_ID_1); + assertThat(authenticationStats.getTotalAttempts()).isEqualTo(500); + assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(400); + assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0); + assertThat(authenticationStats.getFrr()).isWithin(0f).of(0.8f); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java index b522cab0801b..5147a08b5216 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java @@ -28,6 +28,7 @@ import static com.android.server.notification.NotificationRecordLogger.Notificat import static com.android.server.notification.NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_OTHER; import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED; import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -48,6 +49,8 @@ import com.android.internal.util.FrameworkStatsLog; import org.junit.Test; import org.junit.runner.RunWith; +import java.time.Duration; + @SmallTest @RunWith(AndroidJUnit4.class) @@ -230,4 +233,12 @@ public class NotificationRecordLoggerTest extends UiServiceTestCase { NotificationRecordLogger.NotificationCancelledEvent.fromCancelReason( REASON_CANCEL, DISMISSAL_OTHER)); } + + @Test + public void testGetAgeInMinutes() { + long postTimeMs = Duration.ofMinutes(5).toMillis(); + long whenMs = Duration.ofMinutes(2).toMillis(); + int age = NotificationRecordLogger.getAgeInMinutes(postTimeMs, whenMs); + assertThat(age).isEqualTo(3); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java index 318f932bf4e4..3034942953a1 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java @@ -248,8 +248,7 @@ public class PermissionHelperTest extends UiServiceTestCase { verify(mPermManager).grantRuntimePermission( "pkg", Manifest.permission.POST_NOTIFICATIONS, Context.DEVICE_ID_DEFAULT, 10); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, - USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, - FLAG_PERMISSION_USER_SET, true, Context.DEVICE_ID_DEFAULT, 10); + USER_FLAG_MASK, FLAG_PERMISSION_USER_SET, true, Context.DEVICE_ID_DEFAULT, 10); } @Test @@ -267,8 +266,7 @@ public class PermissionHelperTest extends UiServiceTestCase { verify(mPermManager).grantRuntimePermission( "pkg", Manifest.permission.POST_NOTIFICATIONS, Context.DEVICE_ID_DEFAULT, 10); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, - USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, - FLAG_PERMISSION_USER_SET, true, Context.DEVICE_ID_DEFAULT, 10); + USER_FLAG_MASK, FLAG_PERMISSION_USER_SET, true, Context.DEVICE_ID_DEFAULT, 10); } @Test @@ -282,8 +280,7 @@ public class PermissionHelperTest extends UiServiceTestCase { eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(Context.DEVICE_ID_DEFAULT), eq(10), anyString()); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, - USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, - FLAG_PERMISSION_USER_SET, true, Context.DEVICE_ID_DEFAULT, 10); + USER_FLAG_MASK, FLAG_PERMISSION_USER_SET, true, Context.DEVICE_ID_DEFAULT, 10); } @Test @@ -310,8 +307,7 @@ public class PermissionHelperTest extends UiServiceTestCase { eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(Context.DEVICE_ID_DEFAULT), eq(10), anyString()); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, - USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, - true, Context.DEVICE_ID_DEFAULT, 10); + USER_FLAG_MASK, 0, true, Context.DEVICE_ID_DEFAULT, 10); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index ae587003c1c2..8ec3ac6ca3fd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2871,14 +2871,14 @@ public class ActivityRecordTests extends WindowTestsBase { .setTask(sourceRecord.getTask()).build(); secondRecord.showStartingWindow(null /* prev */, true /* newTask */, false, true /* startActivity */, sourceRecord); - assertFalse(secondRecord.mSplashScreenStyleSolidColor); + assertTrue(secondRecord.mAllowIconSplashScreen); secondRecord.onStartingWindowDrawn(); final ActivityRecord finalRecord = new ActivityBuilder(mAtm) .setTask(sourceRecord.getTask()).build(); finalRecord.showStartingWindow(null /* prev */, true /* newTask */, false, true /* startActivity */, secondRecord); - assertTrue(finalRecord.mSplashScreenStyleSolidColor); + assertFalse(finalRecord.mAllowIconSplashScreen); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java index 0566f460c655..381b27b68b41 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java @@ -811,6 +811,28 @@ public class LetterboxUiControllerTest extends WindowTestsBase { /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT); } + @Test + public void testOverrideOrientationIfNeeded_userAspectRatioApplied_unspecifiedOverridden() { + spyOn(mController); + doReturn(true).when(mController).shouldApplyUserMinAspectRatioOverride(); + + assertEquals(mController.overrideOrientationIfNeeded( + /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_PORTRAIT); + + // unchanged if orientation is specified + assertEquals(mController.overrideOrientationIfNeeded( + /* candidate */ SCREEN_ORIENTATION_LANDSCAPE), SCREEN_ORIENTATION_LANDSCAPE); + } + + @Test + public void testOverrideOrientationIfNeeded_userAspectRatioNotApplied_returnsUnchanged() { + spyOn(mController); + doReturn(false).when(mController).shouldApplyUserMinAspectRatioOverride(); + + assertEquals(mController.overrideOrientationIfNeeded( + /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED); + } + // shouldApplyUser...Override @Test public void testShouldApplyUserFullscreenOverride_trueProperty_returnsFalse() throws Exception { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 7a3fc3c29d2b..36a8fc1c43a0 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -10229,7 +10229,7 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); sDefaults.putInt(KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 0); sDefaults.putBoolean(KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, false); - sDefaults.putBoolean(KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL, true); + sDefaults.putBoolean(KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL, false); sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA}); sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true); diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index f1af68f5cfee..53f347e3b192 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -71,13 +71,6 @@ public class SignalStrength implements Parcelable { */ public static final int INVALID = Integer.MAX_VALUE; - private static final int LTE_RSRP_THRESHOLDS_NUM = 4; - - private static final int WCDMA_RSCP_THRESHOLDS_NUM = 4; - - /* The type of signal measurement */ - private static final String MEASUREMENT_TYPE_RSCP = "rscp"; - // Timestamp of SignalStrength since boot // Effectively final. Timestamp is set during construction of SignalStrength private long mTimestampMillis; @@ -92,28 +85,9 @@ public class SignalStrength implements Parcelable { CellSignalStrengthNr mNr; /** - * Create a new SignalStrength from a intent notifier Bundle - * - * This method may be used by external applications. - * - * @param m Bundle from intent notifier - * @return newly created SignalStrength - * - * @hide - */ - @UnsupportedAppUsage - public static SignalStrength newFromBundle(Bundle m) { - SignalStrength ret; - ret = new SignalStrength(); - ret.setFromNotifierBundle(m); - return ret; - } - - /** * This constructor is used to create SignalStrength with default * values. * - * @return newly created SignalStrength * @hide */ @UnsupportedAppUsage @@ -164,20 +138,20 @@ public class SignalStrength implements Parcelable { * Returns a List of CellSignalStrength Components of this SignalStrength Report. * * Use this API to access underlying - * {@link android.telephony#CellSignalStrength CellSignalStrength} objects that provide more + * {@link android.telephony.CellSignalStrength CellSignalStrength} objects that provide more * granular information about the SignalStrength report. Only valid (non-empty) * CellSignalStrengths will be returned. The order of any returned elements is not guaranteed, * and the list may contain more than one instance of a CellSignalStrength type. * * @return a List of CellSignalStrength or an empty List if there are no valid measurements. * - * @see android.telephony#CellSignalStrength - * @see android.telephony#CellSignalStrengthNr - * @see android.telephony#CellSignalStrengthLte - * @see android.telephony#CellSignalStrengthTdscdma - * @see android.telephony#CellSignalStrengthWcdma - * @see android.telephony#CellSignalStrengthCdma - * @see android.telephony#CellSignalStrengthGsm + * @see android.telephony.CellSignalStrength + * @see android.telephony.CellSignalStrengthNr + * @see android.telephony.CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthTdscdma + * @see android.telephony.CellSignalStrengthWcdma + * @see android.telephony.CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthGsm */ @NonNull public List<CellSignalStrength> getCellSignalStrengths() { return getCellSignalStrengths(CellSignalStrength.class); @@ -187,7 +161,7 @@ public class SignalStrength implements Parcelable { * Returns a List of CellSignalStrength Components of this SignalStrength Report. * * Use this API to access underlying - * {@link android.telephony#CellSignalStrength CellSignalStrength} objects that provide more + * {@link android.telephony.CellSignalStrength CellSignalStrength} objects that provide more * granular information about the SignalStrength report. Only valid (non-empty) * CellSignalStrengths will be returned. The order of any returned elements is not guaranteed, * and the list may contain more than one instance of a CellSignalStrength type. @@ -197,13 +171,13 @@ public class SignalStrength implements Parcelable { * return values. * @return a List of CellSignalStrength or an empty List if there are no valid measurements. * - * @see android.telephony#CellSignalStrength - * @see android.telephony#CellSignalStrengthNr - * @see android.telephony#CellSignalStrengthLte - * @see android.telephony#CellSignalStrengthTdscdma - * @see android.telephony#CellSignalStrengthWcdma - * @see android.telephony#CellSignalStrengthCdma - * @see android.telephony#CellSignalStrengthGsm + * @see android.telephony.CellSignalStrength + * @see android.telephony.CellSignalStrengthNr + * @see android.telephony.CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthTdscdma + * @see android.telephony.CellSignalStrengthWcdma + * @see android.telephony.CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthGsm */ @NonNull public <T extends CellSignalStrength> List<T> getCellSignalStrengths( @NonNull Class<T> clazz) { @@ -319,7 +293,7 @@ public class SignalStrength implements Parcelable { * */ public static final @android.annotation.NonNull Parcelable.Creator<SignalStrength> CREATOR = - new Parcelable.Creator<SignalStrength>() { + new Parcelable.Creator<>() { public SignalStrength createFromParcel(Parcel in) { return new SignalStrength(in); } @@ -327,7 +301,7 @@ public class SignalStrength implements Parcelable { public SignalStrength[] newArray(int size) { return new SignalStrength[size]; } - }; + }; /** * Get the GSM RSSI in ASU. @@ -338,7 +312,7 @@ public class SignalStrength implements Parcelable { * * @deprecated this information should be retrieved from * {@link CellSignalStrengthGsm#getAsuLevel}. - * @see android.telephony#CellSignalStrengthGsm + * @see android.telephony.CellSignalStrengthGsm * @see android.telephony.SignalStrength#getCellSignalStrengths */ @Deprecated @@ -352,7 +326,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthGsm#getBitErrorRate}. * - * @see android.telephony#CellSignalStrengthGsm + * @see android.telephony.CellSignalStrengthGsm * @see android.telephony.SignalStrength#getCellSignalStrengths() */ @Deprecated @@ -368,7 +342,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthCdma#getCdmaDbm}. * - * @see android.telephony#CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthCdma * @see android.telephony.SignalStrength#getCellSignalStrengths() */ @Deprecated @@ -382,7 +356,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthCdma#getCdmaEcio}. * - * @see android.telephony#CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthCdma * @see android.telephony.SignalStrength#getCellSignalStrengths() */ @Deprecated @@ -398,7 +372,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthCdma#getEvdoDbm}. * - * @see android.telephony#CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthCdma * @see android.telephony.SignalStrength#getCellSignalStrengths() */ @Deprecated @@ -412,7 +386,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthCdma#getEvdoEcio}. * - * @see android.telephony#CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthCdma * @see android.telephony.SignalStrength#getCellSignalStrengths() */ @Deprecated @@ -426,7 +400,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthCdma#getEvdoSnr}. * - * @see android.telephony#CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthCdma * @see android.telephony.SignalStrength#getCellSignalStrengths() */ @Deprecated @@ -438,7 +412,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthLte#getRssi}. * - * @see android.telephony#CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthLte * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -452,7 +426,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthLte#getRsrp}. * - * @see android.telephony#CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthLte * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -466,7 +440,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthLte#getRsrq}. * - * @see android.telephony#CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthLte * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -480,7 +454,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthLte#getRssnr}. * - * @see android.telephony#CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthLte * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -494,7 +468,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthLte#getCqi}. * - * @see android.telephony#CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthLte * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -527,7 +501,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrength#getAsuLevel}. Because the levels vary by technology, * this method is misleading and should not be used. - * @see android.telephony#CellSignalStrength + * @see android.telephony.CellSignalStrength * @see android.telephony.SignalStrength#getCellSignalStrengths * @hide */ @@ -543,7 +517,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrength#getDbm()}. Because the levels vary by technology, * this method is misleading and should not be used. - * @see android.telephony#CellSignalStrength + * @see android.telephony.CellSignalStrength * @see android.telephony.SignalStrength#getCellSignalStrengths * @hide */ @@ -559,7 +533,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthGsm#getDbm}. * - * @see android.telephony#CellSignalStrengthGsm + * @see android.telephony.CellSignalStrengthGsm * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -575,7 +549,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthGsm#getLevel}. * - * @see android.telephony#CellSignalStrengthGsm + * @see android.telephony.CellSignalStrengthGsm * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -591,7 +565,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthGsm#getAsuLevel}. * - * @see android.telephony#CellSignalStrengthGsm + * @see android.telephony.CellSignalStrengthGsm * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -607,7 +581,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthCdma#getLevel}. * - * @see android.telephony#CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthCdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -625,7 +599,7 @@ public class SignalStrength implements Parcelable { * ASU for CDMA, the resultant value is Android-specific and is not recommended * for use. * - * @see android.telephony#CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthCdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -641,7 +615,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthCdma#getEvdoLevel}. * - * @see android.telephony#CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthCdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -659,7 +633,7 @@ public class SignalStrength implements Parcelable { * ASU for EvDO, the resultant value is Android-specific and is not recommended * for use. * - * @see android.telephony#CellSignalStrengthCdma + * @see android.telephony.CellSignalStrengthCdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -675,7 +649,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthLte#getDbm}. * - * @see android.telephony#CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthLte * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -691,7 +665,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthLte#getLevel}. * - * @see android.telephony#CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthLte * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -708,7 +682,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthLte#getAsuLevel}. * - * @see android.telephony#CellSignalStrengthLte + * @see android.telephony.CellSignalStrengthLte * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -739,7 +713,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthTdscdma#getDbm}. * - * @see android.telephony#CellSignalStrengthTdscdma + * @see android.telephony.CellSignalStrengthTdscdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -758,7 +732,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthTdscdma#getLevel}. * - * @see android.telephony#CellSignalStrengthTdscdma + * @see android.telephony.CellSignalStrengthTdscdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -774,7 +748,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthTdscdma#getAsuLevel}. * - * @see android.telephony#CellSignalStrengthTdscdma + * @see android.telephony.CellSignalStrengthTdscdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -790,7 +764,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthWcdma#getRscp}. * - * @see android.telephony#CellSignalStrengthWcdma + * @see android.telephony.CellSignalStrengthWcdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -805,7 +779,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthWcdma#getAsuLevel}. * - * @see android.telephony#CellSignalStrengthWcdma + * @see android.telephony.CellSignalStrengthWcdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -828,7 +802,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthWcdma#getDbm}. * - * @see android.telephony#CellSignalStrengthWcdma + * @see android.telephony.CellSignalStrengthWcdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -843,7 +817,7 @@ public class SignalStrength implements Parcelable { * @deprecated this information should be retrieved from * {@link CellSignalStrengthWcdma#getDbm}. * - * @see android.telephony#CellSignalStrengthWcdma + * @see android.telephony.CellSignalStrengthWcdma * @see android.telephony.SignalStrength#getCellSignalStrengths() * @hide */ @@ -895,32 +869,12 @@ public class SignalStrength implements Parcelable { } /** - * Set SignalStrength based on intent notifier map - * - * @param m intent notifier map - * - * @deprecated this method relies on non-stable implementation details, and full access to - * internal storage is available via {@link getCellSignalStrengths()}. - * @hide - */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - private void setFromNotifierBundle(Bundle m) { - mCdma = m.getParcelable("Cdma", android.telephony.CellSignalStrengthCdma.class); - mGsm = m.getParcelable("Gsm", android.telephony.CellSignalStrengthGsm.class); - mWcdma = m.getParcelable("Wcdma", android.telephony.CellSignalStrengthWcdma.class); - mTdscdma = m.getParcelable("Tdscdma", android.telephony.CellSignalStrengthTdscdma.class); - mLte = m.getParcelable("Lte", android.telephony.CellSignalStrengthLte.class); - mNr = m.getParcelable("Nr", android.telephony.CellSignalStrengthNr.class); - } - - /** * Set intent notifier Bundle based on SignalStrength * * @param m intent notifier Bundle * * @deprecated this method relies on non-stable implementation details, and full access to - * internal storage is available via {@link getCellSignalStrengths()}. + * internal storage is available via {@link #getCellSignalStrengths()}. * @hide */ @Deprecated diff --git a/tools/lint/fix/soong_lint_fix.py b/tools/lint/fix/soong_lint_fix.py index acc0ad043171..b42f9eec99d0 100644 --- a/tools/lint/fix/soong_lint_fix.py +++ b/tools/lint/fix/soong_lint_fix.py @@ -64,27 +64,27 @@ class SoongModule: class SoongLintFix: """ - This class creates a command line tool that will - apply lint fixes to the platform via the necessary - combination of soong and shell commands. + This class creates a command line tool that will apply lint fixes to the + platform via the necessary combination of soong and shell commands. - It breaks up these operations into a few "private" methods - that are intentionally exposed so experimental code can tweak behavior. + It breaks up these operations into a few "private" methods that are + intentionally exposed so experimental code can tweak behavior. - The entry point, `run`, will apply lint fixes using the - intermediate `suggested-fixes` directory that soong creates during its - invocation of lint. + The entry point, `run`, will apply lint fixes using the intermediate + `suggested-fixes` directory that soong creates during its invocation of + lint. Basic usage: ``` from soong_lint_fix import SoongLintFix - SoongLintFix().run() + opts = SoongLintFixOptions() + opts.parse_args(sys.argv) + SoongLintFix(opts).run() ``` """ - def __init__(self): - self._parser = _setup_parser() - self._args = None + def __init__(self, opts): + self._opts = opts self._kwargs = None self._modules = [] @@ -96,19 +96,18 @@ class SoongLintFix: self._find_modules() self._lint() - if not self._args.no_fix: + if not self._opts.no_fix: self._fix() - if self._args.print: + if self._opts.print: self._print() def _setup(self): - self._args = self._parser.parse_args() env = os.environ.copy() - if self._args.check: - env["ANDROID_LINT_CHECK"] = self._args.check - if self._args.lint_module: - env["ANDROID_LINT_CHECK_EXTRA_MODULES"] = self._args.lint_module + if self._opts.check: + env["ANDROID_LINT_CHECK"] = self._opts.check + if self._opts.lint_module: + env["ANDROID_LINT_CHECK_EXTRA_MODULES"] = self._opts.lint_module self._kwargs = { "env": env, @@ -131,7 +130,7 @@ class SoongLintFix: with open(f"{ANDROID_PRODUCT_OUT}/module-info.json") as f: module_info = json.load(f) - for module_name in self._args.modules: + for module_name in self._opts.modules: module = SoongModule(module_name) module.find(module_info) self._modules.append(module) @@ -169,6 +168,20 @@ class SoongLintFix: print(f.read()) +class SoongLintFixOptions: + """Options for SoongLintFix""" + + def __init__(self): + self.modules = [] + self.check = None + self.lint_module = None + self.no_fix = False + self.print = False + + def parse_args(self, args=None): + _setup_parser().parse_args(args, self) + + def _setup_parser(): parser = argparse.ArgumentParser(description=""" This is a python script that applies lint fixes to the platform: @@ -199,4 +212,6 @@ def _setup_parser(): return parser if __name__ == "__main__": - SoongLintFix().run() + opts = SoongLintFixOptions() + opts.parse_args(sys.argv) + SoongLintFix(opts).run() diff --git a/tools/lint/utils/Android.bp b/tools/lint/utils/Android.bp index 75e8d6863c20..439c86d564c7 100644 --- a/tools/lint/utils/Android.bp +++ b/tools/lint/utils/Android.bp @@ -43,3 +43,9 @@ java_test_host { "AndroidUtilsLintChecker", ], } + +python_binary_host { + name: "enforce_permission_counter", + srcs: ["enforce_permission_counter.py"], + libs: ["soong_lint_fix"], +} diff --git a/tools/lint/utils/enforce_permission_counter.py b/tools/lint/utils/enforce_permission_counter.py new file mode 100644 index 000000000000..b5c2ffe9885e --- /dev/null +++ b/tools/lint/utils/enforce_permission_counter.py @@ -0,0 +1,82 @@ +# 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. + +import re + +import soong_lint_fix + +# Libraries that constitute system_server. +# It is non-trivial to keep in sync with services/Android.bp as some +# module are post-processed (e.g, services.core). +TARGETS = [ + "services.core.unboosted", + "services.accessibility", + "services.appprediction", + "services.appwidget", + "services.autofill", + "services.backup", + "services.companion", + "services.contentcapture", + "services.contentsuggestions", + "services.coverage", + "services.devicepolicy", + "services.midi", + "services.musicsearch", + "services.net", + "services.people", + "services.print", + "services.profcollect", + "services.restrictions", + "services.searchui", + "services.smartspace", + "services.systemcaptions", + "services.translation", + "services.texttospeech", + "services.usage", + "services.usb", + "services.voiceinteraction", + "services.wallpapereffectsgeneration", + "services.wifi", +] + + +class EnforcePermissionMigratedCounter: + """Wrapper around lint_fix to count the number of AIDL methods annotated.""" + def run(self): + opts = soong_lint_fix.SoongLintFixOptions() + opts.check = "AnnotatedAidlCounter" + opts.lint_module = "AndroidUtilsLintChecker" + opts.no_fix = True + opts.modules = TARGETS + + self.linter = soong_lint_fix.SoongLintFix(opts) + self.linter.run() + self.parse_lint_reports() + + def parse_lint_reports(self): + counts = { "unannotated": 0, "enforced": 0, "notRequired": 0 } + for module in self.linter._modules: + with open(module.lint_report, "r") as f: + content = f.read() + keys = dict(re.findall(r'(\w+)=(\d+)', content)) + for key in keys: + counts[key] += int(keys[key]) + print(counts) + total = sum(counts.values()) + annotated_percent = (1 - (counts["unannotated"] / total)) * 100 + print("Annotated methods = %.2f%%" % (annotated_percent)) + + +if __name__ == "__main__": + EnforcePermissionMigratedCounter().run() |