Merge "Allow DISALLOW_CONFIG_DEFAULT_APPS to apply on the personal profile" into main
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 2babf6a..6337022 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -93,16 +93,33 @@
],
}
+// Jars in "ravenwood-runtime" are set to the classpath, sorted alphabetically.
+// Rename some of the dependencies to make sure they're included in the intended order.
+java_genrule {
+ name: "100-framework-minus-apex.ravenwood",
+ cmd: "cp $(in) $(out)",
+ srcs: [":framework-minus-apex.ravenwood"],
+ out: ["100-framework-minus-apex.ravenwood.jar"],
+ visibility: ["//visibility:private"],
+}
+
+java_genrule {
+ // Use 200 to make sure it comes before the mainline stub ("all-updatable...").
+ name: "200-kxml2-android",
+ cmd: "cp $(in) $(out)",
+ srcs: [":kxml2-android"],
+ out: ["200-kxml2-android.jar"],
+ visibility: ["//visibility:private"],
+}
+
android_ravenwood_libgroup {
name: "ravenwood-runtime",
libs: [
- // Prefixed with "200" to ensure it's sorted early in Tradefed classpath
- // so that we provide a concrete implementation before Mainline stubs
+ "100-framework-minus-apex.ravenwood",
"200-kxml2-android",
"all-updatable-modules-system-stubs",
"android.test.mock.ravenwood",
- "framework-minus-apex.ravenwood",
- "hoststubgen-helper-framework-runtime.ravenwood",
+ "ravenwood-helper-runtime",
"hoststubgen-helper-runtime.ravenwood",
// Provide runtime versions of utils linked in below
diff --git a/core/api/current.txt b/core/api/current.txt
index db7334e2..2d03be7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7955,9 +7955,11 @@
field public static final String LOCK_TASK_POLICY = "lockTask";
field public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended";
field public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
+ field @FlaggedApi("android.app.admin.flags.policy_engine_migration_v2_enabled") public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity";
field public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
field public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY = "persistentPreferredActivity";
field public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
+ field @FlaggedApi("android.app.admin.flags.security_log_v2_enabled") public static final String SECURITY_LOGGING_POLICY = "securityLogging";
field public static final String STATUS_BAR_DISABLED_POLICY = "statusBarDisabled";
field @FlaggedApi("android.app.admin.flags.policy_engine_migration_v2_enabled") public static final String USB_DATA_SIGNALING_POLICY = "usbDataSignaling";
field public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY = "userControlDisabledPackages";
@@ -22496,6 +22498,7 @@
method @NonNull public static android.view.Surface createPersistentInputSurface();
method public int dequeueInputBuffer(long);
method public int dequeueOutputBuffer(@NonNull android.media.MediaCodec.BufferInfo, long);
+ method @FlaggedApi("android.media.codec.null_output_surface") public void detachOutputSurface();
method protected void finalize();
method public void flush();
method @NonNull public String getCanonicalName();
@@ -22519,6 +22522,7 @@
method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
+ method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueSecureInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>, @NonNull java.util.ArrayDeque<android.media.MediaCodec.CryptoInfo>);
method public void release();
method public void releaseOutputBuffer(int, boolean);
method public void releaseOutputBuffer(int, long);
@@ -22543,6 +22547,7 @@
field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
field public static final int BUFFER_FLAG_PARTIAL_FRAME = 8; // 0x8
field @Deprecated public static final int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
+ field @FlaggedApi("android.media.codec.null_output_surface") public static final int CONFIGURE_FLAG_DETACHED_SURFACE = 8; // 0x8
field public static final int CONFIGURE_FLAG_ENCODE = 1; // 0x1
field public static final int CONFIGURE_FLAG_USE_BLOCK_MODEL = 2; // 0x2
field public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4; // 0x4
@@ -22694,6 +22699,7 @@
method @NonNull public android.media.MediaCodec.QueueRequest setIntegerParameter(@NonNull String, int);
method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int);
method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
+ method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setMultiFrameEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>, @NonNull java.util.ArrayDeque<android.media.MediaCodec.CryptoInfo>);
method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
}
@@ -22788,6 +22794,7 @@
field @Deprecated public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
field @Deprecated public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
field public static final String FEATURE_AdaptivePlayback = "adaptive-playback";
+ field @FlaggedApi("android.media.codec.null_output_surface") public static final String FEATURE_DetachedSurface = "detached-surface";
field @FlaggedApi("android.media.codec.dynamic_color_aspects") public static final String FEATURE_DynamicColorAspects = "dynamic-color-aspects";
field public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
field public static final String FEATURE_EncodingStatistics = "encoding-statistics";
@@ -39648,7 +39655,7 @@
method @Nullable public java.util.Date getKeyValidityStart();
method @NonNull public String getKeystoreAlias();
method public int getMaxUsageCount();
- method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
+ method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
method public int getPurposes();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
@@ -39656,7 +39663,7 @@
method public boolean isDevicePropertiesAttestationIncluded();
method @NonNull public boolean isDigestsSpecified();
method public boolean isInvalidatedByBiometricEnrollment();
- method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public boolean isMgf1DigestsSpecified();
+ method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public boolean isMgf1DigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isStrongBoxBacked();
method public boolean isUnlockedDeviceRequired();
@@ -39688,7 +39695,7 @@
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMaxUsageCount(int);
- method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@NonNull java.lang.String...);
+ method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@NonNull java.lang.String...);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
@@ -39793,14 +39800,14 @@
method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
method @Nullable public java.util.Date getKeyValidityStart();
method public int getMaxUsageCount();
- method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
+ method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
method public int getPurposes();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
method public boolean isInvalidatedByBiometricEnrollment();
- method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public boolean isMgf1DigestsSpecified();
+ method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public boolean isMgf1DigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
@@ -39822,7 +39829,7 @@
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
method @NonNull public android.security.keystore.KeyProtection.Builder setMaxUsageCount(int);
- method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public android.security.keystore.KeyProtection.Builder setMgf1Digests(@Nullable java.lang.String...);
+ method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public android.security.keystore.KeyProtection.Builder setMgf1Digests(@Nullable java.lang.String...);
method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
@@ -50509,7 +50516,7 @@
method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction);
method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
method public default int getBufferTransformHint();
- method @FlaggedApi("com.android.window.flags.get_host_token_api") @Nullable public default android.os.IBinder getHostToken();
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.window.InputTransferToken getInputTransferToken();
method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
method public default void setChildBoundingInsets(@NonNull android.graphics.Rect);
method public default void setTouchableRegion(@Nullable android.graphics.Region);
@@ -52219,6 +52226,7 @@
public class SurfaceControlViewHost {
ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder);
+ ctor @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.window.InputTransferToken);
method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage();
method @Nullable public android.view.View getView();
method public void relayout(int, int);
@@ -52420,7 +52428,7 @@
method public final void cancelPendingInputEvents();
method public boolean checkInputConnectionProxy(android.view.View);
method public void clearAnimation();
- method @FlaggedApi("autofill_credman_dev_integration") public void clearCredentialManagerRequest();
+ method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") public void clearCredentialManagerRequest();
method public void clearFocus();
method public void clearViewTranslationCallback();
method public static int combineMeasuredStates(int, int);
@@ -52530,8 +52538,8 @@
method @FlaggedApi("android.view.flags.sensitive_content_app_protection_api") public final int getContentSensitivity();
method @UiContext public final android.content.Context getContext();
method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
- method @FlaggedApi("autofill_credman_dev_integration") @Nullable public final android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException> getCredentialManagerCallback();
- method @FlaggedApi("autofill_credman_dev_integration") @Nullable public final android.credentials.GetCredentialRequest getCredentialManagerRequest();
+ method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") @Nullable public final android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException> getCredentialManagerCallback();
+ method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") @Nullable public final android.credentials.GetCredentialRequest getCredentialManagerRequest();
method public final boolean getDefaultFocusHighlightEnabled();
method public static int getDefaultSize(int, int);
method public android.view.Display getDisplay();
@@ -52916,7 +52924,7 @@
method public void setContentDescription(CharSequence);
method @FlaggedApi("android.view.flags.sensitive_content_app_protection_api") public final void setContentSensitivity(int);
method public void setContextClickable(boolean);
- method @FlaggedApi("autofill_credman_dev_integration") public void setCredentialManagerRequest(@NonNull android.credentials.GetCredentialRequest, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>);
+ method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") public void setCredentialManagerRequest(@NonNull android.credentials.GetCredentialRequest, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>);
method public void setDefaultFocusHighlightEnabled(boolean);
method @Deprecated public void setDrawingCacheBackgroundColor(@ColorInt int);
method @Deprecated public void setDrawingCacheEnabled(boolean);
@@ -53795,11 +53803,11 @@
method public abstract int addChildCount(int);
method public abstract void asyncCommit();
method public abstract android.view.ViewStructure asyncNewChild(int);
- method @FlaggedApi("autofill_credman_dev_integration") public void clearCredentialManagerRequest();
+ method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") public void clearCredentialManagerRequest();
method @Nullable public abstract android.view.autofill.AutofillId getAutofillId();
method public abstract int getChildCount();
- method @FlaggedApi("autofill_credman_dev_integration") @Nullable public android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException> getCredentialManagerCallback();
- method @FlaggedApi("autofill_credman_dev_integration") @Nullable public android.credentials.GetCredentialRequest getCredentialManagerRequest();
+ method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") @Nullable public android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException> getCredentialManagerCallback();
+ method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") @Nullable public android.credentials.GetCredentialRequest getCredentialManagerRequest();
method public abstract android.os.Bundle getExtras();
method public abstract CharSequence getHint();
method public abstract CharSequence getText();
@@ -53824,7 +53832,7 @@
method public abstract void setClickable(boolean);
method public abstract void setContentDescription(CharSequence);
method public abstract void setContextClickable(boolean);
- method @FlaggedApi("autofill_credman_dev_integration") public void setCredentialManagerRequest(@NonNull android.credentials.GetCredentialRequest, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>);
+ method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") public void setCredentialManagerRequest(@NonNull android.credentials.GetCredentialRequest, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>);
method public abstract void setDataIsSensitive(boolean);
method public abstract void setDimens(int, int, int, int, int, int);
method public abstract void setElevation(float);
@@ -54365,9 +54373,9 @@
method @Deprecated public android.view.Display getDefaultDisplay();
method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
method public default boolean isCrossWindowBlurEnabled();
- method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerBatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerBatchedSurfaceControlInputReceiver(int, @NonNull android.window.InputTransferToken, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void registerTrustedPresentationListener(@NonNull android.os.IBinder, @NonNull android.window.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.window.InputTransferToken, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public default void removeProposedRotationListener(@NonNull java.util.function.IntConsumer);
method @FlaggedApi("com.android.window.flags.screen_recording_callbacks") @RequiresPermission(android.Manifest.permission.DETECT_SCREEN_RECORDING) public default void removeScreenRecordingCallback(@NonNull java.util.function.Consumer<java.lang.Integer>);
@@ -61348,6 +61356,12 @@
field public static final int EDGE_RIGHT = 1; // 0x1
}
+ @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public final class InputTransferToken implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.InputTransferToken> CREATOR;
+ }
+
public interface OnBackAnimationCallback extends android.window.OnBackInvokedCallback {
method public default void onBackCancelled();
method public default void onBackProgressed(@NonNull android.window.BackEvent);
@@ -61395,11 +61409,11 @@
@FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public final class TrustedPresentationThresholds implements android.os.Parcelable {
ctor @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public TrustedPresentationThresholds(@FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @IntRange(from=1) int);
method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public int describeContents();
+ method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public float getMinAlpha();
+ method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public float getMinFractionRendered();
+ method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @IntRange(from=1) public int getStabilityRequirementMillis();
method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public void writeToParcel(@NonNull android.os.Parcel, int);
field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @NonNull public static final android.os.Parcelable.Creator<android.window.TrustedPresentationThresholds> CREATOR;
- field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public final float minAlpha;
- field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public final float minFractionRendered;
- field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @IntRange(from=1) public final int stabilityRequirementMs;
}
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 88f9aff..159410d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1307,6 +1307,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.app.admin.DevicePolicyState getDevicePolicyState();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public String getFinancedDeviceKioskRoleHolder();
+ method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int getMaxPolicyStorageLimit();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public java.util.List<android.os.UserHandle> getPolicyManagedProfiles(@NonNull android.os.UserHandle);
@@ -1329,6 +1330,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS) public void setApplicationExemptions(@NonNull String, @NonNull java.util.Set<java.lang.Integer>) throws android.content.pm.PackageManager.NameNotFoundException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
+ method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setMaxPolicyStorageLimit(int);
method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
@@ -3191,6 +3193,8 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideDataStream(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideWearableConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("android.app.wearable.enable_data_request_observer_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void registerDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void startHotwordRecognition(@Nullable android.content.ComponentName, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void stopHotwordRecognition(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("android.app.wearable.enable_data_request_observer_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void unregisterDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
field public static final int STATUS_ACCESS_DENIED = 5; // 0x5
field @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") public static final int STATUS_CHANNEL_ERROR = 7; // 0x7
@@ -10430,9 +10434,11 @@
method public int getFlags();
method public int getMode();
field public static final int BUGREPORT_FLAG_DEFER_CONSENT = 2; // 0x2
+ field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL = 4; // 0x4
field public static final int BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA = 1; // 0x1
field public static final int BUGREPORT_MODE_FULL = 0; // 0x0
field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1
+ field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_MODE_ONBOARDING = 7; // 0x7
field public static final int BUGREPORT_MODE_REMOTE = 2; // 0x2
field public static final int BUGREPORT_MODE_TELEPHONY = 4; // 0x4
field public static final int BUGREPORT_MODE_WEAR = 3; // 0x3
@@ -13188,6 +13194,7 @@
method @Nullable public android.service.voice.HotwordDetectedResult getHotwordDetectedResult();
method @NonNull public java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra> getKeyphraseRecognitionExtras();
method @Deprecated @Nullable public byte[] getTriggerAudio();
+ method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") public boolean isRecognitionStopped();
field public static final int DATA_FORMAT_RAW = 0; // 0x0
field public static final int DATA_FORMAT_TRIGGER_AUDIO = 1; // 0x1
}
@@ -13294,6 +13301,7 @@
method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer);
field @Deprecated public static final int INITIALIZATION_STATUS_SUCCESS = 0; // 0x0
field @Deprecated public static final int INITIALIZATION_STATUS_UNKNOWN = 100; // 0x64
+ field @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") public static final String KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK = "android.service.voice.HotwordDetectionService.KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK";
field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService";
}
@@ -13578,7 +13586,11 @@
method @BinderThread public abstract void onQueryServiceStatus(@NonNull java.util.Set<java.lang.Integer>, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>);
method @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") @BinderThread public void onSecureWearableConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @BinderThread public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionResult>);
+ method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onStartHotwordRecognition(@NonNull java.util.function.Consumer<android.service.voice.HotwordAudioStream>, @NonNull java.util.function.Consumer<java.lang.Integer>);
method public abstract void onStopDetection(@NonNull String);
+ method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onStopHotwordAudioStream();
+ method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onStopHotwordRecognition(@NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onValidatedByHotwordDetectionService();
field public static final String SERVICE_INTERFACE = "android.service.wearable.WearableSensingService";
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index cd84c84..3838b94 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2277,9 +2277,7 @@
}
public final class BugreportParams {
- field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL = 4; // 0x4
field @FlaggedApi("android.os.bugreport_mode_max_value") public static final int BUGREPORT_MODE_MAX_VALUE = 7; // 0x7
- field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_MODE_ONBOARDING = 7; // 0x7
}
public class Build {
@@ -3172,6 +3170,7 @@
method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setDataFormat(int);
method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHalEventReceivedMillis(long);
method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHotwordDetectedResult(@NonNull android.service.voice.HotwordDetectedResult);
+ method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setIsRecognitionStopped(boolean);
method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setKeyphraseRecognitionExtras(@NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ab9a4ec..23fe731 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3927,6 +3927,7 @@
if (keyCode == KeyEvent.KEYCODE_ESCAPE && mWindow.shouldCloseOnTouchOutside()) {
event.startTracking();
+ finish();
return true;
}
@@ -4027,10 +4028,7 @@
}
if (keyCode == KeyEvent.KEYCODE_ESCAPE
- && mWindow.shouldCloseOnTouchOutside()
- && event.isTracking()
- && !event.isCanceled()) {
- finish();
+ && event.isTracking()) {
return true;
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index d0d76a4..0e20138 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -672,7 +672,16 @@
*/
@Override
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ event.startTracking();
+ return true;
+ }
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ if (mCancelable) {
+ cancel();
+ } else {
+ dismiss();
+ }
event.startTracking();
return true;
}
@@ -712,11 +721,6 @@
}
break;
case KeyEvent.KEYCODE_ESCAPE:
- if (mCancelable) {
- cancel();
- } else {
- dismiss();
- }
return true;
}
}
diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java
index d7aafa0..a884ab0 100644
--- a/core/java/android/app/admin/DevicePolicyIdentifiers.java
+++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java
@@ -16,6 +16,8 @@
package android.app.admin;
+import static android.app.admin.flags.Flags.FLAG_SECURITY_LOG_V2_ENABLED;
+
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.TestApi;
@@ -45,6 +47,12 @@
public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
/**
+ * String identifier for {@link DevicePolicyManager#setSecurityLoggingEnabled}.
+ */
+ @FlaggedApi(FLAG_SECURITY_LOG_V2_ENABLED)
+ public static final String SECURITY_LOGGING_POLICY = "securityLogging";
+
+ /**
* String identifier for {@link DevicePolicyManager#setLockTaskPackages}.
*/
public static final String LOCK_TASK_POLICY = "lockTask";
@@ -174,6 +182,12 @@
public static final String USB_DATA_SIGNALING_POLICY = "usbDataSignaling";
/**
+ * String identifier for {@link DevicePolicyManager#setRequiredPasswordComplexity}.
+ */
+ @FlaggedApi(Flags.FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED)
+ public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity";
+
+ /**
* @hide
*/
public static final String USER_RESTRICTION_PREFIX = "userRestriction_";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9d50810..c53b54c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -52,6 +52,7 @@
import static android.Manifest.permission.SET_TIME;
import static android.Manifest.permission.SET_TIME_ZONE;
import static android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED;
+import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED;
import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
@@ -13976,6 +13977,24 @@
* privacy-sensitive events happening outside the managed profile would have been redacted
* already.
*
+ * Starting from {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, after the security logging
+ * policy has been set, {@link PolicyUpdateReceiver#onPolicySetResult(Context, String,
+ * Bundle, TargetUser, PolicyUpdateResult)} will notify the admin on whether the policy was
+ * successfully set or not. This callback will contain:
+ * <ul>
+ * <li> The policy identifier {@link DevicePolicyIdentifiers#SECURITY_LOGGING_POLICY}
+ * <li> The {@link TargetUser} that this policy relates to
+ * <li> The {@link PolicyUpdateResult}, which will be
+ * {@link PolicyUpdateResult#RESULT_POLICY_SET} if the policy was successfully set or the
+ * reason the policy failed to be set
+ * e.g. {@link PolicyUpdateResult#RESULT_FAILURE_CONFLICTING_ADMIN_POLICY})
+ * </ul>
+ * If there has been a change to the policy,
+ * {@link PolicyUpdateReceiver#onPolicyChanged(Context, String, Bundle, TargetUser,
+ * PolicyUpdateResult)} will notify the admin of this change. This callback will contain the
+ * same parameters as PolicyUpdateReceiver#onPolicySetResult and the {@link PolicyUpdateResult}
+ * will contain the reason why the policy changed.
+ *
* @param admin Which device admin this request is associated with, or {@code null}
* if called by a delegated app.
* @param enabled whether security logging should be enabled or not.
@@ -17330,4 +17349,46 @@
}
return new HashSet<>();
}
+
+ /**
+ * Controls the maximum storage size allowed for policies associated with an admin.
+ * Setting a limit of -1 effectively removes any storage restrictions.
+ *
+ * @param storageLimit Maximum storage allowed in bytes. Use -1 to disable limits.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED)
+ public void setMaxPolicyStorageLimit(int storageLimit) {
+ if (mService != null) {
+ try {
+ mService.setMaxPolicyStorageLimit(mContext.getPackageName(), storageLimit);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Retrieves the current maximum storage limit for policies associated with an admin.
+ *
+ * @return The maximum storage limit in bytes, or -1 if no limit is enforced.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED)
+ public int getMaxPolicyStorageLimit() {
+ if (mService != null) {
+ try {
+ return mService.getMaxPolicyStorageLimit(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return -1;
+ }
}
\ No newline at end of file
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 304359b..07ee8de 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -333,4 +333,9 @@
*/
public abstract List<EnforcingUser> getUserRestrictionSources(String restriction,
@UserIdInt int userId);
+
+ /**
+ * Enforces resolved security logging policy, should only be invoked from device policy engine.
+ */
+ public abstract void enforceSecurityLoggingPolicy(boolean enabled);
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index f72fdc0..c4cbdd6 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -615,4 +615,7 @@
int getContentProtectionPolicy(in ComponentName who, String callerPackageName);
int[] getSubscriptionIds(String callerPackageName);
+
+ void setMaxPolicyStorageLimit(String packageName, int storageLimit);
+ int getMaxPolicyStorageLimit(String packageName);
}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 7a4a3f9..9fa7362 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1,5 +1,7 @@
package android.app.assist;
+import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
+
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1278,7 +1280,7 @@
*
* @hide
*/
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
@Nullable
public GetCredentialRequest getCredentialManagerRequest() {
return mGetCredentialRequest;
@@ -1291,7 +1293,7 @@
* @hide
*
*/
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
@Nullable
public OutcomeReceiver<GetCredentialResponse,
GetCredentialException> getCredentialManagerCallback() {
diff --git a/core/java/android/app/wearable/IWearableSensingManager.aidl b/core/java/android/app/wearable/IWearableSensingManager.aidl
index 3cbc8a2..f678022 100644
--- a/core/java/android/app/wearable/IWearableSensingManager.aidl
+++ b/core/java/android/app/wearable/IWearableSensingManager.aidl
@@ -17,6 +17,7 @@
package android.app.wearable;
import android.app.PendingIntent;
+import android.content.ComponentName;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
@@ -38,4 +39,8 @@
void registerDataRequestObserver(int dataType, in PendingIntent dataRequestPendingIntent, in RemoteCallback statusCallback);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)")
void unregisterDataRequestObserver(int dataType, in PendingIntent dataRequestPendingIntent, in RemoteCallback statusCallback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)")
+ void startHotwordRecognition(in ComponentName targetVisComponentName, in RemoteCallback statusCallback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)")
+ void stopHotwordRecognition(in RemoteCallback statusCallback);
}
\ No newline at end of file
diff --git a/core/java/android/app/wearable/WearableSensingManager.java b/core/java/android/app/wearable/WearableSensingManager.java
index 3b281e9..637f677 100644
--- a/core/java/android/app/wearable/WearableSensingManager.java
+++ b/core/java/android/app/wearable/WearableSensingManager.java
@@ -28,6 +28,7 @@
import android.app.PendingIntent;
import android.app.ambientcontext.AmbientContextEvent;
import android.companion.CompanionDeviceManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@@ -92,9 +93,13 @@
public static final int STATUS_SUCCESS = 1;
/**
- * The value of the status code that indicates one or more of the
- * requested events are not supported.
+ * The value of the status code that indicates one or more of the requested events are not
+ * supported.
*/
+ // TODO(b/324635656): Deprecate this status code. Update Javadoc:
+ // @deprecated WearableSensingManager does not deal with events. Use {@link
+ // STATUS_UNSUPPORTED_OPERATION} instead for operations not supported by the implementation of
+ // {@link WearableSensingService}.
public static final int STATUS_UNSUPPORTED = 2;
/**
@@ -382,6 +387,83 @@
}
}
+ /**
+ * Requests the wearable to start hotword recognition.
+ *
+ * <p>When this method is called, the system will attempt to provide a {@link
+ * android.service.wearable.WearableHotwordAudioConsumer} to {@link WearableSensingService}.
+ * After first-stage hotword is detected on a wearable, {@link WearableSensingService} should
+ * send the hotword audio to the {@link android.service.wearable.WearableHotwordAudioConsumer},
+ * which will forward the data to the {@link android.service.voice.HotwordDetectionService} for
+ * second-stage hotword validation. If hotword is detected there, the audio data will be
+ * forwarded to the {@link android.service.voice.VoiceInteractionService}.
+ *
+ * <p>If the {@code targetVisComponentName} provided here is not null, when {@link
+ * WearableSensingService} sends hotword audio to the {@link
+ * android.service.wearable.WearableHotwordAudioConsumer}, the system will check whether the
+ * {@link android.service.voice.VoiceInteractionService} at that time is {@code
+ * targetVisComponentName}. If not, the system will call {@link
+ * WearableSensingService#onActiveHotwordAudioStopRequested()} and will not forward the audio
+ * data to the current {@link android.service.voice.HotwordDetectionService} nor {@link
+ * android.service.voice.VoiceInteractionService}. The system will not send a status code to
+ * {@code statusConsumer} regarding the {@code targetVisComponentName} check. The caller is
+ * responsible for determining whether the system's {@link
+ * android.service.voice.VoiceInteractionService} is the same as {@code targetVisComponentName}.
+ * The check here is just a protection against race conditions.
+ *
+ * <p>Calling this method again will send a new {@link
+ * android.service.wearable.WearableHotwordAudioConsumer} to {@link WearableSensingService}. For
+ * audio data sent to the new consumer, the system will perform the above check using the newly
+ * provided {@code targetVisComponentName}. The {@link WearableSensingService} should not
+ * continue to use the previous consumers after receiving a new one.
+ *
+ * <p>If the {@code statusConsumer} returns {@link STATUS_SUCCESS}, the caller should call
+ * {@link #stopListeningForHotword(Executor, Consumer)} when it wants the wearable to stop
+ * listening for hotword. If the {@code statusConsumer} returns any other status code, a failure
+ * has occurred and calling {@link #stopListeningForHotword(Executor, Consumer)} is not
+ * required. The system will not retry listening automatically. The caller should call this
+ * method again if they want to retry.
+ *
+ * <p>If a failure occurred after the {@link statusConsumer} returns {@link STATUS_SUCCESS},
+ * {@link statusConsumer} will be invoked again with a status code other than {@link
+ * STATUS_SUCCESS}.
+ *
+ * @param targetVisComponentName The ComponentName of the target VoiceInteractionService.
+ * @param executor Executor on which to run the consumer callback.
+ * @param statusConsumer A consumer that handles the status codes.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+ @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
+ public void startHotwordRecognition(
+ @Nullable ComponentName targetVisComponentName,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull @StatusCode Consumer<Integer> statusConsumer) {
+ try {
+ mService.startHotwordRecognition(
+ targetVisComponentName, createStatusCallback(executor, statusConsumer));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Requests the wearable to stop hotword recognition.
+ *
+ * @param executor Executor on which to run the consumer callback.
+ * @param statusConsumer A consumer that handles the status codes.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+ @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
+ public void stopHotwordRecognition(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull @StatusCode Consumer<Integer> statusConsumer) {
+ try {
+ mService.stopHotwordRecognition(createStatusCallback(executor, statusConsumer));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private static RemoteCallback createStatusCallback(
Executor executor, Consumer<Integer> statusConsumer) {
return new RemoteCallback(
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index c7d93bf..317fa58 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -142,3 +142,10 @@
description: "Enable extra check to limit access to hidden prfiles data in Launcher apps APIs."
bug: "321988638"
}
+
+flag {
+ name: "reorder_wallpaper_during_user_switch"
+ namespace: "multiuser"
+ description: "Reorder loading home and lock screen wallpapers during a user switch."
+ bug: "324911115"
+}
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 870546a..ba356bb 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -40,7 +40,7 @@
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
- "com.android.hoststubgen.nativesubstitution.CursorWindow_host")
+ "com.android.platform.test.ravenwood.nativesubstitution.CursorWindow_host")
public class CursorWindow extends SQLiteClosable implements Parcelable {
private static final String STATS_TAG = "CursorWindowStats";
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index f2ef185..f7b4173 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -21,7 +21,6 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.admin.flags.Flags;
-import android.compat.annotation.UnsupportedAppUsage;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -127,12 +126,8 @@
/**
* Options for a lightweight bugreport intended to be taken for onboarding-related flows.
- *
- * @hide
*/
- @TestApi
@FlaggedApi(Flags.FLAG_ONBOARDING_BUGREPORT_V2_ENABLED)
- @UnsupportedAppUsage
public static final int BUGREPORT_MODE_ONBOARDING = IDumpstate.BUGREPORT_MODE_ONBOARDING;
/**
@@ -180,10 +175,7 @@
* The bugreport may be retrieved multiple times using
* {@link BugreportManager#retrieveBugreport(
* String, ParcelFileDescriptor, Executor, BugreportManager.BugreportCallback)}.
- *
- * @hide
*/
- @TestApi
@FlaggedApi(Flags.FLAG_ONBOARDING_BUGREPORT_V2_ENABLED)
public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL =
IDumpstate.BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL;
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index fbec518..3950c25 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -42,7 +42,7 @@
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
- "com.android.hoststubgen.nativesubstitution.MessageQueue_host")
+ "com.android.platform.test.ravenwood.nativesubstitution.MessageQueue_host")
public final class MessageQueue {
private static final String TAG = "MessageQueue";
private static final boolean DEBUG = false;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 8e860c3..ccfb632 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -233,7 +233,8 @@
* {@link #readSparseArray(ClassLoader, Class)}.
*/
@RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.Parcel_host")
+@RavenwoodNativeSubstitutionClass(
+ "com.android.platform.test.ravenwood.nativesubstitution.Parcel_host")
public final class Parcel {
private static final boolean DEBUG_RECYCLE = false;
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 6532d5c..17dfdda 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -75,7 +75,8 @@
* you to close it when done with it.
*/
@RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.ParcelFileDescriptor_host")
+@RavenwoodNativeSubstitutionClass(
+ "com.android.platform.test.ravenwood.nativesubstitution.ParcelFileDescriptor_host")
public class ParcelFileDescriptor implements Parcelable, Closeable {
private static final String TAG = "ParcelFileDescriptor";
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index a818919..0a38691 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -56,7 +56,8 @@
*/
@SystemApi
@RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.SystemProperties_host")
+@RavenwoodNativeSubstitutionClass(
+ "com.android.platform.test.ravenwood.nativesubstitution.SystemProperties_host")
public class SystemProperties {
private static final String TAG = "SystemProperties";
private static final boolean TRACK_KEY_ACCESS = false;
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 43163b3..7631454 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -15,10 +15,11 @@
}
flag {
- name: "mgf1_digest_setter"
+ name: "mgf1_digest_setter_v2"
namespace: "hardware_backed_security"
description: "Feature flag for mgf1 digest setter in key generation and import parameters."
bug: "308378912"
+ is_fixed_read_only: true
}
flag {
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 94d8516..a08264e 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -22,6 +22,7 @@
import static android.service.voice.VoiceInteractionService.MULTIPLE_ACTIVE_HOTWORD_DETECTORS;
import android.annotation.ElapsedRealtimeLong;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -432,7 +433,10 @@
@ElapsedRealtimeLong
private final long mHalEventReceivedMillis;
- private EventPayload(boolean captureAvailable,
+ private final boolean mIsRecognitionStopped;
+
+ private EventPayload(
+ boolean captureAvailable,
@Nullable AudioFormat audioFormat,
int captureSession,
@DataFormat int dataFormat,
@@ -440,7 +444,8 @@
@Nullable HotwordDetectedResult hotwordDetectedResult,
@Nullable ParcelFileDescriptor audioStream,
@NonNull List<KeyphraseRecognitionExtra> keyphraseExtras,
- @ElapsedRealtimeLong long halEventReceivedMillis) {
+ @ElapsedRealtimeLong long halEventReceivedMillis,
+ boolean isRecognitionStopped) {
mCaptureAvailable = captureAvailable;
mCaptureSession = captureSession;
mAudioFormat = audioFormat;
@@ -450,6 +455,7 @@
mAudioStream = audioStream;
mKephraseExtras = keyphraseExtras;
mHalEventReceivedMillis = halEventReceivedMillis;
+ mIsRecognitionStopped = isRecognitionStopped;
}
/**
@@ -592,6 +598,12 @@
return mHalEventReceivedMillis;
}
+ /** Returns whether the system has stopped hotword recognition because of this detection. */
+ @FlaggedApi(android.app.wearable.Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+ public boolean isRecognitionStopped() {
+ return mIsRecognitionStopped;
+ }
+
/**
* Builder class for {@link EventPayload} objects
*
@@ -610,6 +622,8 @@
private List<KeyphraseRecognitionExtra> mKeyphraseExtras = Collections.emptyList();
@ElapsedRealtimeLong
private long mHalEventReceivedMillis = -1;
+ // default to true to keep prior behavior
+ private boolean mIsRecognitionStopped = true;
public Builder() {}
@@ -746,13 +760,31 @@
}
/**
+ * Sets whether the system has stopped hotword recognition because of this detection.
+ */
+ @FlaggedApi(android.app.wearable.Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+ @NonNull
+ public Builder setIsRecognitionStopped(boolean isRecognitionStopped) {
+ mIsRecognitionStopped = isRecognitionStopped;
+ return this;
+ }
+
+ /**
* Builds an {@link EventPayload} instance
*/
@NonNull
public EventPayload build() {
- return new EventPayload(mCaptureAvailable, mAudioFormat, mCaptureSession,
- mDataFormat, mData, mHotwordDetectedResult, mAudioStream,
- mKeyphraseExtras, mHalEventReceivedMillis);
+ return new EventPayload(
+ mCaptureAvailable,
+ mAudioFormat,
+ mCaptureSession,
+ mDataFormat,
+ mData,
+ mHotwordDetectedResult,
+ mAudioStream,
+ mKeyphraseExtras,
+ mHalEventReceivedMillis,
+ mIsRecognitionStopped);
}
}
}
@@ -786,14 +818,20 @@
/**
* Called when the keyphrase is spoken.
- * This implicitly stops listening for the keyphrase once it's detected.
- * Clients should start a recognition again once they are done handling this
- * detection.
*
- * @param eventPayload Payload data for the detection event.
- * This may contain the trigger audio, if requested when calling
- * {@link AlwaysOnHotwordDetector#startRecognition(int)}.
+ * <p>This implicitly stops listening for the keyphrase once it's detected. Clients should
+ * start a recognition again once they are done handling this detection.
+ *
+ * @param eventPayload Payload data for the detection event. This may contain the trigger
+ * audio, if requested when calling {@link
+ * AlwaysOnHotwordDetector#startRecognition(int)}.
*/
+ // TODO(b/324635656): Update Javadoc for 24Q3 release:
+ // 1. Prepend to the first paragraph:
+ // If {@code eventPayload.isRecognitionStopped()} returns true, this...
+ // 2. Append to the description for @param eventPayload:
+ // ...or if the audio comes from {@link
+ // android.service.wearable.WearableSensingService}.
public abstract void onDetected(@NonNull EventPayload eventPayload);
/**
@@ -1632,6 +1670,20 @@
}
@Override
+ public void onKeyphraseDetectedFromExternalSource(HotwordDetectedResult result) {
+ Slog.i(TAG, "onKeyphraseDetectedFromExternalSource");
+ EventPayload.Builder eventPayloadBuilder = new EventPayload.Builder();
+ if (android.app.wearable.Flags.enableHotwordWearableSensingApi()) {
+ eventPayloadBuilder.setIsRecognitionStopped(false);
+ }
+ Message.obtain(
+ mHandler,
+ MSG_HOTWORD_DETECTED,
+ eventPayloadBuilder.setHotwordDetectedResult(result).build())
+ .sendToTarget();
+ }
+
+ @Override
public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
Slog.w(TAG, "Generic sound trigger event detected at AOHD: " + event);
}
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index ccf8b67..60e9de7 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -19,6 +19,7 @@
import static java.util.Objects.requireNonNull;
import android.annotation.DurationMillisLong;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -79,6 +80,16 @@
private static final long UPDATE_TIMEOUT_MILLIS = 20000;
/**
+ * The PersistableBundle options key used in {@link #onDetect(ParcelFileDescriptor, AudioFormat,
+ * PersistableBundle, Callback)} to indicate whether the system will close the audio stream
+ * after {@code Callback} is invoked.
+ */
+ @FlaggedApi(android.app.wearable.Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+ public static final String KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK =
+ "android.service.voice.HotwordDetectionService."
+ + "KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK";
+
+ /**
* Feature flag for Attention Service.
*
* @hide
@@ -364,6 +375,11 @@
* PersistableBundle)}.
* @param callback The callback to use for responding to the detection request.
*/
+ // TODO(b/324635656): Update Javadoc for 24Q3 release. Change the last paragraph to:
+ // <p>Upon invoking the {@code callback}, the system will send the detection result to
+ // the {@link HotwordDetector}'s callback. If {@code
+ // options.getBoolean(KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK, true)} returns true,
+ // the system will also close the {@code audioStream} after {@code callback} is invoked.
public void onDetect(
@NonNull ParcelFileDescriptor audioStream,
@NonNull AudioFormat audioFormat,
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index f1bc792..a835b0f 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -223,6 +223,13 @@
}
@Override
+ public void onKeyphraseDetectedFromExternalSource(HotwordDetectedResult result) {
+ if (DEBUG) {
+ Slog.i(TAG, "Ignored #onKeyphraseDetectedFromExternalSource event");
+ }
+ }
+
+ @Override
public void onGenericSoundTriggerDetected(
SoundTrigger.GenericRecognitionEvent recognitionEvent) throws RemoteException {
if (DEBUG) {
diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java
index 23847fe..1eb4d67 100644
--- a/core/java/android/service/voice/VisualQueryDetector.java
+++ b/core/java/android/service/voice/VisualQueryDetector.java
@@ -414,6 +414,13 @@
}
@Override
+ public void onKeyphraseDetectedFromExternalSource(HotwordDetectedResult result) {
+ if (DEBUG) {
+ Slog.i(TAG, "Ignored #onKeyphraseDetectedFromExternalSource event");
+ }
+ }
+
+ @Override
public void onGenericSoundTriggerDetected(
SoundTrigger.GenericRecognitionEvent recognitionEvent) throws RemoteException {
if (DEBUG) {
diff --git a/core/java/android/service/voice/VoiceInteractionManagerInternal.java b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
index 270f848..7d27733 100644
--- a/core/java/android/service/voice/VoiceInteractionManagerInternal.java
+++ b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
@@ -19,14 +19,17 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.media.AudioFormat;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import com.android.internal.annotations.Immutable;
/**
- * @hide
- * Private interface to the VoiceInteractionManagerService for use by ActivityManagerService.
+ * @hide Private interface to the VoiceInteractionManagerService for use within system_server.
*/
public abstract class VoiceInteractionManagerInternal {
@@ -77,6 +80,25 @@
public abstract void onPreCreatedUserConversion(@UserIdInt int userId);
/**
+ * Called by {@link com.android.server.wearable.WearableSensingManagerPerUserService} when a
+ * wearable starts sending audio data for hotword detection.
+ *
+ * @param audioStream The audio data.
+ * @param audioFormat The format of the audio data.
+ * @param options Options supporting hotword detection.
+ * @param targetVisComponentName The target VoiceInteractionService ComponentName
+ * @param userId The user ID of the calling wearable service
+ * @param callback The callback to notify the caller of the hotword detection result.
+ */
+ public abstract void startListeningFromWearable(
+ ParcelFileDescriptor audioStream,
+ AudioFormat audioFormat,
+ PersistableBundle options,
+ ComponentName targetVisComponentName,
+ int userId,
+ WearableHotwordDetectionCallback callback);
+
+ /**
* Provides the uids of the currently active
* {@link android.service.voice.HotwordDetectionService} and its owning package. The
* HotwordDetectionService is an isolated service, so it has a separate uid.
@@ -101,4 +123,20 @@
return mOwnerUid;
}
}
+
+ /**
+ * Callback for returning the detected hotword result to the wearable.
+ *
+ * @hide
+ */
+ public interface WearableHotwordDetectionCallback {
+ /** Called when hotword is detected. */
+ void onDetected();
+
+ /** Called when hotword is not detected. */
+ void onRejected();
+
+ /** Called when an unexpected error occurs. */
+ void onError(String errorMessage);
+ }
}
diff --git a/core/java/android/service/wearable/IWearableSensingService.aidl b/core/java/android/service/wearable/IWearableSensingService.aidl
index f67dcff..22d8fda 100644
--- a/core/java/android/service/wearable/IWearableSensingService.aidl
+++ b/core/java/android/service/wearable/IWearableSensingService.aidl
@@ -33,6 +33,10 @@
void provideData(in PersistableBundle data, in SharedMemory sharedMemory, in RemoteCallback callback);
void registerDataRequestObserver(int dataType, in RemoteCallback dataRequestCallback, int dataRequestObserverId, in String packageName, in RemoteCallback statusCallback);
void unregisterDataRequestObserver(int dataType, int dataRequestObserverId, in String packageName, in RemoteCallback statusCallback);
+ void startHotwordRecognition(in RemoteCallback wearableHotwordCallback, in RemoteCallback statusCallback);
+ void stopHotwordRecognition(in RemoteCallback statusCallback);
+ void onValidatedByHotwordDetectionService();
+ void stopActiveHotwordAudio();
void startDetection(in AmbientContextEventRequest request, in String packageName,
in RemoteCallback detectionResultCallback, in RemoteCallback statusCallback);
void stopDetection(in String packageName);
diff --git a/core/java/android/service/wearable/WearableSensingService.java b/core/java/android/service/wearable/WearableSensingService.java
index bb6e030..808c3ae 100644
--- a/core/java/android/service/wearable/WearableSensingService.java
+++ b/core/java/android/service/wearable/WearableSensingService.java
@@ -37,6 +37,7 @@
import android.os.SharedMemory;
import android.service.ambientcontext.AmbientContextDetectionResult;
import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
+import android.service.voice.HotwordAudioStream;
import android.util.Slog;
import android.util.SparseArray;
@@ -85,6 +86,14 @@
"android.app.wearable.WearableSensingStatusBundleKey";
/**
+ * The bundle key for hotword audio stream, used in {@code RemoteCallback#sendResult}.
+ *
+ * @hide
+ */
+ public static final String HOTWORD_AUDIO_STREAM_BUNDLE_KEY =
+ "android.app.wearable.HotwordAudioStreamBundleKey";
+
+ /**
* The {@link Intent} that must be declared as handled by the service. To be supported, the
* service must also require the
* {@link android.Manifest.permission#BIND_WEARABLE_SENSING_SERVICE}
@@ -181,6 +190,50 @@
dataType, packageName, dataRequester, statusConsumer);
}
+ @Override
+ public void startHotwordRecognition(
+ RemoteCallback wearableHotwordCallback, RemoteCallback statusCallback) {
+ Consumer<HotwordAudioStream> hotwordAudioConsumer =
+ (hotwordAudioStream) -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ HOTWORD_AUDIO_STREAM_BUNDLE_KEY, hotwordAudioStream);
+ wearableHotwordCallback.sendResult(bundle);
+ };
+ Consumer<Integer> statusConsumer =
+ response -> {
+ Bundle bundle = new Bundle();
+ bundle.putInt(STATUS_RESPONSE_BUNDLE_KEY, response);
+ statusCallback.sendResult(bundle);
+ };
+ WearableSensingService.this.onStartHotwordRecognition(
+ hotwordAudioConsumer, statusConsumer);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void stopHotwordRecognition(RemoteCallback statusCallback) {
+ Consumer<Integer> statusConsumer =
+ response -> {
+ Bundle bundle = new Bundle();
+ bundle.putInt(STATUS_RESPONSE_BUNDLE_KEY, response);
+ statusCallback.sendResult(bundle);
+ };
+ WearableSensingService.this.onStopHotwordRecognition(statusConsumer);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onValidatedByHotwordDetectionService() {
+ WearableSensingService.this.onValidatedByHotwordDetectionService();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void stopActiveHotwordAudio() {
+ WearableSensingService.this.onStopHotwordAudioStream();
+ }
+
/** {@inheritDoc} */
@Override
public void startDetection(
@@ -377,6 +430,100 @@
}
/**
+ * Called when the wearable is requested to start hotword recognition.
+ *
+ * <p>This method is expected to be overridden by a derived class. The implementation should
+ * store the {@code hotwordAudioConsumer} and send it the audio data when first-stage hotword is
+ * detected from the wearable. It should also send a {@link
+ * WearableSensingManager#STATUS_SUCCESS} status code to the {@code statusConsumer} unless it
+ * encounters an error condition described by a status code listed in {@link
+ * WearableSensingManager}, such as {@link WearableSensingManager#STATUS_WEARABLE_UNAVAILABLE},
+ * in which case it should return the corresponding status code.
+ *
+ * <p>The implementation should also store the {@code statusConsumer}. If the wearable stops
+ * listening for hotword for any reason other than {@link #onStopListeningForHotword(Consumer)}
+ * being invoked, it should send an appropriate status code listed in {@link
+ * WearableSensingManager} to {@code statusConsumer}. If the error condition cannot be described
+ * by any of those status codes, it should send a {@link WearableSensingManager#STATUS_UNKNOWN}.
+ *
+ * <p>If this method is called again, the implementation should use the new {@code
+ * hotwordAudioConsumer} and discard any previous ones it received.
+ *
+ * <p>At this time, the {@code timestamp} field in the {@link HotwordAudioStream} is not used
+ * and will be discarded by the system.
+ *
+ * @param hotwordAudioConsumer The consumer for the wearable hotword audio data.
+ * @param statusConsumer The consumer for the service status.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+ @BinderThread
+ public void onStartHotwordRecognition(
+ @NonNull Consumer<HotwordAudioStream> hotwordAudioConsumer,
+ @NonNull Consumer<Integer> statusConsumer) {
+ if (Flags.enableUnsupportedOperationStatusCode()) {
+ statusConsumer.accept(WearableSensingManager.STATUS_UNSUPPORTED_OPERATION);
+ }
+ }
+
+ /**
+ * Called when the wearable is requested to stop hotword recognition.
+ *
+ * <p>This method is expected to be overridden by a derived class. It should send a {@link
+ * WearableSensingManager#STATUS_SUCCESS} status code to the {@code statusConsumer} unless it
+ * encounters an error condition described by a status code listed in {@link
+ * WearableSensingManager}, such as {@link WearableSensingManager#STATUS_WEARABLE_UNAVAILABLE},
+ * in which case it should return the corresponding status code.
+ *
+ * @param statusConsumer The consumer for the service status.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+ @BinderThread
+ public void onStopHotwordRecognition(@NonNull Consumer<Integer> statusConsumer) {
+ if (Flags.enableUnsupportedOperationStatusCode()) {
+ statusConsumer.accept(WearableSensingManager.STATUS_UNSUPPORTED_OPERATION);
+ }
+ }
+
+ /**
+ * Called when hotword audio data sent to the {@code hotwordAudioConsumer} in {@link
+ * #onStartListeningForHotword(Consumer, Consumer)} is accepted by the
+ * {@link android.service.voice.HotwordDetectionService} as valid hotword.
+ *
+ * <p>After the implementation of this class sends the hotword audio data to the {@code
+ * hotwordAudioConsumer} in {@link #onStartListeningForHotword(Consumer,
+ * Consumer)}, the system will forward the data into {@link
+ * android.service.voice.HotwordDetectionService} (which runs in an isolated process) for
+ * second-stage hotword detection. If accepted as valid hotword there, this method will be
+ * called, and then the system will send the data to the currently active {@link
+ * android.service.voice.AlwaysOnHotwordDetector} (which may not run in an isolated process).
+ *
+ * <p>This method is expected to be overridden by a derived class. The implementation must
+ * request the wearable to turn on the microphone indicator to notify the user that audio data
+ * is being used outside of the isolated environment.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+ @BinderThread
+ public void onValidatedByHotwordDetectionService() {}
+
+ /**
+ * Called when the currently active hotword audio stream is no longer needed.
+ *
+ * <p>This method can be called as a result of hotword rejection by {@link
+ * android.service.voice.HotwordDetectionService}, or the {@link
+ * android.service.voice.AlwaysOnHotwordDetector} closing the data stream it received, or a
+ * non-recoverable error occurred before the data reaches the {@link
+ * android.service.voice.HotwordDetectionService} or the {@link
+ * android.service.voice.AlwaysOnHotwordDetector}.
+ *
+ * <p>This method is expected to be overridden by a derived class. The implementation should
+ * stop sending hotword audio data to the {@code hotwordAudioConsumer} in {@link
+ * #onStartListeningForHotword(Consumer, Consumer)}
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+ @BinderThread
+ public void onStopHotwordAudioStream() {}
+
+ /**
* Called when a client app requests starting detection of the events in the request. The
* implementation should keep track of whether the user has explicitly consented to detecting
* the events using on-going ambient sensor (e.g. microphone), and agreed to share the
@@ -460,4 +607,6 @@
statusCallback.sendResult(bundle);
};
}
+
+
}
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index d2c5975..0a73fd1 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -50,7 +50,7 @@
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
- "com.android.hoststubgen.nativesubstitution.EventLog_host")
+ "com.android.platform.test.ravenwood.nativesubstitution.EventLog_host")
public class EventLog {
/** @hide */ public EventLog() {}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 31576c5..b33214d 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -73,7 +73,7 @@
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
- "com.android.hoststubgen.nativesubstitution.Log_host")
+ "com.android.platform.test.ravenwood.nativesubstitution.Log_host")
public final class Log {
/** @hide */
@IntDef({ASSERT, ERROR, WARN, INFO, DEBUG, VERBOSE})
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index ffe0c71..9413f5c 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -19,10 +19,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
+import android.content.Context;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.HardwareBuffer;
-import android.os.IBinder;
+import android.os.Looper;
import android.window.InputTransferToken;
import android.window.SurfaceSyncGroup;
@@ -180,32 +181,25 @@
}
/**
- * Gets the token used for associating this {@link AttachedSurfaceControl} with
- * {@link SurfaceControlViewHost} instances.
- *
- * <p>This token should be passed to {@link SurfaceControlViewHost}'s constructor.
- * This token will be {@code null} if the window does not have an input channel.
- *
- * @return The SurfaceControlViewHost link token.
- */
- @Nullable
- @FlaggedApi(Flags.FLAG_GET_HOST_TOKEN_API)
- default IBinder getHostToken() {
- throw new UnsupportedOperationException("The getHostToken needs to be "
- + "implemented before making this call.");
- }
-
- /**
* Gets the token used for associating this {@link AttachedSurfaceControl} with an embedded
* {@link SurfaceControlViewHost} or {@link SurfaceControl}
*
- * @return The SurfaceControlViewHost link token. This can return {@code null} if the
- * {@link AttachedSurfaceControl} was created with no registered input
- * @hide
+ * <p>This token should be passed to
+ * {@link SurfaceControlViewHost#SurfaceControlViewHost(Context, Display, InputTransferToken)}
+ * or
+ * {@link WindowManager#registerBatchedSurfaceControlInputReceiver(int, InputTransferToken,
+ * SurfaceControl, Choreographer, SurfaceControlInputReceiver)} or
+ * {@link WindowManager#registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken,
+ * SurfaceControl, Looper, SurfaceControlInputReceiver)}
+ *
+ * @return The SurfaceControlViewHost link token.
+ * @throws IllegalStateException if the {@link AttachedSurfaceControl} was created with no
+ * registered input
*/
- @Nullable
+ @NonNull
+ @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
default InputTransferToken getInputTransferToken() {
- throw new UnsupportedOperationException("The getHostToken needs to be "
+ throw new UnsupportedOperationException("The getInputTransferToken needs to be "
+ "implemented before making this call.");
}
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 58765b4..1dd9cbb 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -33,6 +34,8 @@
import android.window.InputTransferToken;
import android.window.WindowTokenClient;
+import com.android.window.flags.Flags;
+
import dalvik.system.CloseGuard;
import java.util.Objects;
@@ -347,6 +350,25 @@
@Nullable IBinder hostToken) {
this(context, display, hostToken == null ? null : new InputTransferToken(hostToken),
"untracked");
+
+ }
+
+ /**
+ * Construct a new SurfaceControlViewHost. The root Surface will be
+ * allocated internally and is accessible via getSurfacePackage().
+ * <p>
+ * The hostInputTransferToken parameter allows the host and embedded to be associated with
+ * each other to allow transferring touch gesture and focus. This is also used for ANR
+ * reporting. It's accessible from {@link AttachedSurfaceControl#getInputTransferToken()}.
+ *
+ * @param context The Context object for your activity or application.
+ * @param display The Display the hierarchy will be placed on.
+ * @param hostInputTransferToken The host input transfer token, as discussed above.
+ */
+ @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+ public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
+ @Nullable InputTransferToken hostInputTransferToken) {
+ this(context, display, hostInputTransferToken, "untracked");
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 254c4ae..25ade62 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,6 +18,7 @@
import static android.content.res.Resources.ID_NULL;
import static android.os.Trace.TRACE_TAG_APP;
+import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
@@ -6995,7 +6996,7 @@
*
* @see #setCredentialManagerRequest
*/
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
public void clearCredentialManagerRequest() {
if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) {
Log.v(AUTOFILL_LOG_TAG, "clearCredentialManagerRequest called");
@@ -7027,7 +7028,7 @@
* @param callback to be invoked when either a response or an exception needs to be
* propagated for the given view
*/
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
public void setCredentialManagerRequest(@NonNull GetCredentialRequest request,
@NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {
Preconditions.checkNotNull(request, "request must not be null");
@@ -9944,7 +9945,7 @@
*
* @return The credential request associated with this View.
*/
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
@Nullable
public final GetCredentialRequest getCredentialManagerRequest() {
if (mViewCredentialHandler == null) {
@@ -9968,7 +9969,7 @@
* @return The callback associated with this view that will be invoked on a response from
* {@link CredentialManager} .
*/
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
@Nullable
public final OutcomeReceiver<GetCredentialResponse,
GetCredentialException> getCredentialManagerCallback() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 28a7334..657c8e6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -103,7 +103,6 @@
import android.animation.AnimationHandler;
import android.animation.LayoutTransition;
import android.annotation.AnyThread;
-import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
@@ -240,7 +239,6 @@
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.SurfaceCallbackHelper;
import com.android.modules.expresslog.Counter;
-import com.android.window.flags.Flags;
import java.io.IOException;
import java.io.OutputStream;
@@ -11220,25 +11218,15 @@
}
/**
- * @return Returns a token used for associating the root surface
- * to {@link SurfaceControlViewHost}.
- */
- @Nullable
- @Override
- @FlaggedApi(Flags.FLAG_GET_HOST_TOKEN_API)
- public IBinder getHostToken() {
- return getInputToken();
- }
-
- /**
* {@inheritDoc}
*/
- @Nullable
+ @NonNull
@Override
public InputTransferToken getInputTransferToken() {
IBinder inputToken = getInputToken();
if (inputToken == null) {
- return null;
+ throw new IllegalStateException(
+ "Called getInputTransferToken for Window with no input channel");
}
return new InputTransferToken(inputToken);
}
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index d86cc4a..131fca7 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
+
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -361,7 +363,7 @@
* {@link ViewStructure#setCredentialManagerRequest(GetCredentialRequest, OutcomeReceiver)}
*/
@Nullable
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
public GetCredentialRequest getCredentialManagerRequest() {
return null;
}
@@ -376,7 +378,7 @@
* {@link ViewStructure#setCredentialManagerRequest(GetCredentialRequest, OutcomeReceiver)}
*/
@Nullable
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
public OutcomeReceiver<
GetCredentialResponse, GetCredentialException> getCredentialManagerCallback() {
return null;
@@ -551,7 +553,7 @@
* @param request the request to be fired
* @param callback the callback where the response or exception, is returned
*/
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
public void setCredentialManagerRequest(@NonNull GetCredentialRequest request,
@NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {}
@@ -559,7 +561,7 @@
* Clears the credential request previously set through
* {@link ViewStructure#setCredentialManagerRequest(GetCredentialRequest, OutcomeReceiver)}
*/
- @FlaggedApi("autofill_credman_dev_integration")
+ @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
public void clearCredentialManagerRequest() {}
/**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 58fb273..0302a0d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -123,6 +123,7 @@
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.window.InputTransferToken;
import android.window.TaskFpsCallback;
import android.window.TrustedPresentationThresholds;
@@ -6097,25 +6098,28 @@
* receive batched input event. For those events that are batched, the invocation will happen
* once per {@link Choreographer} frame, and other input events will be delivered immediately.
* This is different from
- * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
- * SurfaceControlInputReceiver)} in that the input events are received batched. The caller must
- * invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up the
- * resources when no longer needing to use the {@link SurfaceControlInputReceiver}
+ * { #registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl,
+ * Looper, SurfaceControlInputReceiver)} in that the input events are received batched. The
+ * caller must invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up
+ * the resources when no longer needing to use the {@link SurfaceControlInputReceiver}
*
- * @param displayId The display that the SurfaceControl will be placed on. Input will
- * only work
- * if SurfaceControl is on that display and that display was touched.
- * @param surfaceControl The SurfaceControl to register the InputChannel for
- * @param hostToken The host token to link the InputChannel for. This is primarily for ANRs
- * to ensure the host receives the ANR if any issues with touch on the
- * InputChannel
- * @param choreographer The Choreographer used for batching. This should match the rendering
- * Choreographer.
- * @param receiver The SurfaceControlInputReceiver that will receive the input events
+ * @param displayId The display that the SurfaceControl will be placed on. Input
+ * will only work if SurfaceControl is on that display and that
+ * display was touched.
+ * @param surfaceControl The SurfaceControl to register the InputChannel for
+ * @param hostInputTransferToken The host token to link the embedded. This is used to handle
+ * transferring touch gesture from host to embedded and for ANRs
+ * to ensure the host receives the ANR if any issues with
+ * touch on the embedded.
+ * @param choreographer The Choreographer used for batching. This should match the
+ * rendering Choreographer.
+ * @param receiver The SurfaceControlInputReceiver that will receive the input
+ * events
*/
@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
default void registerBatchedSurfaceControlInputReceiver(int displayId,
- @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
+ @NonNull InputTransferToken hostInputTransferToken,
+ @NonNull SurfaceControl surfaceControl,
@NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
throw new UnsupportedOperationException(
"registerBatchedSurfaceControlInputReceiver is not implemented");
@@ -6123,26 +6127,30 @@
/**
* Registers a {@link SurfaceControlInputReceiver} for a {@link SurfaceControl} that will
- * receive every input event. This is different than calling @link
- * #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
- * SurfaceControlInputReceiver)} in that the input events are received unbatched. The caller
- * must invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up the
- * resources when no longer needing to use the {@link SurfaceControlInputReceiver}
+ * receive every input event. This is different than calling
+ * {@link #registerBatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl,
+ * Choreographer, SurfaceControlInputReceiver)} in that the input events are received
+ * unbatched.
+ * The caller must invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to
+ * clean up the resources when no longer needing to use the {@link SurfaceControlInputReceiver}
*
- * @param displayId The display that the SurfaceControl will be placed on. Input will only
- * work if SurfaceControl is on that display and that display was
- * touched.
- * @param hostToken The host token to link the InputChannel for. This is primarily for ANRs
- * to ensure the host receives the ANR if any issues with touch on the
- * InputChannel
- * @param surfaceControl The SurfaceControl to register the InputChannel for
- * @param looper The looper to use when invoking callbacks.
- * @param receiver The SurfaceControlInputReceiver that will receive the input events
- **/
+ * @param displayId The display that the SurfaceControl will be placed on. Input
+ * will only work if SurfaceControl is on that display and that
+ * display was touched.
+ * @param surfaceControl The SurfaceControl to register the InputChannel for
+ * @param hostInputTransferToken The host token to link the embedded. This is used to handle
+ * transferring touch gesture from host to embedded and for ANRs
+ * to ensure the host receives the ANR if any issues with
+ * touch on the embedded.
+ * @param looper The looper to use when invoking callbacks.
+ * @param receiver The SurfaceControlInputReceiver that will receive the input
+ * events.
+ */
@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
default void registerUnbatchedSurfaceControlInputReceiver(int displayId,
- @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
- @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
+ @NonNull InputTransferToken hostInputTransferToken,
+ @NonNull SurfaceControl surfaceControl, @NonNull Looper looper,
+ @NonNull SurfaceControlInputReceiver receiver) {
throw new UnsupportedOperationException(
"registerUnbatchedSurfaceControlInputReceiver is not implemented");
}
@@ -6152,10 +6160,10 @@
* specified token.
* <p>
* Must be called on the same {@link Looper} thread to which was passed to the
- * {@link #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl,
+ * {@link #registerBatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl,
* Choreographer,
* SurfaceControlInputReceiver)} or
- * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
+ * {@link #registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl, Looper,
* SurfaceControlInputReceiver)}
*
* @param surfaceControl The SurfaceControl to remove and unregister the input channel for.
@@ -6171,7 +6179,7 @@
* if the SurfaceControl was registered for input via
* { #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
* SurfaceControlInputReceiver)} or
- * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
+ * {@link #registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl, Looper,
* SurfaceControlInputReceiver)}.
* <p>
* This is helpful for testing to ensure the test waits for the layer to be registered with
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 2fb5213..1e3d062 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -535,19 +535,19 @@
@Override
public void registerBatchedSurfaceControlInputReceiver(int displayId,
- @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
- @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
- mGlobal.registerBatchedSurfaceControlInputReceiver(displayId,
- new InputTransferToken(hostToken),
+ @NonNull InputTransferToken hostInputTransferToken,
+ @NonNull SurfaceControl surfaceControl, @NonNull Choreographer choreographer,
+ @NonNull SurfaceControlInputReceiver receiver) {
+ mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostInputTransferToken,
surfaceControl, choreographer, receiver);
}
@Override
- public void registerUnbatchedSurfaceControlInputReceiver(
- int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
- @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
- mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId,
- new InputTransferToken(hostToken),
+ public void registerUnbatchedSurfaceControlInputReceiver(int displayId,
+ @NonNull InputTransferToken hostInputTransferToken,
+ @NonNull SurfaceControl surfaceControl, @NonNull Looper looper,
+ @NonNull SurfaceControlInputReceiver receiver) {
+ mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId, hostInputTransferToken,
surfaceControl, looper, receiver);
}
diff --git a/core/java/android/window/InputTransferToken.java b/core/java/android/window/InputTransferToken.java
index 0601b2a..bed0e0e 100644
--- a/core/java/android/window/InputTransferToken.java
+++ b/core/java/android/window/InputTransferToken.java
@@ -16,6 +16,7 @@
package android.window;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.os.Binder;
import android.os.IBinder;
@@ -23,13 +24,15 @@
import android.os.Parcelable;
import android.view.SurfaceControlViewHost;
+import com.android.window.flags.Flags;
+
import java.util.Objects;
/**
* A token that can be used to request focus on or to transfer touch gesture to a
* {@link SurfaceControlViewHost} or {@link android.view.SurfaceControl} that has an input channel.
- * @hide
*/
+@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
public final class InputTransferToken implements Parcelable {
/**
* @hide
diff --git a/core/java/android/window/TrustedPresentationThresholds.java b/core/java/android/window/TrustedPresentationThresholds.java
index 90f8834..a30c8fa 100644
--- a/core/java/android/window/TrustedPresentationThresholds.java
+++ b/core/java/android/window/TrustedPresentationThresholds.java
@@ -19,15 +19,15 @@
import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntRange;
-import android.annotation.SuppressLint;
import android.os.Parcel;
import android.os.Parcelable;
-import android.view.SurfaceControl;
import androidx.annotation.NonNull;
import com.android.window.flags.Flags;
+import java.util.Objects;
+
/**
* Threshold values that are sent with
* {@link android.view.WindowManager#registerTrustedPresentationListener(IBinder,
@@ -36,33 +36,53 @@
@FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public final class TrustedPresentationThresholds implements Parcelable {
/**
- * The min alpha the {@link SurfaceControl} is required to have to be considered inside the
+ * The min alpha the Window is required to have to be considered inside the
* threshold.
*/
@FloatRange(from = 0f, fromInclusive = false, to = 1f)
- @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
- @SuppressLint("InternalField") // simple data class
- public final float minAlpha;
+ private final float mMinAlpha;
/**
- * The min fraction of the SurfaceControl that was presented to the user to be considered
+ * The min fraction of the Window that was presented to the user to be considered
* inside the threshold.
*/
@FloatRange(from = 0f, fromInclusive = false, to = 1f)
- @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
- @SuppressLint("InternalField") // simple data class
- public final float minFractionRendered;
+ private final float mMinFractionRendered;
/**
- * The time in milliseconds required for the {@link SurfaceControl} to be in the threshold.
+ * The time in milliseconds required for the Window to be in the threshold.
*/
@IntRange(from = 1)
+ private final int mStabilityRequirementMs;
+
+ /**
+ * The min alpha the Window is required to have to be considered inside the
+ * threshold.
+ */
@FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
- @SuppressLint("InternalField") // simple data class
- public final int stabilityRequirementMs;
+ public @FloatRange(from = 0f, fromInclusive = false, to = 1f) float getMinAlpha() {
+ return mMinAlpha;
+ }
+
+ /**
+ * The min fraction of the Window that was presented to the user to be considered
+ * inside the threshold.
+ */
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+ public @FloatRange(from = 0f, fromInclusive = false, to = 1f) float getMinFractionRendered() {
+ return mMinFractionRendered;
+ }
+
+ /**
+ * The time in milliseconds required for the Window to be in the threshold.
+ */
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+ public @IntRange(from = 1) int getStabilityRequirementMillis() {
+ return mStabilityRequirementMs;
+ }
private void checkValid() {
- if (minAlpha <= 0 || minFractionRendered <= 0 || stabilityRequirementMs < 1) {
+ if (mMinAlpha <= 0 || mMinFractionRendered <= 0 || mStabilityRequirementMs < 1) {
throw new IllegalArgumentException(
"TrustedPresentationThresholds values are invalid");
}
@@ -71,23 +91,23 @@
/**
* Creates a new TrustedPresentationThresholds.
*
- * @param minAlpha The min alpha the {@link SurfaceControl} is required to
+ * @param minAlpha The min alpha the Window is required to
* have to be considered inside the
* threshold.
- * @param minFractionRendered The min fraction of the SurfaceControl that was presented
+ * @param minFractionRendered The min fraction of the Window that was presented
* to the user to be considered
* inside the threshold.
* @param stabilityRequirementMs The time in milliseconds required for the
- * {@link SurfaceControl} to be in the threshold.
+ * Window to be in the threshold.
*/
@FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public TrustedPresentationThresholds(
@FloatRange(from = 0f, fromInclusive = false, to = 1f) float minAlpha,
@FloatRange(from = 0f, fromInclusive = false, to = 1f) float minFractionRendered,
@IntRange(from = 1) int stabilityRequirementMs) {
- this.minAlpha = minAlpha;
- this.minFractionRendered = minFractionRendered;
- this.stabilityRequirementMs = stabilityRequirementMs;
+ this.mMinAlpha = minAlpha;
+ this.mMinFractionRendered = minFractionRendered;
+ this.mStabilityRequirementMs = stabilityRequirementMs;
checkValid();
}
@@ -95,18 +115,18 @@
@FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public String toString() {
return "TrustedPresentationThresholds { "
- + "minAlpha = " + minAlpha + ", "
- + "minFractionRendered = " + minFractionRendered + ", "
- + "stabilityRequirementMs = " + stabilityRequirementMs
+ + "minAlpha = " + mMinAlpha + ", "
+ + "minFractionRendered = " + mMinFractionRendered + ", "
+ + "stabilityRequirementMs = " + mStabilityRequirementMs
+ " }";
}
@Override
@FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeFloat(minAlpha);
- dest.writeFloat(minFractionRendered);
- dest.writeInt(stabilityRequirementMs);
+ dest.writeFloat(mMinAlpha);
+ dest.writeFloat(mMinFractionRendered);
+ dest.writeInt(mStabilityRequirementMs);
}
@Override
@@ -115,13 +135,34 @@
return 0;
}
+
+ @Override
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+ public int hashCode() {
+ return Objects.hash(mMinAlpha, mMinFractionRendered, mStabilityRequirementMs);
+ }
+
+ @Override
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof TrustedPresentationThresholds that)) {
+ return false;
+ }
+ return mMinAlpha == that.mMinAlpha
+ && mMinFractionRendered == that.mMinFractionRendered
+ && mStabilityRequirementMs == that.mStabilityRequirementMs;
+ }
+
/**
* @hide
*/
TrustedPresentationThresholds(@NonNull Parcel in) {
- minAlpha = in.readFloat();
- minFractionRendered = in.readFloat();
- stabilityRequirementMs = in.readInt();
+ mMinAlpha = in.readFloat();
+ mMinFractionRendered = in.readFloat();
+ mStabilityRequirementMs = in.readInt();
checkValid();
}
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 069affb..3ffa274 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -20,14 +20,6 @@
flag {
namespace: "window_surfaces"
- name: "get_host_token_api"
- description: "Feature flag to associate the host and embedded windows"
- is_fixed_read_only: true
- bug: "304508760"
-}
-
-flag {
- namespace: "window_surfaces"
name: "transfer_gesture_to_embedded"
description: "Enable public API for Window Surfaces"
bug: "287076178"
diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
index ba87caa..5cb5963 100644
--- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
+++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
@@ -40,6 +40,13 @@
in SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
in HotwordDetectedResult result);
+ /**
+ * Called when the keyphrase is detected from audio coming from an external source.
+ *
+ * @param result Successful detection result payload.
+ */
+ void onKeyphraseDetectedFromExternalSource(in HotwordDetectedResult result);
+
/**
* Called when a generic sound trigger event is witnessed.
*
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index ed943cb..eef6ce7 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -57,7 +57,7 @@
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
- "com.android.hoststubgen.nativesubstitution.LongArrayMultiStateCounter_host")
+ "com.android.platform.test.ravenwood.nativesubstitution.LongArrayMultiStateCounter_host")
public final class LongArrayMultiStateCounter implements Parcelable {
/**
@@ -65,7 +65,7 @@
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
- "com.android.hoststubgen.nativesubstitution"
+ "com.android.platform.test.ravenwood.nativesubstitution"
+ ".LongArrayMultiStateCounter_host$LongArrayContainer_host")
public static class LongArrayContainer {
private static NativeAllocationRegistry sRegistry;
diff --git a/core/java/com/android/internal/os/LongMultiStateCounter.java b/core/java/com/android/internal/os/LongMultiStateCounter.java
index 064609f..e5662c7 100644
--- a/core/java/com/android/internal/os/LongMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongMultiStateCounter.java
@@ -57,7 +57,7 @@
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
- "com.android.hoststubgen.nativesubstitution.LongMultiStateCounter_host")
+ "com.android.platform.test.ravenwood.nativesubstitution.LongMultiStateCounter_host")
public final class LongMultiStateCounter implements Parcelable {
private static NativeAllocationRegistry sRegistry;
diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp
index 6be553b..beffb9a 100644
--- a/core/tests/BroadcastRadioTests/Android.bp
+++ b/core/tests/BroadcastRadioTests/Android.bp
@@ -18,6 +18,7 @@
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
+ default_team: "trendy_team_aaos_framework",
default_applicable_licenses: ["frameworks_base_license"],
}
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 4982f37..244fe30 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -618,7 +618,7 @@
* @see #isMgf1DigestsSpecified()
*/
@NonNull
- @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+ @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
public @KeyProperties.DigestEnum Set<String> getMgf1Digests() {
if (mMgf1Digests.isEmpty()) {
throw new IllegalStateException("Mask generation function (MGF) not specified");
@@ -633,7 +633,7 @@
* @see #getMgf1Digests()
*/
@NonNull
- @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+ @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
public boolean isMgf1DigestsSpecified() {
return !mMgf1Digests.isEmpty();
}
@@ -1292,7 +1292,7 @@
* <p>See {@link KeyProperties}.{@code DIGEST} constants.
*/
@NonNull
- @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+ @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
public Builder setMgf1Digests(@NonNull @KeyProperties.DigestEnum String... mgf1Digests) {
mMgf1Digests = Set.of(mgf1Digests);
return this;
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 7b6b2d1..2495d1a 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -401,7 +401,7 @@
* @see #isMgf1DigestsSpecified()
*/
@NonNull
- @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+ @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
public @KeyProperties.DigestEnum Set<String> getMgf1Digests() {
if (mMgf1Digests.isEmpty()) {
throw new IllegalStateException("Mask generation function (MGF) not specified");
@@ -416,7 +416,7 @@
* @see #getMgf1Digests()
*/
@NonNull
- @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+ @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
public boolean isMgf1DigestsSpecified() {
return !mMgf1Digests.isEmpty();
}
@@ -799,7 +799,7 @@
* <p>See {@link KeyProperties}.{@code DIGEST} constants.
*/
@NonNull
- @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+ @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
public Builder setMgf1Digests(@Nullable @KeyProperties.DigestEnum String... mgf1Digests) {
mMgf1Digests = Set.of(mgf1Digests);
return this;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 83ddfc5..e6c652c 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -974,7 +974,7 @@
private static boolean getMgf1DigestSetterFlag() {
try {
- return Flags.mgf1DigestSetter();
+ return Flags.mgf1DigestSetterV2();
} catch (SecurityException e) {
Log.w(TAG, "Cannot read MGF1 Digest setter flag value", e);
return false;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 2d8c5a3..e6a63b9 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -259,7 +259,7 @@
private static boolean getMgf1DigestSetterFlag() {
try {
- return Flags.mgf1DigestSetter();
+ return Flags.mgf1DigestSetterV2();
} catch (SecurityException e) {
Log.w(NAME, "Cannot read MGF1 Digest setter flag value", e);
return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
index fd91ac0..e1e41ee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
@@ -58,7 +58,7 @@
return false
}
- return controller.moveToDesktopWithoutDecor(taskId, WindowContainerTransaction())
+ return controller.moveToDesktop(taskId, WindowContainerTransaction())
}
override fun printShellCommandHelp(pw: PrintWriter, prefix: String) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 42c8d74..837cb99 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -244,47 +244,14 @@
fun moveToDesktop(
taskId: Int,
wct: WindowContainerTransaction = WindowContainerTransaction()
- ) {
+ ): Boolean {
shellTaskOrganizer.getRunningTaskInfo(taskId)?.let {
task -> moveToDesktop(task, wct)
- }
- }
-
- /** Move a task with given `taskId` to desktop without decor */
- fun moveToDesktopWithoutDecor(
- taskId: Int,
- wct: WindowContainerTransaction
- ): Boolean {
- val task = shellTaskOrganizer.getRunningTaskInfo(taskId) ?: return false
- moveToDesktopWithoutDecor(task, wct)
+ } ?: return false
return true
}
/**
- * Move a task to desktop without decor
- */
- private fun moveToDesktopWithoutDecor(
- task: RunningTaskInfo,
- wct: WindowContainerTransaction
- ) {
- KtProtoLog.v(
- WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: moveToDesktopWithoutDecor taskId=%d",
- task.taskId
- )
- exitSplitIfApplicable(wct, task)
- // Bring other apps to front first
- bringDesktopAppsToFront(task.displayId, wct)
- addMoveToDesktopChanges(wct, task)
-
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
- } else {
- shellTaskOrganizer.applyTransaction(wct)
- }
- }
-
- /**
* Move a task to desktop
*/
fun moveToDesktop(
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 4ee25c4..ac94a6f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,6 +16,7 @@
package android.media;
+import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
@@ -2213,6 +2214,18 @@
*/
public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4;
+ /**
+ * Configure the codec with a detached output surface.
+ * <p>
+ * This flag is only defined for a video decoder. MediaCodec
+ * configured with this flag will be in Surface mode even though
+ * the surface parameter is null.
+ *
+ * @see detachOutputSurface
+ */
+ @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+ public static final int CONFIGURE_FLAG_DETACHED_SURFACE = 8;
+
/** @hide */
@IntDef(
flag = true,
@@ -2395,6 +2408,31 @@
private native void native_setSurface(@NonNull Surface surface);
/**
+ * Detach the current output surface of a codec.
+ * <p>
+ * Detaches the currently associated output Surface from the
+ * MediaCodec decoder. This allows the SurfaceView or other
+ * component holding the Surface to be safely destroyed or
+ * modified without affecting the decoder's operation. After
+ * calling this method (and after it returns), the decoder will
+ * enter detached-Surface mode and will no longer render
+ * output.
+ *
+ * @throws IllegalStateException if the codec was not
+ * configured in surface mode.
+ * @see CONFIGURE_FLAG_DETACHED_SURFACE
+ */
+ @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+ public void detachOutputSurface() {
+ if (!mHasSurface) {
+ throw new IllegalStateException("codec was not configured for an output surface");
+ }
+ // note: we still have a surface in detached mode, so keep mHasSurface
+ // we also technically allow calling detachOutputSurface multiple times in a row
+ // native_detachSurface();
+ }
+
+ /**
* Create a persistent input surface that can be used with codecs that normally have an input
* surface, such as video encoders. A persistent input can be reused by subsequent
* {@link MediaCodec} or {@link MediaRecorder} instances, but can only be used by at
@@ -3212,6 +3250,51 @@
}
}
+ /**
+ * Similar to {@link #queueInputBuffers queueInputBuffers} but submits multiple access units
+ * in a buffer that is potentially encrypted.
+ * <strong>Check out further notes at {@link #queueInputBuffers queueInputBuffers}.</strong>
+ *
+ * @param index The index of a client-owned input buffer previously returned
+ * in a call to {@link #dequeueInputBuffer}.
+ * @param bufferInfos ArrayDeque of {@link MediaCodec.BufferInfo} that describes the
+ * contents in the buffer. The ArrayDeque and the BufferInfo objects provided
+ * can be recycled by the caller for re-use.
+ * @param cryptoInfos ArrayDeque of {@link MediaCodec.CryptoInfo} objects to facilitate the
+ * decryption of the contents. The ArrayDeque and the CryptoInfo objects
+ * provided can be reused immediately after the call returns. These objects
+ * should correspond to bufferInfo objects to ensure correct decryption.
+ * @throws IllegalStateException if not in the Executing state or not in asynchronous mode.
+ * @throws MediaCodec.CodecException upon codec error.
+ * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
+ * access units are not contiguous.
+ * @throws CryptoException if an error occurs while attempting to decrypt the buffer.
+ * An error code associated with the exception helps identify the
+ * reason for the failure.
+ */
+ @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+ public final void queueSecureInputBuffers(
+ int index,
+ @NonNull ArrayDeque<BufferInfo> bufferInfos,
+ @NonNull ArrayDeque<CryptoInfo> cryptoInfos) {
+ synchronized(mBufferLock) {
+ if (mBufferMode == BUFFER_MODE_BLOCK) {
+ throw new IncompatibleWithBlockModelException("queueSecureInputBuffers() "
+ + "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ + "Please use getQueueRequest() to queue buffers");
+ }
+ invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
+ mDequeuedInputBuffers.remove(index);
+ }
+ try {
+ native_queueSecureInputBuffers(
+ index, bufferInfos.toArray(), cryptoInfos.toArray());
+ } catch (CryptoException | IllegalStateException | IllegalArgumentException e) {
+ revalidateByteBuffer(mCachedInputBuffers, index, true /* input */);
+ throw e;
+ }
+ }
+
private native final void native_queueSecureInputBuffer(
int index,
int offset,
@@ -3219,6 +3302,11 @@
long presentationTimeUs,
int flags) throws CryptoException;
+ private native final void native_queueSecureInputBuffers(
+ int index,
+ @NonNull Object[] bufferInfos,
+ @NonNull Object[] cryptoInfos) throws CryptoException, CodecException;
+
/**
* Returns the index of an input buffer to be filled with valid data
* or -1 if no such buffer is currently available.
@@ -3464,7 +3552,7 @@
mLinearBlock = block;
mOffset = offset;
mSize = size;
- mCryptoInfo = null;
+ mCryptoInfos.clear();
return this;
}
@@ -3498,7 +3586,44 @@
mLinearBlock = block;
mOffset = offset;
mSize = size;
- mCryptoInfo = cryptoInfo;
+ mCryptoInfos.clear();
+ mCryptoInfos.add(cryptoInfo);
+ return this;
+ }
+
+ /**
+ * Set an encrypted linear block to this queue request. Exactly one buffer must be
+ * set for a queue request before calling {@link #queue}. The block can contain multiple
+ * access units and if present should be laid out contiguously and without gaps.
+ *
+ * @param block The linear block object
+ * @param bufferInfos ArrayDeque of {@link MediaCodec.BufferInfo} that describes the
+ * contents in the buffer. The ArrayDeque and the BufferInfo objects
+ * provided can be recycled by the caller for re-use.
+ * @param cryptoInfos ArrayDeque of {@link MediaCodec.CryptoInfo} that describes the
+ * structure of the encrypted input samples. The ArrayDeque and the
+ * BufferInfo objects provided can be recycled by the caller for re-use.
+ * @return this object
+ * @throws IllegalStateException if a buffer is already set
+ * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
+ * access units are not contiguous.
+ */
+ @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+ public @NonNull QueueRequest setMultiFrameEncryptedLinearBlock(
+ @NonNull LinearBlock block,
+ @NonNull ArrayDeque<MediaCodec.BufferInfo> bufferInfos,
+ @NonNull ArrayDeque<MediaCodec.CryptoInfo> cryptoInfos) {
+ if (!isAccessible()) {
+ throw new IllegalStateException("The request is stale");
+ }
+ if (mLinearBlock != null || mHardwareBuffer != null) {
+ throw new IllegalStateException("Cannot set block twice");
+ }
+ mLinearBlock = block;
+ mBufferInfos.clear();
+ mBufferInfos.addAll(bufferInfos);
+ mCryptoInfos.clear();
+ mCryptoInfos.addAll(cryptoInfos);
return this;
}
@@ -3710,8 +3835,10 @@
mBufferInfos.add(info);
}
if (mLinearBlock != null) {
+
mCodec.native_queueLinearBlock(
- mIndex, mLinearBlock, mCryptoInfo,
+ mIndex, mLinearBlock,
+ mCryptoInfos.isEmpty() ? null : mCryptoInfos.toArray(),
mBufferInfos.toArray(),
mTuningKeys, mTuningValues);
} else if (mHardwareBuffer != null) {
@@ -3726,11 +3853,11 @@
mLinearBlock = null;
mOffset = 0;
mSize = 0;
- mCryptoInfo = null;
mHardwareBuffer = null;
mPresentationTimeUs = 0;
mFlags = 0;
mBufferInfos.clear();
+ mCryptoInfos.clear();
mTuningKeys.clear();
mTuningValues.clear();
return this;
@@ -3750,11 +3877,11 @@
private LinearBlock mLinearBlock = null;
private int mOffset = 0;
private int mSize = 0;
- private MediaCodec.CryptoInfo mCryptoInfo = null;
private HardwareBuffer mHardwareBuffer = null;
private long mPresentationTimeUs = 0;
private @BufferFlag int mFlags = 0;
private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
+ private final ArrayDeque<CryptoInfo> mCryptoInfos = new ArrayDeque<>();
private final ArrayList<String> mTuningKeys = new ArrayList<>();
private final ArrayList<Object> mTuningValues = new ArrayList<>();
@@ -3764,7 +3891,7 @@
private native void native_queueLinearBlock(
int index,
@NonNull LinearBlock block,
- @Nullable CryptoInfo cryptoInfo,
+ @Nullable Object[] cryptoInfos,
@NonNull Object[] bufferInfos,
@NonNull ArrayList<String> keys,
@NonNull ArrayList<Object> values);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 86f89ab..3174c37 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -20,6 +20,7 @@
import static android.media.Utils.sortDistinctRanges;
import static android.media.codec.Flags.FLAG_DYNAMIC_COLOR_ASPECTS;
import static android.media.codec.Flags.FLAG_HLG_EDITING;
+import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
import android.annotation.FlaggedApi;
@@ -778,6 +779,17 @@
public static final String FEATURE_Roi = "region-of-interest";
/**
+ * <b>video decoder only</b>: codec supports detaching the
+ * output surface when in Surface mode.
+ * <p> If true, the codec can be configured in Surface mode
+ * without an actual surface (in detached surface mode).
+ * @see MediaCodec#CONFIGURE_FLAG_DETACHED_SURFACE
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+ public static final String FEATURE_DetachedSurface = "detached-surface";
+
+ /**
* Query codec feature capabilities.
* <p>
* These features are supported to be used by the codec. These
@@ -814,6 +826,9 @@
if (android.media.codec.Flags.dynamicColorAspects()) {
features.add(new Feature(FEATURE_DynamicColorAspects, (1 << 8), true));
}
+ if (android.media.codec.Flags.nullOutputSurface()) {
+ features.add(new Feature(FEATURE_DetachedSurface, (1 << 9), true));
+ }
// feature to exclude codec from REGULAR codec list
features.add(new Feature(FEATURE_SpecialCodec, (1 << 30), false, true));
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 7fa3ed6..144b01a 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -1017,7 +1017,8 @@
updateRoutesOnHandler(currentRoutes);
RoutingSessionInfo oldInfo = mSystemController.getRoutingSessionInfo();
- mSystemController.setRoutingSessionInfo(currentSystemSessionInfo);
+ mSystemController.setRoutingSessionInfo(ensureClientPackageNameForSystemSession(
+ currentSystemSessionInfo, mContext.getPackageName()));
if (!oldInfo.equals(currentSystemSessionInfo)) {
notifyControllerUpdated(mSystemController);
}
@@ -1440,6 +1441,25 @@
}
}
+ /**
+ * Sets the routing session's {@linkplain RoutingSessionInfo#getClientPackageName() client
+ * package name} to {@code packageName} if empty and returns the session.
+ *
+ * <p>This method must only be used for {@linkplain RoutingSessionInfo#isSystemSession()
+ * system routing sessions}.
+ */
+ private static RoutingSessionInfo ensureClientPackageNameForSystemSession(
+ @NonNull RoutingSessionInfo sessionInfo, @NonNull String packageName) {
+ if (!sessionInfo.isSystemSession()
+ || !TextUtils.isEmpty(sessionInfo.getClientPackageName())) {
+ return sessionInfo;
+ }
+
+ return new RoutingSessionInfo.Builder(sessionInfo)
+ .setClientPackageName(packageName)
+ .build();
+ }
+
/** Callback for receiving events about media route discovery. */
public abstract static class RouteCallback {
/**
@@ -2891,25 +2911,6 @@
}
/**
- * Sets the routing session's {@linkplain RoutingSessionInfo#getClientPackageName() client
- * package name} to {@link #mClientPackageName} if empty and returns the session.
- *
- * <p>This method must only be used for {@linkplain RoutingSessionInfo#isSystemSession()
- * system routing sessions}.
- */
- private RoutingSessionInfo ensureClientPackageNameForSystemSession(
- RoutingSessionInfo sessionInfo) {
- if (!sessionInfo.isSystemSession()
- || !TextUtils.isEmpty(sessionInfo.getClientPackageName())) {
- return sessionInfo;
- }
-
- return new RoutingSessionInfo.Builder(sessionInfo)
- .setClientPackageName(mClientPackageName)
- .build();
- }
-
- /**
* Requests the release of a {@linkplain RoutingSessionInfo routing session}. Calls {@link
* #onSessionReleasedOnHandler(RoutingSessionInfo)} on success.
*
@@ -2997,7 +2998,7 @@
RoutingController oldController;
if (oldSession.isSystemSession()) {
mSystemController.setRoutingSessionInfo(
- ensureClientPackageNameForSystemSession(oldSession));
+ ensureClientPackageNameForSystemSession(oldSession, mClientPackageName));
oldController = mSystemController;
} else {
oldController = new RoutingController(oldSession);
@@ -3006,7 +3007,7 @@
RoutingController newController;
if (newSession.isSystemSession()) {
mSystemController.setRoutingSessionInfo(
- ensureClientPackageNameForSystemSession(newSession));
+ ensureClientPackageNameForSystemSession(newSession, mClientPackageName));
newController = mSystemController;
} else {
newController = new RoutingController(newSession);
@@ -3033,7 +3034,7 @@
RoutingController controller;
if (session.isSystemSession()) {
mSystemController.setRoutingSessionInfo(
- ensureClientPackageNameForSystemSession(session));
+ ensureClientPackageNameForSystemSession(session, mClientPackageName));
controller = mSystemController;
} else {
controller = new RoutingController(session);
@@ -3303,7 +3304,8 @@
public RoutingSessionInfo getSystemSessionInfo() {
RoutingSessionInfo currentSystemSessionInfo = null;
try {
- currentSystemSessionInfo = mMediaRouterService.getSystemSessionInfo();
+ currentSystemSessionInfo = ensureClientPackageNameForSystemSession(
+ mMediaRouterService.getSystemSessionInfo(), mContext.getPackageName());
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 8cdd59e..8396005 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -458,6 +458,24 @@
presentationTimeUs, flags, errorDetailMsg);
}
+status_t JMediaCodec::queueSecureInputBuffers(
+ size_t index,
+ size_t offset,
+ size_t size,
+ const sp<RefBase> &auInfos_,
+ const sp<RefBase> &cryptoInfos_,
+ AString *errorDetailMsg) {
+ sp<BufferInfosWrapper> auInfos((BufferInfosWrapper *)auInfos_.get());
+ sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
+ return mCodec->queueSecureInputBuffers(
+ index,
+ offset,
+ size,
+ auInfos,
+ cryptoInfos,
+ errorDetailMsg);
+}
+
status_t JMediaCodec::queueBuffer(
size_t index, const std::shared_ptr<C2Buffer> &buffer,
const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
@@ -470,19 +488,16 @@
size_t index,
const sp<hardware::HidlMemory> &buffer,
size_t offset,
- const CryptoPlugin::SubSample *subSamples,
- size_t numSubSamples,
- const uint8_t key[16],
- const uint8_t iv[16],
- CryptoPlugin::Mode mode,
- const CryptoPlugin::Pattern &pattern,
+ size_t size,
const sp<RefBase> &infos,
+ const sp<RefBase> &cryptoInfos_,
const sp<AMessage> &tunings,
AString *errorDetailMsg) {
sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
+ sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
return mCodec->queueEncryptedBuffer(
- index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
- auInfo, tunings, errorDetailMsg);
+ index, buffer, offset, size, auInfo, cryptoInfos,
+ tunings, errorDetailMsg);
}
status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
@@ -2262,6 +2277,61 @@
CryptoPlugin::Pattern mPattern;
};
+// This class takes away all dependencies on java(env and jni) and
+// could be used for taking cryptoInfo objects to MediaCodec.
+struct MediaCodecCryptoInfo: public CodecCryptoInfo {
+ explicit MediaCodecCryptoInfo(const NativeCryptoInfo &cryptoInfo) {
+ if (cryptoInfo.mErr == OK) {
+ mNumSubSamples = cryptoInfo.mNumSubSamples;
+ mMode = cryptoInfo.mMode;
+ mPattern = cryptoInfo.mPattern;
+ if (cryptoInfo.mKey != nullptr) {
+ mKeyBuffer = ABuffer::CreateAsCopy(cryptoInfo.mKey, 16);
+ mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
+ }
+ if (cryptoInfo.mIv != nullptr) {
+ mIvBuffer = ABuffer::CreateAsCopy(cryptoInfo.mIv, 16);
+ mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
+ }
+ if (cryptoInfo.mSubSamples != nullptr) {
+ mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
+ if (mSubSamplesBuffer.get()) {
+ CryptoPlugin::SubSample * samples =
+ (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
+ for (int s = 0 ; s < mNumSubSamples ; s++) {
+ samples[s].mNumBytesOfClearData =
+ cryptoInfo.mSubSamples[s].mNumBytesOfClearData;
+ samples[s].mNumBytesOfEncryptedData =
+ cryptoInfo.mSubSamples[s].mNumBytesOfEncryptedData;
+ }
+ mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
+ }
+ }
+
+ }
+ }
+
+ explicit MediaCodecCryptoInfo(jint size) {
+ mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * 1);
+ mNumSubSamples = 1;
+ if (mSubSamplesBuffer.get()) {
+ CryptoPlugin::SubSample * samples =
+ (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
+ samples[0].mNumBytesOfClearData = size;
+ samples[0].mNumBytesOfEncryptedData = 0;
+ mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
+ }
+ }
+ ~MediaCodecCryptoInfo() {}
+
+protected:
+ // all backup buffers for the base object.
+ sp<ABuffer> mKeyBuffer;
+ sp<ABuffer> mIvBuffer;
+ sp<ABuffer> mSubSamplesBuffer;
+
+};
+
static void android_media_MediaCodec_queueSecureInputBuffer(
JNIEnv *env,
jobject thiz,
@@ -2430,6 +2500,99 @@
codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
}
+static status_t extractCryptoInfosFromObjectArray(JNIEnv * const env,
+ jint * const totalSize,
+ std::vector<std::unique_ptr<CodecCryptoInfo>> * const cryptoInfoObjs,
+ const jobjectArray &objArray,
+ AString * const errorDetailMsg) {
+ if (env == nullptr
+ || cryptoInfoObjs == nullptr
+ || totalSize == nullptr) {
+ if (errorDetailMsg) {
+ *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
+ }
+ return BAD_VALUE;
+ }
+ const jsize numEntries = env->GetArrayLength(objArray);
+ if (numEntries <= 0) {
+ if (errorDetailMsg) {
+ *errorDetailMsg = "Error: No CryptoInfo found while queuing for large frame input";
+ }
+ return BAD_VALUE;
+ }
+ cryptoInfoObjs->clear();
+ *totalSize = 0;
+ jint size = 0;
+ for (jsize i = 0; i < numEntries ; i++) {
+ jobject param = env->GetObjectArrayElement(objArray, i);
+ if (param == NULL) {
+ if (errorDetailMsg) {
+ *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
+ }
+ return BAD_VALUE;
+ }
+ NativeCryptoInfo nativeInfo(env, param);
+ std::unique_ptr<CodecCryptoInfo> info(new MediaCodecCryptoInfo(nativeInfo));
+ for (int i = 0; i < info->mNumSubSamples; i++) {
+ size += info->mSubSamples[i].mNumBytesOfClearData;
+ size += info->mSubSamples[i].mNumBytesOfEncryptedData;
+ }
+ cryptoInfoObjs->push_back(std::move(info));
+ }
+ *totalSize = size;
+ return OK;
+}
+
+
+static void android_media_MediaCodec_queueSecureInputBuffers(
+ JNIEnv *env,
+ jobject thiz,
+ jint index,
+ jobjectArray bufferInfosObjs,
+ jobjectArray cryptoInfoObjs) {
+ ALOGV("android_media_MediaCodec_queueSecureInputBuffers");
+
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
+ return;
+ }
+ sp<BufferInfosWrapper> auInfos =
+ new BufferInfosWrapper{decltype(auInfos->value)()};
+ sp<CryptoInfosWrapper> cryptoInfos =
+ new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
+ AString errorDetailMsg;
+ jint initialOffset = 0;
+ jint totalSize = 0;
+ status_t err = extractInfosFromObject(
+ env,
+ &initialOffset,
+ &totalSize,
+ &auInfos->value,
+ bufferInfosObjs,
+ &errorDetailMsg);
+ if (err == OK) {
+ err = extractCryptoInfosFromObjectArray(env,
+ &totalSize,
+ &cryptoInfos->value,
+ cryptoInfoObjs,
+ &errorDetailMsg);
+ }
+ if (err == OK) {
+ err = codec->queueSecureInputBuffers(
+ index,
+ initialOffset,
+ totalSize,
+ auInfos,
+ cryptoInfos,
+ &errorDetailMsg);
+ }
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
+}
+
static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
ALOGV("android_media_MediaCodec_mapHardwareBuffer");
AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
@@ -2762,7 +2925,7 @@
static void android_media_MediaCodec_native_queueLinearBlock(
JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
- jobject cryptoInfoObj, jobjectArray objArray, jobject keys, jobject values) {
+ jobjectArray cryptoInfoArray, jobjectArray objArray, jobject keys, jobject values) {
ALOGV("android_media_MediaCodec_native_queueLinearBlock");
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -2780,8 +2943,8 @@
"error occurred while converting tunings from Java to native");
return;
}
- jint totalSize;
- jint initialOffset;
+ jint totalSize = 0;
+ jint initialOffset = 0;
std::vector<AccessUnitInfo> infoVec;
AString errorDetailMsg;
err = extractInfosFromObject(env,
@@ -2832,8 +2995,19 @@
"MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
return;
}
- auto cryptoInfo =
- cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{totalSize};
+ sp<CryptoInfosWrapper> cryptoInfos = new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
+ jint sampleSize = 0;
+ if (cryptoInfoArray != nullptr) {
+ extractCryptoInfosFromObjectArray(env,
+ &sampleSize,
+ &cryptoInfos->value,
+ cryptoInfoArray,
+ &errorDetailMsg);
+ } else {
+ sampleSize = totalSize;
+ std::unique_ptr<CodecCryptoInfo> cryptoInfo{new MediaCodecCryptoInfo(totalSize)};
+ cryptoInfos->value.push_back(std::move(cryptoInfo));
+ }
if (env->ExceptionCheck()) {
// Creation of cryptoInfo failed. Let the exception bubble up.
return;
@@ -2842,11 +3016,9 @@
index,
memory,
initialOffset,
- cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
- (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
- cryptoInfo.mMode,
- cryptoInfo.mPattern,
+ sampleSize,
infos,
+ cryptoInfos,
tunings,
&errorDetailMsg);
ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
@@ -3950,6 +4122,9 @@
{ "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
(void *)android_media_MediaCodec_queueSecureInputBuffer },
+ { "native_queueSecureInputBuffers", "(I[Ljava/lang/Object;[Ljava/lang/Object;)V",
+ (void *)android_media_MediaCodec_queueSecureInputBuffers },
+
{ "native_mapHardwareBuffer",
"(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
(void *)android_media_MediaCodec_mapHardwareBuffer },
@@ -3957,7 +4132,7 @@
{ "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
{ "native_queueLinearBlock",
- "(ILandroid/media/MediaCodec$LinearBlock;Landroid/media/MediaCodec$CryptoInfo;"
+ "(ILandroid/media/MediaCodec$LinearBlock;[Ljava/lang/Object;"
"[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
(void *)android_media_MediaCodec_native_queueLinearBlock },
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 02708ef..abb23f5 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -114,6 +114,14 @@
uint32_t flags,
AString *errorDetailMsg);
+ status_t queueSecureInputBuffers(
+ size_t index,
+ size_t offset,
+ size_t size,
+ const sp<RefBase> &auInfos,
+ const sp<RefBase> &cryptoInfos,
+ AString *errorDetailMsg);
+
status_t queueBuffer(
size_t index, const std::shared_ptr<C2Buffer> &buffer,
const sp<RefBase> &infos, const sp<AMessage> &tunings,
@@ -123,13 +131,9 @@
size_t index,
const sp<hardware::HidlMemory> &buffer,
size_t offset,
- const CryptoPlugin::SubSample *subSamples,
- size_t numSubSamples,
- const uint8_t key[16],
- const uint8_t iv[16],
- CryptoPlugin::Mode mode,
- const CryptoPlugin::Pattern &pattern,
+ size_t size,
const sp<RefBase> &infos,
+ const sp<RefBase> &cryptoInfos,
const sp<AMessage> &tunings,
AString *errorDetailMsg);
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 64e8efe..6efb028 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -314,6 +314,23 @@
return event;
}
+jobject AInputEvent_toJava(JNIEnv* env, const AInputEvent* aInputEvent) {
+ LOG_ALWAYS_FATAL_IF(aInputEvent == nullptr, "Expected aInputEvent to be non-null");
+ const int32_t eventType = AInputEvent_getType(aInputEvent);
+ switch (eventType) {
+ case AINPUT_EVENT_TYPE_MOTION:
+ return android::android_view_MotionEvent_obtainAsCopy(env,
+ static_cast<const MotionEvent&>(
+ *aInputEvent));
+ case AINPUT_EVENT_TYPE_KEY:
+ return android::android_view_KeyEvent_fromNative(env,
+ static_cast<const KeyEvent&>(
+ *aInputEvent));
+ default:
+ LOG_ALWAYS_FATAL("Unexpected event type %d in AInputEvent_toJava.", eventType);
+ }
+}
+
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
int ident, ALooper_callbackFunc callback, void* data) {
InputQueue* iq = static_cast<InputQueue*>(queue);
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 9605108..3302265 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -90,6 +90,7 @@
AInputEvent_getSource;
AInputEvent_getType;
AInputEvent_release; # introduced=31
+ AInputEvent_toJava; # introduced=35
AInputQueue_attachLooper;
AInputQueue_detachLooper;
AInputQueue_finishEvent;
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
index f9dd04b..0728daf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
@@ -40,7 +40,6 @@
): Modifier {
val translationX by viewModel.translationX(params).collectAsState(initial = 0f)
val translationY by viewModel.translationY(params).collectAsState(initial = 0f)
- val alpha by viewModel.alpha.collectAsState(initial = 1f)
val scaleViewModel by viewModel.scale(params).collectAsState(initial = BurnInScaleViewModel())
return this.graphicsLayer {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 0b320a2..ef2b6f0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -27,7 +27,10 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -56,11 +59,10 @@
private val testScope = kosmos.testScope
private val repository by lazy { kosmos.fakeKeyguardRepository }
private val sceneInteractor by lazy { kosmos.sceneInteractor }
- private val commandQueue by lazy {
- FakeCommandQueue()
- }
+ private val commandQueue by lazy { FakeCommandQueue() }
private val bouncerRepository = FakeKeyguardBouncerRepository()
private val shadeRepository = FakeShadeRepository()
+ private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
private val transitionState: MutableStateFlow<ObservableTransitionState> =
MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Gone))
@@ -73,6 +75,7 @@
bouncerRepository = bouncerRepository,
configurationInteractor = ConfigurationInteractor(FakeConfigurationRepository()),
shadeRepository = shadeRepository,
+ keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor,
sceneInteractorProvider = { sceneInteractor },
)
}
@@ -188,6 +191,49 @@
}
@Test
+ fun dismissAlpha() =
+ testScope.runTest {
+ val dismissAlpha by collectLastValue(underTest.dismissAlpha)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ testScope,
+ )
+
+ repository.setStatusBarState(StatusBarState.KEYGUARD)
+ shadeRepository.setLegacyShadeExpansion(1f)
+
+ // When not dismissable, no alpha value (null) should emit
+ repository.setKeyguardDismissible(false)
+ assertThat(dismissAlpha).isNull()
+
+ repository.setKeyguardDismissible(true)
+ assertThat(dismissAlpha).isGreaterThan(0.95f)
+ }
+
+ @Test
+ fun dismissAlpha_whenShadeIsExpandedEmitsNull() =
+ testScope.runTest {
+ val dismissAlpha by collectLastValue(underTest.dismissAlpha)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ testScope,
+ )
+
+ repository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+ shadeRepository.setQsExpansion(1f)
+
+ repository.setKeyguardDismissible(false)
+ assertThat(dismissAlpha).isNull()
+
+ repository.setKeyguardDismissible(true)
+ assertThat(dismissAlpha).isNull()
+ }
+
+ @Test
fun animationDozingTransitions() =
testScope.runTest {
kosmos.fakeSceneContainerFlags.enabled = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt
index 83782e2..837a9db 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt
@@ -25,6 +25,8 @@
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
@@ -42,49 +44,69 @@
@RunWith(AndroidJUnit4::class)
class AodAlphaViewModelTest : SysuiTestCase() {
- @Mock
- private lateinit var occludedToLockscreenTransitionViewModel:
- OccludedToLockscreenTransitionViewModel
+ @Mock private lateinit var goneToAodTransitionViewModel: GoneToAodTransitionViewModel
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val keyguardRepository = kosmos.fakeKeyguardRepository
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
- private val occludedToLockscreenAlpha = MutableStateFlow(0f)
private lateinit var underTest: AodAlphaViewModel
+ private val enterFromTopAnimationAlpha = MutableStateFlow(0f)
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(occludedToLockscreenTransitionViewModel.lockscreenAlpha)
- .thenReturn(occludedToLockscreenAlpha)
- kosmos.occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel
+ whenever(goneToAodTransitionViewModel.enterFromTopAnimationAlpha)
+ .thenReturn(enterFromTopAnimationAlpha)
+ kosmos.goneToAodTransitionViewModel = goneToAodTransitionViewModel
underTest = kosmos.aodAlphaViewModel
}
@Test
- fun alpha() =
+ fun alpha_WhenGoneToAod() =
testScope.runTest {
val alpha by collectLastValue(underTest.alpha)
keyguardTransitionRepository.sendTransitionSteps(
- from = KeyguardState.OFF,
- to = KeyguardState.LOCKSCREEN,
+ from = KeyguardState.AOD,
+ to = KeyguardState.GONE,
testScope = testScope,
)
-
- keyguardRepository.setKeyguardAlpha(0.1f)
- assertThat(alpha).isEqualTo(0.1f)
- keyguardRepository.setKeyguardAlpha(0.5f)
- assertThat(alpha).isEqualTo(0.5f)
- keyguardRepository.setKeyguardAlpha(0.2f)
- assertThat(alpha).isEqualTo(0.2f)
- keyguardRepository.setKeyguardAlpha(0f)
assertThat(alpha).isEqualTo(0f)
- occludedToLockscreenAlpha.value = 0.8f
- assertThat(alpha).isEqualTo(0.8f)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ testScope = testScope,
+ )
+ enterFromTopAnimationAlpha.value = 0.5f
+ assertThat(alpha).isEqualTo(0.5f)
+
+ enterFromTopAnimationAlpha.value = 1f
+ assertThat(alpha).isEqualTo(1f)
+ }
+
+ @Test
+ fun alpha_WhenGoneToDozing() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.alpha)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.AOD,
+ to = KeyguardState.GONE,
+ testScope = testScope,
+ )
+ assertThat(alpha).isEqualTo(0f)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.GONE,
+ to = KeyguardState.DOZING,
+ testScope = testScope,
+ )
+ assertThat(alpha).isEqualTo(1f)
}
@Test
@@ -92,17 +114,53 @@
testScope.runTest {
val alpha by collectLastValue(underTest.alpha)
- keyguardTransitionRepository.sendTransitionSteps(
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.GONE,
- testScope = testScope,
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ assertThat(alpha).isNull()
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.5f,
+ )
+ )
+ assertThat(alpha).isNull()
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 1f,
+ )
+ )
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ fun enterFromTopAlpha() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.alpha)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ transitionState = TransitionState.STARTED,
+ )
)
- keyguardRepository.setKeyguardAlpha(0.1f)
- assertThat(alpha).isEqualTo(0f)
- keyguardRepository.setKeyguardAlpha(0.5f)
- assertThat(alpha).isEqualTo(0f)
- keyguardRepository.setKeyguardAlpha(1f)
- assertThat(alpha).isEqualTo(0f)
+ enterFromTopAnimationAlpha.value = 0.2f
+ assertThat(alpha).isEqualTo(0.2f)
+
+ enterFromTopAnimationAlpha.value = 1f
+ assertThat(alpha).isEqualTo(1f)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
index d52696a..74fa465 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
@@ -65,7 +65,6 @@
clockControllerProvider = { clockController },
)
private val burnInFlow = MutableStateFlow(BurnInModel())
- private val enterFromTopAnimationAlpha = MutableStateFlow(0f)
@Before
fun setUp() {
@@ -74,8 +73,6 @@
MockitoAnnotations.initMocks(this)
whenever(burnInInteractor.keyguardBurnIn).thenReturn(burnInFlow)
kosmos.burnInInteractor = burnInInteractor
- whenever(goneToAodTransitionViewModel.enterFromTopAnimationAlpha)
- .thenReturn(enterFromTopAnimationAlpha)
whenever(goneToAodTransitionViewModel.enterFromTopTranslationY(anyInt()))
.thenReturn(emptyFlow())
kosmos.goneToAodTransitionViewModel = goneToAodTransitionViewModel
@@ -278,16 +275,4 @@
assertThat(translationY).isEqualTo(0)
assertThat(scale).isEqualTo(BurnInScaleViewModel(scale = 0.5f, scaleClockOnly = false))
}
-
- @Test
- fun alpha() =
- testScope.runTest {
- val alpha by collectLastValue(underTest.alpha)
-
- enterFromTopAnimationAlpha.value = 0.2f
- assertThat(alpha).isEqualTo(0.2f)
-
- enterFromTopAnimationAlpha.value = 1f
- assertThat(alpha).isEqualTo(1f)
- }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index bf1d76f..e04cbfd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -255,14 +255,21 @@
testScope.runTest {
val alpha by collectLastValue(underTest.alpha(viewState))
+ // Default value check
+ assertThat(alpha).isEqualTo(1f)
+
// Hub transition state is idle with hub open.
communalRepository.setTransitionState(
flowOf(ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal))
)
runCurrent()
- // Set keyguard alpha to 1.0f.
- keyguardInteractor.setAlpha(1.0f)
+ // Run at least 1 transition to make sure value remains at 0
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ testScope,
+ )
// Alpha property remains 0 regardless.
assertThat(alpha).isEqualTo(0f)
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 91e6b62..ee260e1 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -421,9 +421,11 @@
smallTimeListener?.update(shouldTimeListenerRun)
largeTimeListener?.update(shouldTimeListenerRun)
- // Query ZenMode data
- zenModeCallback.onZenChanged(zenModeController.zen)
- zenModeCallback.onNextAlarmChanged()
+ bgExecutor.execute {
+ // Query ZenMode data
+ zenModeCallback.onZenChanged(zenModeController.zen)
+ zenModeCallback.onNextAlarmChanged()
+ }
}
fun unregisterListeners() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b5ca79e7..63fd608 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -690,18 +690,17 @@
} else {
resetStateLocked();
}
- } else {
- if (lastSimStateWasLocked && mShowing) {
- if (DEBUG_SIM_STATES) {
- Log.d(TAG, "SIM moved to "
- + "NOT_READY/ABSENT/UNKNOWN when the previous state "
- + "was locked. Reset the state.");
- }
+ }
+ if (simState == TelephonyManager.SIM_STATE_ABSENT) {
+ // MVNO SIMs can become transiently NOT_READY when switching networks,
+ // so we should only lock when they are ABSENT.
+ if (lastSimStateWasLocked) {
+ if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
+ + "previous state was locked. Reset the state.");
resetStateLocked();
}
+ mSimWasLocked.append(slotId, false);
}
-
- mSimWasLocked.append(slotId, false);
}
break;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index e20f570..7593ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -150,6 +150,7 @@
when (toState) {
KeyguardState.DREAMING -> TO_DREAMING_DURATION
KeyguardState.AOD -> TO_AOD_DURATION
+ KeyguardState.DOZING -> TO_DOZING_DURATION
KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
else -> DEFAULT_DURATION
}.inWholeMilliseconds
@@ -160,6 +161,7 @@
private val DEFAULT_DURATION = 500.milliseconds
val TO_DREAMING_DURATION = 933.milliseconds
val TO_AOD_DURATION = 1300.milliseconds
+ val TO_DOZING_DURATION = 933.milliseconds
val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 1da0a0e..57e9ac7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
+import android.util.MathUtils
import com.android.app.animation.Interpolators
import com.android.systemui.communal.shared.model.CommunalSceneKey
import com.android.systemui.dagger.SysUISingleton
@@ -208,7 +209,10 @@
}
transitionRepository.updateTransition(
id,
- 1f - shadeExpansion,
+ // This maps the shadeExpansion to a much faster curve, to match
+ // the existing logic
+ 1f -
+ MathUtils.constrainedMap(0f, 1f, 0.95f, 1f, shadeExpansion),
nextState,
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 22d11d0..405d1d4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -37,6 +37,7 @@
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.res.R
@@ -79,6 +80,7 @@
bouncerRepository: KeyguardBouncerRepository,
configurationInteractor: ConfigurationInteractor,
shadeRepository: ShadeRepository,
+ keyguardTransitionInteractor: KeyguardTransitionInteractor,
sceneInteractorProvider: Provider<SceneInteractor>,
) {
// TODO(b/296118689): move to a repository
@@ -233,8 +235,33 @@
/** The position of the keyguard clock. */
val clockPosition: Flow<Position> = repository.clockPosition
+ @Deprecated("Use the relevant TransitionViewModel")
val keyguardAlpha: Flow<Float> = repository.keyguardAlpha
+ /**
+ * When the lockscreen can be dismissed, emit an alpha value as the user swipes up. This is
+ * useful just before the code commits to moving to GONE.
+ */
+ val dismissAlpha: Flow<Float?> =
+ combine(
+ shadeRepository.legacyShadeExpansion,
+ statusBarState,
+ keyguardTransitionInteractor.currentKeyguardState,
+ isKeyguardDismissible,
+ ) { legacyShadeExpansion, statusBarState, currentKeyguardState, isKeyguardDismissible ->
+ if (
+ statusBarState == StatusBarState.KEYGUARD &&
+ isKeyguardDismissible &&
+ currentKeyguardState == LOCKSCREEN
+ ) {
+ MathUtils.constrainedMap(0f, 1f, 0.95f, 1f, legacyShadeExpansion)
+ } else {
+ null
+ }
+ }
+ .onStart { emit(null) }
+ .distinctUntilChanged()
+
val keyguardTranslationY: Flow<Float> =
configurationInteractor
.dimensionPixelSize(R.dimen.keyguard_translate_distance_on_swipe_up)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 310f13d..d1fd719 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -56,7 +56,6 @@
constructor(
@Application val scope: CoroutineScope,
private val repository: KeyguardTransitionRepository,
- private val keyguardInteractor: dagger.Lazy<KeyguardInteractor>,
private val fromLockscreenTransitionInteractor: dagger.Lazy<FromLockscreenTransitionInteractor>,
private val fromPrimaryBouncerTransitionInteractor:
dagger.Lazy<FromPrimaryBouncerTransitionInteractor>,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 1b7a507..5604ef2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -179,7 +179,7 @@
}
launch {
- viewModel.lockscreenStateAlpha.collect { alpha ->
+ viewModel.lockscreenStateAlpha(viewState).collect { alpha ->
childViews[statusViewId]?.alpha = alpha
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
index d4ea728..f208e85 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
@@ -19,15 +19,15 @@
package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
/** Models UI state for the alpha of the AOD (always-on display). */
@@ -35,27 +35,28 @@
class AodAlphaViewModel
@Inject
constructor(
- keyguardInteractor: KeyguardInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
- occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
+ goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
+ goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
) {
/** The alpha level for the entire lockscreen while in AOD. */
val alpha: Flow<Float> =
- combine(
- keyguardTransitionInteractor.transitionValue(KeyguardState.GONE).onStart {
- emit(0f)
- },
- merge(
- keyguardInteractor.keyguardAlpha,
- occludedToLockscreenTransitionViewModel.lockscreenAlpha,
- )
- ) { transitionToGone, alpha ->
- if (transitionToGone == 1f) {
- // Ensures content is not visible when in GONE state
- 0f
- } else {
- alpha
+ combineTransform(
+ keyguardTransitionInteractor.transitions,
+ goneToAodTransitionViewModel.enterFromTopAnimationAlpha.onStart { emit(0f) },
+ goneToDozingTransitionViewModel.lockscreenAlpha.onStart { emit(0f) },
+ ) { step, goneToAodAlpha, goneToDozingAlpha ->
+ if (step.to == GONE) {
+ // When transitioning to GONE, only emit a value when complete as other
+ // transitions may be controlling the alpha fade
+ if (step.value == 1f) {
+ emit(0f)
+ }
+ } else if (step.from == GONE && step.to == AOD) {
+ emit(goneToAodAlpha)
+ } else if (step.from == GONE && step.to == DOZING) {
+ emit(goneToDozingAlpha)
}
}
.distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index 8110de2..6fcbf48 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -31,6 +31,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
@@ -66,9 +67,6 @@
private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
private val keyguardClockViewModel: KeyguardClockViewModel,
) {
- /** Alpha for elements that appear and move during the animation -> AOD */
- val alpha: Flow<Float> = goneToAodTransitionViewModel.enterFromTopAnimationAlpha
-
/** Horizontal translation for elements that need to apply anti-burn-in tactics. */
fun translationX(
params: BurnInParameters,
@@ -131,6 +129,9 @@
return combine(
merge(
keyguardTransitionInteractor.transition(GONE, AOD).map { it.value },
+ keyguardTransitionInteractor.transition(AOD, PRIMARY_BOUNCER).map {
+ 1f - it.value
+ },
keyguardTransitionInteractor.transition(ALTERNATE_BOUNCER, AOD).map {
it.value
},
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
index 3a98359..a3888c3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
@@ -57,21 +57,32 @@
var startValue = 0f
return transitionAnimation.sharedFlowWithState(
duration = 500.milliseconds,
- onStart = {
- startValue = currentTranslationY() ?: 0f
- startValue
- },
+ onStart = { startValue = currentTranslationY() ?: 0f },
onStep = { MathUtils.lerp(startValue, 0f, FAST_OUT_SLOW_IN.getInterpolation(it)) },
)
}
/** Ensure alpha is set to be visible */
- val lockscreenAlpha: Flow<Float> =
- transitionAnimation.sharedFlow(
+ fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
+ var startAlpha: Float? = null
+ return transitionAnimation.sharedFlow(
duration = 500.milliseconds,
- onStart = { 1f },
- onStep = { 1f },
+ onStep = {
+ if (startAlpha == null) {
+ startAlpha = viewState.alpha()
+ }
+ MathUtils.lerp(startAlpha!!, 1f, it)
+ },
+ onFinish = {
+ startAlpha = null
+ 1f
+ },
+ onCancel = {
+ startAlpha = null
+ 1f
+ },
)
+ }
val shortcutsAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
@@ -88,5 +99,10 @@
onFinish = { 1f },
)
- override val deviceEntryParentViewAlpha: Flow<Float> = lockscreenAlpha
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ transitionAnimation.sharedFlow(
+ duration = 500.milliseconds,
+ onStart = { 1f },
+ onStep = { 1f },
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
index e4610c1..f81941b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
@@ -50,6 +50,8 @@
onCancel = { 0f },
)
+ val lockscreenAlpha: Flow<Float> = shortcutsAlpha
+
override val deviceEntryParentViewAlpha: Flow<Float> =
transitionAnimation.immediatelyTransitionTo(1f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
new file mode 100644
index 0000000..55a289e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DOZING_DURATION
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/** Breaks down GONE->DOZING transition into discrete steps for corresponding views to consume. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class GoneToDozingTransitionViewModel
+@Inject
+constructor(
+ animationFlow: KeyguardTransitionAnimationFlow,
+) {
+
+ private val transitionAnimation =
+ animationFlow.setup(
+ duration = TO_DOZING_DURATION,
+ from = KeyguardState.GONE,
+ to = KeyguardState.DOZING,
+ )
+
+ val lockscreenAlpha: Flow<Float> =
+ transitionAnimation.sharedFlow(
+ duration = 500.milliseconds,
+ onStep = { 0f },
+ onCancel = { 1f },
+ onFinish = { 1f },
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 83be651..f790d35 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -48,6 +48,7 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
@@ -63,15 +64,25 @@
private val communalInteractor: CommunalInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
- private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
- private val lockscreenToGoneTransitionViewModel: LockscreenToGoneTransitionViewModel,
private val alternateBouncerToGoneTransitionViewModel:
AlternateBouncerToGoneTransitionViewModel,
- private val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
- private val lockscreenToGlanceableHubTransitionViewModel:
- LockscreenToGlanceableHubTransitionViewModel,
+ private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
+ private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
private val glanceableHubToLockscreenTransitionViewModel:
GlanceableHubToLockscreenTransitionViewModel,
+ private val lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel,
+ private val lockscreenToGlanceableHubTransitionViewModel:
+ LockscreenToGlanceableHubTransitionViewModel,
+ private val lockscreenToGoneTransitionViewModel: LockscreenToGoneTransitionViewModel,
+ private val lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel,
+ private val lockscreenToPrimaryBouncerTransitionViewModel:
+ LockscreenToPrimaryBouncerTransitionViewModel,
+ private val occludedToAodTransitionViewModel: OccludedToAodTransitionViewModel,
+ private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
+ private val primaryBouncerToAodTransitionViewModel: PrimaryBouncerToAodTransitionViewModel,
+ private val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
+ private val primaryBouncerToLockscreenTransitionViewModel:
+ PrimaryBouncerToLockscreenTransitionViewModel,
private val screenOffAnimationController: ScreenOffAnimationController,
private val aodBurnInViewModel: AodBurnInViewModel,
private val aodAlphaViewModel: AodAlphaViewModel,
@@ -110,13 +121,24 @@
// The transitions are mutually exclusive, so they are safe to merge to get the last
// value emitted by any of them. Do not add flows that cannot make this guarantee.
merge(
- aodAlphaViewModel.alpha,
- lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
- glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
- lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState),
- primaryBouncerToGoneTransitionViewModel.lockscreenAlpha,
- alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
- )
+ aodAlphaViewModel.alpha,
+ keyguardInteractor.dismissAlpha.filterNotNull(),
+ alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
+ aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
+ dozingToLockscreenTransitionViewModel.lockscreenAlpha,
+ glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
+ lockscreenToDreamingTransitionViewModel.lockscreenAlpha,
+ lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
+ lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState),
+ lockscreenToOccludedTransitionViewModel.lockscreenAlpha,
+ lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha,
+ occludedToAodTransitionViewModel.lockscreenAlpha,
+ occludedToLockscreenTransitionViewModel.lockscreenAlpha,
+ primaryBouncerToAodTransitionViewModel.lockscreenAlpha,
+ primaryBouncerToGoneTransitionViewModel.lockscreenAlpha,
+ primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha,
+ )
+ .onStart { emit(1f) }
) { isIdleOnCommunal, alpha ->
if (isIdleOnCommunal) {
// Keyguard should not show while the communal hub is fully visible. This check
@@ -131,10 +153,13 @@
}
/** Specific alpha value for elements visible during [KeyguardState.LOCKSCREEN] */
- val lockscreenStateAlpha: Flow<Float> = aodToLockscreenTransitionViewModel.lockscreenAlpha
+ @Deprecated("only used for legacy status view")
+ fun lockscreenStateAlpha(viewState: ViewStateAccessor): Flow<Float> {
+ return aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState)
+ }
/** For elements that appear and move during the animation -> AOD */
- val burnInLayerAlpha: Flow<Float> = aodBurnInViewModel.alpha
+ val burnInLayerAlpha: Flow<Float> = aodAlphaViewModel.alpha
fun translationY(params: BurnInParameters): Flow<Float> {
return aodBurnInViewModel.translationY(params)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt
index ce47f3c6..0cfc757 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt
@@ -51,6 +51,8 @@
onStep = { 1f - it }
)
+ val lockscreenAlpha: Flow<Float> = shortcutsAlpha
+
override val deviceEntryParentViewAlpha: Flow<Float> =
shadeDependentFlows.transitionFlow(
flowWhenShadeIsNotExpanded =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt
index 07c1141..c61b1f5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt
@@ -23,6 +23,7 @@
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
@@ -47,6 +48,15 @@
val deviceEntryBackgroundViewAlpha: Flow<Float> =
transitionAnimation.immediatelyTransitionTo(0f)
+ /** Lockscreen views alpha */
+ val lockscreenAlpha: Flow<Float> =
+ transitionAnimation.sharedFlow(
+ startTime = 233.milliseconds,
+ duration = 250.milliseconds,
+ onStep = { it },
+ onStart = { 0f },
+ )
+
override val deviceEntryParentViewAlpha: Flow<Float> =
deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled
->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt
index 5879d18..942903b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt
@@ -51,6 +51,12 @@
val deviceEntryBackgroundViewAlpha: Flow<Float> =
transitionAnimation.immediatelyTransitionTo(0f)
+ val lockscreenAlpha: Flow<Float> =
+ transitionAnimation.sharedFlow(
+ duration = FromPrimaryBouncerTransitionInteractor.TO_AOD_DURATION,
+ onStep = { it }
+ )
+
override val deviceEntryParentViewAlpha: Flow<Float> =
deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
isUdfpsEnrolledAndEnabled ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
index 284a134..34c9ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
@@ -23,6 +24,7 @@
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
@@ -58,10 +60,13 @@
val shortcutsAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
- duration = FromPrimaryBouncerTransitionInteractor.TO_LOCKSCREEN_DURATION,
+ duration = 250.milliseconds,
+ interpolator = EMPHASIZED_ACCELERATE,
onStep = { it }
)
+ val lockscreenAlpha: Flow<Float> = shortcutsAlpha
+
override val deviceEntryParentViewAlpha: Flow<Float> =
transitionAnimation.immediatelyTransitionTo(1f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
index 3671dd4..b4cc196 100644
--- a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
@@ -39,7 +39,10 @@
/**
* Returns {@link UserHandle} as returned statically by {@link Process#myUserHandle()}.
*
- * Please strongly consider using {@link com.android.systemui.settings.UserTracker} instead.
+ * This should not be used to get the "current" user. This information only applies to the
+ * current process, not the current state of SystemUI. Please use
+ * {@link com.android.systemui.settings.UserTracker} if you want to learn about the currently
+ * active user in SystemUI.
*/
public UserHandle myUserHandle() {
return Process.myUserHandle();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 2968490..fe45df8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -71,7 +71,6 @@
import android.util.Log;
import android.util.MathUtils;
import android.view.HapticFeedbackConstants;
-import android.view.InputDevice;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -1158,9 +1157,9 @@
// Occluded->Lockscreen
collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
mOccludedToLockscreenTransition, mMainDispatcher);
- collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
- setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
if (!KeyguardShadeMigrationNssl.isEnabled()) {
+ collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
collectFlow(mView,
mOccludedToLockscreenTransitionViewModel.getLockscreenTranslationY(),
setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
@@ -1169,9 +1168,11 @@
// Lockscreen->Dreaming
collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(),
mLockscreenToDreamingTransition, mMainDispatcher);
- collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(),
- setDreamLockscreenTransitionAlpha(mNotificationStackScrollLayoutController),
- mMainDispatcher);
+ if (!KeyguardShadeMigrationNssl.isEnabled()) {
+ collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(),
+ setDreamLockscreenTransitionAlpha(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
+ }
collectFlow(mView, mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY(
mLockscreenToDreamingTransitionTranslationY),
setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
@@ -1179,8 +1180,10 @@
// Gone->Dreaming
collectFlow(mView, mKeyguardTransitionInteractor.getGoneToDreamingTransition(),
mGoneToDreamingTransition, mMainDispatcher);
- collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(),
- setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ if (!KeyguardShadeMigrationNssl.isEnabled()) {
+ collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ }
collectFlow(mView, mGoneToDreamingTransitionViewModel.lockscreenTranslationY(
mGoneToDreamingTransitionTranslationY),
setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
@@ -1188,16 +1191,18 @@
// Lockscreen->Occluded
collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToOccludedTransition(),
mLockscreenToOccludedTransition, mMainDispatcher);
- collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
- setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
if (!KeyguardShadeMigrationNssl.isEnabled()) {
+ collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(),
setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
}
// Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth)
- collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
- setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ if (!KeyguardShadeMigrationNssl.isEnabled()) {
+ collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ }
}
@VisibleForTesting
@@ -2734,6 +2739,9 @@
}
private void updateKeyguardBottomAreaAlpha() {
+ if (KeyguardShadeMigrationNssl.isEnabled()) {
+ return;
+ }
if (mIsOcclusionTransitionRunning) {
return;
}
@@ -5057,19 +5065,6 @@
return false;
}
- final boolean isTrackpadTwoOrThreeFingerSwipe = isTrackpadScroll(
- mTrackpadGestureFeaturesEnabled, event) || isTrackpadThreeFingerSwipe(
- mTrackpadGestureFeaturesEnabled, event);
-
- // On expanding, single mouse click expands the panel instead of dragging.
- if (isFullyCollapsed() && (event.isFromSource(InputDevice.SOURCE_MOUSE)
- && !isTrackpadTwoOrThreeFingerSwipe)) {
- if (event.getAction() == MotionEvent.ACTION_UP) {
- expand(true /* animate */);
- }
- return true;
- }
-
/*
* We capture touch events here and update the expand height here in case according to
* the users fingers. This also handles multi-touch.
@@ -5090,6 +5085,10 @@
mIgnoreXTouchSlop = true;
}
+ final boolean isTrackpadTwoOrThreeFingerSwipe = isTrackpadScroll(
+ mTrackpadGestureFeaturesEnabled, event) || isTrackpadThreeFingerSwipe(
+ mTrackpadGestureFeaturesEnabled, event);
+
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
if (QuickStepContract.ALLOW_BACK_GESTURE_IN_SHADE && mAnimateBack) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index ff00cb3..476b054 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -25,31 +25,37 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
-import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
-import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
+import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE
import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
+import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
+import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
@@ -85,67 +91,32 @@
keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val shadeInteractor: ShadeInteractor,
communalInteractor: CommunalInteractor,
+ private val alternateBouncerToGoneTransitionViewModel:
+ AlternateBouncerToGoneTransitionViewModel,
+ private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
+ private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
+ private val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
+ private val glanceableHubToLockscreenTransitionViewModel:
+ GlanceableHubToLockscreenTransitionViewModel,
+ private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
+ private val goneToDreamingTransitionViewModel: GoneToDreamingTransitionViewModel,
+ private val lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel,
+ private val lockscreenToGlanceableHubTransitionViewModel:
+ LockscreenToGlanceableHubTransitionViewModel,
+ private val lockscreenToGoneTransitionViewModel: LockscreenToGoneTransitionViewModel,
+ private val lockscreenToPrimaryBouncerTransitionViewModel:
+ LockscreenToPrimaryBouncerTransitionViewModel,
+ private val lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel,
+ private val occludedToAodTransitionViewModel: OccludedToAodTransitionViewModel,
private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
- lockscreenToGoneTransitionViewModel: LockscreenToGoneTransitionViewModel,
- alternateBouncerToGoneTransitionViewModel: AlternateBouncerToGoneTransitionViewModel,
- primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
- lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel,
- dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
- lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel,
- glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel,
- lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel,
+ private val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
+ private val primaryBouncerToLockscreenTransitionViewModel:
+ PrimaryBouncerToLockscreenTransitionViewModel,
private val aodBurnInViewModel: AodBurnInViewModel,
) {
private val statesForConstrainedNotifications: Set<KeyguardState> =
setOf(AOD, LOCKSCREEN, DOZING, ALTERNATE_BOUNCER, PRIMARY_BOUNCER)
- private val edgeToAlphaViewModel =
- mapOf<Edge?, (ViewStateAccessor) -> Flow<Float>>(
- Edge(from = LOCKSCREEN, to = DREAMING) to
- { _: ViewStateAccessor ->
- lockscreenToDreamingTransitionViewModel.lockscreenAlpha
- },
- Edge(from = LOCKSCREEN, to = GONE) to
- { viewState: ViewStateAccessor ->
- lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState)
- },
- Edge(from = ALTERNATE_BOUNCER, to = GONE) to
- { _: ViewStateAccessor ->
- alternateBouncerToGoneTransitionViewModel.lockscreenAlpha
- },
- Edge(from = PRIMARY_BOUNCER, to = GONE) to
- { _: ViewStateAccessor ->
- primaryBouncerToGoneTransitionViewModel.lockscreenAlpha
- },
- Edge(from = DREAMING, to = LOCKSCREEN) to
- { _: ViewStateAccessor ->
- dreamingToLockscreenTransitionViewModel.lockscreenAlpha
- },
- Edge(from = LOCKSCREEN, to = OCCLUDED) to
- { _: ViewStateAccessor ->
- lockscreenToOccludedTransitionViewModel.lockscreenAlpha
- },
- Edge(from = OCCLUDED, to = LOCKSCREEN) to
- { _: ViewStateAccessor ->
- occludedToLockscreenTransitionViewModel.lockscreenAlpha
- },
- )
-
- private val lockscreenTransitionInProgress: Flow<Edge?> =
- keyguardTransitionInteractor.transitions
- .map { step ->
- if (
- (step.transitionState == STARTED || step.transitionState == RUNNING) &&
- (step.from == LOCKSCREEN || step.to == LOCKSCREEN)
- ) {
- Edge(step.from, step.to)
- } else {
- null
- }
- }
- .distinctUntilChanged()
- .onStart { emit(null) }
-
private val lockscreenToGlanceableHubRunning =
keyguardTransitionInteractor
.transition(LOCKSCREEN, GLANCEABLE_HUB)
@@ -300,54 +271,79 @@
private val alphaForShadeAndQsExpansion: Flow<Float> =
interactor.configurationBasedDimensions
.flatMapLatest { configurationBasedDimensions ->
- combine(
+ combineTransform(
shadeInteractor.shadeExpansion,
shadeInteractor.qsExpansion,
) { shadeExpansion, qsExpansion ->
if (shadeExpansion > 0f || qsExpansion > 0f) {
if (configurationBasedDimensions.useSplitShade) {
- 1f
+ emit(1f)
} else {
// Fade as QS shade expands
- 1f - qsExpansion
+ emit(1f - qsExpansion)
}
- } else {
- // Not visible unless the shade/qs is visible
- 0f
}
}
}
- .distinctUntilChanged()
+ .onStart { emit(0f) }
+
+ private val alphaWhenGoneAndShadeState: Flow<Float> =
+ combineTransform(
+ keyguardTransitionInteractor.transitions
+ .map { step -> step.to == GONE && step.transitionState == FINISHED }
+ .distinctUntilChanged(),
+ keyguardInteractor.statusBarState,
+ ) { isGoneTransitionFinished, statusBarState ->
+ if (isGoneTransitionFinished && statusBarState == SHADE) {
+ emit(1f)
+ }
+ }
fun expansionAlpha(viewState: ViewStateAccessor): Flow<Float> {
- // Due to issues with the legacy shade, some shade expansion events are sent incorrectly,
- // such as when the shade resets. This can happen while the transition to/from LOCKSCREEN
- // is running. Therefore use a series of flatmaps to prevent unwanted interruptions while
- // those transitions are in progress. Without this, the alpha value will produce a visible
- // flicker.
- return lockscreenTransitionInProgress
- .flatMapLatest { edge ->
- edgeToAlphaViewModel.getOrDefault(
- edge,
- { _: ViewStateAccessor ->
- isOnLockscreenWithoutShade.flatMapLatest { isOnLockscreenWithoutShade ->
- combineTransform(
- keyguardInteractor.keyguardAlpha,
- shadeCollpaseFadeIn,
- alphaForShadeAndQsExpansion,
- ) { alpha, shadeCollpaseFadeIn, alphaForShadeAndQsExpansion ->
- if (isOnLockscreenWithoutShade) {
- if (!shadeCollpaseFadeIn) {
- emit(alpha)
- }
- } else {
- emit(alphaForShadeAndQsExpansion)
- }
- }
+ // All transition view models are mututally exclusive, and safe to merge
+ val alphaTransitions =
+ merge(
+ alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
+ aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
+ dozingToLockscreenTransitionViewModel.lockscreenAlpha,
+ dreamingToLockscreenTransitionViewModel.lockscreenAlpha,
+ goneToDreamingTransitionViewModel.lockscreenAlpha,
+ goneToDozingTransitionViewModel.lockscreenAlpha,
+ lockscreenToDreamingTransitionViewModel.lockscreenAlpha,
+ lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState),
+ lockscreenToOccludedTransitionViewModel.lockscreenAlpha,
+ lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha,
+ occludedToAodTransitionViewModel.lockscreenAlpha,
+ occludedToLockscreenTransitionViewModel.lockscreenAlpha,
+ primaryBouncerToGoneTransitionViewModel.lockscreenAlpha,
+ primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha,
+ )
+
+ return merge(
+ alphaTransitions,
+ // Sends a final alpha value of 1f when truly gone, to make sure HUNs appear
+ alphaWhenGoneAndShadeState,
+ // These remaining cases handle alpha changes within an existing state, such as
+ // shade expansion or swipe to dismiss
+ combineTransform(
+ isOnLockscreenWithoutShade,
+ shadeCollpaseFadeIn,
+ alphaForShadeAndQsExpansion,
+ keyguardInteractor.dismissAlpha,
+ ) {
+ isOnLockscreenWithoutShade,
+ shadeCollpaseFadeIn,
+ alphaForShadeAndQsExpansion,
+ dismissAlpha ->
+ if (isOnLockscreenWithoutShade) {
+ if (!shadeCollpaseFadeIn && dismissAlpha != null) {
+ emit(dismissAlpha)
}
+ } else {
+ emit(alphaForShadeAndQsExpansion)
}
- )(viewState)
- }
+ },
+ )
.distinctUntilChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index f9702dd..a39bfe0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -81,6 +81,7 @@
statusContainer.setOnHoverListener(
statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer)
)
+ statusContainer.setOnClickListener { shadeViewController.expand(/* animate= */true) }
progressProvider?.setReadyToHandleTransition(true)
configurationController.addCallback(configurationListener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
index f3807e4..c381749 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
@@ -59,6 +59,24 @@
}
@Test
+ fun lockscreenAlphaStartsFromViewStateAccessorAlpha() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor(alpha = { 0.5f })
+ val alpha by collectLastValue(underTest.lockscreenAlpha(viewState))
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+
+ repository.sendTransitionStep(step(0f))
+ assertThat(alpha).isEqualTo(0.5f)
+
+ repository.sendTransitionStep(step(0.5f))
+ assertThat(alpha).isEqualTo(0.75f)
+
+ repository.sendTransitionStep(step(1f))
+ assertThat(alpha).isEqualTo(1f)
+ }
+
+ @Test
fun deviceEntryBackgroundView_udfps_alphaFadeIn() =
testScope.runTest {
fingerprintPropertyRepository.supportsUdfps()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 17e4e0f..61fee16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -186,6 +186,8 @@
FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository();
FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+ KeyguardTransitionInteractor keyguardTransitionInteractor =
+ mKosmos.getKeyguardTransitionInteractor();
KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
keyguardRepository,
new FakeCommandQueue(),
@@ -194,12 +196,10 @@
new FakeKeyguardBouncerRepository(),
new ConfigurationInteractor(configurationRepository),
shadeRepository,
+ keyguardTransitionInteractor,
() -> sceneInteractor);
CommunalInteractor communalInteractor = mKosmos.getCommunalInteractor();
- KeyguardTransitionInteractor keyguardTransitionInteractor =
- mKosmos.getKeyguardTransitionInteractor();
-
mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor();
mFromPrimaryBouncerTransitionInteractor =
mKosmos.getFromPrimaryBouncerTransitionInteractor();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index 2f765d5..061f88e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -213,6 +213,8 @@
mKosmos.getDeviceUnlockedInteractor());
FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+ KeyguardTransitionInteractor keyguardTransitionInteractor =
+ mKosmos.getKeyguardTransitionInteractor();
KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
mKeyguardRepository,
new FakeCommandQueue(),
@@ -221,11 +223,9 @@
new FakeKeyguardBouncerRepository(),
new ConfigurationInteractor(configurationRepository),
mShadeRepository,
+ keyguardTransitionInteractor,
() -> sceneInteractor);
- KeyguardTransitionInteractor keyguardTransitionInteractor =
- mKosmos.getKeyguardTransitionInteractor();
-
mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor();
mFromPrimaryBouncerTransitionInteractor =
mKosmos.getFromPrimaryBouncerTransitionInteractor();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index fb105e2..1396a43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -122,6 +122,10 @@
val shadeRepository = FakeShadeRepository()
val sceneContainerFlags = FakeSceneContainerFlags()
val configurationRepository = FakeConfigurationRepository()
+ val keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
+ fromLockscreenTransitionInteractor = kosmos.fromLockscreenTransitionInteractor
+ fromPrimaryBouncerTransitionInteractor = kosmos.fromPrimaryBouncerTransitionInteractor
+
val keyguardInteractor =
KeyguardInteractor(
keyguardRepository,
@@ -131,11 +135,9 @@
FakeKeyguardBouncerRepository(),
ConfigurationInteractor(configurationRepository),
shadeRepository,
+ keyguardTransitionInteractor,
{ kosmos.sceneInteractor },
)
- val keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
- fromLockscreenTransitionInteractor = kosmos.fromLockscreenTransitionInteractor
- fromPrimaryBouncerTransitionInteractor = kosmos.fromPrimaryBouncerTransitionInteractor
whenever(deviceEntryUdfpsInteractor.isUdfpsSupported).thenReturn(emptyFlow())
shadeInteractor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 9055ba4..2da88e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -47,6 +47,8 @@
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.mockLargeScreenHeaderHelper
import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
+import com.android.systemui.statusbar.policy.SplitShadeStateController
+import com.android.systemui.statusbar.policy.splitShadeStateController
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
@@ -65,6 +67,7 @@
@RunWith(AndroidJUnit4::class)
class SharedNotificationContainerViewModelTest : SysuiTestCase() {
val aodBurnInViewModel = mock(AodBurnInViewModel::class.java)
+ val splitShadeStateController = mock(SplitShadeStateController::class.java)
lateinit var translationYFlow: MutableStateFlow<Float>
val kosmos =
@@ -77,6 +80,7 @@
init {
kosmos.aodBurnInViewModel = aodBurnInViewModel
+ kosmos.splitShadeStateController = splitShadeStateController
}
val testScope = kosmos.testScope
val configurationRepository = kosmos.fakeConfigurationRepository
@@ -93,7 +97,7 @@
@Before
fun setUp() {
- overrideResource(R.bool.config_use_split_notification_shade, false)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())).thenReturn(false)
translationYFlow = MutableStateFlow(0f)
whenever(aodBurnInViewModel.translationY(any())).thenReturn(translationYFlow)
underTest = kosmos.sharedNotificationContainerViewModel
@@ -102,7 +106,8 @@
@Test
fun validateMarginStartInSplitShade() =
testScope.runTest {
- overrideResource(R.bool.config_use_split_notification_shade, true)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(true)
overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -115,7 +120,8 @@
@Test
fun validateMarginStart() =
testScope.runTest {
- overrideResource(R.bool.config_use_split_notification_shade, false)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(false)
overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -130,7 +136,9 @@
testScope.runTest {
mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
- overrideResource(R.bool.config_use_split_notification_shade, true)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(true)
+ overrideResource(R.bool.config_use_large_screen_shade_header, true)
overrideResource(R.dimen.large_screen_shade_header_height, 10)
overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
@@ -147,12 +155,13 @@
testScope.runTest {
mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
- overrideResource(R.bool.config_use_split_notification_shade, true)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(true)
+ overrideResource(R.bool.config_use_large_screen_shade_header, true)
overrideResource(R.dimen.large_screen_shade_header_height, 10)
overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
val dimens by collectLastValue(underTest.configurationBasedDimensions)
-
configurationRepository.onAnyConfigurationChange()
// Should directly use the header height (flagged on value)
@@ -162,7 +171,8 @@
@Test
fun validatePaddingTop() =
testScope.runTest {
- overrideResource(R.bool.config_use_split_notification_shade, false)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(false)
overrideResource(R.dimen.large_screen_shade_header_height, 10)
overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
@@ -421,7 +431,8 @@
val bounds by collectLastValue(underTest.bounds)
// When not in split shade
- overrideResource(R.bool.config_use_split_notification_shade, false)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(false)
configurationRepository.onAnyConfigurationChange()
runCurrent()
@@ -443,7 +454,9 @@
// When in split shade
whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
- overrideResource(R.bool.config_use_split_notification_shade, true)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(true)
+ overrideResource(R.bool.config_use_large_screen_shade_header, true)
overrideResource(R.dimen.large_screen_shade_header_height, 10)
overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
@@ -470,7 +483,9 @@
// When in split shade
whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
- overrideResource(R.bool.config_use_split_notification_shade, true)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(true)
+ overrideResource(R.bool.config_use_large_screen_shade_header, true)
overrideResource(R.dimen.large_screen_shade_header_height, 10)
overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
@@ -528,7 +543,8 @@
showLockscreen()
- overrideResource(R.bool.config_use_split_notification_shade, false)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(false)
configurationRepository.onAnyConfigurationChange()
keyguardInteractor.setNotificationContainerBounds(
NotificationContainerBounds(top = 1f, bottom = 2f)
@@ -551,7 +567,8 @@
showLockscreen()
- overrideResource(R.bool.config_use_split_notification_shade, false)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(false)
configurationRepository.onAnyConfigurationChange()
keyguardInteractor.setNotificationContainerBounds(
NotificationContainerBounds(top = 1f, bottom = 2f)
@@ -587,7 +604,8 @@
// Show lockscreen with shade expanded
showLockscreenWithShadeExpanded()
- overrideResource(R.bool.config_use_split_notification_shade, false)
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+ .thenReturn(false)
configurationRepository.onAnyConfigurationChange()
keyguardInteractor.setNotificationContainerBounds(
NotificationContainerBounds(top = 1f, bottom = 2f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 76c9740..56fc7b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -60,6 +60,7 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.domain.interactor.PowerInteractorFactory;
@@ -162,7 +163,8 @@
MockitoAnnotations.initMocks(this);
when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager);
-
+ KeyguardTransitionInteractor keyguardTransitionInteractor =
+ mKosmos.getKeyguardTransitionInteractor();
mKeyguardInteractor = new KeyguardInteractor(
mKeyguardRepository,
mCommandQueue,
@@ -171,6 +173,7 @@
new FakeKeyguardBouncerRepository(),
new ConfigurationInteractor(new FakeConfigurationRepository()),
new FakeShadeRepository(),
+ keyguardTransitionInteractor,
() -> mKosmos.getSceneInteractor());
mViewModel =
new KeyguardStatusBarViewModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index b7560ad..1687ccb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -22,15 +22,16 @@
import android.app.StatusBarManager.WINDOW_STATUS_BAR
import android.view.LayoutInflater
import android.view.MotionEvent
+import android.view.View
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.OnPreDrawListener
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.ShadeControllerImpl
@@ -48,8 +49,6 @@
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
-import java.util.Optional
-import javax.inject.Provider
import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentCaptor
@@ -60,6 +59,8 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import java.util.Optional
+import javax.inject.Provider
@SmallTest
class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@@ -98,7 +99,7 @@
val parent = FrameLayout(mContext) // add parent to keep layout params
view =
LayoutInflater.from(mContext).inflate(R.layout.status_bar, parent, false)
- as PhoneStatusBarView
+ as PhoneStatusBarView
controller = createAndInitController(view)
}
}
@@ -231,6 +232,27 @@
verify(centralSurfacesImpl).setInteracting(any(), any())
}
+ @Test
+ fun shadeIsExpandedOnStatusIconClick() {
+ val view = createViewMock()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ controller = createAndInitController(view)
+ }
+ val statusContainer = view.requireViewById<View>(R.id.system_icons)
+ statusContainer.performClick()
+ verify(shadeViewController).expand(any())
+ }
+
+ @Test
+ fun shadeIsNotExpandedOnStatusBarGeneralClick() {
+ val view = createViewMock()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ controller = createAndInitController(view)
+ }
+ view.performClick()
+ verify(shadeViewController, never()).expand(any())
+ }
+
private fun getCommandQueueCallback(): CommandQueue.Callbacks {
val captor = argumentCaptor<CommandQueue.Callbacks>()
verify(commandQueue).addCallback(captor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
index ca0e526..76913e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
@@ -61,6 +62,7 @@
FakeKeyguardBouncerRepository(),
ConfigurationInteractor(FakeConfigurationRepository()),
FakeShadeRepository(),
+ kosmos.keyguardTransitionInteractor,
) {
kosmos.sceneInteractor
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 97bd96d..d87df0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -420,6 +420,8 @@
mKosmos.getDeviceUnlockedInteractor());
FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+ KeyguardTransitionInteractor keyguardTransitionInteractor =
+ mKosmos.getKeyguardTransitionInteractor();
KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
keyguardRepository,
new FakeCommandQueue(),
@@ -428,11 +430,9 @@
new FakeKeyguardBouncerRepository(),
new ConfigurationInteractor(configurationRepository),
shadeRepository,
+ keyguardTransitionInteractor,
() -> sceneInteractor);
- KeyguardTransitionInteractor keyguardTransitionInteractor =
- mKosmos.getKeyguardTransitionInteractor();
-
mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor();
mFromPrimaryBouncerTransitionInteractor =
mKosmos.getFromPrimaryBouncerTransitionInteractor();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index 0bba36b..3893a9b7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -23,6 +23,7 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
import com.android.systemui.scene.domain.interactor.SceneInteractor
@@ -30,6 +31,8 @@
import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import kotlinx.coroutines.flow.MutableSharedFlow
/**
* Simply put, I got tired of adding a constructor argument and then having to tweak dozens of
@@ -50,6 +53,11 @@
sceneInteractor: SceneInteractor = mock(),
powerInteractor: PowerInteractor = PowerInteractorFactory.create().powerInteractor,
): WithDependencies {
+ // Mock this until the class is replaced by kosmos
+ val keyguardTransitionInteractor: KeyguardTransitionInteractor = mock()
+ val currentKeyguardStateFlow = MutableSharedFlow<KeyguardState>()
+ whenever(keyguardTransitionInteractor.currentKeyguardState)
+ .thenReturn(currentKeyguardStateFlow)
return WithDependencies(
repository = repository,
commandQueue = commandQueue,
@@ -67,6 +75,7 @@
configurationInteractor = ConfigurationInteractor(configurationRepository),
shadeRepository = shadeRepository,
sceneInteractorProvider = { sceneInteractor },
+ keyguardTransitionInteractor = keyguardTransitionInteractor,
powerInteractor = powerInteractor,
),
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
index 58d99b5..5140a9f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
@@ -36,6 +36,7 @@
bouncerRepository = keyguardBouncerRepository,
configurationInteractor = configurationInteractor,
shadeRepository = shadeRepository,
+ keyguardTransitionInteractor = keyguardTransitionInteractor,
sceneInteractorProvider = { sceneInteractor },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
index 0c38fd9..6df7493 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
@@ -26,7 +26,6 @@
KeyguardTransitionInteractor(
scope = applicationCoroutineScope,
repository = keyguardTransitionRepository,
- keyguardInteractor = Lazy { keyguardInteractor },
fromLockscreenTransitionInteractor = Lazy { fromLockscreenTransitionInteractor },
fromPrimaryBouncerTransitionInteractor =
Lazy { fromPrimaryBouncerTransitionInteractor },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt
index 6b89e0f..9fb3284 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt
@@ -18,7 +18,6 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
@@ -26,8 +25,8 @@
val Kosmos.aodAlphaViewModel by Fixture {
AodAlphaViewModel(
- keyguardInteractor = keyguardInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
- occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
+ goneToAodTransitionViewModel = goneToAodTransitionViewModel,
+ goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
new file mode 100644
index 0000000..4daf460
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+val Kosmos.goneToDozingTransitionViewModel by Fixture {
+ GoneToDozingTransitionViewModel(
+ animationFlow = keyguardTransitionAnimationFlow,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index 24bb9c5..4939237b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -37,14 +37,24 @@
communalInteractor = communalInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
notificationsKeyguardInteractor = notificationsKeyguardInteractor,
- aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
- lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel,
alternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel,
+ aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
+ dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
+ glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
+ lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel,
+ lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel,
+ lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel,
+ lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel,
+ lockscreenToPrimaryBouncerTransitionViewModel =
+ lockscreenToPrimaryBouncerTransitionViewModel,
+ occludedToAodTransitionViewModel = occludedToAodTransitionViewModel,
+ occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
+ primaryBouncerToAodTransitionViewModel = primaryBouncerToAodTransitionViewModel,
primaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel,
+ primaryBouncerToLockscreenTransitionViewModel =
+ primaryBouncerToLockscreenTransitionViewModel,
screenOffAnimationController = screenOffAnimationController,
aodBurnInViewModel = aodBurnInViewModel,
aodAlphaViewModel = aodAlphaViewModel,
- lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel,
- glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 30d4105..8882de0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -21,14 +21,21 @@
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.aodToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.dozingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dreamingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.goneToDozingTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.goneToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.lockscreenToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.lockscreenToOccludedTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.lockscreenToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.occludedToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.occludedToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.primaryBouncerToGoneTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.primaryBouncerToLockscreenTransitionViewModel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -43,15 +50,24 @@
keyguardTransitionInteractor = keyguardTransitionInteractor,
shadeInteractor = shadeInteractor,
communalInteractor = communalInteractor,
- occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
- lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel,
alternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel,
- primaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel,
- lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel,
+ aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
+ dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
dreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel,
- lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel,
+ goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
+ goneToDreamingTransitionViewModel = goneToDreamingTransitionViewModel,
glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
+ lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel,
lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel,
+ lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel,
+ lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel,
+ lockscreenToPrimaryBouncerTransitionViewModel =
+ lockscreenToPrimaryBouncerTransitionViewModel,
+ occludedToAodTransitionViewModel = occludedToAodTransitionViewModel,
+ occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
+ primaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel,
+ primaryBouncerToLockscreenTransitionViewModel =
+ primaryBouncerToLockscreenTransitionViewModel,
aodBurnInViewModel = aodBurnInViewModel,
)
}
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 35ce481..132804f 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -24,6 +24,46 @@
visibility: ["//visibility:public"],
}
+java_library_host {
+ name: "ravenwood-helper-libcore-runtime.host",
+ srcs: [
+ "runtime-helper-src/libcore-fake/**/*.java",
+ ],
+ visibility: ["//visibility:private"],
+}
+
+java_host_for_device {
+ name: "ravenwood-helper-libcore-runtime",
+ libs: [
+ "ravenwood-helper-libcore-runtime.host",
+ ],
+ visibility: ["//visibility:private"],
+}
+
+java_library {
+ name: "ravenwood-helper-framework-runtime",
+ srcs: [
+ "runtime-helper-src/framework/**/*.java",
+ ],
+ libs: [
+ "framework-minus-apex.ravenwood",
+ ],
+ visibility: ["//visibility:private"],
+}
+
+// Combine ravenwood-helper-*-runtime and create a single library, which we include
+// in the ravenwood runtime.
+// We do it this way rather than including the individual jars in the runtime, because
+// for some reason we couldn't include a java_host_for_device module in the ravenwood runtime.
+java_library {
+ name: "ravenwood-helper-runtime",
+ defaults: ["ravenwood-internal-only-visibility-java"],
+ static_libs: [
+ "ravenwood-helper-framework-runtime",
+ "ravenwood-helper-libcore-runtime",
+ ],
+}
+
java_library {
name: "ravenwood-junit-impl",
srcs: [
@@ -58,16 +98,6 @@
visibility: ["//visibility:public"],
}
-java_library {
- // Prefixed with "200" to ensure it's sorted early in Tradefed classpath
- // so that we provide a concrete implementation before Mainline stubs
- name: "200-kxml2-android",
- static_libs: [
- "kxml2-android",
- ],
- visibility: ["//frameworks/base"],
-}
-
java_host_for_device {
name: "androidx.test.monitor-for-device",
libs: [
diff --git a/ravenwood/api-maintainers.md b/ravenwood/api-maintainers.md
index d84cb67..4b2f968 100644
--- a/ravenwood/api-maintainers.md
+++ b/ravenwood/api-maintainers.md
@@ -82,7 +82,7 @@
```
@RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.MyComplexClass_host")
+@RavenwoodNativeSubstitutionClass("com.android.platform.test.ravenwood.nativesubstitution.MyComplexClass_host")
public class MyComplexClass {
private static native void nativeDoThing(long nativePtr);
...
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/CursorWindow_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/CursorWindow_host.java
similarity index 98%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/CursorWindow_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/CursorWindow_host.java
index eba9910..f38d565 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/CursorWindow_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/CursorWindow_host.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/EventLog_host.java
similarity index 97%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/EventLog_host.java
index 6480cfc..55d4ffb 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/EventLog_host.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
import com.android.internal.os.RuntimeInit;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
similarity index 97%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
index cdfa302..5930a14 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
import android.util.Log;
import android.util.Log.Level;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java
similarity index 99%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java
index 4d39d88..7414110 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
import android.os.BadParcelableException;
import android.os.Parcel;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongMultiStateCounter_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongMultiStateCounter_host.java
similarity index 98%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongMultiStateCounter_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongMultiStateCounter_host.java
index a5d0fc6..9486651 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongMultiStateCounter_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongMultiStateCounter_host.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
import android.os.BadParcelableException;
import android.os.Parcel;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/MessageQueue_host.java
similarity index 97%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/MessageQueue_host.java
index 65da4a1..5e81124 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/MessageQueue_host.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java
similarity index 98%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java
index 0ebaac60..2d79914 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
import static android.os.ParcelFileDescriptor.MODE_APPEND;
import static android.os.ParcelFileDescriptor.MODE_CREATE;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
similarity index 99%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
index d63bff6..81ad31e 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
similarity index 98%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
index 2f6a361..eba6c8b 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
import android.util.SparseArray;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
similarity index 96%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
index fbcc648..1e12030 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
@@ -13,9 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.hoststubgen.runtimehelper;
-
-import com.android.hoststubgen.hosthelper.HostTestException;
+package com.android.platform.test.ravenwood.runtimehelper;
import java.io.File;
import java.io.PrintStream;
@@ -79,7 +77,7 @@
private static void ensurePropertyNotSet(String key) {
if (System.getProperty(key) != null) {
- throw new HostTestException("System property \"" + key + "\" is set unexpectedly");
+ throw new RuntimeException("System property \"" + key + "\" is set unexpectedly");
}
}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/android/system/ErrnoException.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/ErrnoException.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/android/system/ErrnoException.java
rename to ravenwood/runtime-helper-src/libcore-fake/android/system/ErrnoException.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/com/android/okhttp/internalandroidapi/Dns.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/okhttp/internalandroidapi/Dns.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/com/android/okhttp/internalandroidapi/Dns.java
rename to ravenwood/runtime-helper-src/libcore-fake/com/android/okhttp/internalandroidapi/Dns.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java
rename to ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/io/IoUtils.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoUtils.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/io/IoUtils.java
rename to ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoUtils.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/EmptyArray.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java
rename to ravenwood/runtime-helper-src/libcore-fake/libcore/util/EmptyArray.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/HexEncoding.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/HexEncoding.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/HexEncoding.java
rename to ravenwood/runtime-helper-src/libcore-fake/libcore/util/HexEncoding.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/SneakyThrow.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java
rename to ravenwood/runtime-helper-src/libcore-fake/libcore/util/SneakyThrow.java
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index e349fa3..babb6c2 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -22,6 +22,8 @@
import static android.app.Notification.FLAG_LOCAL_ONLY;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_ONGOING_EVENT;
+import static android.app.Notification.VISIBILITY_PRIVATE;
+import static android.app.Notification.VISIBILITY_PUBLIC;
import android.annotation.NonNull;
import android.app.Notification;
@@ -145,7 +147,8 @@
mUngroupedNotifications.getOrDefault(key, new ArrayMap<>());
NotificationAttributes attr = new NotificationAttributes(sbn.getNotification().flags,
- sbn.getNotification().getSmallIcon(), sbn.getNotification().color);
+ sbn.getNotification().getSmallIcon(), sbn.getNotification().color,
+ sbn.getNotification().visibility);
children.put(sbn.getKey(), attr);
mUngroupedNotifications.put(key, children);
@@ -158,25 +161,29 @@
if (notificationsToGroup.size() > 0) {
if (autogroupSummaryExists) {
NotificationAttributes attr = new NotificationAttributes(flags,
- sbn.getNotification().getSmallIcon(), sbn.getNotification().color);
+ sbn.getNotification().getSmallIcon(), sbn.getNotification().color,
+ VISIBILITY_PRIVATE);
if (Flags.autogroupSummaryIconUpdate()) {
- attr = updateAutobundledSummaryIcon(sbn.getPackageName(), childrenAttr, attr);
+ attr = updateAutobundledSummaryAttributes(sbn.getPackageName(), childrenAttr,
+ attr);
}
mCallback.updateAutogroupSummary(sbn.getUserId(), sbn.getPackageName(), attr);
} else {
Icon summaryIcon = sbn.getNotification().getSmallIcon();
int summaryIconColor = sbn.getNotification().color;
+ int summaryVisibility = VISIBILITY_PRIVATE;
if (Flags.autogroupSummaryIconUpdate()) {
- // Calculate the initial summary icon and icon color
- NotificationAttributes iconAttr = getAutobundledSummaryIconAndColor(
+ // Calculate the initial summary icon, icon color and visibility
+ NotificationAttributes iconAttr = getAutobundledSummaryAttributes(
sbn.getPackageName(), childrenAttr);
summaryIcon = iconAttr.icon;
summaryIconColor = iconAttr.iconColor;
+ summaryVisibility = iconAttr.visibility;
}
NotificationAttributes attr = new NotificationAttributes(flags, summaryIcon,
- summaryIconColor);
+ summaryIconColor, summaryVisibility);
mCallback.addAutoGroupSummary(sbn.getUserId(), sbn.getPackageName(), sbn.getKey(),
attr);
}
@@ -238,18 +245,19 @@
mCallback.removeAutoGroupSummary(userId, sbn.getPackageName());
} else {
NotificationAttributes attr = new NotificationAttributes(summaryFlags,
- sbn.getNotification().getSmallIcon(), sbn.getNotification().color);
- boolean iconUpdated = false;
+ sbn.getNotification().getSmallIcon(), sbn.getNotification().color,
+ VISIBILITY_PRIVATE);
+ boolean attributesUpdated = false;
if (Flags.autogroupSummaryIconUpdate()) {
- NotificationAttributes newAttr = updateAutobundledSummaryIcon(sbn.getPackageName(),
- childrenAttrs, attr);
+ NotificationAttributes newAttr = updateAutobundledSummaryAttributes(
+ sbn.getPackageName(), childrenAttrs, attr);
if (!newAttr.equals(attr)) {
- iconUpdated = true;
+ attributesUpdated = true;
attr = newAttr;
}
}
- if (updateSummaryFlags || iconUpdated) {
+ if (updateSummaryFlags || attributesUpdated) {
mCallback.updateAutogroupSummary(userId, sbn.getPackageName(), attr);
}
}
@@ -268,12 +276,13 @@
}
}
- NotificationAttributes getAutobundledSummaryIconAndColor(@NonNull String packageName,
+ NotificationAttributes getAutobundledSummaryAttributes(@NonNull String packageName,
@NonNull List<NotificationAttributes> childrenAttr) {
Icon newIcon = null;
boolean childrenHaveSameIcon = true;
int newColor = Notification.COLOR_INVALID;
boolean childrenHaveSameColor = true;
+ int newVisibility = VISIBILITY_PRIVATE;
// Both the icon drawable and the icon background color are updated according to this rule:
// - if all child icons are identical => use the common icon
@@ -296,6 +305,10 @@
childrenHaveSameColor = false;
}
}
+ // Check for visibility. If at least one child is public, then set to public
+ if (state.visibility == VISIBILITY_PUBLIC) {
+ newVisibility = VISIBILITY_PUBLIC;
+ }
}
if (!childrenHaveSameIcon) {
newIcon = getMonochromeAppIcon(packageName);
@@ -304,13 +317,13 @@
newColor = COLOR_DEFAULT;
}
- return new NotificationAttributes(0, newIcon, newColor);
+ return new NotificationAttributes(0, newIcon, newColor, newVisibility);
}
- NotificationAttributes updateAutobundledSummaryIcon(@NonNull String packageName,
+ NotificationAttributes updateAutobundledSummaryAttributes(@NonNull String packageName,
@NonNull List<NotificationAttributes> childrenAttr,
@NonNull NotificationAttributes oldAttr) {
- NotificationAttributes newAttr = getAutobundledSummaryIconAndColor(packageName,
+ NotificationAttributes newAttr = getAutobundledSummaryAttributes(packageName,
childrenAttr);
Icon newIcon = newAttr.icon;
int newColor = newAttr.iconColor;
@@ -321,7 +334,7 @@
newColor = oldAttr.iconColor;
}
- return new NotificationAttributes(oldAttr.flags, newIcon, newColor);
+ return new NotificationAttributes(oldAttr.flags, newIcon, newColor, newAttr.visibility);
}
/**
@@ -358,17 +371,20 @@
public final int flags;
public final int iconColor;
public final Icon icon;
+ public final int visibility;
- public NotificationAttributes(int flags, Icon icon, int iconColor) {
+ public NotificationAttributes(int flags, Icon icon, int iconColor, int visibility) {
this.flags = flags;
this.icon = icon;
this.iconColor = iconColor;
+ this.visibility = visibility;
}
public NotificationAttributes(@NonNull NotificationAttributes attr) {
this.flags = attr.flags;
this.icon = attr.icon;
this.iconColor = attr.iconColor;
+ this.visibility = attr.visibility;
}
@Override
@@ -379,12 +395,13 @@
if (!(o instanceof NotificationAttributes that)) {
return false;
}
- return flags == that.flags && iconColor == that.iconColor && icon.sameAs(that.icon);
+ return flags == that.flags && iconColor == that.iconColor && icon.sameAs(that.icon)
+ && visibility == that.visibility;
}
@Override
public int hashCode() {
- return Objects.hash(flags, iconColor, icon);
+ return Objects.hash(flags, iconColor, icon, visibility);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ea4e67a..d751186 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1038,15 +1038,17 @@
}
int oldFlags = summary.getSbn().getNotification().flags;
- boolean iconUpdated =
+ boolean attributesUpdated =
!summaryAttr.icon.sameAs(summary.getSbn().getNotification().getSmallIcon())
- || summaryAttr.iconColor != summary.getSbn().getNotification().color;
+ || summaryAttr.iconColor != summary.getSbn().getNotification().color
+ || summaryAttr.visibility != summary.getSbn().getNotification().visibility;
- if (oldFlags != summaryAttr.flags || iconUpdated) {
+ if (oldFlags != summaryAttr.flags || attributesUpdated) {
summary.getSbn().getNotification().flags =
summaryAttr.flags != GroupHelper.FLAG_INVALID ? summaryAttr.flags : oldFlags;
summary.getSbn().getNotification().setSmallIcon(summaryAttr.icon);
summary.getSbn().getNotification().color = summaryAttr.iconColor;
+ summary.getSbn().getNotification().visibility = summaryAttr.visibility;
mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground,
mPostNotificationTrackerFactory.newTracker(null)));
}
@@ -2939,7 +2941,8 @@
public void addAutoGroupSummary(int userId, String pkg, String triggeringKey,
NotificationAttributes summaryAttr) {
NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey,
- summaryAttr.flags, summaryAttr.icon, summaryAttr.iconColor);
+ summaryAttr.flags, summaryAttr.icon, summaryAttr.iconColor,
+ summaryAttr.visibility);
if (r != null) {
final boolean isAppForeground =
mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
@@ -6725,7 +6728,7 @@
// Creates a 'fake' summary for a package that has exceeded the solo-notification limit.
NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey,
- int flagsToSet, Icon summaryIcon, int summaryIconColor) {
+ int flagsToSet, Icon summaryIcon, int summaryIconColor, int summaryVisibilty) {
NotificationRecord summaryRecord = null;
boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
synchronized (mNotificationLock) {
@@ -6760,6 +6763,7 @@
.setGroup(GroupHelper.AUTOGROUP_KEY)
.setFlag(flagsToSet, true)
.setColor(summaryIconColor)
+ .setVisibility(summaryVisibilty)
.build();
summaryNotification.extras.putAll(extras);
Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index d644235..449e9ab 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -240,7 +240,7 @@
@Override
protected boolean canRestoreAnyVersion() {
- return false;
+ return true;
}
@Override
diff --git a/services/core/java/com/android/server/wearable/RemoteWearableSensingService.java b/services/core/java/com/android/server/wearable/RemoteWearableSensingService.java
index 62a637e..3077fb8 100644
--- a/services/core/java/com/android/server/wearable/RemoteWearableSensingService.java
+++ b/services/core/java/com/android/server/wearable/RemoteWearableSensingService.java
@@ -257,6 +257,55 @@
statusCallback));
}
+ /**
+ * Request the wearable to start hotword recognition.
+ *
+ * @param wearableHotwordCallback The callback to send hotword audio data and format to.
+ * @param statusCallback The callback for service status.
+ */
+ public void startHotwordRecognition(
+ RemoteCallback wearableHotwordCallback, RemoteCallback statusCallback) {
+ if (DEBUG) {
+ Slog.i(TAG, "Starting to listen for hotword.");
+ }
+ var unused =
+ post(
+ service ->
+ service.startHotwordRecognition(
+ wearableHotwordCallback, statusCallback));
+ }
+
+ /**
+ * Request the wearable to stop hotword recognition.
+ *
+ * @param statusCallback The callback for service status.
+ */
+ public void stopHotwordRecognition(RemoteCallback statusCallback) {
+ if (DEBUG) {
+ Slog.i(TAG, "Stopping hotword recognition.");
+ }
+ var unused = post(service -> service.stopHotwordRecognition(statusCallback));
+ }
+
+ /**
+ * Signals to the {@link WearableSensingService} that hotword audio data is accepted by the
+ * {@link android.service.voice.HotwordDetectionService} as valid hotword.
+ */
+ public void onValidatedByHotwordDetectionService() {
+ if (DEBUG) {
+ Slog.i(TAG, "Requesting hotword audio data egress.");
+ }
+ var unused = post(service -> service.onValidatedByHotwordDetectionService());
+ }
+
+ /** Stops the active hotword audio stream from the wearable. */
+ public void stopActiveHotwordAudio() {
+ if (DEBUG) {
+ Slog.i(TAG, "Stopping hotword audio.");
+ }
+ var unused = post(service -> service.stopActiveHotwordAudio());
+ }
+
private static class SecureWearableConnectionContext {
final ParcelFileDescriptor mSecureWearableConnection;
final RemoteCallback mStatusCallback;
diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
index 9ba4433..2b43203 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
@@ -16,6 +16,8 @@
package com.android.server.wearable;
+import static android.service.wearable.WearableSensingService.HOTWORD_AUDIO_STREAM_BUNDLE_KEY;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,18 +30,23 @@
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
+import android.os.Binder;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.SharedMemory;
+import android.service.voice.HotwordAudioStream;
+import android.service.voice.VoiceInteractionManagerInternal;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
import android.system.OsConstants;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import com.android.server.infra.AbstractPerUserSystemService;
import java.io.IOException;
@@ -58,6 +65,7 @@
@VisibleForTesting
RemoteWearableSensingService mRemoteService;
+ @Nullable private VoiceInteractionManagerInternal mVoiceInteractionManagerInternal;
private ComponentName mComponentName;
private final Object mSecureChannelLock = new Object();
@@ -99,6 +107,15 @@
}
}
+ @GuardedBy("mLock")
+ private boolean ensureVoiceInteractionManagerInternalInitiated() {
+ if (mVoiceInteractionManagerInternal == null) {
+ mVoiceInteractionManagerInternal =
+ LocalServices.getService(VoiceInteractionManagerInternal.class);
+ }
+ return mVoiceInteractionManagerInternal != null;
+ }
+
/**
* get the currently bound component name.
*/
@@ -334,4 +351,109 @@
dataType, dataRequestObserverId, packageName, statusCallback);
}
}
+
+ /** Handles starting hotword listening. */
+ public void onStartHotwordRecognition(
+ ComponentName targetVisComponentName, RemoteCallback statusCallback) {
+ synchronized (mLock) {
+ if (!setUpServiceIfNeeded()) {
+ Slog.w(TAG, "Detection service is not available at this moment.");
+ notifyStatusCallback(
+ statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+ return;
+ }
+ if (!ensureVoiceInteractionManagerInternalInitiated()) {
+ Slog.w(TAG, "Voice interaction manager is not available at this moment.");
+ notifyStatusCallback(
+ statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+ return;
+ }
+ ensureRemoteServiceInitiated();
+ mRemoteService.startHotwordRecognition(
+ createWearableHotwordCallback(targetVisComponentName), statusCallback);
+ }
+ }
+
+ /** Handles stopping hotword listening. */
+ public void onStopHotwordRecognition(RemoteCallback statusCallback) {
+ synchronized (mLock) {
+ if (!setUpServiceIfNeeded()) {
+ Slog.w(TAG, "Detection service is not available at this moment.");
+ notifyStatusCallback(
+ statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+ return;
+ }
+ ensureRemoteServiceInitiated();
+ mRemoteService.stopHotwordRecognition(statusCallback);
+ }
+ }
+
+ private void onValidatedByHotwordDetectionService() {
+ synchronized (mLock) {
+ if (!setUpServiceIfNeeded()) {
+ Slog.w(TAG, "Wearable sensing service is not available at this moment.");
+ return;
+ }
+ ensureRemoteServiceInitiated();
+ mRemoteService.onValidatedByHotwordDetectionService();
+ }
+ }
+
+ private void stopActiveHotwordAudio() {
+ synchronized (mLock) {
+ if (!setUpServiceIfNeeded()) {
+ Slog.w(TAG, "Wearable sensing service is not available at this moment.");
+ return;
+ }
+ ensureRemoteServiceInitiated();
+ mRemoteService.stopActiveHotwordAudio();
+ }
+ }
+
+ private RemoteCallback createWearableHotwordCallback(ComponentName targetVisComponentName) {
+ return new RemoteCallback(
+ result -> {
+ HotwordAudioStream hotwordAudioStream =
+ result.getParcelable(
+ HOTWORD_AUDIO_STREAM_BUNDLE_KEY, HotwordAudioStream.class);
+ if (hotwordAudioStream == null) {
+ Slog.w(TAG, "No hotword audio stream received, unable to process hotword.");
+ return;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mVoiceInteractionManagerInternal.startListeningFromWearable(
+ hotwordAudioStream.getAudioStreamParcelFileDescriptor(),
+ hotwordAudioStream.getAudioFormat(),
+ hotwordAudioStream.getMetadata(),
+ targetVisComponentName,
+ getUserId(),
+ createHotwordDetectionCallback());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ });
+ }
+
+ private WearableHotwordDetectionCallback createHotwordDetectionCallback() {
+ return new WearableHotwordDetectionCallback() {
+ @Override
+ public void onDetected() {
+ Slog.i(TAG, "hotwordDetectionCallback onDetected.");
+ onValidatedByHotwordDetectionService();
+ }
+
+ @Override
+ public void onRejected() {
+ Slog.i(TAG, "hotwordDetectionCallback onRejected.");
+ stopActiveHotwordAudio();
+ }
+
+ @Override
+ public void onError(String errorMessage) {
+ Slog.i(TAG, "hotwordDetectionCallback onError. ErrorMessage: " + errorMessage);
+ stopActiveHotwordAudio();
+ }
+ };
+ }
}
diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
index 78952fa..00c3026 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
@@ -496,6 +496,42 @@
}
@Override
+ public void startHotwordRecognition(
+ ComponentName targetVisComponentName, RemoteCallback statusCallback) {
+ Slog.i(TAG, "WearableSensingManagerInternal startHotwordRecognition.");
+ Objects.requireNonNull(statusCallback);
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE, TAG);
+ if (!mIsServiceEnabled) {
+ Slog.w(TAG, "Service not available.");
+ WearableSensingManagerPerUserService.notifyStatusCallback(
+ statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+ return;
+ }
+ callPerUserServiceIfExist(
+ service ->
+ service.onStartHotwordRecognition(
+ targetVisComponentName, statusCallback),
+ statusCallback);
+ }
+
+ @Override
+ public void stopHotwordRecognition(RemoteCallback statusCallback) {
+ Slog.i(TAG, "WearableSensingManagerInternal stopHotwordRecognition.");
+ Objects.requireNonNull(statusCallback);
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE, TAG);
+ if (!mIsServiceEnabled) {
+ Slog.w(TAG, "Service not available.");
+ WearableSensingManagerPerUserService.notifyStatusCallback(
+ statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+ return;
+ }
+ callPerUserServiceIfExist(
+ service -> service.onStopHotwordRecognition(statusCallback), statusCallback);
+ }
+
+ @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
new WearableSensingShellCommand(WearableSensingManagerService.this).exec(
diff --git a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
index 817901f..fa2d9bf 100644
--- a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
+++ b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
@@ -322,15 +322,17 @@
var listener = trustedPresentationInfo.mListener;
boolean lastState = trustedPresentationInfo.mLastComputedTrustedPresentationState;
boolean newState =
- (alpha >= trustedPresentationInfo.mThresholds.minAlpha) && (fractionRendered
- >= trustedPresentationInfo.mThresholds.minFractionRendered);
+ (alpha >= trustedPresentationInfo.mThresholds.getMinAlpha())
+ && (fractionRendered >= trustedPresentationInfo.mThresholds
+ .getMinFractionRendered());
trustedPresentationInfo.mLastComputedTrustedPresentationState = newState;
ProtoLog.v(WM_DEBUG_TPL,
"lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f "
+ "minFractionRendered=%f",
- lastState, newState, alpha, trustedPresentationInfo.mThresholds.minAlpha,
- fractionRendered, trustedPresentationInfo.mThresholds.minFractionRendered);
+ lastState, newState, alpha, trustedPresentationInfo.mThresholds.getMinAlpha(),
+ fractionRendered, trustedPresentationInfo.mThresholds
+ .getMinFractionRendered());
if (lastState && !newState) {
// We were in the trusted presentation state, but now we left it,
@@ -350,13 +352,15 @@
trustedPresentationInfo.mEnteredTrustedPresentationStateTime = currTimeMs;
mHandler.postDelayed(() -> {
computeTpl(mLastWindowHandles);
- }, (long) (trustedPresentationInfo.mThresholds.stabilityRequirementMs * 1.5));
+ }, (long) (trustedPresentationInfo.mThresholds
+ .getStabilityRequirementMillis() * 1.5));
}
// Has the timer elapsed, but we are still in the state? Emit a callback if needed
if (!trustedPresentationInfo.mLastReportedTrustedPresentationState && newState && (
currTimeMs - trustedPresentationInfo.mEnteredTrustedPresentationStateTime
- > trustedPresentationInfo.mThresholds.stabilityRequirementMs)) {
+ > trustedPresentationInfo.mThresholds
+ .getStabilityRequirementMillis())) {
trustedPresentationInfo.mLastReportedTrustedPresentationState = true;
addListenerUpdate(listenerUpdates, listener,
trustedPresentationInfo.mId, /*presentationState*/ true);
@@ -413,15 +417,6 @@
mThresholds = thresholds;
mId = id;
mListener = listener;
- checkValid(thresholds);
- }
-
- private void checkValid(TrustedPresentationThresholds thresholds) {
- if (thresholds.minAlpha <= 0 || thresholds.minFractionRendered <= 0
- || thresholds.stabilityRequirementMs < 1) {
- throw new IllegalArgumentException(
- "TrustedPresentationThresholds values are invalid");
- }
}
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 105dc88..0ccf810c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -102,6 +102,9 @@
DevicePolicyIdentifiers.getIdentifierForUserRestriction(
UserManager.DISALLOW_CELLULAR_2G);
+ //TODO(b/295504706) : Speak to security team to decide what to set Policy_Size_Limit
+ private static final int DEFAULT_POLICY_SIZE_LIMIT = -1;
+
private final Context mContext;
private final UserManager mUserManager;
@@ -122,10 +125,11 @@
* Map containing the current set of admins in each user with active policies.
*/
private final SparseArray<Set<EnforcingAdmin>> mEnforcingAdmins;
+
private final SparseArray<HashMap<EnforcingAdmin, Integer>> mAdminPolicySize;
- //TODO(b/295504706) : Speak to security team to decide what to set Policy_Size_Limit
- private static final int POLICY_SIZE_LIMIT = 99999;
+ private int mPolicySizeLimit = DEFAULT_POLICY_SIZE_LIMIT;
+
private final DeviceAdminServiceController mDeviceAdminServiceController;
DevicePolicyEngine(
@@ -1594,7 +1598,9 @@
existingPolicySize = sizeOf(policyState.getPoliciesSetByAdmins().get(admin));
}
int policySize = sizeOf(value);
- if (currentAdminPoliciesSize + policySize - existingPolicySize < POLICY_SIZE_LIMIT) {
+ // Policy size limit is disabled if mPolicySizeLimit is -1.
+ if (mPolicySizeLimit == -1
+ || currentAdminPoliciesSize + policySize - existingPolicySize < mPolicySizeLimit) {
increasePolicySizeForAdmin(
admin, /* policySizeDiff = */ policySize - existingPolicySize);
return true;
@@ -1642,6 +1648,26 @@
}
}
+ /**
+ * Updates the max allowed size limit for policies per admin. Setting it to -1, disables
+ * the limitation.
+ */
+ void setMaxPolicyStorageLimit(int storageLimit) {
+ if (storageLimit < DEFAULT_POLICY_SIZE_LIMIT && storageLimit != -1) {
+ throw new IllegalArgumentException("Can't set a size limit less than the minimum "
+ + "allowed size.");
+ }
+ mPolicySizeLimit = storageLimit;
+ }
+
+ /**
+ * Returns the max allowed size limit for policies per admin. -1 means the limitation is
+ * disabled.
+ */
+ int getMaxPolicyStorageLimit() {
+ return mPolicySizeLimit;
+ }
+
public void dump(IndentingPrintWriter pw) {
synchronized (mLock) {
pw.println("Local Policies: ");
@@ -1761,6 +1787,7 @@
private static final String TAG_ENFORCING_ADMIN_AND_SIZE = "enforcing-admin-and-size";
private static final String TAG_ENFORCING_ADMIN = "enforcing-admin";
private static final String TAG_POLICY_SUM_SIZE = "policy-sum-size";
+ private static final String TAG_MAX_POLICY_SIZE_LIMIT = "max-policy-size-limit";
private static final String ATTR_USER_ID = "user-id";
private static final String ATTR_POLICY_SUM_SIZE = "size";
@@ -1805,6 +1832,7 @@
writeGlobalPoliciesInner(serializer);
writeEnforcingAdminsInner(serializer);
writeEnforcingAdminSizeInner(serializer);
+ writeMaxPolicySizeInner(serializer);
}
private void writeLocalPoliciesInner(TypedXmlSerializer serializer) throws IOException {
@@ -1886,6 +1914,17 @@
}
}
+ private void writeMaxPolicySizeInner(TypedXmlSerializer serializer)
+ throws IOException {
+ if (!devicePolicySizeTrackingEnabled()) {
+ return;
+ }
+ serializer.startTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT);
+ serializer.attributeInt(
+ /* namespace= */ null, ATTR_POLICY_SUM_SIZE, mPolicySizeLimit);
+ serializer.endTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT);
+ }
+
void readFromFileLocked() {
if (!mFile.exists()) {
Log.d(TAG, "" + mFile + " doesn't exist");
@@ -1926,6 +1965,9 @@
case TAG_ENFORCING_ADMIN_AND_SIZE:
readEnforcingAdminAndSizeInner(parser);
break;
+ case TAG_MAX_POLICY_SIZE_LIMIT:
+ readMaxPolicySizeInner(parser);
+ break;
default:
Slogf.wtf(TAG, "Unknown tag " + tag);
}
@@ -2036,5 +2078,13 @@
}
mAdminPolicySize.get(admin.getUserId()).put(admin, size);
}
+
+ private void readMaxPolicySizeInner(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ if (!devicePolicySizeTrackingEnabled()) {
+ return;
+ }
+ mPolicySizeLimit = parser.getAttributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE);
+ }
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 51eee64..9bf41f9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -101,6 +101,7 @@
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_SUSPENSION;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
+import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
import static android.app.admin.DeviceAdminInfo.USES_POLICY_FORCE_LOCK;
import static android.app.admin.DeviceAdminInfo.USES_POLICY_WIPE_DATA;
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
@@ -237,6 +238,7 @@
import static android.app.admin.flags.Flags.headlessDeviceOwnerSingleUserEnabled;
import static android.app.admin.flags.Flags.policyEngineMigrationV2Enabled;
import static android.app.admin.flags.Flags.assistContentUserRestrictionEnabled;
+import static android.app.admin.flags.Flags.securityLogV2Enabled;
import static android.content.Intent.ACTION_MANAGED_PROFILE_AVAILABLE;
import static android.content.Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -3376,9 +3378,10 @@
applyProfileRestrictionsIfDeviceOwnerLocked();
// TODO: Is this the right place to trigger the migration?
- if (shouldMigrateToDevicePolicyEngine()) {
- migratePoliciesToDevicePolicyEngine();
+ if (shouldMigrateV1ToDevicePolicyEngine()) {
+ migrateV1PoliciesToDevicePolicyEngine();
}
+ migratePoliciesToPolicyEngineLocked();
}
maybeStartSecurityLogMonitorOnActivityManagerReady();
break;
@@ -3392,6 +3395,48 @@
}
}
+ @GuardedBy("getLockObject()")
+ private void maybeMigrateSecurityLoggingPolicyLocked() {
+ if (!securityLogV2Enabled() || mOwners.isSecurityLoggingMigrated()) {
+ return;
+ }
+
+ try {
+ migrateSecurityLoggingPolicyInternalLocked();
+ } catch (Exception e) {
+ Slog.e(LOG_TAG, "Failed to properly migrate security logging to policy engine", e);
+ }
+
+ Slog.i(LOG_TAG, "Marking security logging policy migration complete");
+ mOwners.markSecurityLoggingMigrated();
+ }
+
+ @GuardedBy("getLockObject()")
+ private void migrateSecurityLoggingPolicyInternalLocked() {
+ Slog.i(LOG_TAG, "Migrating security logging policy to policy engine");
+ if (!mInjector.securityLogGetLoggingEnabledProperty()) {
+ Slog.i(LOG_TAG, "Security logs not enabled, exiting");
+ return;
+ }
+
+ // Security logging can be enabled either by DO or by COPE PO.
+ final ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
+ if (admin == null) {
+ Slog.wtf(LOG_TAG, "Security logging is enabled, but no appropriate admin found");
+ return;
+ }
+
+ EnforcingAdmin enforcingAdmin =
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ admin.info.getComponent(),
+ admin.getUserHandle().getIdentifier(),
+ admin);
+ mDevicePolicyEngine.setGlobalPolicy(
+ PolicyDefinition.SECURITY_LOGGING,
+ enforcingAdmin,
+ new BooleanPolicyValue(true));
+ }
+
private void applyManagedSubscriptionsPolicyIfRequired() {
int copeProfileUserId = getOrganizationOwnedProfileUserId();
// This policy is relevant only for COPE devices.
@@ -9480,7 +9525,11 @@
private int getHeadlessDeviceOwnerMode() {
synchronized (getLockObject()) {
- return getDeviceOwnerAdminLocked().info.getHeadlessDeviceOwnerMode();
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ if (deviceOwner == null) {
+ return HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
+ }
+ return deviceOwner.info.getHeadlessDeviceOwnerMode();
}
}
@@ -11998,8 +12047,10 @@
}
if (packageList != null) {
- for (String pkg : packageList) {
- PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
+ if (!devicePolicySizeTrackingEnabled()) {
+ for (String pkg : packageList) {
+ PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
+ }
}
List<InputMethodInfo> enabledImes = mInjector.binderWithCleanCallingIdentity(() ->
@@ -12235,17 +12286,18 @@
}
final CallerIdentity caller = getCallerIdentity(admin);
+ // Only allow the system user to use this method
+ Preconditions.checkCallAuthorization(caller.getUserHandle().isSystem(),
+ "createAndManageUser was called from non-system user");
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_CREATE_AND_MANAGE_USER);
+
if (headlessDeviceOwnerSingleUserEnabled()) {
// Block this method if the device is in headless main user mode
Preconditions.checkCallAuthorization(
getHeadlessDeviceOwnerMode() != HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER,
"createAndManageUser was called while in headless single user mode");
}
- // Only allow the system user to use this method
- Preconditions.checkCallAuthorization(caller.getUserHandle().isSystem(),
- "createAndManageUser was called from non-system user");
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
- checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_CREATE_AND_MANAGE_USER);
final boolean ephemeral = (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0;
final boolean demo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0
@@ -14318,8 +14370,10 @@
public void setLockTaskPackages(ComponentName who, String callerPackageName, String[] packages)
throws SecurityException {
Objects.requireNonNull(packages, "packages is null");
- for (String pkg : packages) {
- PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
+ if (!devicePolicySizeTrackingEnabled()) {
+ for (String pkg : packages) {
+ PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
+ }
}
CallerIdentity caller = getCallerIdentity(who, callerPackageName);
@@ -15721,6 +15775,11 @@
return enforcingUsers;
}
+ @Override
+ public void enforceSecurityLoggingPolicy(boolean enabled) {
+ enforceLoggingPolicy(enabled);
+ }
+
private List<EnforcingUser> getEnforcingUsers(Set<EnforcingAdmin> admins) {
List<EnforcingUser> enforcingUsers = new ArrayList();
ComponentName deviceOwner = mOwners.getDeviceOwnerComponent();
@@ -15738,6 +15797,20 @@
}
}
+ private void enforceLoggingPolicy(boolean securityLoggingEnabled) {
+ Slogf.i(LOG_TAG, "Enforcing security logging, securityLoggingEnabled: %b",
+ securityLoggingEnabled);
+ SecurityLog.setLoggingEnabledProperty(securityLoggingEnabled);
+ if (securityLoggingEnabled) {
+ mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
+ synchronized (getLockObject()) {
+ maybePauseDeviceWideLoggingLocked();
+ }
+ } else {
+ mSecurityLogMonitor.stop();
+ }
+ }
+
private Intent createShowAdminSupportIntent(int userId) {
// This method is called with AMS lock held, so don't take DPMS lock
final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
@@ -17586,19 +17659,32 @@
}
@Override
- public void setSecurityLoggingEnabled(ComponentName admin, String packageName,
+ public void setSecurityLoggingEnabled(ComponentName who, String packageName,
boolean enabled) {
if (!mHasFeature) {
return;
}
- final CallerIdentity caller = getCallerIdentity(admin, packageName);
+ final CallerIdentity caller = getCallerIdentity(who, packageName);
- synchronized (getLockObject()) {
- if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
- UserHandle.USER_ALL);
+ if (securityLogV2Enabled()) {
+ EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+ caller.getPackageName(),
+ caller.getUserId());
+ if (enabled) {
+ mDevicePolicyEngine.setGlobalPolicy(
+ PolicyDefinition.SECURITY_LOGGING,
+ admin,
+ new BooleanPolicyValue(true));
} else {
- if (admin != null) {
+ mDevicePolicyEngine.removeGlobalPolicy(
+ PolicyDefinition.SECURITY_LOGGING,
+ admin);
+ }
+ } else {
+ synchronized (getLockObject()) {
+ if (who != null) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(caller)
|| isDefaultDeviceOwner(caller));
@@ -17607,17 +17693,17 @@
Preconditions.checkCallAuthorization(
isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
}
- }
- if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
- return;
- }
- mInjector.securityLogSetLoggingEnabledProperty(enabled);
- if (enabled) {
- mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
- maybePauseDeviceWideLoggingLocked();
- } else {
- mSecurityLogMonitor.stop();
+ if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
+ return;
+ }
+ mInjector.securityLogSetLoggingEnabledProperty(enabled);
+ if (enabled) {
+ mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
+ maybePauseDeviceWideLoggingLocked();
+ } else {
+ mSecurityLogMonitor.stop();
+ }
}
}
DevicePolicyEventLogger
@@ -17633,26 +17719,36 @@
return false;
}
- synchronized (getLockObject()) {
- if (!isSystemUid(getCallerIdentity())) {
- final CallerIdentity caller = getCallerIdentity(admin, packageName);
- if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
- caller.getPackageName(), UserHandle.USER_ALL);
- } else {
- if (admin != null) {
- Preconditions.checkCallAuthorization(
- isProfileOwnerOfOrganizationOwnedDevice(caller)
- || isDefaultDeviceOwner(caller));
- } else {
- // A delegate app passes a null admin component, which is expected
- Preconditions.checkCallAuthorization(
- isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
- }
- }
- }
+ final CallerIdentity caller = getCallerIdentity(admin, packageName);
+ if (isSystemUid(caller)) {
+ // Settings uses this for privacy transparency.
+ // TODO: create a separate @hidden API for settings.
return mInjector.securityLogGetLoggingEnabledProperty();
}
+
+ if (securityLogV2Enabled()) {
+ final EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+ caller.getPackageName(),
+ caller.getUserId());
+ final Boolean policy = mDevicePolicyEngine.getGlobalPolicySetByAdmin(
+ PolicyDefinition.SECURITY_LOGGING, enforcingAdmin);
+ return Boolean.TRUE.equals(policy);
+ } else {
+ synchronized (getLockObject()) {
+ if (admin != null) {
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(caller)
+ || isDefaultDeviceOwner(caller));
+ } else {
+ // A delegate app passes a null admin component, which is expected
+ Preconditions.checkCallAuthorization(
+ isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
+ }
+ return mInjector.securityLogGetLoggingEnabledProperty();
+ }
+ }
}
private void recordSecurityLogRetrievalTime() {
@@ -17727,17 +17823,32 @@
}
final CallerIdentity caller = getCallerIdentity(admin, packageName);
- if (isPermissionCheckFlagEnabled()) {
- Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
- || areAllUsersAffiliatedWithDeviceLocked());
- enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
- UserHandle.USER_ALL);
+ if (securityLogV2Enabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+ caller.getPackageName(),
+ caller.getUserId());
+
+ synchronized (getLockObject()) {
+ Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
+ || areAllUsersAffiliatedWithDeviceLocked());
+ }
+
+ Boolean policy = mDevicePolicyEngine.getGlobalPolicySetByAdmin(
+ PolicyDefinition.SECURITY_LOGGING, enforcingAdmin);
+
+ if (!Boolean.TRUE.equals(policy)) {
+ Slogf.e(LOG_TAG, "%s hasn't enabled security logging but tries to retrieve logs",
+ caller.getPackageName());
+ return null;
+ }
} else {
if (admin != null) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(caller)
- || isDefaultDeviceOwner(caller));
+ || isDefaultDeviceOwner(caller));
} else {
// A delegate app passes a null admin component, which is expected
Preconditions.checkCallAuthorization(
@@ -17745,10 +17856,10 @@
}
Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
|| areAllUsersAffiliatedWithDeviceLocked());
- }
- if (!mInjector.securityLogGetLoggingEnabledProperty()) {
- return null;
+ if (!mInjector.securityLogGetLoggingEnabledProperty()) {
+ return null;
+ }
}
recordSecurityLogRetrievalTime();
@@ -17758,7 +17869,7 @@
.createEvent(DevicePolicyEnums.RETRIEVE_SECURITY_LOGS)
.setAdmin(caller.getPackageName())
.write();
- return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
+ return logs != null ? new ParceledListSlice<>(logs) : null;
}
@Override
@@ -23477,10 +23588,10 @@
hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
return mInjector.binderWithCleanCallingIdentity(() -> {
boolean canForceMigration = forceMigration && !hasNonTestOnlyActiveAdmins();
- if (!canForceMigration && !shouldMigrateToDevicePolicyEngine()) {
+ if (!canForceMigration && !shouldMigrateV1ToDevicePolicyEngine()) {
return false;
}
- return migratePoliciesToDevicePolicyEngine();
+ return migrateV1PoliciesToDevicePolicyEngine();
});
}
@@ -23503,14 +23614,15 @@
});
}
- private boolean shouldMigrateToDevicePolicyEngine() {
+ private boolean shouldMigrateV1ToDevicePolicyEngine() {
return mInjector.binderWithCleanCallingIdentity(() -> !mOwners.isMigratedToPolicyEngine());
}
/**
+ * Migrates the initial set of policies to use policy engine.
* @return {@code true} if policies were migrated successfully, {@code false} otherwise.
*/
- private boolean migratePoliciesToDevicePolicyEngine() {
+ private boolean migrateV1PoliciesToDevicePolicyEngine() {
return mInjector.binderWithCleanCallingIdentity(() -> {
try {
synchronized (getLockObject()) {
@@ -23537,6 +23649,14 @@
});
}
+ /**
+ * Migrates the rest of policies to use policy engine.
+ */
+ @GuardedBy("getLockObject()")
+ private void migratePoliciesToPolicyEngineLocked() {
+ maybeMigrateSecurityLoggingPolicyLocked();
+ }
+
private void migrateAutoTimezonePolicy() {
Slogf.i(LOG_TAG, "Skipping Migration of AUTO_TIMEZONE policy to device policy engine,"
+ "as no way to identify if the value was set by the admin or the user.");
@@ -23965,5 +24085,30 @@
}
return adminOwnedSubscriptions;
});
+
+ }
+
+ @Override
+ public void setMaxPolicyStorageLimit(String callerPackageName, int storageLimit) {
+ if (!devicePolicySizeTrackingEnabled()) {
+ return;
+ }
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
+ enforcePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, caller.getPackageName(),
+ caller.getUserId());
+
+ mDevicePolicyEngine.setMaxPolicyStorageLimit(storageLimit);
+ }
+
+ @Override
+ public int getMaxPolicyStorageLimit(String callerPackageName) {
+ if (!devicePolicySizeTrackingEnabled()) {
+ return -1;
+ }
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
+ enforcePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, caller.getPackageName(),
+ caller.getUserId());
+
+ return mDevicePolicyEngine.getMaxPolicyStorageLimit();
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index bb275e45..c5a9888 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -616,6 +616,19 @@
}
}
+ void markSecurityLoggingMigrated() {
+ synchronized (mData) {
+ mData.mSecurityLoggingMigrated = true;
+ mData.writeDeviceOwner();
+ }
+ }
+
+ boolean isSecurityLoggingMigrated() {
+ synchronized (mData) {
+ return mData.mSecurityLoggingMigrated;
+ }
+ }
+
@GuardedBy("mData")
void pushToAppOpsLocked() {
if (!mSystemReady) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
index 37d4f95..d9fef10 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
@@ -16,6 +16,7 @@
package com.android.server.devicepolicy;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+import static android.app.admin.flags.Flags.securityLogV2Enabled;
import android.annotation.Nullable;
import android.app.admin.SystemUpdateInfo;
@@ -86,6 +87,7 @@
private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value";
private static final String ATTR_MIGRATED_TO_POLICY_ENGINE = "migratedToPolicyEngine";
+ private static final String ATTR_SECURITY_LOG_MIGRATED = "securityLogMigrated";
// Internal state for the device owner package.
OwnerInfo mDeviceOwner;
@@ -113,6 +115,7 @@
private final PolicyPathProvider mPathProvider;
boolean mMigratedToPolicyEngine = false;
+ boolean mSecurityLoggingMigrated = false;
OwnersData(PolicyPathProvider pathProvider) {
mPathProvider = pathProvider;
@@ -397,6 +400,9 @@
out.startTag(null, TAG_POLICY_ENGINE_MIGRATION);
out.attributeBoolean(null, ATTR_MIGRATED_TO_POLICY_ENGINE, mMigratedToPolicyEngine);
+ if (securityLogV2Enabled()) {
+ out.attributeBoolean(null, ATTR_SECURITY_LOG_MIGRATED, mSecurityLoggingMigrated);
+ }
out.endTag(null, TAG_POLICY_ENGINE_MIGRATION);
}
@@ -457,6 +463,8 @@
case TAG_POLICY_ENGINE_MIGRATION:
mMigratedToPolicyEngine = parser.getAttributeBoolean(
null, ATTR_MIGRATED_TO_POLICY_ENGINE, false);
+ mSecurityLoggingMigrated = securityLogV2Enabled()
+ && parser.getAttributeBoolean(null, ATTR_SECURITY_LOG_MIGRATED, false);
break;
default:
Slog.e(TAG, "Unexpected tag: " + tag);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index b09908e..3474db3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -134,6 +134,13 @@
permissionName));
}
+ static PolicyDefinition<Boolean> SECURITY_LOGGING = new PolicyDefinition<>(
+ new NoArgsPolicyKey(DevicePolicyIdentifiers.SECURITY_LOGGING_POLICY),
+ TRUE_MORE_RESTRICTIVE,
+ POLICY_FLAG_GLOBAL_ONLY_POLICY,
+ PolicyEnforcerCallbacks::enforceSecurityLogging,
+ new BooleanPolicySerializer());
+
static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.LOCK_TASK_POLICY),
new TopPriority<>(List.of(
@@ -356,6 +363,8 @@
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
GENERIC_PERMISSION_GRANT);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.SECURITY_LOGGING_POLICY,
+ SECURITY_LOGGING);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
USER_CONTROLLED_DISABLED_PACKAGES);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 506dbe8..4aaefa6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -21,6 +21,7 @@
import android.app.AppGlobals;
import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IntentFilterPolicyKey;
import android.app.admin.LockTaskPolicy;
import android.app.admin.PackagePermissionPolicyKey;
@@ -127,6 +128,14 @@
}
}
+ static boolean enforceSecurityLogging(
+ @Nullable Boolean value, @NonNull Context context, int userId,
+ @NonNull PolicyKey policyKey) {
+ final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
+ dpmi.enforceSecurityLoggingPolicy(Boolean.TRUE.equals(value));
+ return true;
+ }
+
static boolean setLockTask(
@Nullable LockTaskPolicy policy, @NonNull Context context, int userId) {
List<String> packages = Collections.emptyList();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index 939a3dc..7a4454b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -101,6 +101,10 @@
/** Minimum time between forced fetch attempts. */
private static final long FORCE_FETCH_THROTTLE_NS = TimeUnit.SECONDS.toNanos(10);
+ /**
+ * Monitor thread is not null iff SecurityLogMonitor is running, i.e. started and not stopped.
+ * Pausing doesn't change it.
+ */
@GuardedBy("mLock")
private Thread mMonitorThread = null;
@GuardedBy("mLock")
@@ -147,7 +151,6 @@
void start(int enabledUser) {
Slog.i(TAG, "Starting security logging for user " + enabledUser);
mEnabledUser = enabledUser;
- SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
mLock.lock();
try {
if (mMonitorThread == null) {
@@ -160,6 +163,11 @@
mMonitorThread = new Thread(this);
mMonitorThread.start();
+
+ SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
+ Slog.i(TAG, "Security log monitor thread started");
+ } else {
+ Slog.i(TAG, "Security log monitor thread is already running");
}
} finally {
mLock.unlock();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index d50affb..a0f2395 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -18,7 +18,6 @@
import static android.content.pm.ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED;
import static android.content.pm.ShortcutInfo.DISABLED_REASON_NOT_DISABLED;
import static android.content.pm.ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
-import static android.content.pm.ShortcutInfo.DISABLED_REASON_VERSION_LOWER;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyOrNull;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyStringOrNull;
@@ -78,7 +77,6 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
-import android.content.pm.LauncherApps.PinItemRequest;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageInfo;
import android.content.pm.ShortcutInfo;
@@ -4844,7 +4842,7 @@
doReturn(expected != DISABLED_REASON_SIGNATURE_MISMATCH).when(
mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), anyString());
- assertEquals(expected, spi.canRestoreTo(mService, pi, anyVersionOk));
+ assertEquals(expected, spi.canRestoreTo(mService, pi, true));
}
public void testCanRestoreTo() {
@@ -4872,7 +4870,6 @@
checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x");
checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x", "y");
checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x");
- checkCanRestoreTo(DISABLED_REASON_VERSION_LOWER, spi1, false, 9, true, "sig1");
// Any version okay.
checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, true, 9, true, "sig1");
@@ -5983,14 +5980,6 @@
});
}
- public void testBackupAndRestore_publisherLowerVersion() {
- prepareForBackupTest();
-
- addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
-
- checkBackupAndRestore_publisherNotRestored(ShortcutInfo.DISABLED_REASON_VERSION_LOWER);
- }
-
public void testBackupAndRestore_publisherWrongSignature() {
prepareForBackupTest();
@@ -6626,252 +6615,6 @@
});
}
-
- /**
- * Restored to a lower version with no manifest shortcuts. All shortcuts are now invisible,
- * and all calls from the publisher should ignore them.
- */
- public void testBackupAndRestore_disabledShortcutsAreIgnored() {
- // Publish two manifest shortcuts.
- addManifestShortcutResource(
- new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
- R.xml.shortcut_5_altalt);
- updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(mServiceContext,
- genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
-
- runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertTrue(mManager.setDynamicShortcuts(list(
- makeShortcutWithShortLabel("s1", "original-title"),
- makeShortcut("s2"), makeShortcut("s3"))));
- });
-
- // Pin from launcher 1.
- runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- list("ms1", "ms2", "ms3", "ms4", "s1", "s2"), HANDLE_USER_0);
- });
-
- doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
- any(byte[].class), anyString());
-
- backupAndRestore();
-
- // Lower the version and remove the manifest shortcuts.
- addManifestShortcutResource(
- new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
- R.xml.shortcut_0);
- addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
-
- // When re-installing the app, the manifest shortcut should be re-published.
- mService.mPackageMonitor.onReceive(mServiceContext,
- genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
- mService.mPackageMonitor.onReceive(mServiceContext,
- genPackageAddIntent(LAUNCHER_1, USER_0));
-
- // No shortcuts should be visible to the publisher.
- runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertWith(getCallerVisibleShortcuts())
- .isEmpty();
- });
-
- final Runnable checkAllDisabledForLauncher = () -> {
- runWithCaller(LAUNCHER_1, USER_0, () -> {
- assertWith(getShortcutAsLauncher(USER_0))
- .areAllPinned()
- .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2")
- .areAllDisabled()
- .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_VERSION_LOWER)
-
- .forShortcutWithId("s1", si -> {
- assertEquals("original-title", si.getShortLabel());
- })
- .forShortcutWithId("ms1", si -> {
- assertEquals("string-com.android.test.1-user:0-res:"
- + R.string.shortcut_title1 + "/en"
- , si.getShortLabel());
- })
- .forShortcutWithId("ms2", si -> {
- assertEquals("string-com.android.test.1-user:0-res:"
- + R.string.shortcut_title2 + "/en"
- , si.getShortLabel());
- })
- .forShortcutWithId("ms3", si -> {
- assertEquals("string-com.android.test.1-user:0-res:"
- + R.string.shortcut_title1 + "/en"
- , si.getShortLabel());
- assertEquals("string-com.android.test.1-user:0-res:"
- + R.string.shortcut_title2 + "/en"
- , si.getLongLabel());
- })
- .forShortcutWithId("ms4", si -> {
- assertEquals("string-com.android.test.1-user:0-res:"
- + R.string.shortcut_title2 + "/en"
- , si.getShortLabel());
- assertEquals("string-com.android.test.1-user:0-res:"
- + R.string.shortcut_title2 + "/en"
- , si.getLongLabel());
- });
- });
- };
-
- checkAllDisabledForLauncher.run();
-
- runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
-
- makeCallerForeground(); // CALLING_PACKAGE_1 is now in the foreground.
-
- // All changing API calls should be ignored.
-
- getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
- checkAllDisabledForLauncher.run();
-
- getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
- checkAllDisabledForLauncher.run();
-
- getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
- checkAllDisabledForLauncher.run();
-
- getManager().removeAllDynamicShortcuts();
- getManager().removeDynamicShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
- checkAllDisabledForLauncher.run();
-
- getManager().updateShortcuts(list(makeShortcutWithShortLabel("s1", "new-title")));
- checkAllDisabledForLauncher.run();
-
-
- // Add a shortcut -- even though ms1 was immutable, it will succeed.
- assertTrue(getManager().addDynamicShortcuts(list(
- makeShortcutWithShortLabel("ms1", "original-title"))));
-
- runWithCaller(LAUNCHER_1, USER_0, () -> {
- assertWith(getShortcutAsLauncher(USER_0))
- .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2")
-
- .selectByIds("ms1")
- .areAllEnabled()
- .areAllDynamic()
- .areAllPinned()
- .forAllShortcuts(si -> {
- assertEquals("original-title", si.getShortLabel());
- })
-
- // The rest still exist and disabled.
- .revertToOriginalList()
- .selectByIds("ms2", "ms3", "ms4", "s1", "s2")
- .areAllDisabled()
- .areAllPinned()
- ;
- });
-
- assertTrue(getManager().setDynamicShortcuts(list(
- makeShortcutWithShortLabel("ms2", "new-title-2"))));
-
- runWithCaller(LAUNCHER_1, USER_0, () -> {
- assertWith(getShortcutAsLauncher(USER_0))
- .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2")
-
- .selectByIds("ms1")
- .areAllEnabled()
- .areAllNotDynamic() // ms1 was not in the list, so no longer dynamic.
- .areAllPinned()
- .areAllMutable()
- .forAllShortcuts(si -> {
- assertEquals("original-title", si.getShortLabel());
- })
-
- .revertToOriginalList()
- .selectByIds("ms2")
- .areAllEnabled()
- .areAllDynamic()
- .areAllPinned()
- .areAllMutable()
- .forAllShortcuts(si -> {
- assertEquals("new-title-2", si.getShortLabel());
- })
-
- // The rest still exist and disabled.
- .revertToOriginalList()
- .selectByIds("ms3", "ms4", "s1", "s2")
- .areAllDisabled()
- .areAllPinned()
- ;
- });
-
- // Prepare for requestPinShortcut().
- setDefaultLauncher(USER_0, LAUNCHER_1);
- mPinConfirmActivityFetcher = (packageName, userId) ->
- new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS);
-
- mManager.requestPinShortcut(
- makeShortcutWithShortLabel("ms3", "new-title-3"),
- /*PendingIntent=*/ null);
-
- // Note this was pinned, so it'll be accepted right away.
- runWithCaller(LAUNCHER_1, USER_0, () -> {
- assertWith(getShortcutAsLauncher(USER_0))
- .selectByIds("ms3")
- .areAllEnabled()
- .areAllNotDynamic()
- .areAllPinned()
- .areAllMutable()
- .forAllShortcuts(si -> {
- assertEquals("new-title-3", si.getShortLabel());
- // The new one replaces the old manifest shortcut, so the long label
- // should be gone now.
- assertNull(si.getLongLabel());
- });
- });
-
- // Now, change the launcher to launcher2, and request pin again.
- setDefaultLauncher(USER_0, LAUNCHER_2);
-
- reset(mServiceContext);
-
- assertTrue(mManager.isRequestPinShortcutSupported());
- mManager.requestPinShortcut(
- makeShortcutWithShortLabel("ms4", "new-title-4"),
- /*PendingIntent=*/ null);
-
- // Initially there should be no pinned shortcuts for L2.
- runWithCaller(LAUNCHER_2, USER_0, () -> {
- assertWith(getShortcutAsLauncher(USER_0))
- .selectPinned()
- .isEmpty();
-
- final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
-
- verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
-
- assertEquals(LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT,
- intent.getValue().getAction());
- assertEquals(LAUNCHER_2, intent.getValue().getComponent().getPackageName());
-
- // Check the request object.
- final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
-
- assertNotNull(request);
- assertEquals(PinItemRequest.REQUEST_TYPE_SHORTCUT, request.getRequestType());
-
- assertWith(request.getShortcutInfo())
- .haveIds("ms4")
- .areAllOrphan()
- .forAllShortcuts(si -> {
- assertEquals("new-title-4", si.getShortLabel());
- // The new one replaces the old manifest shortcut, so the long label
- // should be gone now.
- assertNull(si.getLongLabel());
- });
- assertTrue(request.accept());
-
- assertWith(getShortcutAsLauncher(USER_0))
- .selectPinned()
- .haveIds("ms4")
- .areAllEnabled();
- });
- });
- }
-
/**
* Test for restoring the pre-P backup format.
*/
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index 5eb76e3..f077914 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -22,6 +22,9 @@
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_ONGOING_EVENT;
+import static android.app.Notification.VISIBILITY_PRIVATE;
+import static android.app.Notification.VISIBILITY_PUBLIC;
+import static android.app.Notification.VISIBILITY_SECRET;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static com.android.server.notification.GroupHelper.BASE_FLAGS;
@@ -81,6 +84,8 @@
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+ private final int DEFAULT_VISIBILITY = VISIBILITY_PRIVATE;
+
private @Mock GroupHelper.Callback mCallback;
private @Mock PackageManager mPackageManager;
@@ -127,7 +132,7 @@
}
private NotificationAttributes getNotificationAttributes(int flags) {
- return new NotificationAttributes(flags, mSmallIcon, COLOR_DEFAULT);
+ return new NotificationAttributes(flags, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY);
}
@Test
@@ -704,7 +709,8 @@
final Icon icon = mock(Icon.class);
when(icon.sameAs(icon)).thenReturn(true);
final int iconColor = Color.BLUE;
- final NotificationAttributes attr = new NotificationAttributes(BASE_FLAGS, icon, iconColor);
+ final NotificationAttributes attr = new NotificationAttributes(BASE_FLAGS, icon, iconColor,
+ DEFAULT_VISIBILITY);
// Add notifications with same icon and color
for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
@@ -744,7 +750,7 @@
doReturn(monochromeIcon).when(groupHelper).getMonochromeAppIcon(eq(pkg));
final NotificationAttributes initialAttr = new NotificationAttributes(BASE_FLAGS,
- initialIcon, initialIconColor);
+ initialIcon, initialIconColor, DEFAULT_VISIBILITY);
// Add notifications with same icon and color
for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
@@ -769,7 +775,42 @@
// Summary should be updated to the default color and the icon to the monochrome icon
NotificationAttributes newAttr = new NotificationAttributes(BASE_FLAGS, monochromeIcon,
- COLOR_DEFAULT);
+ COLOR_DEFAULT, DEFAULT_VISIBILITY);
+ verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), eq(newAttr));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAddSummary_diffVisibility() {
+ final String pkg = "package";
+ final Icon icon = mock(Icon.class);
+ when(icon.sameAs(icon)).thenReturn(true);
+ final int iconColor = Color.BLUE;
+ final NotificationAttributes attr = new NotificationAttributes(BASE_FLAGS, icon, iconColor,
+ VISIBILITY_PRIVATE);
+
+ // Add notifications with same icon and color and default visibility (private)
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, null,
+ icon, iconColor);
+ mGroupHelper.onNotificationPosted(sbn, false);
+ }
+ // Check that the summary has private visibility
+ verify(mCallback, times(1)).addAutoGroupSummary(
+ anyInt(), eq(pkg), anyString(), eq(attr));
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
+
+ // After auto-grouping, add new notification with public visibility
+ StatusBarNotification sbn = getSbn(pkg, AUTOGROUP_AT_COUNT,
+ String.valueOf(AUTOGROUP_AT_COUNT), UserHandle.SYSTEM, null, icon, iconColor);
+ sbn.getNotification().visibility = VISIBILITY_PUBLIC;
+ mGroupHelper.onNotificationPosted(sbn, true);
+
+ // Check that the summary visibility was updated
+ NotificationAttributes newAttr = new NotificationAttributes(BASE_FLAGS, icon, iconColor,
+ VISIBILITY_PUBLIC);
verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), eq(newAttr));
}
@@ -781,7 +822,7 @@
when(initialIcon.sameAs(initialIcon)).thenReturn(true);
final int initialIconColor = Color.BLUE;
final NotificationAttributes initialAttr = new NotificationAttributes(
- GroupHelper.FLAG_INVALID, initialIcon, initialIconColor);
+ GroupHelper.FLAG_INVALID, initialIcon, initialIconColor, DEFAULT_VISIBILITY);
// Add AUTOGROUP_AT_COUNT-1 notifications with same icon and color
ArrayList<StatusBarNotification> notifications = new ArrayList<>();
@@ -817,11 +858,12 @@
// Create notifications with the same icon
List<NotificationAttributes> childrenAttr = new ArrayList<>();
for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
- childrenAttr.add(new NotificationAttributes(0, icon, COLOR_DEFAULT));
+ childrenAttr.add(new NotificationAttributes(0, icon, COLOR_DEFAULT,
+ DEFAULT_VISIBILITY));
}
//Check that the generated summary icon is the same as the child notifications'
- Icon summaryIcon = mGroupHelper.getAutobundledSummaryIconAndColor(pkg, childrenAttr).icon;
+ Icon summaryIcon = mGroupHelper.getAutobundledSummaryAttributes(pkg, childrenAttr).icon;
assertThat(summaryIcon).isEqualTo(icon);
}
@@ -837,11 +879,12 @@
// Create notifications with different icons
List<NotificationAttributes> childrenAttr = new ArrayList<>();
for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
- childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), COLOR_DEFAULT));
+ childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), COLOR_DEFAULT,
+ DEFAULT_VISIBILITY));
}
// Check that the generated summary icon is the monochrome icon
- Icon summaryIcon = groupHelper.getAutobundledSummaryIconAndColor(pkg, childrenAttr).icon;
+ Icon summaryIcon = groupHelper.getAutobundledSummaryAttributes(pkg, childrenAttr).icon;
assertThat(summaryIcon).isEqualTo(monochromeIcon);
}
@@ -853,11 +896,12 @@
// Create notifications with the same icon color
List<NotificationAttributes> childrenAttr = new ArrayList<>();
for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
- childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor));
+ childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor,
+ DEFAULT_VISIBILITY));
}
// Check that the generated summary icon color is the same as the child notifications'
- int summaryIconColor = mGroupHelper.getAutobundledSummaryIconAndColor(pkg,
+ int summaryIconColor = mGroupHelper.getAutobundledSummaryAttributes(pkg,
childrenAttr).iconColor;
assertThat(summaryIconColor).isEqualTo(iconColor);
}
@@ -869,17 +913,62 @@
// Create notifications with different icon colors
List<NotificationAttributes> childrenAttr = new ArrayList<>();
for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
- childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), i));
+ childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), i,
+ DEFAULT_VISIBILITY));
}
// Check that the generated summary icon color is the default color
- int summaryIconColor = mGroupHelper.getAutobundledSummaryIconAndColor(pkg,
+ int summaryIconColor = mGroupHelper.getAutobundledSummaryAttributes(pkg,
childrenAttr).iconColor;
assertThat(summaryIconColor).isEqualTo(Notification.COLOR_DEFAULT);
}
@Test
@EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAutobundledSummaryVisibility_hasPublicChildren() {
+ final String pkg = "package";
+ final int iconColor = Color.BLUE;
+ // Create notifications with private and public visibility
+ List<NotificationAttributes> childrenAttr = new ArrayList<>();
+ childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor,
+ VISIBILITY_PUBLIC));
+ for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+ childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor,
+ VISIBILITY_PRIVATE));
+ }
+
+ // Check that the generated summary visibility is public
+ int summaryVisibility = mGroupHelper.getAutobundledSummaryAttributes(pkg,
+ childrenAttr).visibility;
+ assertThat(summaryVisibility).isEqualTo(VISIBILITY_PUBLIC);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAutobundledSummaryVisibility_noPublicChildren() {
+ final String pkg = "package";
+ final int iconColor = Color.BLUE;
+ int visibility = VISIBILITY_PRIVATE;
+ // Create notifications with either private or secret visibility
+ List<NotificationAttributes> childrenAttr = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ if (i % 2 == 0) {
+ visibility = VISIBILITY_PRIVATE;
+ } else {
+ visibility = VISIBILITY_SECRET;
+ }
+ childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor,
+ visibility));
+ }
+
+ // Check that the generated summary visibility is private
+ int summaryVisibility = mGroupHelper.getAutobundledSummaryAttributes(pkg,
+ childrenAttr).visibility;
+ assertThat(summaryVisibility).isEqualTo(VISIBILITY_PRIVATE);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
public void testMonochromeAppIcon_adaptiveIconExists() throws Exception {
final String pkg = "testPackage";
final int monochromeIconResId = 1234;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 6aacfd7..94d24a9 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -37,6 +37,7 @@
import static android.app.Notification.FLAG_ONGOING_EVENT;
import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
import static android.app.Notification.FLAG_USER_INITIATED_JOB;
+import static android.app.Notification.VISIBILITY_PRIVATE;
import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
@@ -2338,7 +2339,7 @@
mService.updateAutobundledSummaryLocked(0, "pkg",
new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
- mock(Icon.class), 0), false);
+ mock(Icon.class), 0, VISIBILITY_PRIVATE), false);
waitForIdle();
assertTrue(summary.getSbn().isOngoing());
@@ -2357,7 +2358,7 @@
mService.updateAutobundledSummaryLocked(0, "pkg",
new NotificationAttributes(GroupHelper.BASE_FLAGS,
- mock(Icon.class), 0), false);
+ mock(Icon.class), 0, VISIBILITY_PRIVATE), false);
waitForIdle();
assertFalse(summary.getSbn().isOngoing());
@@ -3479,7 +3480,8 @@
when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true);
NotificationRecord r = mService.createAutoGroupSummary(temp.getUserId(),
- temp.getSbn().getPackageName(), temp.getKey(), 0, mock(Icon.class), 0);
+ temp.getSbn().getPackageName(), temp.getKey(), 0, mock(Icon.class), 0,
+ VISIBILITY_PRIVATE);
assertThat(r.isImportanceFixed()).isTrue();
}
@@ -12215,9 +12217,10 @@
// grouphelper is a mock here, so make the calls it would make
// add summary
- mService.addNotification(mService.createAutoGroupSummary(nr1.getUserId(),
- nr1.getSbn().getPackageName(), nr1.getKey(),
- GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0));
+ mService.addNotification(
+ mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
+ nr1.getKey(), GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0,
+ VISIBILITY_PRIVATE));
// cancel both children
mBinderService.cancelNotificationWithTag(PKG, PKG, nr0.getSbn().getTag(),
@@ -12246,7 +12249,7 @@
mService.addNotification(nr1);
mService.addNotification(
mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
- nr1.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0));
+ nr1.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0, VISIBILITY_PRIVATE));
// add notifications + summary for USER_ALL
NotificationRecord nr0_all =
@@ -12259,7 +12262,7 @@
mService.addNotification(
mService.createAutoGroupSummary(nr0_all.getUserId(),
nr0_all.getSbn().getPackageName(),
- nr0_all.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0));
+ nr0_all.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0, VISIBILITY_PRIVATE));
// cancel both children for USER_ALL
mBinderService.cancelNotificationWithTag(PKG, PKG, nr0_all.getSbn().getTag(),
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index 20a0850..368a96b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -73,6 +73,8 @@
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SharedMemory;
+import android.service.voice.AlwaysOnHotwordDetector;
+import android.service.voice.HotwordAudioStream;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
import android.service.voice.HotwordDetectionServiceFailure;
@@ -81,6 +83,7 @@
import android.service.voice.IDspHotwordDetectionCallback;
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
import android.service.voice.VisualQueryDetectionServiceFailure;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
@@ -405,7 +408,83 @@
audioStream,
audioFormat,
options,
- callback);
+ callback,
+ /* shouldCloseAudioStreamWithDelayOnDetect= */ true);
+ }
+
+ void startListeningFromWearableLocked(
+ ParcelFileDescriptor audioStream,
+ AudioFormat audioFormat,
+ PersistableBundle options,
+ WearableHotwordDetectionCallback wearableCallback) {
+ if (DEBUG) {
+ Slog.d(TAG, "startListeningFromWearableLocked");
+ }
+ IMicrophoneHotwordDetectionVoiceInteractionCallback voiceInteractionCallback =
+ new IMicrophoneHotwordDetectionVoiceInteractionCallback() {
+ @Override
+ public void onDetected(
+ HotwordDetectedResult hotwordDetectedResult,
+ AudioFormat audioFormatFromCallback,
+ ParcelFileDescriptor audioStreamFromCallback) {
+ wearableCallback.onDetected();
+ try {
+ // This uses the DSP hotword code path to send the result to
+ // AlwaysOnHotwordDetector. DSP trigger and wearable trigger operates
+ // independently.
+ mCallback.onKeyphraseDetectedFromExternalSource(hotwordDetectedResult);
+ } catch (RemoteException ex) {
+ Slog.w(
+ TAG,
+ "RemoteException when sending HotwordDetectedResult to"
+ + " VoiceInteractionService.",
+ ex);
+ wearableCallback.onError(
+ "RemoteException when sending HotwordDetectedResult to"
+ + " VoiceInteractionService.");
+ notifyOnDetectorRemoteException();
+ }
+
+ // Close the local copies of the file descriptors after sending them to
+ // another process.
+ for (HotwordAudioStream resultAudioStream :
+ hotwordDetectedResult.getAudioStreams()) {
+ try {
+ resultAudioStream.getAudioStreamParcelFileDescriptor().close();
+ } catch (IOException ex) {
+ Slog.i(
+ TAG,
+ "Unable to close audio stream parcel file descriptor,",
+ ex);
+ }
+ }
+ }
+
+ @Override
+ public void onHotwordDetectionServiceFailure(
+ HotwordDetectionServiceFailure hotwordDetectionServiceFailure) {
+ wearableCallback.onError(
+ "onHotwordDetectionServiceFailure: "
+ + hotwordDetectionServiceFailure);
+ }
+
+ @Override
+ public void onRejected(HotwordRejectedResult hotwordRejectedResult) {
+ wearableCallback.onRejected();
+ }
+
+ @Override
+ public IBinder asBinder() {
+ // This callback will only be used locally within the same process.
+ return null;
+ }
+ };
+ handleExternalSourceHotwordDetectionLocked(
+ audioStream,
+ audioFormat,
+ options,
+ voiceInteractionCallback,
+ /* shouldCloseAudioStreamWithDelayOnDetect= */ false);
}
@SuppressWarnings("GuardedBy")
@@ -413,7 +492,8 @@
ParcelFileDescriptor audioStream,
AudioFormat audioFormat,
@Nullable PersistableBundle options,
- IMicrophoneHotwordDetectionVoiceInteractionCallback callback) {
+ IMicrophoneHotwordDetectionVoiceInteractionCallback callback,
+ boolean shouldCloseAudioStreamWithDelayOnDetect) {
if (DEBUG) {
Slog.d(TAG, "#handleExternalSourceHotwordDetectionLocked");
}
@@ -482,12 +562,22 @@
// TODO: what if we cancelled and started a new one?
mRemoteDetectionService.run(
service -> {
+ PersistableBundle optionsToSend = options;
+ if (android.app.wearable.Flags.enableHotwordWearableSensingApi()) {
+ if (optionsToSend == null) {
+ optionsToSend = new PersistableBundle();
+ }
+ optionsToSend.putBoolean(
+ HotwordDetectionService
+ .KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK,
+ shouldCloseAudioStreamWithDelayOnDetect);
+ }
service.detectFromMicrophoneSource(
serviceAudioSource,
// TODO: consider making a proxy callback + copy of audio format
AUDIO_SOURCE_EXTERNAL,
audioFormat,
- options,
+ optionsToSend,
new IDspHotwordDetectionCallback.Stub() {
@Override
public void onRejected(HotwordRejectedResult result)
@@ -530,18 +620,23 @@
getDetectorType(),
METRICS_EXTERNAL_SOURCE_DETECTED,
mVoiceInteractionServiceUid);
- mScheduledExecutorService.schedule(
- () -> {
- bestEffortClose(serviceAudioSink, audioSource);
- },
- EXTERNAL_HOTWORD_CLEANUP_MILLIS,
- TimeUnit.MILLISECONDS);
-
+ if (shouldCloseAudioStreamWithDelayOnDetect) {
+ mScheduledExecutorService.schedule(
+ () -> {
+ bestEffortClose(
+ serviceAudioSink, audioSource);
+ },
+ EXTERNAL_HOTWORD_CLEANUP_MILLIS,
+ TimeUnit.MILLISECONDS);
+ }
try {
enforcePermissionsForDataDelivery();
} catch (SecurityException e) {
- Slog.w(TAG, "Ignoring #onDetected due to a "
- + "SecurityException", e);
+ Slog.w(
+ TAG,
+ "Ignoring #onDetected due to a "
+ + "SecurityException",
+ e);
HotwordMetricsLogger.writeDetectorEvent(
getDetectorType(),
EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION,
@@ -560,11 +655,16 @@
}
HotwordDetectedResult newResult;
try {
- newResult = mHotwordAudioStreamCopier
- .startCopyingAudioStreams(triggerResult);
+ newResult =
+ mHotwordAudioStreamCopier
+ .startCopyingAudioStreams(
+ triggerResult);
} catch (IOException e) {
- Slog.w(TAG, "Ignoring #onDetected due to a "
- + "IOException", e);
+ Slog.w(
+ TAG,
+ "Ignoring #onDetected due to a "
+ + "IOException",
+ e);
// TODO: Write event
try {
callback.onHotwordDetectionServiceFailure(
@@ -578,7 +678,12 @@
return;
}
try {
- callback.onDetected(newResult, /* audioFormat= */ null,
+ // The ParcelFileDescriptors in newResult might be
+ // closed after this call. Parcelling newResult can
+ // throw an exception
+ callback.onDetected(
+ newResult,
+ /* audioFormat= */ null,
/* audioStream= */ null);
} catch (RemoteException e) {
notifyOnDetectorRemoteException();
@@ -588,8 +693,7 @@
+ HotwordDetectedResult.getUsageSize(newResult)
+ " bits from hotword trusted process");
if (mDebugHotwordLogging) {
- Slog.i(TAG,
- "Egressed detected result: " + newResult);
+ Slog.i(TAG, "Egressed detected result: " + newResult);
}
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index cd390a1..f1f5458 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -63,6 +63,7 @@
import android.service.voice.VisualQueryDetectionService;
import android.service.voice.VisualQueryDetectionServiceFailure;
import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
import android.speech.IRecognitionServiceManager;
import android.util.Slog;
import android.util.SparseArray;
@@ -451,6 +452,25 @@
session.startListeningFromExternalSourceLocked(audioStream, audioFormat, options, callback);
}
+ public void startListeningFromWearableLocked(
+ ParcelFileDescriptor audioStream,
+ AudioFormat audioFormat,
+ PersistableBundle options,
+ WearableHotwordDetectionCallback callback) {
+ if (DEBUG) {
+ Slog.d(TAG, "startListeningFromWearableLocked");
+ }
+ DetectorSession trustedSession = getDspTrustedHotwordDetectorSessionLocked();
+ if (trustedSession == null) {
+ callback.onError(
+ "Unable to start listening from wearable because the trusted hotword detection"
+ + " session is not available.");
+ return;
+ }
+ trustedSession.startListeningFromWearableLocked(
+ audioStream, audioFormat, options, callback);
+ }
+
/**
* This method is only used by SoftwareHotwordDetector.
*/
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 4cdec70..ecb0f96 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.voiceinteraction;
+
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
@@ -74,6 +75,7 @@
import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
import android.service.voice.VoiceInteractionSession;
@@ -319,6 +321,46 @@
mServiceStub.mRoleObserver.onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT,
UserHandle.of(userId));
}
+
+ @Override
+ public void startListeningFromWearable(
+ ParcelFileDescriptor audioStreamFromWearable,
+ AudioFormat audioFormatFromWearable,
+ PersistableBundle options,
+ ComponentName targetVisComponentName,
+ int userId,
+ WearableHotwordDetectionCallback callback) {
+ Slog.d(TAG, "#startListeningFromWearable");
+ VoiceInteractionManagerServiceImpl impl = mServiceStub.mImpl;
+ if (impl == null) {
+ callback.onError(
+ "Unable to start listening from wearable because the service impl is"
+ + " null.");
+ return;
+ }
+ if (targetVisComponentName != null && !targetVisComponentName.equals(impl.mComponent)) {
+ callback.onError(
+ TextUtils.formatSimple(
+ "Unable to start listening from wearable because the target"
+ + " VoiceInteractionService %s is different from the current"
+ + " VoiceInteractionService %s",
+ targetVisComponentName, impl.mComponent));
+ return;
+ }
+ if (userId != impl.mUser) {
+ callback.onError(
+ TextUtils.formatSimple(
+ "Unable to start listening from wearable because the target userId"
+ + " %s is different from the current"
+ + " VoiceInteractionManagerServiceImpl's userId %s",
+ userId, impl.mUser));
+ return;
+ }
+ synchronized (mServiceStub) {
+ impl.startListeningFromWearableLocked(
+ audioStreamFromWearable, audioFormatFromWearable, options, callback);
+ }
+ }
}
// implementation entry point and binder service
@@ -1706,7 +1748,10 @@
if (keyphrase.equals(phrase.getText())) {
ArraySet<Locale> locales = new ArraySet<>();
locales.add(phrase.getLocale());
- return new KeyphraseMetadata(phrase.getId(), phrase.getText(), locales,
+ return new KeyphraseMetadata(
+ phrase.getId(),
+ phrase.getText(),
+ locales,
phrase.getRecognitionModes());
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 7538142..84b36d5 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -65,6 +65,7 @@
import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
import android.system.OsConstants;
@@ -857,6 +858,24 @@
options, token, callback);
}
+ public void startListeningFromWearableLocked(
+ ParcelFileDescriptor audioStream,
+ AudioFormat audioFormat,
+ PersistableBundle options,
+ WearableHotwordDetectionCallback callback) {
+ if (DEBUG) {
+ Slog.d(TAG, "startListeningFromWearable");
+ }
+ if (mHotwordDetectionConnection == null) {
+ callback.onError(
+ "Unable to start listening from wearable because the hotword detection"
+ + " connection is null.");
+ return;
+ }
+ mHotwordDetectionConnection.startListeningFromWearableLocked(
+ audioStream, audioFormat, options, callback);
+ }
+
public void stopListeningFromMicLocked() {
if (DEBUG) {
Slog.d(TAG, "stopListeningFromMicLocked");
diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml
index c62db1ea..13b5f0d 100644
--- a/tests/Input/AndroidTest.xml
+++ b/tests/Input/AndroidTest.xml
@@ -4,6 +4,7 @@
-->
<configuration description="Runs Input Tests">
<option name="test-tag" value="InputTests" />
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on" />
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
index 14230fe..0fb4f90 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
@@ -42,6 +42,7 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.TextView;
+import android.window.InputTransferToken;
public class EmbeddedWindowService extends Service {
private static final String TAG = "EmbeddedWindowService";
@@ -118,7 +119,7 @@
@Override
public void attachEmbeddedSurfaceControl(SurfaceControl parentSc, int displayId,
- IBinder hostToken) {
+ InputTransferToken inputTransferToken) {
mHandler.post(() -> {
Paint paint = new Paint();
paint.setTextSize(40);
@@ -134,7 +135,7 @@
c.drawText("Remote", 250, 250, paint);
surface.unlockCanvasAndPost(c);
WindowManager wm = getSystemService(WindowManager.class);
- wm.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
+ wm.registerBatchedSurfaceControlInputReceiver(displayId, inputTransferToken,
mSurfaceControl,
Choreographer.getInstance(), event -> {
Log.d(TAG, "onInputEvent-remote " + event);
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
index 6b65b40e..e81f5f8 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
@@ -20,10 +20,12 @@
import com.android.test.viewembed.IAttachEmbeddedWindowCallback;
import android.view.WindowManager.LayoutParams;
import android.view.SurfaceControl;
+import android.window.InputTransferToken;
interface IAttachEmbeddedWindow {
void attachEmbedded(IBinder hostToken, int width, int height, in IAttachEmbeddedWindowCallback callback);
void relayout(in LayoutParams lp);
- oneway void attachEmbeddedSurfaceControl(in SurfaceControl parentSurfaceControl, int displayId, IBinder hostToken);
+ oneway void attachEmbeddedSurfaceControl(in SurfaceControl parentSurfaceControl, int displayId,
+ in InputTransferToken inputTransferToken);
oneway void tearDownEmbeddedSurfaceControl();
}
\ No newline at end of file
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
index 7330ec1..e700bc2 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
@@ -139,7 +139,7 @@
surface.unlockCanvasAndPost(c);
WindowManager wm = getSystemService(WindowManager.class);
wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
- attachedSurfaceControl.getHostToken(), mLocalSurfaceControl,
+ attachedSurfaceControl.getInputTransferToken(), mLocalSurfaceControl,
Choreographer.getInstance(), event -> {
Log.d(TAG, "onInputEvent-sc " + event);
return false;
@@ -160,7 +160,8 @@
WindowManager wm = getSystemService(WindowManager.class);
wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
- mLocalSurfaceView.getHostToken(), mLocalSurfaceView.getSurfaceControl(),
+ mLocalSurfaceView.getRootSurfaceControl().getInputTransferToken(),
+ mLocalSurfaceView.getSurfaceControl(),
Choreographer.getInstance(), event -> {
Log.d(TAG, "onInputEvent-local " + event);
return false;
@@ -210,7 +211,8 @@
}
try {
mIAttachEmbeddedWindow.attachEmbeddedSurfaceControl(mParentSurfaceControl,
- getDisplayId(), mRemoteSurfaceView.getHostToken());
+ getDisplayId(),
+ mRemoteSurfaceView.getRootSurfaceControl().getInputTransferToken());
} catch (RemoteException e) {
Log.e(TAG, "Failed to load embedded SurfaceControl", e);
}
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
index c6dd29c..30333da 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -54,6 +54,7 @@
// This library is _not_ specific to Android APIs.
java_library_host {
name: "hoststubgen-helper-runtime",
+ defaults: ["ravenwood-internal-only-visibility-java"],
srcs: [
"helper-runtime-src/**/*.java",
],
@@ -64,11 +65,11 @@
"guava",
],
jarjar_rules: "jarjar-rules.txt",
- visibility: ["//visibility:public"],
}
java_library {
name: "hoststubgen-helper-runtime.ravenwood",
+ defaults: ["ravenwood-internal-only-visibility-java"],
srcs: [
"helper-runtime-src/**/*.java",
],
@@ -79,7 +80,6 @@
"guava",
],
jarjar_rules: "jarjar-rules.txt",
- visibility: ["//visibility:public"],
}
// Host-side stub generator tool.
@@ -152,34 +152,3 @@
"hoststubgen_dump.txt",
],
}
-
-java_library_host {
- name: "hoststubgen-helper-libcore-runtime",
- srcs: [
- "helper-framework-runtime-src/libcore-fake/**/*.java",
- ],
- visibility: ["//visibility:private"],
-}
-
-java_host_for_device {
- name: "hoststubgen-helper-libcore-runtime.ravenwood",
- libs: [
- "hoststubgen-helper-libcore-runtime",
- ],
- visibility: ["//visibility:private"],
-}
-
-java_library {
- name: "hoststubgen-helper-framework-runtime.ravenwood",
- defaults: ["ravenwood-internal-only-visibility-java"],
- srcs: [
- "helper-framework-runtime-src/framework/**/*.java",
- ],
- libs: [
- "hoststubgen-helper-runtime.ravenwood",
- "framework-minus-apex.ravenwood",
- ],
- static_libs: [
- "hoststubgen-helper-libcore-runtime.ravenwood",
- ],
-}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 3c55237..ce856cd 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -25,6 +25,7 @@
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.OutputStream
+import java.time.LocalDateTime
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.jar.JarOutputStream
@@ -42,6 +43,13 @@
return source.contains(protoLogSimpleClassName)
}
+ private fun zipEntry(path: String): ZipEntry {
+ val entry = ZipEntry(path)
+ // Use a constant time to improve the cachability of build actions.
+ entry.timeLocal = LocalDateTime.of(2008, 1, 1, 0, 0, 0)
+ return entry
+ }
+
private fun processClasses(command: CommandOptions) {
val groups = injector.readLogGroups(
command.protoLogGroupsJarArg,
@@ -77,7 +85,7 @@
}
}.map { future ->
val (path, outSrc) = future.get()
- outJar.putNextEntry(ZipEntry(path))
+ outJar.putNextEntry(zipEntry(path))
outJar.write(outSrc.toByteArray())
outJar.closeEntry()
}
@@ -90,7 +98,7 @@
val cachePackage = cacheSplit.dropLast(1).joinToString(".")
val cachePath = "gen/${cacheSplit.joinToString("/")}.java"
- outJar.putNextEntry(ZipEntry(cachePath))
+ outJar.putNextEntry(zipEntry(cachePath))
outJar.write(generateLogGroupCache(cachePackage, cacheName, groups,
command.protoLogImplClassNameArg, command.protoLogGroupsClassNameArg).toByteArray())