Merge "Add the first test for multi-session IME" into main
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 74382a6..3ab0934 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -270,6 +270,7 @@
],
jni_libs: [
"libandroid_runtime",
+ "libravenwood_runtime",
],
}
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index f56a950..28efa1e 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -1144,31 +1144,47 @@
],
}
-droidstubs {
- name: "api_versions_public",
- srcs: [":android_stubs_current_with_test_libs{.jar}"],
+// Defaults for `droidstubs` modules that generate `api-versions.xml` files for
+// the various API surfaces.
+stubs_defaults {
+ name: "api_versions_base_defaults",
+ defaults_visibility: ["//visibility:private"],
generate_stubs: false,
api_levels_annotations_enabled: true,
api_levels_annotations_dirs: [
"sdk-dir",
"api-versions-jars-dir",
],
- api_levels_sdk_type: "public",
+}
+
+// Defaults for `droidstubs` modules that generate complete `api-versions.xml`
+// files, i.e. include SDK extensions.
+stubs_defaults {
+ name: "api_versions_complete_defaults",
+ defaults_visibility: ["//visibility:private"],
+ defaults: ["api_versions_base_defaults"],
extensions_info_file: ":sdk-extensions-info",
+}
+
+// Produces an `api-versions.xml` file that includes up-to-date information
+// about all the public APIs, both updatable and non-updatable and historic
+// information about all previous dessert and SDK extension releases.
+droidstubs {
+ name: "api_versions_public",
+ defaults: ["api_versions_complete_defaults"],
+ srcs: [":android_stubs_current_with_test_libs{.jar}"],
+ api_levels_sdk_type: "public",
visibility: ["//frameworks/base"],
}
+// Produces an `api-versions.xml` file that includes up-to-date information
+// about all the system APIs, both updatable and non-updatable and historic
+// information about all previous dessert and SDK extension releases.
droidstubs {
name: "api_versions_system",
+ defaults: ["api_versions_complete_defaults"],
srcs: [":android_system_stubs_current_with_test_libs{.jar}"],
- generate_stubs: false,
- api_levels_annotations_enabled: true,
- api_levels_annotations_dirs: [
- "sdk-dir",
- "api-versions-jars-dir",
- ],
api_levels_sdk_type: "system",
- extensions_info_file: ":sdk-extensions-info",
dists: [
// Make the api-versions.xml file for the system API available in the
// sdk build target.
@@ -1180,42 +1196,43 @@
],
}
-// This module can be built with:
-// m out/soong/.intermediates/frameworks/base/api/api_versions_module_lib/android_common/metalava/api-versions.xml
-droidstubs {
- name: "api_versions_module_lib",
- srcs: [":android_module_stubs_current_with_test_libs{.jar}"],
- generate_stubs: false,
- api_levels_annotations_enabled: true,
+// Defaults for `droidstubs` modules that generate `api-versions.xml` files that
+// only include non-updatable code, i.e. for platform API only, not SDK
+// extensions.
+stubs_defaults {
+ name: "api_versions_non_updatable_defaults",
+ defaults_visibility: ["//visibility:private"],
+ defaults: ["api_versions_base_defaults"],
// this only has the non-updatable portions of the module lib sdk,
// which can reference classes from updatable apexes, so remove references to them
// from this api_versions file.
flags: ["--remove-missing-class-references-in-api-levels"],
- api_levels_annotations_dirs: [
- "sdk-dir",
- "api-versions-jars-dir",
- ],
- api_levels_sdk_type: "module-lib",
// extensions_info_file is purposefully omitted, because this module should just be
// the non-updatable portions of the sdk, and extension sdks are updatable.
}
+// Produces an `api-versions.xml` file that includes up-to-date information
+// about only the non-updatable module-lib APIs and historic information about
+// all previous dessert and SDK extension releases. That historic information
+// may include information about APIs that were previously not-updatable which
+// have since become updatable.
+droidstubs {
+ name: "api_versions_module_lib",
+ defaults: ["api_versions_non_updatable_defaults"],
+ srcs: [":android_module_stubs_current_with_test_libs{.jar}"],
+ api_levels_sdk_type: "module-lib",
+}
+
+// Produces an `api-versions.xml` file that includes up-to-date information
+// about only the non-updatable system-server APIs and historic information
+// about all previous dessert and SDK extension releases. That historic
+// information may include information about APIs that were previously
+// not-updatable which have since become updatable.
droidstubs {
name: "api_versions_system_server",
+ defaults: ["api_versions_non_updatable_defaults"],
srcs: [":android_system_server_stubs_current_with_test_libs{.jar}"],
- generate_stubs: false,
- api_levels_annotations_enabled: true,
- // this only has the non-updatable portions of the system server sdk,
- // which can reference classes from updatable apexes, so remove references to them
- // from this api_versions file.
- flags: ["--remove-missing-class-references-in-api-levels"],
- api_levels_annotations_dirs: [
- "sdk-dir",
- "api-versions-jars-dir",
- ],
api_levels_sdk_type: "system-server",
- // extensions_info_file is purposefully omitted, because this module should just be
- // the non-updatable portions of the sdk, and extension sdks are updatable.
}
/////////////////////////////////////////////////////////////////////
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f10c0fc..eabe1f1 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -872,6 +872,7 @@
public static final class AppOpsManager.OpEventProxyInfo implements android.os.Parcelable {
method public int describeContents();
method @Nullable public String getAttributionTag();
+ method @FlaggedApi("android.permission.flags.device_id_in_op_proxy_info_enabled") @Nullable public String getDeviceId();
method @Nullable public String getPackageName();
method @IntRange(from=0) public int getUid();
method public void writeToParcel(@NonNull android.os.Parcel, int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 0372b7b..2437be8 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1529,9 +1529,9 @@
package android.hardware {
@Deprecated public class Camera {
- method @Deprecated public static void getCameraInfo(int, @NonNull android.content.Context, boolean, android.hardware.Camera.CameraInfo);
+ method @Deprecated public static void getCameraInfo(int, @NonNull android.content.Context, int, android.hardware.Camera.CameraInfo);
method @Deprecated public static int getNumberOfCameras(@NonNull android.content.Context);
- method @Deprecated public static android.hardware.Camera open(int, @NonNull android.content.Context, boolean);
+ method @Deprecated public static android.hardware.Camera open(int, @NonNull android.content.Context, int);
method @Deprecated public final void setPreviewSurface(android.view.Surface) throws java.io.IOException;
}
@@ -1606,11 +1606,15 @@
public final class CameraManager {
method @NonNull public android.hardware.camera2.CameraCharacteristics getCameraCharacteristics(@NonNull String, boolean) throws android.hardware.camera2.CameraAccessException;
method public String[] getCameraIdListNoLazy() throws android.hardware.camera2.CameraAccessException;
+ method @FlaggedApi("com.android.window.flags.camera_compat_for_freeform") public static int getRotationOverrideInternal(@Nullable android.content.Context, @Nullable android.content.pm.PackageManager, @Nullable String);
method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, boolean, @Nullable android.os.Handler, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
method @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openCamera(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
method public static boolean shouldOverrideToPortrait(@Nullable android.content.pm.PackageManager, @Nullable String);
field public static final String LANDSCAPE_TO_PORTRAIT_PROP = "camera.enable_landscape_to_portrait";
field public static final long OVERRIDE_CAMERA_LANDSCAPE_TO_PORTRAIT = 250678880L; // 0xef10e60L
+ field @FlaggedApi("com.android.window.flags.camera_compat_for_freeform") public static final int ROTATION_OVERRIDE_NONE = 0; // 0x0
+ field @FlaggedApi("com.android.window.flags.camera_compat_for_freeform") public static final int ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT = 1; // 0x1
+ field @FlaggedApi("com.android.window.flags.camera_compat_for_freeform") public static final int ROTATION_OVERRIDE_ROTATION_ONLY = 2; // 0x2
}
public abstract static class CameraManager.AvailabilityCallback {
@@ -3989,15 +3993,15 @@
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void addVirtualStylusIdForTestSession();
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void finishTrackingPendingImeVisibilityRequests();
method public int getDisplayId();
- method @FlaggedApi("android.view.inputmethod.imm_userhandle_hostsidetests") @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getEnabledInputMethodListAsUser(@NonNull android.os.UserHandle);
- method @FlaggedApi("android.view.inputmethod.imm_userhandle_hostsidetests") @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodSubtype> getEnabledInputMethodSubtypeListAsUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getEnabledInputMethodListAsUser(@NonNull android.os.UserHandle);
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodSubtype> getEnabledInputMethodSubtypeListAsUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
method public boolean hasActiveInputConnection(@Nullable android.view.View);
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests();
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void hideSoftInputFromServerForTest();
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View);
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown();
- method @FlaggedApi("android.view.inputmethod.imm_userhandle_hostsidetests") @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public boolean isStylusHandwritingAvailableAsUser(@NonNull android.os.UserHandle);
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public boolean isStylusHandwritingAvailableAsUser(@NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void setStylusWindowIdleTimeoutForTest(long);
field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 68cc17b..caaaf51 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -7438,6 +7438,7 @@
}
mDdmSyncStageUpdater.next(Stage.Running);
+ long timestampApplicationOnCreateNs = 0;
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
@@ -7480,8 +7481,10 @@
+ data.instrumentationName + ": " + e.toString(), e);
}
try {
+ timestampApplicationOnCreateNs = SystemClock.elapsedRealtimeNanos();
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
+ timestampApplicationOnCreateNs = 0;
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
@@ -7519,7 +7522,7 @@
}
try {
- mgr.finishAttachApplication(mStartSeq);
+ mgr.finishAttachApplication(mStartSeq, timestampApplicationOnCreateNs);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 20b2357..2d0f6fc 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -3457,6 +3457,8 @@
private @Nullable String mPackageName;
/** Attribution tag of the proxy that noted the op */
private @Nullable String mAttributionTag;
+ /** Persistent device Id of the proxy that noted the op */
+ private @Nullable String mDeviceId;
/**
* Reinit existing object with new state.
@@ -3464,14 +3466,16 @@
* @param uid UID of the proxy app that noted the op
* @param packageName Package of the proxy that noted the op
* @param attributionTag attribution tag of the proxy that noted the op
+ * @param deviceId Persistent device Id of the proxy that noted the op
*
* @hide
*/
public void reinit(@IntRange(from = 0) int uid, @Nullable String packageName,
- @Nullable String attributionTag) {
+ @Nullable String attributionTag, @Nullable String deviceId) {
mUid = Preconditions.checkArgumentNonnegative(uid);
mPackageName = packageName;
mAttributionTag = attributionTag;
+ mDeviceId = deviceId;
}
@@ -3505,16 +3509,33 @@
@IntRange(from = 0) int uid,
@Nullable String packageName,
@Nullable String attributionTag) {
+ this(uid, packageName, attributionTag,
+ VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+ }
+
+ /**
+ * Creates a new OpEventProxyInfo.
+ *
+ * @param uid UID of the proxy app that noted the op
+ * @param packageName Package of the proxy that noted the op
+ * @param attributionTag Attribution tag of the proxy that noted the op
+ * @param deviceId Persistent device Id of the proxy that noted the op
+ *
+ * @hide
+ */
+ public OpEventProxyInfo(
+ @IntRange(from = 0) int uid,
+ @Nullable String packageName,
+ @Nullable String attributionTag,
+ @Nullable String deviceId) {
this.mUid = uid;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mUid,
"from", 0);
this.mPackageName = packageName;
this.mAttributionTag = attributionTag;
-
- // onConstructed(); // You can define this method to get a callback
+ this.mDeviceId = deviceId;
}
-
/**
* Copy constructor
*
@@ -3525,6 +3546,7 @@
mUid = orig.mUid;
mPackageName = orig.mPackageName;
mAttributionTag = orig.mAttributionTag;
+ mDeviceId = orig.mDeviceId;
}
/**
@@ -3551,6 +3573,9 @@
return mAttributionTag;
}
+ @FlaggedApi(Flags.FLAG_DEVICE_ID_IN_OP_PROXY_INFO_ENABLED)
+ public @Nullable String getDeviceId() { return mDeviceId; }
+
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -3560,10 +3585,12 @@
byte flg = 0;
if (mPackageName != null) flg |= 0x2;
if (mAttributionTag != null) flg |= 0x4;
+ if (mDeviceId != null) flg |= 0x8;
dest.writeByte(flg);
dest.writeInt(mUid);
if (mPackageName != null) dest.writeString(mPackageName);
if (mAttributionTag != null) dest.writeString(mAttributionTag);
+ if (mDeviceId != null) dest.writeString(mDeviceId);
}
@Override
@@ -3581,14 +3608,14 @@
int uid = in.readInt();
String packageName = (flg & 0x2) == 0 ? null : in.readString();
String attributionTag = (flg & 0x4) == 0 ? null : in.readString();
-
+ String deviceId = (flg & 0x8) == 0 ? null : in.readString();
this.mUid = uid;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mUid,
"from", 0);
this.mPackageName = packageName;
this.mAttributionTag = attributionTag;
-
+ this.mDeviceId = deviceId;
// onConstructed(); // You can define this method to get a callback
}
diff --git a/core/java/android/app/GrammaticalInflectionManager.java b/core/java/android/app/GrammaticalInflectionManager.java
index f0bc3e2..37e51f8 100644
--- a/core/java/android/app/GrammaticalInflectionManager.java
+++ b/core/java/android/app/GrammaticalInflectionManager.java
@@ -104,7 +104,7 @@
* Sets the current grammatical gender for all privileged applications. The value will be
* stored in an encrypted file at {@link android.os.Environment#getDataSystemCeDirectory(int)}
*
- * @param grammaticalGender the terms of address the user preferred in system.
+ * @param grammaticalGender the grammatical gender set by the user for the system.
*
* @see Configuration#getGrammaticalGender
* @hide
@@ -123,12 +123,12 @@
}
/**
- * Get the current grammatical gender of privileged application from the encrypted file.
+ * Allows privileged preloaded applications to get the system grammatical gender when set.
*
- * @return the value of system grammatical gender only if the calling app has the permission,
- * otherwise throwing an exception.
+ * @return The value of system grammatical gender only if the calling app has the
+ * permission, otherwise throwing an exception.
*
- * @throws SecurityException if the caller does not have the required permission.
+ * @throws SecurityException If the caller does not have the required permission.
*
* @see Configuration#getGrammaticalGender
*/
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 3765c81..e8b57f2 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -196,7 +196,7 @@
oneway void finishReceiver(in IBinder who, int resultCode, in String resultData, in Bundle map,
boolean abortBroadcast, int flags);
void attachApplication(in IApplicationThread app, long startSeq);
- void finishAttachApplication(long startSeq);
+ void finishAttachApplication(long startSeq, long timestampApplicationOnCreateNs);
List<ActivityManager.RunningTaskInfo> getTasks(int maxNum);
@UnsupportedAppUsage
void moveTaskToFront(in IApplicationThread caller, in String callingPackage, int task,
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 25dbedc..c3bac71 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3259,8 +3259,9 @@
boolean mustClearCookie = false;
if (!parcel.hasClassCookie(Notification.class)) {
// This is the "root" notification, and not an "inner" notification (including
- // publicVersion or anything else that might be embedded in extras).
- parcel.setClassCookie(Notification.class, this);
+ // publicVersion or anything else that might be embedded in extras). So we want
+ // to use its token for every inner notification (might be null).
+ parcel.setClassCookie(Notification.class, mAllowlistToken);
mustClearCookie = true;
}
try {
@@ -3269,7 +3270,7 @@
writeToParcelImpl(parcel, flags);
} finally {
if (mustClearCookie) {
- parcel.removeClassCookie(Notification.class, this);
+ parcel.removeClassCookie(Notification.class, mAllowlistToken);
}
}
} else {
@@ -3293,14 +3294,9 @@
parcel.writeInt(1);
if (Flags.secureAllowlistToken()) {
- Notification rootNotification = (Notification) parcel.getClassCookie(
- Notification.class);
- if (rootNotification != null && rootNotification != this) {
- // Always use the same token as the root notification
- parcel.writeStrongBinder(rootNotification.mAllowlistToken);
- } else {
- parcel.writeStrongBinder(mAllowlistToken);
- }
+ // Always use the same token as the root notification (might be null).
+ IBinder rootNotificationToken = (IBinder) parcel.getClassCookie(Notification.class);
+ parcel.writeStrongBinder(rootNotificationToken);
} else {
parcel.writeStrongBinder(mAllowlistToken);
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 8171723..9437c74 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -300,6 +300,16 @@
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016;
+ /**
+ * The corresponding vendor API for Android V
+ *
+ * <p>Starting with Android V, the vendor API format has switched to YYYYMM.
+ *
+ * @see <a href="https://preview.source.android.com/docs/core/architecture/api-flags">Vendor API
+ * level</a>
+ */
+ private static final int VENDOR_API_FOR_ANDROID_V = 202404;
+
// Service registry information.
// This information is never changed once static initialization has completed.
private static final Map<Class<?>, String> SYSTEM_SERVICE_NAMES =
@@ -465,9 +475,10 @@
new CachedServiceFetcher<VcnManager>() {
@Override
public VcnManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- if (shouldCheckTelephonyFeatures()
- && !ctx.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) {
+ final String telephonyFeatureToCheck = getVcnFeatureDependency();
+
+ if (telephonyFeatureToCheck != null
+ && !ctx.getPackageManager().hasSystemFeature(telephonyFeatureToCheck)) {
return null;
}
@@ -1768,16 +1779,24 @@
// partition SDK level, not application's target SDK version (which BTW we
// also check through Compatibility framework a few lines below).
@SuppressWarnings("AndroidFrameworkCompatChange")
- private static boolean shouldCheckTelephonyFeatures() {
+ @Nullable
+ private static String getVcnFeatureDependency() {
+ // Check SDK version of the client app. Apps targeting pre-V SDK might
+ // have not checked for existence of these features.
+ if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) {
+ return null;
+ }
+
// Check SDK version of the vendor partition. Pre-V devices might have
// incorrectly under-declared telephony features.
final int vendorApiLevel = SystemProperties.getInt(
"ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
- if (vendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) return false;
+ if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) {
+ return PackageManager.FEATURE_TELEPHONY;
+ } else {
+ return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION;
+ }
- // Check SDK version of the client app. Apps targeting pre-V SDK might
- // have not checked for existence of these features.
- return Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN);
}
/**
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index e4425ca..8c4667f 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -40,3 +40,13 @@
description: "Add a new callback in Service to indicate a FGS has reached its timeout."
bug: "317799821"
}
+
+flag {
+ namespace: "system_performance"
+ name: "app_start_info_timestamps"
+ description: "Additional timestamps."
+ bug: "287153617"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index e5f2976..23b2ea4 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -18,6 +18,7 @@
import android.Manifest;
import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -40,6 +41,15 @@
@SystemService(Context.TRUST_SERVICE)
public class TrustManager {
+ /**
+ * Intent action used to identify services that can serve as significant providers.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String ACTION_BIND_SIGNIFICANT_PLACE_PROVIDER =
+ "com.android.trust.provider.SignificantPlaceProvider.BIND";
+
private static final int MSG_TRUST_CHANGED = 1;
private static final int MSG_TRUST_MANAGED_CHANGED = 2;
private static final int MSG_TRUST_ERROR = 3;
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 2dced96..72f992a 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -35,6 +35,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.SparseArray;
import android.widget.RemoteViews;
import android.widget.RemoteViews.InteractionHandler;
@@ -52,12 +53,15 @@
*/
public class AppWidgetHost {
+ private static final String TAG = "AppWidgetHost";
+
static final int HANDLE_UPDATE = 1;
static final int HANDLE_PROVIDER_CHANGED = 2;
static final int HANDLE_PROVIDERS_CHANGED = 3;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
static final int HANDLE_VIEW_DATA_CHANGED = 4;
static final int HANDLE_APP_WIDGET_REMOVED = 5;
+ static final int HANDLE_VIEW_UPDATE_DEFERRED = 6;
final static Object sServiceLock = new Object();
@UnsupportedAppUsage
@@ -131,6 +135,15 @@
msg.sendToTarget();
}
+ public void updateAppWidgetDeferred(int appWidgetId) {
+ Handler handler = mWeakHandler.get();
+ if (handler == null) {
+ return;
+ }
+ Message msg = handler.obtainMessage(HANDLE_VIEW_UPDATE_DEFERRED, appWidgetId, 0, null);
+ msg.sendToTarget();
+ }
+
private static boolean isLocalBinder() {
return Process.myPid() == Binder.getCallingPid();
}
@@ -163,6 +176,10 @@
viewDataChanged(msg.arg1, msg.arg2);
break;
}
+ case HANDLE_VIEW_UPDATE_DEFERRED: {
+ updateAppWidgetDeferred(msg.arg1);
+ break;
+ }
}
}
}
@@ -480,14 +497,32 @@
void onUpdateProviderInfo(@Nullable AppWidgetProviderInfo appWidget);
/**
- * This function is called when the RemoteViews of the app widget is updated
- * @param views The new RemoteViews to be set for the app widget
+ * This function is called when the {@code RemoteViews} of the app widget is updated
+ * @param views The new {@code RemoteViews} to be set for the app widget
*
* @hide
*/
void updateAppWidget(@Nullable RemoteViews views);
/**
+ * Called for the listener to handle deferred {@code RemoteViews} updates. Default
+ * implementation is to update the widget directly.
+ * @param packageName The package name used for uid verification on the service side
+ * @param appWidgetId The widget id of the listener
+ *
+ * @hide
+ */
+ default void updateAppWidgetDeferred(String packageName, int appWidgetId) {
+ RemoteViews latestViews = null;
+ try {
+ latestViews = sService.getAppWidgetViews(packageName, appWidgetId);
+ } catch (Exception e) {
+ Log.e(TAG, "updateAppWidgetDeferred: ", e);
+ }
+ updateAppWidget(latestViews);
+ }
+
+ /**
* This function is called when the view ID is changed for the app widget
* @param viewId The new view ID to be be set for the widget
*
@@ -563,6 +598,15 @@
}
}
+ private void updateAppWidgetDeferred(int appWidgetId) {
+ AppWidgetHostListener v = getListener(appWidgetId);
+ if (v == null) {
+ Log.e(TAG, "updateAppWidgetDeferred: null listener for id: " + appWidgetId);
+ return;
+ }
+ v.updateAppWidgetDeferred(mContextOpPackageName, appWidgetId);
+ }
+
/**
* Clear the list of Views that have been created by this AppWidgetHost.
*/
diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java
index 3486d5e..afddc77 100644
--- a/core/java/android/content/res/AssetFileDescriptor.java
+++ b/core/java/android/content/res/AssetFileDescriptor.java
@@ -419,6 +419,10 @@
if (available <= 0) {
return -1;
}
+ if (count == 0) {
+ // Java's InputStream explicitly specifies that this returns zero.
+ return 0;
+ }
if (count > available) count = available;
try {
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index a9f70c9..32d2a6f 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -308,8 +308,8 @@
*/
public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
Context context = ActivityThread.currentApplication().getApplicationContext();
- boolean overrideToPortrait = CameraManager.shouldOverrideToPortrait(context);
- getCameraInfo(cameraId, context, overrideToPortrait, cameraInfo);
+ final int rotationOverride = CameraManager.getRotationOverride(context);
+ getCameraInfo(cameraId, context, rotationOverride, cameraInfo);
}
/**
@@ -320,8 +320,8 @@
@SuppressLint("UnflaggedApi") // @TestApi without associated feature.
@TestApi
public static void getCameraInfo(int cameraId, @NonNull Context context,
- boolean overrideToPortrait, CameraInfo cameraInfo) {
- _getCameraInfo(cameraId, overrideToPortrait, context.getDeviceId(),
+ int rotationOverride, CameraInfo cameraInfo) {
+ _getCameraInfo(cameraId, rotationOverride, context.getDeviceId(),
getDevicePolicyFromContext(context), cameraInfo);
IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
IAudioService audioService = IAudioService.Stub.asInterface(b);
@@ -336,7 +336,7 @@
}
}
- private native static void _getCameraInfo(int cameraId, boolean overrideToPortrait,
+ private native static void _getCameraInfo(int cameraId, int rotationOverride,
int deviceId, int devicePolicy, CameraInfo cameraInfo);
private static int getDevicePolicyFromContext(Context context) {
@@ -441,8 +441,8 @@
*/
public static Camera open(int cameraId) {
Context context = ActivityThread.currentApplication().getApplicationContext();
- boolean overrideToPortrait = CameraManager.shouldOverrideToPortrait(context);
- return open(cameraId, context, overrideToPortrait);
+ final int rotationOverride = CameraManager.getRotationOverride(context);
+ return open(cameraId, context, rotationOverride);
}
/**
@@ -452,8 +452,8 @@
*/
@SuppressLint("UnflaggedApi") // @TestApi without associated feature.
@TestApi
- public static Camera open(int cameraId, @NonNull Context context, boolean overrideToPortrait) {
- return new Camera(cameraId, context, overrideToPortrait);
+ public static Camera open(int cameraId, @NonNull Context context, int rotationOverride) {
+ return new Camera(cameraId, context, rotationOverride);
}
/**
@@ -524,7 +524,7 @@
return open(cameraId);
}
- private int cameraInit(int cameraId, Context context, boolean overrideToPortrait) {
+ private int cameraInit(int cameraId, Context context, int rotationOverride) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
@@ -544,7 +544,7 @@
boolean forceSlowJpegMode = shouldForceSlowJpegMode();
return native_setup(new WeakReference<>(this), cameraId,
- ActivityThread.currentOpPackageName(), overrideToPortrait, forceSlowJpegMode,
+ ActivityThread.currentOpPackageName(), rotationOverride, forceSlowJpegMode,
context.getDeviceId(), getDevicePolicyFromContext(context));
}
@@ -562,9 +562,9 @@
}
/** used by Camera#open, Camera#open(int) */
- Camera(int cameraId, @NonNull Context context, boolean overrideToPortrait) {
+ Camera(int cameraId, @NonNull Context context, int rotationOverride) {
Objects.requireNonNull(context);
- int err = cameraInit(cameraId, context, overrideToPortrait);
+ final int err = cameraInit(cameraId, context, rotationOverride);
if (checkInitErrors(err)) {
if (err == -EACCES) {
throw new RuntimeException("Fail to connect to camera service");
@@ -629,7 +629,7 @@
@UnsupportedAppUsage
private native int native_setup(Object cameraThis, int cameraId, String packageName,
- boolean overrideToPortrait, boolean forceSlowJpegMode, int deviceId, int devicePolicy);
+ int rotationOverride, boolean forceSlowJpegMode, int deviceId, int devicePolicy);
private native final void native_release();
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 90a2cf0..2191fd5 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -28,6 +28,8 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.ActivityManager;
+import android.app.TaskInfo;
import android.app.compat.CompatChanges;
import android.companion.virtual.VirtualDeviceManager;
import android.compat.annotation.ChangeId;
@@ -169,6 +171,36 @@
"camera.enable_landscape_to_portrait";
/**
+ * Does not override landscape feed to portrait.
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public static final int ROTATION_OVERRIDE_NONE = ICameraService.ROTATION_OVERRIDE_NONE;
+
+ /**
+ * Crops and rotates landscape camera feed to portrait, and changes sensor orientation to
+ * portrait.
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public static final int ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT =
+ ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT;
+
+ /**
+ * Crops and rotates landscape camera feed to portrait, but doesn't change sensor orientation.
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public static final int ROTATION_OVERRIDE_ROTATION_ONLY =
+ ICameraService.ROTATION_OVERRIDE_ROTATION_ONLY;
+
+ /**
* Enable physical camera availability callbacks when the logical camera is unavailable
*
* <p>Previously once a logical camera becomes unavailable, no
@@ -627,7 +659,8 @@
CameraMetadataNative physicalCameraInfo =
cameraService.getCameraCharacteristics(physicalCameraId,
mContext.getApplicationInfo().targetSdkVersion,
- /*overrideToPortrait*/ false, DEVICE_ID_DEFAULT,
+ /*rotationOverride*/ ICameraService.ROTATION_OVERRIDE_NONE,
+ DEVICE_ID_DEFAULT,
DEVICE_POLICY_DEFAULT);
StreamConfiguration[] configs = physicalCameraInfo.get(
CameraCharacteristics.
@@ -674,7 +707,7 @@
@NonNull
public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
throws CameraAccessException {
- return getCameraCharacteristics(cameraId, shouldOverrideToPortrait(mContext));
+ return getCameraCharacteristics(cameraId, getRotationOverride(mContext));
}
/**
@@ -699,7 +732,16 @@
@NonNull
public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId,
boolean overrideToPortrait) throws CameraAccessException {
- CameraCharacteristics characteristics;
+ return getCameraCharacteristics(cameraId,
+ overrideToPortrait
+ ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
+ : ICameraService.ROTATION_OVERRIDE_NONE);
+ }
+
+ @NonNull
+ private CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId,
+ int rotationOverride) throws CameraAccessException {
+ CameraCharacteristics characteristics = null;
if (CameraManagerGlobal.sCameraServiceDisabled) {
throw new IllegalArgumentException("No cameras available on device");
}
@@ -711,7 +753,7 @@
}
try {
CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId,
- mContext.getApplicationInfo().targetSdkVersion, overrideToPortrait,
+ mContext.getApplicationInfo().targetSdkVersion, rotationOverride,
mContext.getDeviceId(), getDevicePolicyFromContext(mContext));
characteristics = prepareCameraCharacteristics(cameraId, info, cameraService);
} catch (ServiceSpecificException e) {
@@ -926,7 +968,7 @@
*/
private CameraDevice openCameraDeviceUserAsync(String cameraId,
CameraDevice.StateCallback callback, Executor executor, final int uid,
- final int oomScoreOffset, boolean overrideToPortrait) throws CameraAccessException {
+ final int oomScoreOffset, int rotationOverride) throws CameraAccessException {
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
Map<String, CameraCharacteristics> physicalIdsToChars =
@@ -961,7 +1003,7 @@
cameraUser = cameraService.connectDevice(callbacks, cameraId,
mContext.getOpPackageName(), mContext.getAttributionTag(), uid,
oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion,
- overrideToPortrait, mContext.getDeviceId(),
+ rotationOverride, mContext.getDeviceId(),
getDevicePolicyFromContext(mContext));
} catch (ServiceSpecificException e) {
if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
@@ -1126,7 +1168,10 @@
@Nullable Handler handler,
@NonNull final CameraDevice.StateCallback callback) throws CameraAccessException {
openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
- USE_CALLING_UID, /*oomScoreOffset*/0, overrideToPortrait);
+ USE_CALLING_UID, /*oomScoreOffset*/0,
+ overrideToPortrait
+ ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
+ : ICameraService.ROTATION_OVERRIDE_NONE);
}
/**
@@ -1240,7 +1285,7 @@
"oomScoreOffset < 0, cannot increase priority of camera client");
}
openCameraForUid(cameraId, callback, executor, USE_CALLING_UID, oomScoreOffset,
- shouldOverrideToPortrait(mContext));
+ getRotationOverride(mContext));
}
/**
@@ -1258,11 +1303,14 @@
* Must be USE_CALLING_UID unless the caller is a trusted service.
* @param oomScoreOffset
* The minimum oom score that cameraservice must see for this client.
+ * @param rotationOverride
+ * The type of rotation override (none, override_to_portrait, rotation_only)
+ * that should be followed for this camera id connection
* @hide
*/
public void openCameraForUid(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
- int clientUid, int oomScoreOffset, boolean overrideToPortrait)
+ int clientUid, int oomScoreOffset, int rotationOverride)
throws CameraAccessException {
if (cameraId == null) {
@@ -1275,7 +1323,7 @@
}
openCameraDeviceUserAsync(cameraId, callback, executor, clientUid, oomScoreOffset,
- overrideToPortrait);
+ rotationOverride);
}
/**
@@ -1297,7 +1345,7 @@
@NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
int clientUid) throws CameraAccessException {
openCameraForUid(cameraId, callback, executor, clientUid, /*oomScoreOffset*/0,
- shouldOverrideToPortrait(mContext));
+ getRotationOverride(mContext));
}
/**
@@ -1442,7 +1490,7 @@
/**
* @hide
*/
- public static boolean shouldOverrideToPortrait(@Nullable Context context) {
+ public static int getRotationOverride(@Nullable Context context) {
PackageManager packageManager = null;
String packageName = null;
@@ -1451,7 +1499,64 @@
packageName = context.getOpPackageName();
}
- return shouldOverrideToPortrait(packageManager, packageName);
+ return getRotationOverride(context, packageManager, packageName);
+ }
+
+ /**
+ * @hide
+ */
+ public static int getRotationOverride(@Nullable Context context,
+ @Nullable PackageManager packageManager, @Nullable String packageName) {
+ if (com.android.window.flags.Flags.cameraCompatForFreeform()) {
+ return getRotationOverrideInternal(context, packageManager, packageName);
+ } else {
+ return shouldOverrideToPortrait(packageManager, packageName)
+ ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
+ : ICameraService.ROTATION_OVERRIDE_NONE;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @FlaggedApi(com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ @TestApi
+ public static int getRotationOverrideInternal(@Nullable Context context,
+ @Nullable PackageManager packageManager, @Nullable String packageName) {
+ if (!CameraManagerGlobal.sLandscapeToPortrait) {
+ return ICameraService.ROTATION_OVERRIDE_NONE;
+ }
+
+ if (context != null) {
+ final ActivityManager activityManager =
+ context.getSystemService(ActivityManager.class);
+ for (ActivityManager.AppTask appTask : activityManager.getAppTasks()) {
+ final TaskInfo taskInfo = appTask.getTaskInfo();
+ if (taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode
+ != 0
+ && taskInfo.topActivity != null
+ && taskInfo.topActivity.getPackageName().equals(packageName)) {
+ // WindowManager has requested rotation override.
+ return ICameraService.ROTATION_OVERRIDE_ROTATION_ONLY;
+ }
+ }
+ }
+
+ if (packageManager != null && packageName != null) {
+ try {
+ return packageManager.getProperty(
+ PackageManager.PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT,
+ packageName).getBoolean()
+ ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
+ : ICameraService.ROTATION_OVERRIDE_NONE;
+ } catch (PackageManager.NameNotFoundException e) {
+ // No such property
+ }
+ }
+
+ return CompatChanges.isChangeEnabled(OVERRIDE_CAMERA_LANDSCAPE_TO_PORTRAIT)
+ ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
+ : ICameraService.ROTATION_OVERRIDE_NONE;
}
/**
@@ -1459,7 +1564,7 @@
*/
@TestApi
public static boolean shouldOverrideToPortrait(@Nullable PackageManager packageManager,
- @Nullable String packageName) {
+ @Nullable String packageName) {
if (!CameraManagerGlobal.sLandscapeToPortrait) {
return false;
}
@@ -1477,6 +1582,7 @@
return CompatChanges.isChangeEnabled(OVERRIDE_CAMERA_LANDSCAPE_TO_PORTRAIT);
}
+
/**
* @hide
*/
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
index 372839d..8898a4c 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
@@ -134,7 +134,8 @@
try {
CameraMetadataNative metadata = cameraService.getSessionCharacteristics(
mCameraId, mTargetSdkVersion,
- CameraManager.shouldOverrideToPortrait(mContext), sessionConfig,
+ CameraManager.getRotationOverride(mContext),
+ sessionConfig,
mContext.getDeviceId(),
mCameraManager.getDevicePolicyFromContext(mContext));
diff --git a/core/java/android/hardware/hdmi/OWNERS b/core/java/android/hardware/hdmi/OWNERS
index 6952e5d..f7a22f5 100644
--- a/core/java/android/hardware/hdmi/OWNERS
+++ b/core/java/android/hardware/hdmi/OWNERS
@@ -3,3 +3,4 @@
include /services/core/java/com/android/server/display/OWNERS
quxiangfang@google.com
+donpaul@google.com
\ No newline at end of file
diff --git a/core/java/android/hardware/location/ISignificantPlaceProvider.aidl b/core/java/android/hardware/location/ISignificantPlaceProvider.aidl
new file mode 100644
index 0000000..e02169e
--- /dev/null
+++ b/core/java/android/hardware/location/ISignificantPlaceProvider.aidl
@@ -0,0 +1,10 @@
+package android.hardware.location;
+
+import android.hardware.location.ISignificantPlaceProviderManager;
+
+/**
+ * @hide
+ */
+oneway interface ISignificantPlaceProvider {
+ void setSignificantPlaceProviderManager(in ISignificantPlaceProviderManager manager);
+}
diff --git a/core/java/android/hardware/location/ISignificantPlaceProviderManager.aidl b/core/java/android/hardware/location/ISignificantPlaceProviderManager.aidl
new file mode 100644
index 0000000..76eefe7
--- /dev/null
+++ b/core/java/android/hardware/location/ISignificantPlaceProviderManager.aidl
@@ -0,0 +1,8 @@
+package android.hardware.location;
+
+/**
+ * @hide
+ */
+interface ISignificantPlaceProviderManager {
+ void setInSignificantPlace(in boolean inSignificantPlace);
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d38354d..c6a9203 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1989,85 +1989,86 @@
* @hide
*/
@StringDef(value = {
- DISALLOW_MODIFY_ACCOUNTS,
- DISALLOW_CONFIG_WIFI,
- DISALLOW_CONFIG_LOCALE,
- DISALLOW_INSTALL_APPS,
- DISALLOW_UNINSTALL_APPS,
- DISALLOW_SHARE_LOCATION,
+ ALLOW_PARENT_PROFILE_APP_LINKING,
+ DISALLOW_ADD_CLONE_PROFILE,
+ DISALLOW_ADD_MANAGED_PROFILE,
+ DISALLOW_ADD_PRIVATE_PROFILE,
+ DISALLOW_ADD_USER,
+ DISALLOW_ADD_WIFI_CONFIG,
+ DISALLOW_ADJUST_VOLUME,
DISALLOW_AIRPLANE_MODE,
- DISALLOW_CONFIG_BRIGHTNESS,
DISALLOW_AMBIENT_DISPLAY,
- DISALLOW_CONFIG_SCREEN_TIMEOUT,
- DISALLOW_INSTALL_UNKNOWN_SOURCES,
- DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
- DISALLOW_CONFIG_BLUETOOTH,
+ DISALLOW_APPS_CONTROL,
+ DISALLOW_ASSIST_CONTENT,
+ DISALLOW_AUTOFILL,
+ DISALLOW_BIOMETRIC,
DISALLOW_BLUETOOTH,
DISALLOW_BLUETOOTH_SHARING,
- DISALLOW_USB_FILE_TRANSFER,
- DISALLOW_CONFIG_CREDENTIALS,
- DISALLOW_REMOVE_USER,
- DISALLOW_REMOVE_MANAGED_PROFILE,
- DISALLOW_DEBUGGING_FEATURES,
- DISALLOW_CONFIG_VPN,
- DISALLOW_CONFIG_LOCATION,
- DISALLOW_CONFIG_DATE_TIME,
- DISALLOW_CONFIG_TETHERING,
- DISALLOW_NETWORK_RESET,
- DISALLOW_FACTORY_RESET,
- DISALLOW_ADD_USER,
- DISALLOW_ADD_MANAGED_PROFILE,
- DISALLOW_ADD_CLONE_PROFILE,
- DISALLOW_ADD_PRIVATE_PROFILE,
- ENSURE_VERIFY_APPS,
- DISALLOW_CONFIG_CELL_BROADCASTS,
- DISALLOW_CONFIG_MOBILE_NETWORKS,
- DISALLOW_APPS_CONTROL,
- DISALLOW_MOUNT_PHYSICAL_MEDIA,
- DISALLOW_UNMUTE_MICROPHONE,
- DISALLOW_ADJUST_VOLUME,
- DISALLOW_OUTGOING_CALLS,
- DISALLOW_SMS,
- DISALLOW_FUN,
- DISALLOW_CREATE_WINDOWS,
- DISALLOW_SYSTEM_ERROR_DIALOGS,
- DISALLOW_CROSS_PROFILE_COPY_PASTE,
- DISALLOW_OUTGOING_BEAM,
- DISALLOW_WALLPAPER,
- DISALLOW_SET_WALLPAPER,
- DISALLOW_SAFE_BOOT,
- DISALLOW_RECORD_AUDIO,
- DISALLOW_RUN_IN_BACKGROUND,
DISALLOW_CAMERA,
- DISALLOW_UNMUTE_DEVICE,
- DISALLOW_DATA_ROAMING,
- DISALLOW_SET_USER_ICON,
- DISALLOW_OEM_UNLOCK,
- DISALLOW_UNIFIED_PASSWORD,
- ALLOW_PARENT_PROFILE_APP_LINKING,
- DISALLOW_AUTOFILL,
+ DISALLOW_CAMERA_TOGGLE,
+ DISALLOW_CELLULAR_2G,
+ DISALLOW_CHANGE_WIFI_STATE,
+ DISALLOW_CONFIG_BLUETOOTH,
+ DISALLOW_CONFIG_BRIGHTNESS,
+ DISALLOW_CONFIG_CELL_BROADCASTS,
+ DISALLOW_CONFIG_CREDENTIALS,
+ DISALLOW_CONFIG_DATE_TIME,
+ DISALLOW_CONFIG_DEFAULT_APPS,
+ DISALLOW_CONFIG_LOCALE,
+ DISALLOW_CONFIG_LOCATION,
+ DISALLOW_CONFIG_MOBILE_NETWORKS,
+ DISALLOW_CONFIG_PRIVATE_DNS,
+ DISALLOW_CONFIG_SCREEN_TIMEOUT,
+ DISALLOW_CONFIG_TETHERING,
+ DISALLOW_CONFIG_VPN,
+ DISALLOW_CONFIG_WIFI,
DISALLOW_CONTENT_CAPTURE,
DISALLOW_CONTENT_SUGGESTIONS,
- DISALLOW_USER_SWITCH,
- DISALLOW_SHARE_INTO_MANAGED_PROFILE,
- DISALLOW_PRINTING,
- DISALLOW_CONFIG_PRIVATE_DNS,
- DISALLOW_MICROPHONE_TOGGLE,
- DISALLOW_CAMERA_TOGGLE,
- KEY_RESTRICTIONS_PENDING,
- DISALLOW_BIOMETRIC,
- DISALLOW_CHANGE_WIFI_STATE,
- DISALLOW_WIFI_TETHERING,
- DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI,
- DISALLOW_WIFI_DIRECT,
- DISALLOW_ADD_WIFI_CONFIG,
- DISALLOW_CELLULAR_2G,
- DISALLOW_ULTRA_WIDEBAND_RADIO,
+ DISALLOW_CREATE_WINDOWS,
+ DISALLOW_CROSS_PROFILE_COPY_PASTE,
+ DISALLOW_DATA_ROAMING,
+ DISALLOW_DEBUGGING_FEATURES,
+ DISALLOW_FACTORY_RESET,
+ DISALLOW_FUN,
DISALLOW_GRANT_ADMIN,
+ DISALLOW_INSTALL_APPS,
+ DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
+ DISALLOW_MICROPHONE_TOGGLE,
+ DISALLOW_MODIFY_ACCOUNTS,
+ DISALLOW_MOUNT_PHYSICAL_MEDIA,
DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
- DISALLOW_THREAD_NETWORK,
+ DISALLOW_NETWORK_RESET,
+ DISALLOW_OEM_UNLOCK,
+ DISALLOW_OUTGOING_BEAM,
+ DISALLOW_OUTGOING_CALLS,
+ DISALLOW_PRINTING,
+ DISALLOW_RECORD_AUDIO,
+ DISALLOW_REMOVE_MANAGED_PROFILE,
+ DISALLOW_REMOVE_USER,
+ DISALLOW_RUN_IN_BACKGROUND,
+ DISALLOW_SAFE_BOOT,
+ DISALLOW_SET_USER_ICON,
+ DISALLOW_SET_WALLPAPER,
+ DISALLOW_SHARE_INTO_MANAGED_PROFILE,
+ DISALLOW_SHARE_LOCATION,
+ DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI,
DISALLOW_SIM_GLOBALLY,
- DISALLOW_ASSIST_CONTENT,
+ DISALLOW_SMS,
+ DISALLOW_SYSTEM_ERROR_DIALOGS,
+ DISALLOW_THREAD_NETWORK,
+ DISALLOW_ULTRA_WIDEBAND_RADIO,
+ DISALLOW_UNIFIED_PASSWORD,
+ DISALLOW_UNINSTALL_APPS,
+ DISALLOW_UNMUTE_DEVICE,
+ DISALLOW_UNMUTE_MICROPHONE,
+ DISALLOW_USB_FILE_TRANSFER,
+ DISALLOW_USER_SWITCH,
+ DISALLOW_WALLPAPER,
+ DISALLOW_WIFI_DIRECT,
+ DISALLOW_WIFI_TETHERING,
+ ENSURE_VERIFY_APPS,
+ KEY_RESTRICTIONS_PENDING,
})
@Retention(RetentionPolicy.SOURCE)
public @interface UserRestrictionKey {}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 6b5e17d..b588308 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -180,3 +180,11 @@
description: "Use runtime permission state to determine appop state"
bug: "266164193"
}
+
+flag {
+ name: "device_id_in_op_proxy_info_enabled"
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "Enable getDeviceId API in OpEventProxyInfo"
+ bug: "337340961"
+}
\ No newline at end of file
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index b9de93c..7653bdb 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -56,11 +56,18 @@
public static class BytesResult {
public final String value;
public final String units;
+ /**
+ * Content description of the {@link #units}.
+ * See {@link View#setContentDescription(CharSequence)}
+ */
+ public final String unitsContentDescription;
public final long roundedBytes;
- public BytesResult(String value, String units, long roundedBytes) {
+ public BytesResult(String value, String units, String unitsContentDescription,
+ long roundedBytes) {
this.value = value;
this.units = units;
+ this.unitsContentDescription = unitsContentDescription;
this.roundedBytes = roundedBytes;
}
}
@@ -271,20 +278,20 @@
final Locale locale = res.getConfiguration().getLocales().get(0);
final NumberFormat numberFormatter = getNumberFormatter(locale, rounded.fractionDigits);
final String formattedNumber = numberFormatter.format(rounded.value);
- final String units;
+ // Since ICU does not give us access to the pattern, we need to extract the unit string
+ // from ICU, which we do by taking out the formatted number out of the formatted string
+ // and trimming the result of spaces and controls.
+ final String formattedMeasure = formatMeasureShort(
+ locale, numberFormatter, rounded.value, rounded.units);
+ final String numberRemoved = deleteFirstFromString(formattedMeasure, formattedNumber);
+ String units = SPACES_AND_CONTROLS.trim(numberRemoved).toString();
+ String unitsContentDescription = units;
if (rounded.units == MeasureUnit.BYTE) {
// ICU spells out "byte" instead of "B".
units = getByteSuffixOverride(res);
- } else {
- // Since ICU does not give us access to the pattern, we need to extract the unit string
- // from ICU, which we do by taking out the formatted number out of the formatted string
- // and trimming the result of spaces and controls.
- final String formattedMeasure = formatMeasureShort(
- locale, numberFormatter, rounded.value, rounded.units);
- final String numberRemoved = deleteFirstFromString(formattedMeasure, formattedNumber);
- units = SPACES_AND_CONTROLS.trim(numberRemoved).toString();
}
- return new BytesResult(formattedNumber, units, rounded.roundedBytes);
+ return new BytesResult(formattedNumber, units, unitsContentDescription,
+ rounded.roundedBytes);
}
/**
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 65d9b3a..cb5a885 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -62,7 +62,6 @@
import android.view.InputDevice;
import android.view.IInputFilter;
import android.view.AppTransitionAnimationSpec;
-import android.view.TaskTransitionSpec;
import android.view.WindowContentFrameStats;
import android.view.WindowManager;
import android.view.SurfaceControl;
@@ -962,19 +961,6 @@
void setTaskSnapshotEnabled(boolean enabled);
/**
- * Customized the task transition animation with a task transition spec.
- *
- * @param spec the spec that will be used to customize the task animations
- */
- void setTaskTransitionSpec(in TaskTransitionSpec spec);
-
- /**
- * Clears any task transition spec that has been previously set and
- * reverts to using the default task transition with no spec changes.
- */
- void clearTaskTransitionSpec();
-
- /**
* Registers the frame rate per second count callback for one given task ID.
* Each callback can only register for receiving FPS callback for one task id until unregister
* is called. If there's no task associated with the given task id,
diff --git a/core/java/android/view/TaskTransitionSpec.aidl b/core/java/android/view/TaskTransitionSpec.aidl
deleted file mode 100644
index 08af15c..0000000
--- a/core/java/android/view/TaskTransitionSpec.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-** Copyright 2021, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.view;
-
-/** @hide */
-parcelable TaskTransitionSpec;
diff --git a/core/java/android/view/TaskTransitionSpec.java b/core/java/android/view/TaskTransitionSpec.java
deleted file mode 100644
index 9a2d3ba..0000000
--- a/core/java/android/view/TaskTransitionSpec.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Holds information about how to execute task transition animations.
- *
- * This class is intended to be used with IWindowManager.setTaskTransitionSpec methods when
- * we want more customization over the way default task transitions are executed.
- *
- * @hide
- */
-public class TaskTransitionSpec implements Parcelable {
- /**
- * The background color to use during task animations (override the default background color)
- */
- public final int backgroundColor;
-
- public TaskTransitionSpec(int backgroundColor) {
- this.backgroundColor = backgroundColor;
- }
-
- public TaskTransitionSpec(Parcel in) {
- this.backgroundColor = in.readInt();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(backgroundColor);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<TaskTransitionSpec>
- CREATOR = new Parcelable.Creator<TaskTransitionSpec>() {
- public TaskTransitionSpec createFromParcel(Parcel in) {
- return new TaskTransitionSpec(in);
- }
-
- public TaskTransitionSpec[] newArray(int size) {
- return new TaskTransitionSpec[size];
- }
- };
-}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f4d2408..9579614 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,6 +40,7 @@
import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout;
import static android.view.flags.Flags.sensitiveContentAppProtection;
+import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;
import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;
import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly;
@@ -5773,7 +5774,7 @@
*/
private static final float FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD = 0.07f;
- static final float MAX_FRAME_RATE = 140;
+ static final float MAX_FRAME_RATE = 120;
// The preferred frame rate of the view that is mainly used for
// touch boosting, view velocity handling, and TextureView.
@@ -17153,10 +17154,12 @@
/**
* Handle a key event before it is processed by any input method
- * associated with the view hierarchy. This can be used to intercept
+ * associated with the view hierarchy. This can be used to intercept
* key events in special situations before the IME consumes them; a
* typical example would be handling the BACK key to update the application's
- * UI instead of allowing the IME to see it and close itself.
+ * UI instead of allowing the IME to see it and close itself. Due to a bug,
+ * this function is not called for BACK key events on Android T and U, when
+ * the IME is shown.
*
* @param keyCode The value in event.getKeyCode().
* @param event Description of the key event.
@@ -32235,7 +32238,11 @@
void decreaseSensitiveViewsCount() {
mSensitiveViewsCount--;
if (mSensitiveViewsCount == 0) {
- mViewRootImpl.notifySensitiveContentAppProtection(false);
+ if (sensitiveContentPrematureProtectionRemovedFix()) {
+ mViewRootImpl.removeSensitiveContentProtectionOnTransactionCommit();
+ } else {
+ mViewRootImpl.notifySensitiveContentAppProtection(false);
+ }
}
if (mSensitiveViewsCount < 0) {
Log.wtf(VIEW_LOG_TAG, "mSensitiveViewsCount is negative" + mSensitiveViewsCount);
@@ -33942,8 +33949,9 @@
protected int calculateFrameRateCategory() {
int category;
switch (getViewRootImpl().intermittentUpdateState()) {
- case ViewRootImpl.INTERMITTENT_STATE_INTERMITTENT ->
- category = FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_INTERMITTENT;
+ case ViewRootImpl.INTERMITTENT_STATE_INTERMITTENT -> category =
+ (sToolkitFrameRateBySizeReadOnlyFlagValue ? FRAME_RATE_CATEGORY_LOW
+ : FRAME_RATE_CATEGORY_NORMAL) | FRAME_RATE_CATEGORY_REASON_INTERMITTENT;
case ViewRootImpl.INTERMITTENT_STATE_NOT_INTERMITTENT ->
category = mSizeBasedFrameRateCategoryAndReason;
default -> category = mLastFrameRateCategory;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 11ad86c..ab529e6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2654,9 +2654,10 @@
ViewRootImpl viewRootImpl = getViewRootImpl();
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
- final boolean isDispatchingBack = (viewRootImpl != null
- && viewRootImpl.getOnBackInvokedDispatcher().isDispatching());
- if (!disallowIntercept || isDispatchingBack) { // Allow back to intercept touch
+ final boolean isBackGestureInProgress = (viewRootImpl != null
+ && viewRootImpl.getOnBackInvokedDispatcher().isBackGestureInProgress());
+ if (!disallowIntercept || isBackGestureInProgress) {
+ // Allow back to intercept touch
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f51d909..1d84375 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -317,6 +317,7 @@
private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV;
private static final boolean DEBUG_TOUCH_NAVIGATION = false || LOCAL_LOGV;
private static final boolean DEBUG_BLAST = false || LOCAL_LOGV;
+ private static final boolean DEBUG_SENSITIVE_CONTENT = false || LOCAL_LOGV;
private static final int LOGTAG_INPUT_FOCUS = 62001;
private static final int LOGTAG_VIEWROOT_DRAW_EVENT = 60004;
@@ -4261,7 +4262,9 @@
updateInfrequentCount();
setPreferredFrameRate(mPreferredFrameRate);
setPreferredFrameRateCategory(mPreferredFrameRateCategory);
- if (!mIsFrameRateConflicted) {
+ if (mPreferredFrameRate > 0
+ || (mLastPreferredFrameRate != 0 && mPreferredFrameRate == 0)
+ ) {
mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING,
FRAME_RATE_SETTING_REEVALUATE_TIME);
@@ -4334,6 +4337,10 @@
if (mSensitiveContentProtectionService == null) {
return;
}
+ if (DEBUG_SENSITIVE_CONTENT) {
+ Log.d(TAG, "Notify sensitive content, package=" + mContext.getPackageName()
+ + ", token=" + getWindowToken() + ", flag=" + showSensitiveContent);
+ }
// The window would be blocked during screen share if it shows sensitive content.
mSensitiveContentProtectionService.setSensitiveContentProtection(
getWindowToken(), mContext.getPackageName(), showSensitiveContent);
@@ -4342,6 +4349,24 @@
}
}
+ /**
+ * Sensitive protection is removed on transaction commit to avoid prematurely removing
+ * the protection.
+ */
+ void removeSensitiveContentProtectionOnTransactionCommit() {
+ if (DEBUG_SENSITIVE_CONTENT) {
+ Log.d(TAG, "Add transaction to remove sensitive content protection, package="
+ + mContext.getPackageName() + ", token=" + getWindowToken());
+ }
+ Transaction t = new Transaction();
+ t.addTransactionCommittedListener(mExecutor, () -> {
+ if (mAttachInfo.mSensitiveViewsCount == 0) {
+ notifySensitiveContentAppProtection(false);
+ }
+ });
+ applyTransactionOnDraw(t);
+ }
+
private void notifyContentCaptureEvents() {
if (!isContentCaptureEnabled()) {
if (DEBUG_CONTENT_CAPTURE) {
@@ -7228,7 +7253,7 @@
private int doOnBackKeyEvent(KeyEvent keyEvent) {
WindowOnBackInvokedDispatcher dispatcher = getOnBackInvokedDispatcher();
OnBackInvokedCallback topCallback = dispatcher.getTopCallback();
- if (dispatcher.isDispatching()) {
+ if (dispatcher.isBackGestureInProgress()) {
return FINISH_NOT_HANDLED;
}
if (topCallback instanceof OnBackAnimationCallback) {
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 16e1415..12bd45a 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -46,6 +46,18 @@
}
flag {
+ name: "sensitive_content_premature_protection_removed_fix"
+ namespace: "permissions"
+ description: "Bug fix where sensitive content protection is prematurely removed."
+ bug: "336626172"
+ # Referenced in WM where WM starts before DeviceConfig
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_arrow_icon_on_hover_when_clickable"
namespace: "toolkit"
description: "Enable default arrow icon when hovering on buttons or clickable widgets."
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 8174da6..1cdcd20 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1671,7 +1671,6 @@
@NonNull
@RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
@TestApi
- @FlaggedApi(Flags.FLAG_IMM_USERHANDLE_HOSTSIDETESTS)
@SuppressLint("UserHandle")
public boolean isStylusHandwritingAvailableAsUser(@NonNull UserHandle user) {
final Context fallbackContext = ActivityThread.currentApplication();
@@ -1816,7 +1815,6 @@
@NonNull
@RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
@TestApi
- @FlaggedApi(Flags.FLAG_IMM_USERHANDLE_HOSTSIDETESTS)
@SuppressLint("UserHandle")
public List<InputMethodInfo> getEnabledInputMethodListAsUser(@NonNull UserHandle user) {
return IInputMethodManagerGlobalInvoker.getEnabledInputMethodList(user.getIdentifier());
@@ -1858,7 +1856,6 @@
@NonNull
@RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
@TestApi
- @FlaggedApi(Flags.FLAG_IMM_USERHANDLE_HOSTSIDETESTS)
@SuppressLint("UserHandle")
public List<InputMethodSubtype> getEnabledInputMethodSubtypeListAsUser(
@NonNull String imeId, boolean allowsImplicitlyEnabledSubtypes,
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index d79903b..fa9458d 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -106,3 +106,13 @@
}
}
+flag {
+ name: "defer_show_soft_input_until_session_creation"
+ namespace: "input_method"
+ description: "Defers showSoftInput until the IME session has been created."
+ bug: "337766845"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index f643bd4..5430f8f 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -382,7 +382,7 @@
/**
* Maps Intent ID to RemoteCollectionItems to avoid duplicate items
*/
- private RemoteCollectionCache mCollectionCache = new RemoteCollectionCache();
+ private @NonNull RemoteCollectionCache mCollectionCache = new RemoteCollectionCache();
/** Cache of ApplicationInfos used by collection items. */
private ApplicationInfoCache mApplicationInfoCache = new ApplicationInfoCache();
@@ -775,6 +775,16 @@
}
/**
+ * Return {@code true} only if this {@code RemoteViews} is a legacy list widget that uses
+ * {@code Intent} for inflating child entries.
+ *
+ * @hide
+ */
+ public boolean isLegacyListRemoteViews() {
+ return mCollectionCache.mIdToUriMapping.size() > 0;
+ }
+
+ /**
* Note all {@link Uri} that are referenced internally, with the expectation that Uri permission
* grants will need to be issued to ensure the recipient of this object is able to render its
* contents.
@@ -1231,8 +1241,8 @@
}
private class RemoteCollectionCache {
- private SparseArray<String> mIdToUriMapping = new SparseArray<>();
- private HashMap<String, RemoteCollectionItems> mUriToCollectionMapping = new HashMap<>();
+ private final SparseArray<String> mIdToUriMapping = new SparseArray<>();
+ private final Map<String, RemoteCollectionItems> mUriToCollectionMapping = new HashMap<>();
RemoteCollectionCache() { }
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
index ee6ba24..3b9b162 100644
--- a/core/java/android/window/ImeOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -16,6 +16,8 @@
package android.window;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
@@ -27,6 +29,8 @@
import android.util.Log;
import android.view.ViewRootImpl;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
/**
@@ -280,7 +284,8 @@
sendStopDispatching();
}
- static class ImeOnBackInvokedCallback implements OnBackInvokedCallback {
+ @VisibleForTesting(visibility = PACKAGE)
+ public static class ImeOnBackInvokedCallback implements OnBackInvokedCallback {
@NonNull
private final IOnBackInvokedCallback mIOnBackInvokedCallback;
/**
@@ -327,7 +332,8 @@
* Subclass of ImeOnBackInvokedCallback indicating that a predictive IME back animation may be
* played instead of invoking the callback.
*/
- static class DefaultImeOnBackAnimationCallback extends ImeOnBackInvokedCallback {
+ @VisibleForTesting(visibility = PACKAGE)
+ public static class DefaultImeOnBackAnimationCallback extends ImeOnBackInvokedCallback {
DefaultImeOnBackAnimationCallback(@NonNull IOnBackInvokedCallback iCallback, int id,
int priority) {
super(iCallback, id, priority);
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 7f6678e..e351d6b 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -114,7 +114,7 @@
/** Updates the dispatcher state on a new {@link MotionEvent}. */
public void onMotionEvent(MotionEvent ev) {
- if (!isDispatching() || ev == null || ev.getAction() != MotionEvent.ACTION_MOVE) {
+ if (!isBackGestureInProgress() || ev == null || ev.getAction() != MotionEvent.ACTION_MOVE) {
return;
}
mTouchTracker.update(ev.getX(), ev.getY(), Float.NaN, Float.NaN);
@@ -176,6 +176,12 @@
mImeDispatcher.registerOnBackInvokedCallback(priority, callback);
return;
}
+ if ((callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback
+ || callback instanceof ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback)
+ && !isOnBackInvokedCallbackEnabled()) {
+ // Fall back to compat back key injection if legacy back behaviour should be used.
+ return;
+ }
if (!mOnBackInvokedCallbacks.containsKey(priority)) {
mOnBackInvokedCallbacks.put(priority, new ArrayList<>());
}
@@ -240,9 +246,9 @@
}
/**
- * Indicates if the dispatcher is actively dispatching to a callback.
+ * Indicates if a user gesture is currently in progress.
*/
- public boolean isDispatching() {
+ public boolean isBackGestureInProgress() {
synchronized (mLock) {
return mTouchTracker.isActive() || mImeDispatchingActive;
}
@@ -469,12 +475,17 @@
@Override
public void onBackStarted(BackMotionEvent backEvent) {
mHandler.post(() -> {
+ final OnBackAnimationCallback callback = getBackAnimationCallback();
+
+ // reset progress animator before dispatching onBackStarted to callback. This
+ // ensures that onBackCancelled (of a previous gesture) is always dispatched
+ // before onBackStarted
+ if (callback != null) mProgressAnimator.reset();
mTouchTracker.setState(BackTouchTracker.TouchTrackerState.ACTIVE);
mTouchTracker.setShouldUpdateStartLocation(true);
mTouchTracker.setGestureStartLocation(
backEvent.getTouchX(), backEvent.getTouchY(), backEvent.getSwipeEdge());
- final OnBackAnimationCallback callback = getBackAnimationCallback();
if (callback != null) {
callback.onBackStarted(new BackEvent(
backEvent.getTouchX(),
@@ -493,14 +504,9 @@
public void onBackCancelled() {
mHandler.post(() -> {
final OnBackAnimationCallback callback = getBackAnimationCallback();
- if (callback == null) {
- mTouchTracker.reset();
- return;
- }
- mProgressAnimator.onBackCancelled(() -> {
- mTouchTracker.reset();
- callback.onBackCancelled();
- });
+ mTouchTracker.reset();
+ if (callback == null) return;
+ mProgressAnimator.onBackCancelled(callback::onBackCancelled);
});
}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 55927cc..e8b4f0b 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -64,3 +64,10 @@
description: "Hides the App Handle when in fullscreen immersive mode"
bug: "336368019"
}
+
+flag {
+ name: "enable_desktop_windowing_quick_switch"
+ namespace: "lse_desktop_experience"
+ description: "Enables quick switch for desktop mode"
+ bug: "338066529"
+}
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
index 7cbacad..8faa4cf 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
@@ -23,6 +23,7 @@
/** {@hide} */
oneway interface IAppWidgetHost {
+ void updateAppWidgetDeferred(int appWidgetId);
void updateAppWidget(int appWidgetId, in RemoteViews views);
void providerChanged(int appWidgetId, in AppWidgetProviderInfo info);
void providersChanged();
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index f4315e3..74c2325 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -523,8 +523,8 @@
ViewRootImpl viewRootImpl = getViewRootImpl();
if (viewRootImpl != null) {
viewRootImpl.getOnBackInvokedDispatcher().onMotionEvent(event);
- // Intercept touch if back dispatching is active.
- if (viewRootImpl.getOnBackInvokedDispatcher().isDispatching()) {
+ // Intercept touch if back gesture is in progress.
+ if (viewRootImpl.getOnBackInvokedDispatcher().isBackGestureInProgress()) {
return true;
}
}
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index 874cc49..ee33eb4 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -99,7 +99,7 @@
private final Map<LogLevel, Integer> mDefaultLogLevelCounts = new ArrayMap<>();
private final Map<IProtoLogGroup, Map<LogLevel, Integer>> mLogLevelCounts = new ArrayMap<>();
- private final ExecutorService mBackgroundLoggingService = Executors.newCachedThreadPool();
+ private final ExecutorService mBackgroundLoggingService = Executors.newSingleThreadExecutor();
public PerfettoProtoLogImpl(String viewerConfigFilePath,
TreeMap<String, IProtoLogGroup> logGroups, Runnable cacheUpdater) {
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 72b98a2..2316f4c 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -529,7 +529,7 @@
}
static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, jint cameraId,
- jboolean overrideToPortrait, jint deviceId,
+ jint rotationOverride, jint deviceId,
jint devicePolicy, jobject info_obj) {
CameraInfo cameraInfo;
if (cameraId >= Camera::getNumberOfCameras(deviceId, devicePolicy) || cameraId < 0) {
@@ -538,7 +538,7 @@
return;
}
- status_t rc = Camera::getCameraInfo(cameraId, overrideToPortrait, deviceId, devicePolicy,
+ status_t rc = Camera::getCameraInfo(cameraId, rotationOverride, deviceId, devicePolicy,
&cameraInfo);
if (rc != NO_ERROR) {
jniThrowRuntimeException(env, "Fail to get camera info");
@@ -557,7 +557,7 @@
// connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jint cameraId, jstring clientPackageName,
- jboolean overrideToPortrait,
+ jint rotationOverride,
jboolean forceSlowJpegMode, jint deviceId,
jint devicePolicy) {
// Convert jstring to String16
@@ -571,7 +571,7 @@
int targetSdkVersion = android_get_application_target_sdk_version();
sp<Camera> camera =
Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID, Camera::USE_CALLING_PID,
- targetSdkVersion, overrideToPortrait, forceSlowJpegMode, deviceId,
+ targetSdkVersion, rotationOverride, forceSlowJpegMode, deviceId,
devicePolicy);
if (camera == NULL) {
return -EACCES;
@@ -600,7 +600,7 @@
// Update default display orientation in case the sensor is reverse-landscape
CameraInfo cameraInfo;
- status_t rc = Camera::getCameraInfo(cameraId, overrideToPortrait, deviceId, devicePolicy,
+ status_t rc = Camera::getCameraInfo(cameraId, rotationOverride, deviceId, devicePolicy,
&cameraInfo);
if (rc != NO_ERROR) {
ALOGE("%s: getCameraInfo error: %d", __FUNCTION__, rc);
@@ -1057,9 +1057,9 @@
static const JNINativeMethod camMethods[] = {
{"_getNumberOfCameras", "(II)I", (void *)android_hardware_Camera_getNumberOfCameras},
- {"_getCameraInfo", "(IZIILandroid/hardware/Camera$CameraInfo;)V",
+ {"_getCameraInfo", "(IIIILandroid/hardware/Camera$CameraInfo;)V",
(void *)android_hardware_Camera_getCameraInfo},
- {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;ZZII)I",
+ {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;IZII)I",
(void *)android_hardware_Camera_native_setup},
{"native_release", "()V", (void *)android_hardware_Camera_release},
{"setPreviewSurface", "(Landroid/view/Surface;)V",
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index a022842..7267eb8 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -190,17 +190,21 @@
return -1;
}
- jbyte* bufferBytes = NULL;
- if (buffer) {
- bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
+ bool is_dir_in = (endpoint & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
+ jbyte *bufferBytes = (jbyte *)malloc(length);
+
+ if (!is_dir_in && buffer) {
+ env->GetByteArrayRegion(buffer, start, length, bufferBytes);
}
- jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout);
+ jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout);
- if (bufferBytes) {
- env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
+ if (is_dir_in && buffer) {
+ env->SetByteArrayRegion(buffer, start, length, bufferBytes);
}
+ free(bufferBytes);
+
return result;
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 3ed9f49..12d62cc 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1828,10 +1828,10 @@
std::string source = "/dev/__properties__/appcompat_override";
std::string target = "/dev/__properties__";
if (access(source.c_str(), F_OK) != 0) {
- fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno)));
+ return;
}
if (access(target.c_str(), F_OK) != 0) {
- fail_fn(CREATE_ERROR("Error accessing %s: %s", target.c_str(), strerror(errno)));
+ return;
}
BindMount(source, target, fail_fn);
// Reload the system properties file, to ensure new values are read into memory
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 8ae2a9b..6ce4b9d 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -21,16 +21,102 @@
android:viewportHeight="24">
<group>
<clip-path
- android:pathData="M12,20.923C10.764,20.923 9.946,20.065 9.131,18.653C8.316,17.241 4.291,10.269 3.476,8.857C2.66,7.445 2.326,6.309 2.944,5.238C3.563,4.167 4.714,3.888 6.344,3.888C7.975,3.888 16.025,3.888 17.656,3.888C19.286,3.888 20.437,4.167 21.056,5.238C21.674,6.309 21.34,7.445 20.524,8.857C19.709,10.269 15.684,17.241 14.869,18.653C14.054,20.065 13.236,20.923 12,20.923H12Z"/>
+ android:pathData="
+ M12.6495 17.375
+ C12.3608 17.875 11.6392 17.875 11.3505 17.375
+ L3.98927 4.625
+ C3.70059 4.125 4.06143 3.5 4.63878 3.5
+ L19.3612 3.5
+ C19.9386 3.5 20.2994 4.125 20.0107 4.625
+ L12.6495 17.375
+ Z
+ "/>
<path
- android:pathData="M5,14.978h14v9.8h-14z"
+ android:pathData="M5,12 h14v9.8h-14z"
android:fillColor="#ffffff"/>
<path
- android:pathData="M18.722,15.576C18.717,15.548 18.713,15.521 18.708,15.493C18.68,15.324 18.646,15.156 18.605,14.991C18.534,14.701 18.445,14.42 18.339,14.146C18.249,13.915 18.146,13.69 18.033,13.472C17.886,13.192 17.722,12.923 17.539,12.667C17.316,12.354 17.067,12.06 16.795,11.789C16.68,11.676 16.562,11.566 16.44,11.461C16.175,11.233 15.893,11.025 15.595,10.839C15.598,10.834 15.6,10.83 15.602,10.825C15.739,10.59 15.875,10.355 16.012,10.119C16.145,9.889 16.279,9.659 16.412,9.429C16.508,9.264 16.604,9.098 16.699,8.933C16.722,8.894 16.74,8.854 16.753,8.812C16.791,8.696 16.792,8.575 16.762,8.462C16.754,8.434 16.745,8.406 16.734,8.38C16.723,8.353 16.71,8.327 16.695,8.302C16.644,8.216 16.571,8.142 16.479,8.087C16.399,8.039 16.308,8.011 16.215,8.002C16.176,7.999 16.137,7.999 16.098,8.003C16.066,8.007 16.034,8.013 16.002,8.021C15.889,8.051 15.785,8.113 15.703,8.202C15.674,8.235 15.647,8.27 15.624,8.309C15.529,8.475 15.433,8.64 15.337,8.805L14.937,9.495C14.801,9.731 14.664,9.966 14.528,10.202C14.513,10.227 14.498,10.253 14.483,10.279C14.462,10.271 14.442,10.263 14.421,10.255C13.669,9.968 12.853,9.811 12,9.811C11.977,9.811 11.954,9.811 11.931,9.811C11.172,9.819 10.444,9.951 9.764,10.188C9.686,10.215 9.608,10.244 9.531,10.274C9.517,10.25 9.503,10.226 9.489,10.202C9.353,9.966 9.216,9.731 9.08,9.495C8.946,9.265 8.813,9.035 8.679,8.805C8.584,8.64 8.488,8.475 8.392,8.31C8.37,8.271 8.343,8.235 8.314,8.203C8.232,8.113 8.127,8.051 8.014,8.021C7.983,8.013 7.951,8.007 7.919,8.004C7.88,8 7.841,7.999 7.802,8.003C7.709,8.011 7.618,8.039 7.537,8.088C7.446,8.142 7.373,8.217 7.322,8.302C7.307,8.327 7.294,8.353 7.283,8.38C7.271,8.407 7.262,8.434 7.255,8.462C7.225,8.575 7.226,8.697 7.264,8.812C7.277,8.854 7.295,8.894 7.318,8.934C7.413,9.099 7.509,9.264 7.605,9.429C7.738,9.659 7.872,9.889 8.005,10.119C8.141,10.355 8.278,10.59 8.414,10.826C8.415,10.828 8.417,10.83 8.418,10.832C8.143,11.003 7.881,11.192 7.634,11.4C7.486,11.524 7.343,11.654 7.207,11.79C6.935,12.061 6.685,12.354 6.462,12.668C6.279,12.923 6.114,13.192 5.968,13.472C5.855,13.691 5.752,13.915 5.662,14.147C5.556,14.42 5.467,14.702 5.396,14.991C5.355,15.157 5.321,15.324 5.293,15.494C5.288,15.521 5.284,15.549 5.279,15.576C5.264,15.675 5.251,15.774 5.241,15.874L18.759,15.874C18.749,15.774 18.736,15.675 18.72,15.576L18.722,15.576Z"
+ android:pathData="
+ M15.97 10.48
+ C15.97 10.46 15.97 10.45 15.96 10.43
+ C15.95 10.33 15.93 10.23 15.90 10.13
+ C15.86 9.96 15.81 9.79 15.75 9.63
+ C15.69 9.50 15.63 9.36 15.57 9.23
+ C15.48 9.07 15.38 8.91 15.27 8.76
+ C15.14 8.57 14.99 8.40 14.83 8.24
+ C14.76 8.17 14.69 8.11 14.62 8.04
+ C14.47 7.91 14.30 7.78 14.12 7.67
+ C14.12 7.67 14.13 7.67 14.13 7.67
+ C14.21 7.53 14.29 7.39 14.37 7.25
+ C14.45 7.11 14.53 6.98 14.61 6.84
+ C14.66 6.74 14.72 6.64 14.78 6.55
+ C14.79 6.52 14.80 6.50 14.81 6.48
+ C14.83 6.41 14.83 6.33 14.81 6.27
+ C14.81 6.25 14.80 6.24 14.80 6.22
+ C14.79 6.20 14.78 6.19 14.77 6.17
+ C14.74 6.12 14.70 6.08 14.65 6.05
+ C14.60 6.02 14.54 6 14.49 6
+ C14.47 5.99 14.44 5.99 14.42 6
+ C14.40 6 14.38 6 14.36 6.01
+ C14.30 6.02 14.23 6.06 14.19 6.11
+ C14.17 6.13 14.15 6.15 14.14 6.18
+ C14.08 6.28 14.03 6.37 13.97 6.47
+ L13.73 6.88
+ C13.65 7.02 13.57 7.16 13.49 7.30
+ C13.48 7.31 13.47 7.33 13.46 7.34
+ C13.45 7.34 13.44 7.33 13.43 7.33
+ C12.98 7.16 12.50 7.07 12 7.07
+ C11.98 7.07 11.97 7.07 11.95 7.07
+ C11.51 7.07 11.07 7.15 10.67 7.29
+ C10.63 7.31 10.58 7.32 10.53 7.34
+ C10.53 7.33 10.52 7.31 10.51 7.30
+ C10.43 7.16 10.35 7.02 10.27 6.88
+ C10.19 6.74 10.11 6.61 10.03 6.47
+ C9.97 6.37 9.92 6.28 9.86 6.18
+ C9.85 6.15 9.83 6.13 9.81 6.11
+ C9.77 6.06 9.70 6.03 9.64 6.01
+ C9.62 6 9.60 6 9.58 6
+ C9.56 5.99 9.53 5.99 9.51 6
+ C9.46 6 9.40 6.02 9.35 6.05
+ C9.30 6.08 9.26 6.12 9.23 6.17
+ C9.22 6.19 9.21 6.20 9.20 6.22
+ C9.20 6.24 9.19 6.25 9.19 6.27
+ C9.17 6.34 9.17 6.41 9.19 6.48
+ C9.20 6.50 9.21 6.52 9.22 6.55
+ C9.28 6.65 9.34 6.74 9.39 6.84
+ C9.47 6.98 9.55 7.11 9.63 7.25
+ C9.71 7.39 9.79 7.53 9.87 7.67
+ C9.87 7.67 9.87 7.67 9.88 7.67
+ C9.71 7.77 9.56 7.88 9.41 8.01
+ C9.32 8.08 9.24 8.16 9.16 8.24
+ C9 8.40 8.85 8.57 8.72 8.76
+ C8.61 8.91 8.51 9.07 8.43 9.23
+ C8.36 9.36 8.30 9.50 8.24 9.63
+ C8.18 9.79 8.13 9.96 8.09 10.13
+ C8.06 10.23 8.04 10.33 8.03 10.43
+ C8.02 10.45 8.02 10.46 8.02 10.48
+ C8.01 10.54 8 10.60 8 10.65
+ L16 10.65
+ C15.99 10.60 15.98 10.54 15.97 10.48
+ L15.97 10.48
+ Z
+ "
android:fillColor="#ffffff"/>
</group>
<path
- android:pathData="M12,20.923C10.764,20.923 9.946,20.065 9.131,18.653C8.316,17.241 4.291,10.269 3.476,8.857C2.66,7.445 2.326,6.309 2.944,5.238C3.563,4.167 4.714,3.888 6.344,3.888C7.975,3.888 16.025,3.888 17.656,3.888C19.286,3.888 20.437,4.167 21.056,5.238C21.674,6.309 21.34,7.445 20.524,8.857C19.709,10.269 15.684,17.241 14.869,18.653C14.054,20.065 13.236,20.923 12,20.923H12Z"
+ android:pathData="
+ M12,20.923
+ C10.764,20.923 9.946,20.065 9.131,18.653
+ C8.316,17.241 4.291,10.269 3.476,8.857
+ C2.66,7.445 2.326,6.309 2.944,5.238
+ C3.563,4.167 4.714,3.888 6.344,3.888
+ C7.975,3.888 16.025,3.888 17.656,3.888
+ C19.286,3.888 20.437,4.167 21.056,5.238
+ C21.674,6.309 21.34,7.445 20.524,8.857
+ C19.709,10.269 15.684,17.241 14.869,18.653
+ C14.054,20.065 13.236,20.923 12,20.923
+ H12
+ Z
+ "
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 50ed422..877d11e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -7038,4 +7038,7 @@
If the gesture is completed faster than this, we assume it's not performed by human and the
event gets ignored. -->
<integer name="config_defaultMinEmergencyGestureTapDurationMillis">200</integer>
+
+ <!-- Whether the system uses auto-suspend mode. -->
+ <bool name="config_useAutoSuspend">true</bool>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 54c9479..1fca4f8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5859,6 +5859,10 @@
<string name="dynamic_mode_notification_title">Battery Saver turned on</string>
<!-- Summary of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]-->
<string name="dynamic_mode_notification_summary">Reducing battery usage to extend battery life</string>
+ <!-- Title of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]-->
+ <string name="dynamic_mode_notification_title_v2">Battery Saver is on</string>
+ <!-- Summary of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]-->
+ <string name="dynamic_mode_notification_summary_v2">Battery Saver is turned on to extend battery life</string>
<!-- Battery saver strings -->
<!-- The user visible name of the notification channel for battery saver notifications [CHAR_LIMIT=80] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d432c05..b3d8f39 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4261,7 +4261,9 @@
<java-symbol type="string" name="battery_saver_charged_notification_summary" />
<java-symbol type="string" name="dynamic_mode_notification_channel_name" />
<java-symbol type="string" name="dynamic_mode_notification_title" />
+ <java-symbol type="string" name="dynamic_mode_notification_title_v2" />
<java-symbol type="string" name="dynamic_mode_notification_summary" />
+ <java-symbol type="string" name="dynamic_mode_notification_summary_v2" />
<java-symbol type="drawable" name="ic_battery" />
<java-symbol type="bool" name="config_skipSensorAvailable" />
@@ -5424,4 +5426,7 @@
<!-- Back swipe thresholds -->
<java-symbol type="dimen" name="navigation_edge_action_progress_threshold" />
<java-symbol type="dimen" name="back_progress_non_linear_factor" />
+
+ <!-- For PowerManagerService to determine whether to use auto-suspend mode -->
+ <java-symbol type="bool" name="config_useAutoSuspend" />
</resources>
diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
index 32aec1a..72f1119 100644
--- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java
+++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
@@ -196,7 +196,7 @@
@RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API,
FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
- public void highVelocity140() throws Throwable {
+ public void highVelocity120() throws Throwable {
mActivityRule.runOnUiThread(() -> {
ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams();
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
@@ -208,7 +208,7 @@
mMovingView.setFrameContentVelocity(1_000_000_000f);
mMovingView.invalidate();
runAfterDraw(() -> {
- assertEquals(140f, mViewRoot.getLastPreferredFrameRate(), 0f);
+ assertEquals(120f, mViewRoot.getLastPreferredFrameRate(), 0f);
});
});
waitForAfterDraw();
@@ -488,16 +488,19 @@
waitForFrameRateCategoryToSettle();
for (int i = 0; i < 5; i++) {
int expectedCategory;
- if (i < 4) {
+ if (i < 2) {
// not intermittent yet.
// It takes 2 frames of intermittency before Views vote as intermittent.
- // It takes 4 more frames for the category to drop to the next category.
expectedCategory =
toolkitFrameRateDefaultNormalReadOnly() ? FRAME_RATE_CATEGORY_NORMAL
: FRAME_RATE_CATEGORY_HIGH;
} else {
// intermittent
- expectedCategory = FRAME_RATE_CATEGORY_NORMAL;
+ // Even though this is not a small View, step 3 is triggered by this flag, which
+ // brings intermittent to LOW
+ expectedCategory = toolkitFrameRateBySizeReadOnly()
+ ? FRAME_RATE_CATEGORY_LOW
+ : FRAME_RATE_CATEGORY_NORMAL;
}
mActivityRule.runOnUiThread(() -> {
mMovingView.invalidate();
@@ -561,6 +564,26 @@
assertEquals(0f, mViewRoot.getLastPreferredFrameRate(), 0f);
}
+ @Test
+ @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
+ FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY
+ })
+ public void frameRateResetWithInvalidations() throws Throwable {
+ mMovingView.setRequestedFrameRate(120f);
+ waitForFrameRateCategoryToSettle();
+ mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL);
+
+ for (int i = 0; i < 120; i++) {
+ mActivityRule.runOnUiThread(() -> {
+ mMovingView.invalidate();
+ runAfterDraw(() -> {});
+ });
+ waitForAfterDraw();
+ }
+
+ assertEquals(0f, mViewRoot.getLastPreferredFrameRate(), 0f);
+ }
+
private void runAfterDraw(@NonNull Runnable runnable) {
Handler handler = new Handler(Looper.getMainLooper());
mAfterDrawLatch = new CountDownLatch(1);
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 7c098f2..a7f8176 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -1174,9 +1174,16 @@
// Infrequent update
Thread.sleep(delay);
+
+ // Even though this is not a small View, step 3 is triggered by this flag, which
+ // brings intermittent to LOW
+ int intermittentExpected = toolkitFrameRateBySizeReadOnly()
+ ? FRAME_RATE_CATEGORY_LOW
+ : FRAME_RATE_CATEGORY_NORMAL;
+
sInstrumentation.runOnMainSync(() -> {
mView.invalidate();
- runAfterDraw(() -> assertEquals(FRAME_RATE_CATEGORY_NORMAL,
+ runAfterDraw(() -> assertEquals(intermittentExpected,
mViewRootImpl.getLastPreferredFrameRateCategory()));
});
waitForAfterDraw();
@@ -1184,7 +1191,7 @@
// When the View vote, it's still considered as intermittent update state
sInstrumentation.runOnMainSync(() -> {
mView.invalidate();
- runAfterDraw(() -> assertEquals(FRAME_RATE_CATEGORY_NORMAL,
+ runAfterDraw(() -> assertEquals(intermittentExpected,
mViewRootImpl.getLastPreferredFrameRateCategory()));
});
waitForAfterDraw();
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index 852d696..d54b862 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -40,6 +40,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.IWindow;
import android.view.IWindowSession;
+import android.view.ImeBackAnimationController;
import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
@@ -50,6 +51,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -77,6 +79,12 @@
@Mock
private OnBackAnimationCallback mCallback2;
@Mock
+ private ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback mImeCallback;
+ @Mock
+ private ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback mDefaultImeCallback;
+ @Mock
+ private ImeBackAnimationController mImeBackAnimationController;
+ @Mock
private Context mContext;
@Mock
private ApplicationInfo mApplicationInfo;
@@ -103,7 +111,7 @@
doReturn(mApplicationInfo).when(mContext).getApplicationInfo();
mDispatcher = new WindowOnBackInvokedDispatcher(mContext, Looper.getMainLooper());
- mDispatcher.attachToWindow(mWindowSession, mWindow, null);
+ mDispatcher.attachToWindow(mWindowSession, mWindow, mImeBackAnimationController);
}
private void waitForIdle() {
@@ -365,6 +373,34 @@
}
@Test
+ public void onBackCancelled_calledBeforeOnBackStartedOfNewGesture() throws RemoteException {
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
+ OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo();
+
+ callbackInfo.getCallback().onBackStarted(mBackEvent);
+
+ waitForIdle();
+ verify(mCallback1).onBackStarted(any(BackEvent.class));
+ clearInvocations(mCallback1);
+
+ callbackInfo.getCallback().onBackCancelled();
+
+ waitForIdle();
+ // verify onBackCancelled not yet called (since BackProgressAnimator animates
+ // progress to 0 first)
+ verify(mCallback1, never()).onBackCancelled();
+
+ // simulate start of new gesture while cancel animation is still running
+ callbackInfo.getCallback().onBackStarted(mBackEvent);
+ waitForIdle();
+
+ // verify that onBackCancelled is called before onBackStarted
+ InOrder orderVerifier = Mockito.inOrder(mCallback1);
+ orderVerifier.verify(mCallback1).onBackCancelled();
+ orderVerifier.verify(mCallback1).onBackStarted(any(BackEvent.class));
+ }
+
+ @Test
public void onDetachFromWindow_cancelCallbackAndIgnoreOnBackInvoked() throws RemoteException {
mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
@@ -392,11 +428,11 @@
callbackInfo.getCallback().onBackStarted(mBackEvent);
waitForIdle();
- assertTrue(mDispatcher.isDispatching());
+ assertTrue(mDispatcher.isBackGestureInProgress());
callbackInfo.getCallback().onBackInvoked();
waitForIdle();
- assertFalse(mDispatcher.isDispatching());
+ assertFalse(mDispatcher.isBackGestureInProgress());
}
@Test
@@ -411,7 +447,7 @@
callbackInfo.getCallback().onBackStarted(mBackEvent);
waitForIdle();
- assertTrue(mDispatcher.isDispatching());
+ assertTrue(mDispatcher.isBackGestureInProgress());
assertTrue(mDispatcher.mTouchTracker.isActive());
main.runWithScissors(() -> mDispatcher.onMotionEvent(mMotionEvent), 100);
@@ -419,4 +455,28 @@
// onBackPressed is called from animator, so it can happen more than once.
verify(mCallback1, atLeast(1)).onBackProgressed(any());
}
+
+ @Test
+ public void registerImeCallbacks_onBackInvokedCallbackEnabled() throws RemoteException {
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback);
+ assertCallbacksSize(/* default */ 1, /* overlay */ 0);
+ assertSetCallbackInfo();
+ assertTopCallback(mImeBackAnimationController);
+
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback);
+ assertCallbacksSize(/* default */ 2, /* overlay */ 0);
+ assertSetCallbackInfo();
+ assertTopCallback(mImeCallback);
+ }
+
+ @Test
+ public void registerImeCallbacks_legacyBack() throws RemoteException {
+ doReturn(false).when(mApplicationInfo).isOnBackInvokedCallbackEnabled();
+
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback);
+ assertNoSetCallbackInfo();
+
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback);
+ assertNoSetCallbackInfo();
+ }
}
diff --git a/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java
index 03cb17e..1d91af5 100644
--- a/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java
+++ b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java
@@ -71,7 +71,7 @@
spyPackageMonitor.register(mMockContext, UserHandle.ALL, mMockHandler);
assertThat(spyPackageMonitor.getRegisteredHandler()).isEqualTo(mMockHandler);
- verify(mMockContext, times(1)).registerReceiverAsUser(any(), eq(UserHandle.ALL), any(),
+ verify(mMockContext, never()).registerReceiverAsUser(any(), eq(UserHandle.ALL), any(),
eq(null), eq(mMockHandler));
assertThrows(IllegalStateException.class,
@@ -97,7 +97,7 @@
@Test
public void testPackageMonitorNotRegisterWithoutSupportPackageRestartQuery() throws Exception {
- PackageMonitor spyPackageMonitor = spy(new TestPackageMonitor(false));
+ PackageMonitor spyPackageMonitor = spy(new TestPackageMonitor());
spyPackageMonitor.register(mMockContext, UserHandle.ALL, mMockHandler);
@@ -106,6 +106,16 @@
}
@Test
+ public void testPackageMonitorRegisterWithSupportPackageRestartQuery() throws Exception {
+ PackageMonitor spyPackageMonitor = spy(new TestPackageMonitor(true));
+
+ spyPackageMonitor.register(mMockContext, UserHandle.ALL, mMockHandler);
+
+ verify(mMockContext, times(1)).registerReceiverAsUser(any(), eq(UserHandle.ALL), any(),
+ eq(null), eq(mMockHandler));
+ }
+
+ @Test
public void testPackageMonitorDoHandlePackageEventUidRemoved() throws Exception {
PackageMonitor spyPackageMonitor = spy(new TestPackageMonitor());
@@ -487,7 +497,7 @@
}
public TestPackageMonitor() {
- super();
+ super(false);
}
}
}
diff --git a/data/keyboards/Android.bp b/data/keyboards/Android.bp
index f15c153..676493d 100644
--- a/data/keyboards/Android.bp
+++ b/data/keyboards/Android.bp
@@ -27,3 +27,24 @@
targets: ["droidcore"],
},
}
+
+prebuilt_usr_keylayout {
+ name: "keylayout_data",
+ srcs: [
+ "*.kl",
+ ],
+}
+
+prebuilt_usr_keychars {
+ name: "keychars_data",
+ srcs: [
+ "*.kcm",
+ ],
+}
+
+prebuilt_usr_idc {
+ name: "idc_data",
+ srcs: [
+ "*.idc",
+ ],
+}
diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk
index c7ce8cd..3353c86 100644
--- a/data/keyboards/keyboards.mk
+++ b/data/keyboards/keyboards.mk
@@ -14,9 +14,8 @@
# Warning: this is actually a product definition, to be inherited from
-PRODUCT_COPY_FILES := \
- $(call find-copy-subdir-files,*.kl,$(LOCAL_PATH),system/usr/keylayout) \
- $(call find-copy-subdir-files,*.kcm,$(LOCAL_PATH),system/usr/keychars) \
- $(call find-copy-subdir-files,*.idc,$(LOCAL_PATH),system/usr/idc)
-
+PRODUCT_PACKAGES += \
+ keylayout_data \
+ keychars_data \
+ idc_data
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 319f115..6d31578 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -465,6 +465,11 @@
* how pixels are stored. This affects the quality (color depth) as
* well as the ability to display transparent/translucent colors.
*/
+ // It's touched by Graphics.cpp, so we need to make this enum usable on Ravenwood.
+ // Otherwise, all the ctors would throw, which would make the class unloadable
+ // because the static initializer needs the enum members because of `sConfigs`.
+ // TODO: Remove it once we expose the outer class.
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public enum Config {
// these native values must match up with the enum in SkBitmap.h
diff --git a/graphics/java/android/graphics/Interpolator.java b/graphics/java/android/graphics/Interpolator.java
index 1045464..994fb2d 100644
--- a/graphics/java/android/graphics/Interpolator.java
+++ b/graphics/java/android/graphics/Interpolator.java
@@ -18,6 +18,9 @@
import android.os.SystemClock;
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+ android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
public class Interpolator {
public Interpolator(int valueCount) {
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index bc58feb..fbb690c 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -28,6 +28,9 @@
/**
* The Matrix class holds a 3x3 matrix for transforming coordinates.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+ android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
public class Matrix {
public static final int MSCALE_X = 0; //!< use with getValues/setValues
@@ -229,7 +232,7 @@
private static class NoImagePreloadHolder {
public static final NativeAllocationRegistry sRegistry =
NativeAllocationRegistry.createMalloced(
- Matrix.class.getClassLoader(), nGetNativeFinalizer());
+ Matrix.class.getClassLoader(), nGetNativeFinalizerWrapper());
}
private final long native_instance;
@@ -238,7 +241,7 @@
* Create an identity matrix
*/
public Matrix() {
- native_instance = nCreate(0);
+ native_instance = nCreateWrapper(0);
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
}
@@ -248,7 +251,7 @@
* @param src The matrix to copy into this matrix
*/
public Matrix(Matrix src) {
- native_instance = nCreate(src != null ? src.native_instance : 0);
+ native_instance = nCreateWrapper(src != null ? src.native_instance : 0);
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
}
@@ -846,6 +849,34 @@
return native_instance;
}
+ /**
+ * Wrapper method we use to switch to ExtraNatives.nCreate(src) only on Ravenwood.
+ *
+ * @see ExtraNatives
+ */
+ @android.ravenwood.annotation.RavenwoodReplace
+ private static long nCreateWrapper(long src) {
+ return nCreate(src);
+ }
+
+ private static long nCreateWrapper$ravenwood(long src) {
+ return ExtraNatives.nCreate(src);
+ }
+
+ /**
+ * Wrapper method we use to switch to ExtraNatives.nGetNativeFinalizer(src) only on Ravenwood.
+ *
+ * @see ExtraNatives
+ */
+ @android.ravenwood.annotation.RavenwoodReplace
+ private static long nGetNativeFinalizerWrapper() {
+ return nGetNativeFinalizer();
+ }
+
+ private static long nGetNativeFinalizerWrapper$ravenwood() {
+ return ExtraNatives.nGetNativeFinalizer();
+ }
+
// ------------------ Regular JNI ------------------------
private static native long nCreate(long nSrc_or_zero);
@@ -943,4 +974,25 @@
private static native float nMapRadius(long nObject, float radius);
@CriticalNative
private static native boolean nEquals(long nA, long nB);
+
+ /**
+ * Due to b/337329128, native methods that are called by the static initializers cannot be
+ * in the same class when running on a host side JVM (such as on Ravenwood and Android Studio).
+ *
+ * There are two methods that are called by the static initializers (either directly or
+ * indirectly) in this class, namely nCreate() and nGetNativeFinalizer(). On Ravenwood
+ * these methods can't be on the Matrix class itself, so we use a nested class to host them.
+ *
+ * We still keep the original nCreate() method and call it on non-ravenwood environment,
+ * in order to avoid problems in downstream (such as Android Studio).
+ *
+ * @see #nCreateWrapper(long)
+ * @see #nGetNativeFinalizerWrapper()
+ *
+ * TODO(b/337110712) Clean it up somehow. (remove the original nCreate() and unify the code?)
+ */
+ private static class ExtraNatives {
+ static native long nCreate(long nSrc_or_zero);
+ static native long nGetNativeFinalizer();
+ }
}
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index deb89fa..073307c 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -36,11 +36,16 @@
* (based on the paint's Style), or it can be used for clipping or to draw
* text on a path.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+ android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
public class Path {
-
- private static final NativeAllocationRegistry sRegistry =
- NativeAllocationRegistry.createMalloced(
- Path.class.getClassLoader(), nGetFinalizer());
+ // See b/337329128 for why we need an inner class here.
+ private static class NoImagePreloadHolder {
+ static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(
+ Path.class.getClassLoader(), nGetFinalizer());
+ }
/**
* @hide
@@ -52,7 +57,7 @@
*/
public Path() {
mNativePath = nInit();
- sRegistry.registerNativeAllocation(this, mNativePath);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePath);
}
/**
@@ -62,7 +67,7 @@
*/
public Path(@Nullable Path src) {
mNativePath = nInit(src != null ? src.mNativePath : 0);
- sRegistry.registerNativeAllocation(this, mNativePath);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePath);
}
/**
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 89d3058..e38038e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -1520,12 +1520,16 @@
@GuardedBy("mLock")
TaskFragmentContainer resolveStartActivityIntent(@NonNull WindowContainerTransaction wct,
int taskId, @NonNull Intent intent, @Nullable Activity launchingActivity) {
- // Skip resolving if started from an isolated navigated TaskFragmentContainer.
if (launchingActivity != null) {
final TaskFragmentContainer taskFragmentContainer = getContainerWithActivity(
launchingActivity);
if (taskFragmentContainer != null
&& taskFragmentContainer.isIsolatedNavigationEnabled()) {
+ // Skip resolving if started from an isolated navigated TaskFragmentContainer.
+ return null;
+ }
+ if (isAssociatedWithOverlay(launchingActivity)) {
+ // Skip resolving if the launching activity associated with an overlay.
return null;
}
}
@@ -1659,9 +1663,8 @@
// is the first embedded TF in the task.
final TaskContainer taskContainer = container.getTaskContainer();
// TODO(b/265271880): remove redundant logic after all TF operations take fragmentToken.
- final Rect taskBounds = taskContainer.getBounds();
final Rect sanitizedBounds = sanitizeBounds(activityStackAttributes.getRelativeBounds(),
- getMinDimensions(intent), taskBounds);
+ getMinDimensions(intent), container);
final int windowingMode = taskContainer
.getWindowingModeForTaskFragment(sanitizedBounds);
mPresenter.createTaskFragment(wct, taskFragmentToken, activityInTask.getActivityToken(),
@@ -1722,17 +1725,14 @@
@GuardedBy("mLock")
@Nullable
TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) {
- // Check pending appeared activity first because there can be a delay for the server
- // update.
- TaskFragmentContainer taskFragmentContainer =
- getContainer(container -> container.hasPendingAppearedActivity(activityToken));
- if (taskFragmentContainer != null) {
- return taskFragmentContainer;
+ for (int i = mTaskContainers.size() - 1; i >= 0; --i) {
+ final TaskFragmentContainer container = mTaskContainers.valueAt(i)
+ .getContainerWithActivity(activityToken);
+ if (container != null) {
+ return container;
+ }
}
-
-
- // Check appeared activity if there is no such pending appeared activity.
- return getContainer(container -> container.hasAppearedActivity(activityToken));
+ return null;
}
@GuardedBy("mLock")
@@ -2096,19 +2096,7 @@
if (container == null) {
return null;
}
- final List<SplitContainer> splitContainers =
- container.getTaskContainer().getSplitContainers();
- if (splitContainers.isEmpty()) {
- return null;
- }
- for (int i = splitContainers.size() - 1; i >= 0; i--) {
- final SplitContainer splitContainer = splitContainers.get(i);
- if (container.equals(splitContainer.getSecondaryContainer())
- || container.equals(splitContainer.getPrimaryContainer())) {
- return splitContainer;
- }
- }
- return null;
+ return container.getTaskContainer().getActiveSplitForContainer(container);
}
/**
@@ -2158,6 +2146,11 @@
return false;
}
+ if (isAssociatedWithOverlay(activity)) {
+ // Can't launch the placeholder if the activity associates an overlay.
+ return false;
+ }
+
final TaskFragmentContainer container = getContainerWithActivity(activity);
if (container != null && !allowLaunchPlaceholder(container)) {
// We don't allow activity in this TaskFragment to launch placeholder.
@@ -2197,6 +2190,11 @@
*/
@GuardedBy("mLock")
private boolean allowLaunchPlaceholder(@NonNull TaskFragmentContainer container) {
+ if (container.isOverlay()) {
+ // Don't launch placeholder if the container is an overlay.
+ return false;
+ }
+
final TaskFragmentContainer topContainer = container.getTaskContainer()
.getTopNonFinishingTaskFragmentContainer();
if (container != topContainer) {
@@ -2470,13 +2468,10 @@
@GuardedBy("mLock")
TaskFragmentContainer getContainer(@NonNull Predicate<TaskFragmentContainer> predicate) {
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
- .getTaskFragmentContainers();
- for (int j = containers.size() - 1; j >= 0; j--) {
- final TaskFragmentContainer container = containers.get(j);
- if (predicate.test(container)) {
- return container;
- }
+ final TaskFragmentContainer container = mTaskContainers.valueAt(i)
+ .getContainer(predicate);
+ if (container != null) {
+ return container;
}
}
return null;
@@ -2641,6 +2636,16 @@
return overlayContainers;
}
+ @GuardedBy("mLock")
+ private boolean isAssociatedWithOverlay(@NonNull Activity activity) {
+ final TaskContainer taskContainer = getTaskContainer(getTaskId(activity));
+ if (taskContainer == null) {
+ return false;
+ }
+ return taskContainer.getContainer(c -> c.isOverlay() && !c.isFinished()
+ && c.getAssociatedActivityToken() == activity.getActivityToken()) != null;
+ }
+
/**
* Creates an overlay container or updates a visible overlay container if its
* {@link TaskFragmentContainer#getTaskId()}, {@link TaskFragmentContainer#getOverlayTag()}
@@ -2734,7 +2739,7 @@
}
// Requesting an always-on-top overlay.
if (!associateLaunchingActivity) {
- if (overlayContainer.isAssociatedWithActivity()) {
+ if (overlayContainer.isOverlayWithActivityAssociation()) {
// Dismiss the overlay container since it has associated with an activity.
Log.w(TAG, "The overlay container with tag:"
+ overlayContainer.getOverlayTag() + " is dismissed because"
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 6231ea0..0e4fb30 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -591,16 +591,14 @@
@NonNull TaskFragmentContainer container,
@NonNull ActivityStackAttributes attributes,
@Nullable Size minDimensions) {
- final Rect taskBounds = container.getTaskContainer().getBounds();
final Rect relativeBounds = sanitizeBounds(attributes.getRelativeBounds(), minDimensions,
- taskBounds);
+ container);
final boolean isFillParent = relativeBounds.isEmpty();
// Note that we only set isolated navigation for overlay container without activity
// association. Activity will be launched to an expanded container on top of the overlay
// if the overlay is associated with an activity. Thus, an overlay with activity association
// will never be isolated navigated.
- final boolean isIsolatedNavigated = container.isOverlay()
- && !container.isAssociatedWithActivity() && !isFillParent;
+ final boolean isIsolatedNavigated = container.isAlwaysOnTopOverlay() && !isFillParent;
final boolean dimOnTask = !isFillParent
&& attributes.getWindowAttributes().getDimAreaBehavior() == DIM_AREA_ON_TASK
&& Flags.fullscreenDimFlag();
@@ -624,7 +622,7 @@
*/
@NonNull
static Rect sanitizeBounds(@NonNull Rect bounds, @Nullable Size minDimension,
- @NonNull Rect taskBounds) {
+ @NonNull TaskFragmentContainer container) {
if (bounds.isEmpty()) {
// Don't need to check if the bounds follows the task bounds.
return bounds;
@@ -633,10 +631,33 @@
// Expand the bounds if the bounds are smaller than minimum dimensions.
return new Rect();
}
+ final TaskContainer taskContainer = container.getTaskContainer();
+ final Rect taskBounds = taskContainer.getBounds();
if (!taskBounds.contains(bounds)) {
// Expand the bounds if the bounds exceed the task bounds.
return new Rect();
}
+
+ if (!container.isOverlay()) {
+ // Stop here if the container is not an overlay.
+ return bounds;
+ }
+
+ final IBinder associatedActivityToken = container.getAssociatedActivityToken();
+
+ if (associatedActivityToken == null) {
+ // Stop here if the container is an always-on-top overlay.
+ return bounds;
+ }
+
+ // Expand the overlay with activity association if the associated activity is part of a
+ // split, or we may need to handle three change transition together.
+ final TaskFragmentContainer associatedContainer = taskContainer
+ .getContainerWithActivity(associatedActivityToken);
+ if (taskContainer.getActiveSplitForContainer(associatedContainer) != null) {
+ return new Rect();
+ }
+
return bounds;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index fdf0910..67d34c7 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -43,6 +43,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.window.extensions.core.util.function.Predicate;
import androidx.window.extensions.embedding.SplitAttributes.SplitType;
import androidx.window.extensions.embedding.SplitAttributes.SplitType.ExpandContainersSplitType;
import androidx.window.extensions.embedding.SplitAttributes.SplitType.RatioSplitType;
@@ -318,6 +319,38 @@
return null;
}
+ @Nullable
+ TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) {
+ return getContainer(container -> container.hasAppearedActivity(activityToken)
+ || container.hasPendingAppearedActivity(activityToken));
+ }
+
+ @Nullable
+ TaskFragmentContainer getContainer(@NonNull Predicate<TaskFragmentContainer> predicate) {
+ for (int i = mContainers.size() - 1; i >= 0; i--) {
+ final TaskFragmentContainer container = mContainers.get(i);
+ if (predicate.test(container)) {
+ return container;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ SplitContainer getActiveSplitForContainer(@Nullable TaskFragmentContainer container) {
+ if (container == null) {
+ return null;
+ }
+ for (int i = mSplitContainers.size() - 1; i >= 0; i--) {
+ final SplitContainer splitContainer = mSplitContainers.get(i);
+ if (container.equals(splitContainer.getSecondaryContainer())
+ || container.equals(splitContainer.getPrimaryContainer())) {
+ return splitContainer;
+ }
+ }
+ return null;
+ }
+
/**
* Returns the always-on-top overlay container in the task, or {@code null} if it doesn't exist.
*/
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 094ebcb..c952dfe 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -465,7 +465,7 @@
return;
}
// Early return if this container is not an overlay with activity association.
- if (!isOverlay() || !isAssociatedWithActivity()) {
+ if (!isOverlayWithActivityAssociation()) {
return;
}
if (mAssociatedActivityToken == activityToken) {
@@ -500,7 +500,7 @@
// sure the controller considers this container as the one containing the activity.
// This is needed when the activity is added as pending appeared activity to one
// TaskFragment while it is also an appeared activity in another.
- return mController.getContainerWithActivity(activityToken) == this;
+ return mTaskContainer.getContainerWithActivity(activityToken) == this;
}
/** Whether this activity has appeared in the TaskFragment on the server side. */
@@ -1019,16 +1019,16 @@
return mAssociatedActivityToken;
}
- boolean isAssociatedWithActivity() {
- return mAssociatedActivityToken != null;
- }
-
/**
* Returns {@code true} if the overlay container should be always on top, which should be
* a non-fill-parent overlay without activity association.
*/
boolean isAlwaysOnTopOverlay() {
- return isOverlay() && !isAssociatedWithActivity();
+ return isOverlay() && mAssociatedActivityToken == null;
+ }
+
+ boolean isOverlayWithActivityAssociation() {
+ return isOverlay() && mAssociatedActivityToken != null;
}
@Override
@@ -1050,7 +1050,7 @@
+ " runningActivityCount=" + getRunningActivityCount()
+ " isFinished=" + mIsFinished
+ " overlayTag=" + mOverlayTag
- + " associatedActivity" + mAssociatedActivityToken
+ + " associatedActivityToken=" + mAssociatedActivityToken
+ " lastRequestedBounds=" + mLastRequestedBounds
+ " pendingAppearedActivities=" + mPendingAppearedActivities
+ (includeContainersToFinishOnExit ? " containersToFinishOnExit="
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index 50abdfd..fab298d 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -21,11 +21,15 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static androidx.window.extensions.embedding.ActivityEmbeddingOptionsProperties.KEY_OVERLAY_TAG;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.SPLIT_ATTRIBUTES;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TEST_TAG;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitPairRuleBuilder;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitPlaceholderRuleBuilder;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
+import static androidx.window.extensions.embedding.SplitPresenter.sanitizeBounds;
import static androidx.window.extensions.embedding.WindowAttributes.DIM_AREA_ON_TASK;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -85,6 +89,7 @@
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -102,6 +107,9 @@
@Rule
public MockitoRule rule = MockitoJUnit.rule();
+ private static final Intent PLACEHOLDER_INTENT = new Intent().setComponent(
+ new ComponentName("test", "placeholder"));
+
@Rule
public final SetFlagsRule mSetFlagRule = new SetFlagsRule();
@@ -259,8 +267,7 @@
mSplitController.setActivityStackAttributesCalculator(params ->
new ActivityStackAttributes.Builder().setRelativeBounds(bounds).build());
final TaskFragmentContainer overlayContainer = createOrUpdateOverlayTaskFragmentIfNeeded(
- mOverlayContainer1.getOverlayTag(),
- mOverlayContainer1.getTopNonFinishingActivity());
+ mOverlayContainer1.getOverlayTag());
assertWithMessage("overlayContainer1 must be updated since the new overlay container"
+ " is launched with the same tag and task")
@@ -280,12 +287,13 @@
mSplitController.setActivityStackAttributesCalculator(params ->
new ActivityStackAttributes.Builder().setRelativeBounds(bounds).build());
final TaskFragmentContainer overlayContainer = createOrUpdateOverlayTaskFragmentIfNeeded(
- mOverlayContainer1.getOverlayTag(), mActivity);
+ mOverlayContainer1.getOverlayTag(), createMockActivity());
assertWithMessage("overlayContainer1 must be dismissed since the new overlay container"
+ " is associated with different launching activity")
.that(mSplitController.getAllNonFinishingOverlayContainers())
.containsExactly(mOverlayContainer2, overlayContainer);
+ assertThat(overlayContainer).isNotEqualTo(mOverlayContainer1);
}
@Test
@@ -323,7 +331,8 @@
}
private void createExistingOverlayContainers(boolean visible) {
- mOverlayContainer1 = createTestOverlayContainer(TASK_ID, "test1", visible);
+ mOverlayContainer1 = createTestOverlayContainer(TASK_ID, "test1", visible,
+ true /* associatedLaunchingActivity */, mActivity);
mOverlayContainer2 = createTestOverlayContainer(TASK_ID + 1, "test2", visible);
List<TaskFragmentContainer> overlayContainers = mSplitController
.getAllNonFinishingOverlayContainers();
@@ -335,17 +344,49 @@
mIntent.setComponent(new ComponentName(ApplicationProvider.getApplicationContext(),
MinimumDimensionActivity.class));
final Rect bounds = new Rect(0, 0, 100, 100);
+ final TaskFragmentContainer overlayContainer =
+ createTestOverlayContainer(TASK_ID, "test1");
- SplitPresenter.sanitizeBounds(bounds, SplitPresenter.getMinDimensions(mIntent),
- TASK_BOUNDS);
+ assertThat(sanitizeBounds(bounds, SplitPresenter.getMinDimensions(mIntent),
+ overlayContainer).isEmpty()).isTrue();
}
@Test
public void testSanitizeBounds_notInTaskBounds_expandOverlay() {
final Rect bounds = new Rect(TASK_BOUNDS);
bounds.offset(10, 10);
+ final TaskFragmentContainer overlayContainer =
+ createTestOverlayContainer(TASK_ID, "test1");
- SplitPresenter.sanitizeBounds(bounds, null, TASK_BOUNDS);
+ assertThat(sanitizeBounds(bounds, null, overlayContainer)
+ .isEmpty()).isTrue();
+ }
+
+ @Test
+ public void testSanitizeBounds_visibleSplit_expandOverlay() {
+ // Launch a visible split
+ final Activity primaryActivity = createMockActivity();
+ final Activity secondaryActivity = createMockActivity();
+ final TaskFragmentContainer primaryContainer =
+ createMockTaskFragmentContainer(primaryActivity, true /* isVisible */);
+ final TaskFragmentContainer secondaryContainer =
+ createMockTaskFragmentContainer(secondaryActivity, true /* isVisible */);
+
+ final SplitPairRule splitPairRule = createSplitPairRuleBuilder(
+ activityActivityPair -> true /* activityPairPredicate */,
+ activityIntentPair -> true /* activityIntentPairPredicate */,
+ parentWindowMetrics -> true /* parentWindowMetricsPredicate */)
+ .build();
+ mSplitController.registerSplit(mTransaction, primaryContainer, primaryActivity,
+ secondaryContainer, splitPairRule, splitPairRule.getDefaultSplitAttributes());
+
+ final Rect bounds = new Rect(0, 0, 100, 100);
+ final TaskFragmentContainer overlayContainer =
+ createTestOverlayContainer(TASK_ID, "test1", true /* isVisible */,
+ true /* associatedLaunchingActivity */, secondaryActivity);
+
+ assertThat(sanitizeBounds(bounds, null, overlayContainer)
+ .isEmpty()).isTrue();
}
@Test
@@ -701,6 +742,70 @@
.doesNotContain(overlayWithAssociation);
}
+ @Test
+ public void testLaunchPlaceholderIfNecessary_skipIfActivityAssociateOverlay() {
+ setupPlaceholderRule(mActivity);
+ createTestOverlayContainer(TASK_ID, "test", true /* isVisible */,
+ true /* associateLaunchingActivity */, mActivity);
+
+
+ mSplitController.mTransactionManager.startNewTransaction();
+ assertThat(mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity,
+ false /* isOnCreated */)).isFalse();
+
+ verify(mTransaction, never()).startActivityInTaskFragment(any(), any(), any(), any());
+ }
+
+ @Test
+ public void testLaunchPlaceholderIfNecessary_skipIfActivityInOverlay() {
+ setupPlaceholderRule(mActivity);
+ createOrUpdateOverlayTaskFragmentIfNeeded("test1", mActivity);
+
+ mSplitController.mTransactionManager.startNewTransaction();
+ assertThat(mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity,
+ false /* isOnCreated */)).isFalse();
+
+ verify(mTransaction, never()).startActivityInTaskFragment(any(), any(), any(), any());
+ }
+
+ /** Setups a rule to launch placeholder for the given activity. */
+ private void setupPlaceholderRule(@NonNull Activity primaryActivity) {
+ final SplitRule placeholderRule = createSplitPlaceholderRuleBuilder(PLACEHOLDER_INTENT,
+ primaryActivity::equals, i -> false, w -> true)
+ .setDefaultSplitAttributes(SPLIT_ATTRIBUTES)
+ .build();
+ mSplitController.setEmbeddingRules(Collections.singleton(placeholderRule));
+ }
+
+ @Test
+ public void testResolveStartActivityIntent_skipIfAssociateOverlay() {
+ final Intent intent = new Intent();
+ mSplitController.setEmbeddingRules(Collections.singleton(
+ createSplitRule(mActivity, intent)));
+ createTestOverlayContainer(TASK_ID, "test", true /* isVisible */,
+ true /* associateLaunchingActivity */, mActivity);
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, mActivity);
+
+ assertThat(container).isNull();
+ verify(mSplitController, never()).resolveStartActivityIntentByRule(any(), anyInt(), any(),
+ any());
+ }
+
+ @Test
+ public void testResolveStartActivityIntent_skipIfLaunchingActivityInOverlay() {
+ final Intent intent = new Intent();
+ mSplitController.setEmbeddingRules(Collections.singleton(
+ createSplitRule(mActivity, intent)));
+ createOrUpdateOverlayTaskFragmentIfNeeded("test1", mActivity);
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, mActivity);
+
+ assertThat(container).isNull();
+ verify(mSplitController, never()).resolveStartActivityIntentByRule(any(), anyInt(), any(),
+ any());
+ }
+
/**
* A simplified version of {@link SplitController#createOrUpdateOverlayTaskFragmentIfNeeded}
*/
@@ -726,9 +831,16 @@
/** Creates a mock TaskFragment that has been registered and appeared in the organizer. */
@NonNull
private TaskFragmentContainer createMockTaskFragmentContainer(@NonNull Activity activity) {
+ return createMockTaskFragmentContainer(activity, false /* isVisible */);
+ }
+
+ /** Creates a mock TaskFragment that has been registered and appeared in the organizer. */
+ @NonNull
+ private TaskFragmentContainer createMockTaskFragmentContainer(
+ @NonNull Activity activity, boolean isVisible) {
final TaskFragmentContainer container = mSplitController.newContainer(activity,
activity.getTaskId());
- setupTaskFragmentInfo(container, activity, false /* isVisible */);
+ setupTaskFragmentInfo(container, activity, isVisible);
return container;
}
@@ -745,17 +857,26 @@
true /* associateLaunchingActivity */);
}
+ @NonNull
+ private TaskFragmentContainer createTestOverlayContainer(int taskId, @NonNull String tag,
+ boolean isVisible, boolean associateLaunchingActivity) {
+ return createTestOverlayContainer(taskId, tag, isVisible, associateLaunchingActivity,
+ null /* launchingActivity */);
+ }
+
// TODO(b/243518738): add more test coverage on overlay container without activity association
// once we have use cases.
@NonNull
private TaskFragmentContainer createTestOverlayContainer(int taskId, @NonNull String tag,
- boolean isVisible, boolean associateLaunchingActivity) {
- Activity activity = createMockActivity();
+ boolean isVisible, boolean associateLaunchingActivity,
+ @Nullable Activity launchingActivity) {
+ final Activity activity = launchingActivity != null
+ ? launchingActivity : createMockActivity();
TaskFragmentContainer overlayContainer = mSplitController.newContainer(
null /* pendingAppearedActivity */, mIntent, activity, taskId,
null /* pairedPrimaryContainer */, tag, Bundle.EMPTY,
associateLaunchingActivity);
- setupTaskFragmentInfo(overlayContainer, activity, isVisible);
+ setupTaskFragmentInfo(overlayContainer, createMockActivity(), isVisible);
return overlayContainer;
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index abfc9c8..44ab2c4 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -538,9 +538,7 @@
// container1.
container2.setInfo(mTransaction, mInfo);
- assertTrue(container1.hasActivity(mActivity.getActivityToken()));
- assertFalse(container2.hasActivity(mActivity.getActivityToken()));
-
+ assertTrue(container2.hasActivity(mActivity.getActivityToken()));
// When the pending appeared record is removed from container1, we respect the appeared
// record in container2.
container1.removePendingAppearedActivity(mActivity.getActivityToken());
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index c2c90c8..c8bfe7a4 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -420,7 +420,7 @@
<dimen name="freeform_decor_caption_height">42dp</dimen>
<!-- Height of desktop mode caption for freeform tasks. -->
- <dimen name="desktop_mode_freeform_decor_caption_height">42dp</dimen>
+ <dimen name="desktop_mode_freeform_decor_caption_height">40dp</dimen>
<!-- Height of desktop mode caption for fullscreen tasks. -->
<dimen name="desktop_mode_fullscreen_decor_caption_height">36dp</dimen>
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 08b7c01..ecfb134 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
@@ -1515,7 +1515,7 @@
@JvmField
val DESKTOP_MODE_INITIAL_BOUNDS_SCALE = SystemProperties
- .getInt("persist.wm.debug.freeform_initial_bounds_scale", 75) / 100f
+ .getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f
/**
* Check if desktop density override is enabled
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index e7d9812..c5f23a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -373,6 +373,10 @@
if (DesktopModeStatus.isEnabled() && mDesktopModeTaskRepository.isPresent()
&& mDesktopModeTaskRepository.get().isActiveTask(taskInfo.taskId)) {
+ if (mDesktopModeTaskRepository.get().isMinimizedTask(taskInfo.taskId)) {
+ // Minimized freeform tasks should not be shown at all.
+ continue;
+ }
// Freeform tasks will be added as a separate entry
if (mostRecentFreeformTaskIndex == Integer.MAX_VALUE) {
mostRecentFreeformTaskIndex = recentTasks.size();
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml
index 5b2ffec..4dd14f4 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml
@@ -20,6 +20,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml
index 9f7d9fc..5c86a38 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml
@@ -20,6 +20,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml
index 882b200..aa70c09 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml
@@ -20,6 +20,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
index f5a8655..bf040d2 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
@@ -20,6 +20,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml
index 51a55e35..c7c804f 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml
@@ -20,6 +20,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml
index 05f937a..214bdfa 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml
@@ -20,6 +20,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 40b59c1..5cf9be4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -395,6 +395,51 @@
}
@Test
+ public void testGetRecentTasks_proto2Enabled_ignoresMinimizedFreeformTasks() {
+ StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
+ DesktopModeStatus.class).startMocking();
+ when(DesktopModeStatus.isEnabled()).thenReturn(true);
+
+ ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+ ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+ ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
+ ActivityManager.RecentTaskInfo t4 = makeTaskInfo(4);
+ ActivityManager.RecentTaskInfo t5 = makeTaskInfo(5);
+ setRawList(t1, t2, t3, t4, t5);
+
+ when(mDesktopModeTaskRepository.isActiveTask(1)).thenReturn(true);
+ when(mDesktopModeTaskRepository.isActiveTask(3)).thenReturn(true);
+ when(mDesktopModeTaskRepository.isActiveTask(5)).thenReturn(true);
+ when(mDesktopModeTaskRepository.isMinimizedTask(3)).thenReturn(true);
+
+ ArrayList<GroupedRecentTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(
+ MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
+
+ // 2 freeform tasks should be grouped into one, 1 task should be skipped, 3 total recents
+ // entries
+ assertEquals(3, recentTasks.size());
+ GroupedRecentTaskInfo freeformGroup = recentTasks.get(0);
+ GroupedRecentTaskInfo singleGroup1 = recentTasks.get(1);
+ GroupedRecentTaskInfo singleGroup2 = recentTasks.get(2);
+
+ // Check that groups have expected types
+ assertEquals(GroupedRecentTaskInfo.TYPE_FREEFORM, freeformGroup.getType());
+ assertEquals(GroupedRecentTaskInfo.TYPE_SINGLE, singleGroup1.getType());
+ assertEquals(GroupedRecentTaskInfo.TYPE_SINGLE, singleGroup2.getType());
+
+ // Check freeform group entries
+ assertEquals(2, freeformGroup.getTaskInfoList().size());
+ assertEquals(t1, freeformGroup.getTaskInfoList().get(0));
+ assertEquals(t5, freeformGroup.getTaskInfoList().get(1));
+
+ // Check single entries
+ assertEquals(t2, singleGroup1.getTaskInfo1());
+ assertEquals(t4, singleGroup2.getTaskInfo1());
+
+ mockitoSession.finishMocking();
+ }
+
+ @Test
public void testRemovedTaskRemovesSplit() {
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp
index 8315c4c..07e97f8 100644
--- a/libs/hwui/jni/Graphics.cpp
+++ b/libs/hwui/jni/Graphics.cpp
@@ -211,11 +211,7 @@
static jfieldID gRegion_nativeInstanceID;
static jmethodID gRegion_constructorMethodID;
-static jclass gByte_class;
-static jobject gVMRuntime;
-static jclass gVMRuntime_class;
-static jmethodID gVMRuntime_newNonMovableArray;
-static jmethodID gVMRuntime_addressOf;
+static jclass gByte_class;
static jclass gColorSpace_class;
static jmethodID gColorSpace_getMethodID;
@@ -789,13 +785,6 @@
gByte_class = (jclass) env->NewGlobalRef(
env->GetStaticObjectField(c, env->GetStaticFieldID(c, "TYPE", "Ljava/lang/Class;")));
- gVMRuntime_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "dalvik/system/VMRuntime"));
- m = env->GetStaticMethodID(gVMRuntime_class, "getRuntime", "()Ldalvik/system/VMRuntime;");
- gVMRuntime = env->NewGlobalRef(env->CallStaticObjectMethod(gVMRuntime_class, m));
- gVMRuntime_newNonMovableArray = GetMethodIDOrDie(env, gVMRuntime_class, "newNonMovableArray",
- "(Ljava/lang/Class;I)Ljava/lang/Object;");
- gVMRuntime_addressOf = GetMethodIDOrDie(env, gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J");
-
gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace"));
gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class,
"get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;");
diff --git a/libs/hwui/jni/android_graphics_Matrix.cpp b/libs/hwui/jni/android_graphics_Matrix.cpp
index ca667b0..c0d791a 100644
--- a/libs/hwui/jni/android_graphics_Matrix.cpp
+++ b/libs/hwui/jni/android_graphics_Matrix.cpp
@@ -376,11 +376,24 @@
{"nEquals", "(JJ)Z", (void*) SkMatrixGlue::equals}
};
+static const JNINativeMethod extra_methods[] = {
+ {"nGetNativeFinalizer", "()J", (void*)SkMatrixGlue::getNativeFinalizer},
+ {"nCreate", "(J)J", (void*)SkMatrixGlue::create},
+};
+
static jclass sClazz;
static jfieldID sNativeInstanceField;
static jmethodID sCtor;
int register_android_graphics_Matrix(JNIEnv* env) {
+ // Methods only used on Ravenwood (for now). See the javadoc on Matrix$ExtraNativesx
+ // for why we need it.
+ //
+ // We don't need it on non-ravenwood, but we don't (yet) have a way to detect ravenwood
+ // environment, so we just always run it.
+ RegisterMethodsOrDie(env, "android/graphics/Matrix$ExtraNatives", extra_methods,
+ NELEM(extra_methods));
+
int result = RegisterMethodsOrDie(env, "android/graphics/Matrix", methods, NELEM(methods));
jclass clazz = FindClassOrDie(env, "android/graphics/Matrix");
diff --git a/location/lib/java/com/android/location/provider/SignificantPlaceProvider.java b/location/lib/java/com/android/location/provider/SignificantPlaceProvider.java
new file mode 100644
index 0000000..0b39a9a
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/SignificantPlaceProvider.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.location.provider;
+
+import android.annotation.Nullable;
+import android.app.trust.TrustManager;
+import android.hardware.location.ISignificantPlaceProvider;
+import android.hardware.location.ISignificantPlaceProviderManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+
+/** @hide */
+public class SignificantPlaceProvider {
+
+ public static final String ACTION = TrustManager.ACTION_BIND_SIGNIFICANT_PLACE_PROVIDER;
+
+ private final IBinder mBinder;
+
+ // write locked on mBinder, read lock is optional depending on atomicity requirements
+ @Nullable private volatile ISignificantPlaceProviderManager mManager;
+
+ @GuardedBy("mBinder")
+ private boolean mInSignificantPlace = false;
+
+ public SignificantPlaceProvider() {
+ mBinder = new Service();
+ mManager = null;
+ }
+
+ public IBinder getBinder() {
+ return mBinder;
+ }
+
+ /** Set whether the device is currently in a trusted location. */
+ public void setInSignificantPlace(boolean inSignificantPlace) {
+ synchronized (mBinder) {
+ if (inSignificantPlace == mInSignificantPlace) {
+ return;
+ }
+
+ mInSignificantPlace = inSignificantPlace;
+ }
+
+ ISignificantPlaceProviderManager manager = mManager;
+ if (manager != null) {
+ try {
+ manager.setInSignificantPlace(inSignificantPlace);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ private final class Service extends ISignificantPlaceProvider.Stub {
+
+ Service() {}
+
+ @Override
+ public void setSignificantPlaceProviderManager(ISignificantPlaceProviderManager manager) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ return;
+ }
+
+ synchronized (mBinder) {
+ if (mInSignificantPlace) {
+ try {
+ manager.setInSignificantPlace(true);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ mManager = manager;
+ }
+ }
+ }
+}
diff --git a/media/OWNERS b/media/OWNERS
index 1e5a458..5e39195 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -11,6 +11,7 @@
nchalko@google.com
philburk@google.com
quxiangfang@google.com
+shuzhenwang@google.com
wonsik@google.com
# go/android-fwk-media-solutions for info on areas of ownership.
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/OWNERS b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/OWNERS
new file mode 100644
index 0000000..f4f9c08
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1344
+include platform/frameworks/base:/media/OWNERS
+
+# Camera
+per-file *Camera* = file:platform/frameworks/av:/camera/OWNERS
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index fc96896..353366d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -89,7 +89,8 @@
public void testCameraInfo() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId,
- /*overrideToPortrait*/false, DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
+ ICameraService.ROTATION_OVERRIDE_NONE, DEVICE_ID_DEFAULT,
+ DEVICE_POLICY_DEFAULT);
assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1);
assertTrue("Orientation was not set for camera " + cameraId,
info.info.orientation != -1);
@@ -164,7 +165,7 @@
ICameraService.USE_CALLING_UID,
ICameraService.USE_CALLING_PID,
getContext().getApplicationInfo().targetSdkVersion,
- /*overrideToPortrait*/false,
+ ICameraService.ROTATION_OVERRIDE_NONE,
/*forceSlowJpegMode*/false,
DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
@@ -266,7 +267,8 @@
clientPackageName, clientAttributionTag,
ICameraService.USE_CALLING_UID, 0 /*oomScoreOffset*/,
getContext().getApplicationInfo().targetSdkVersion,
- /*overrideToPortrait*/false, DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
+ ICameraService.ROTATION_OVERRIDE_NONE, DEVICE_ID_DEFAULT,
+ DEVICE_POLICY_DEFAULT);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected", cameraId));
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index dc8647f..6cf2a41 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -248,7 +248,7 @@
mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
clientPackageName, clientAttributionTag, ICameraService.USE_CALLING_UID,
/*oomScoreOffset*/0, getContext().getApplicationInfo().targetSdkVersion,
- /*overrideToPortrait*/false, DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
+ ICameraService.ROTATION_OVERRIDE_NONE, DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
@@ -415,7 +415,8 @@
@SmallTest
public void testCameraCharacteristics() throws RemoteException {
CameraMetadataNative info = mUtils.getCameraService().getCameraCharacteristics(mCameraId,
- getContext().getApplicationInfo().targetSdkVersion, /*overrideToPortrait*/false,
+ getContext().getApplicationInfo().targetSdkVersion,
+ ICameraService.ROTATION_OVERRIDE_NONE,
DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
assertFalse(info.isEmpty());
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
index 45253bb..68b81db 100644
--- a/packages/SettingsLib/res/values/config.xml
+++ b/packages/SettingsLib/res/values/config.xml
@@ -22,6 +22,9 @@
<!-- Threshold in micro watts above which a charger is rated as "fast"; 1.5A @ 5V -->
<integer name="config_chargingFastThreshold">7500000</integer>
+ <!-- Threshold in micro watts above which a charger is rated as "fast"; 20W -->
+ <integer name="config_chargingFastThreshold_v2">20000000</integer>
+
<!-- When true, show 1/2G networks as 3G. -->
<bool name="config_showMin3G">false</bool>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
index 169c330..57bde56 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
@@ -29,6 +29,7 @@
import android.os.UserManager;
import android.permission.PermissionManager;
import android.text.format.DateUtils;
+import android.util.ArrayMap;
import android.util.IconDrawableFactory;
import android.util.Log;
@@ -127,6 +128,7 @@
final long now = mClock.millis();
final UserManager um = mContext.getSystemService(UserManager.class);
final List<UserHandle> profiles = um.getUserProfiles();
+ ArrayMap<UserHandle, Boolean> shouldIncludeAppsByUsers = new ArrayMap<>();
for (int i = 0; i < appOpsCount; ++i) {
AppOpsManager.PackageOps ops = appOps.get(i);
@@ -134,9 +136,13 @@
int uid = ops.getUid();
UserHandle user = UserHandle.getUserHandleForUid(uid);
+ if (!shouldIncludeAppsByUsers.containsKey(user)) {
+ shouldIncludeAppsByUsers.put(user, shouldHideUser(um, user));
+ }
+
// Don't show apps belonging to background users except for profiles that shouldn't
// be shown in quiet mode.
- if (!profiles.contains(user) || isHideInQuietEnabledForProfile(um, user)) {
+ if (!profiles.contains(user) || !shouldIncludeAppsByUsers.get(user)) {
continue;
}
@@ -200,7 +206,7 @@
return accesses;
}
- private boolean isHideInQuietEnabledForProfile(UserManager userManager, UserHandle userHandle) {
+ private boolean shouldHideUser(UserManager userManager, UserHandle userHandle) {
if (android.multiuser.Flags.enablePrivateSpaceFeatures()
&& android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()) {
return userManager.isQuietModeEnabled(userHandle)
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index 2032328..f659e38 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -145,7 +145,8 @@
final int slowThreshold = context.getResources().getInteger(
R.integer.config_chargingSlowlyThreshold);
final int fastThreshold = context.getResources().getInteger(
- R.integer.config_chargingFastThreshold);
+ getFastChargingThresholdResId());
+
return maxChargingWattage <= 0 ? CHARGING_UNKNOWN :
maxChargingWattage < slowThreshold ? CHARGING_SLOWLY :
maxChargingWattage > fastThreshold ? CHARGING_FAST :
@@ -382,7 +383,7 @@
< context.getResources().getInteger(R.integer.config_chargingSlowlyThreshold)) {
return CHARGING_SLOWLY;
} else if (maxChargingMicroWatt
- > context.getResources().getInteger(R.integer.config_chargingFastThreshold)) {
+ > context.getResources().getInteger(getFastChargingThresholdResId())) {
return CHARGING_FAST;
} else {
return CHARGING_REGULAR;
@@ -410,4 +411,10 @@
return -1;
}
}
+
+ private static int getFastChargingThresholdResId() {
+ return BatteryUtils.isChargingStringV2Enabled()
+ ? R.integer.config_chargingFastThreshold_v2
+ : R.integer.config_chargingFastThreshold;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
index 327e470..ca3af53 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
@@ -27,6 +27,7 @@
import android.util.ArraySet;
import android.view.accessibility.AccessibilityManager;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import java.util.List;
@@ -97,9 +98,18 @@
/** Used to override the system property to enable or reset for charging string V2. */
@VisibleForTesting
public static void setChargingStringV2Enabled(Boolean enabled) {
- SystemProperties.set(
- BatteryUtils.PROPERTY_CHARGING_STRING_V2_KEY,
- enabled == null ? "" : String.valueOf(enabled));
+ setChargingStringV2Enabled(enabled, true /* updateProperty */);
+ }
+
+ /** Used to override the system property to enable or reset for charging string V2. */
+ @VisibleForTesting
+ public static void setChargingStringV2Enabled(
+ @Nullable Boolean enabled, boolean updateProperty) {
+ if (updateProperty) {
+ SystemProperties.set(
+ BatteryUtils.PROPERTY_CHARGING_STRING_V2_KEY,
+ enabled == null ? "" : String.valueOf(enabled));
+ }
BatteryUtils.sChargingStringV2Enabled = enabled;
}
}
diff --git a/packages/SettingsLib/tests/unit/src/com/android/settingslib/fuelgague/BatteryStatusTest.kt b/packages/SettingsLib/tests/unit/src/com/android/settingslib/fuelgague/BatteryStatusTest.kt
index 6c0c1a7..4940610 100644
--- a/packages/SettingsLib/tests/unit/src/com/android/settingslib/fuelgague/BatteryStatusTest.kt
+++ b/packages/SettingsLib/tests/unit/src/com/android/settingslib/fuelgague/BatteryStatusTest.kt
@@ -38,6 +38,7 @@
import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_SLOWLY
import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_UNKNOWN
import com.android.settingslib.fuelgauge.BatteryStatus.isBatteryDefender
+import com.android.settingslib.fuelgauge.BatteryUtils
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.util.Optional
@@ -253,12 +254,17 @@
private val maxChargingCurrent: Optional<Int>,
private val maxChargingVoltage: Optional<Int>,
private val expectedChargingSpeed: Int,
+ private val chargingStringV2Enabled: Boolean,
) {
val context: Context = ApplicationProvider.getApplicationContext()
@Test
fun getChargingSpeed_() {
+ BatteryUtils.setChargingStringV2Enabled(
+ chargingStringV2Enabled,
+ false /* updateProperty */
+ )
val batteryChangedIntent =
Intent(Intent.ACTION_BATTERY_CHANGED).apply {
maxChargingCurrent.ifPresent { putExtra(EXTRA_MAX_CHARGING_CURRENT, it) }
@@ -278,37 +284,57 @@
"maxCurrent=n/a, maxVoltage=n/a -> UNKNOWN",
Optional.empty<Int>(),
Optional.empty<Int>(),
- CHARGING_UNKNOWN
+ CHARGING_UNKNOWN,
+ false /* chargingStringV2Enabled */
),
arrayOf(
"maxCurrent=0, maxVoltage=9000000 -> UNKNOWN",
Optional.of(0),
Optional.of(0),
- CHARGING_UNKNOWN
+ CHARGING_UNKNOWN,
+ false /* chargingStringV2Enabled */
),
arrayOf(
"maxCurrent=1500000, maxVoltage=5000000 -> CHARGING_REGULAR",
Optional.of(1500000),
Optional.of(5000000),
- CHARGING_REGULAR
+ CHARGING_REGULAR,
+ false /* chargingStringV2Enabled */
),
arrayOf(
"maxCurrent=1000000, maxVoltage=5000000 -> CHARGING_REGULAR",
Optional.of(1000000),
Optional.of(5000000),
- CHARGING_REGULAR
+ CHARGING_REGULAR,
+ false /* chargingStringV2Enabled */
),
arrayOf(
"maxCurrent=1500001, maxVoltage=5000000 -> CHARGING_FAST",
Optional.of(1501000),
Optional.of(5000000),
- CHARGING_FAST
+ CHARGING_FAST,
+ false /* chargingStringV2Enabled */
),
arrayOf(
"maxCurrent=999999, maxVoltage=5000000 -> CHARGING_SLOWLY",
Optional.of(999999),
Optional.of(5000000),
- CHARGING_SLOWLY
+ CHARGING_SLOWLY,
+ false /* chargingStringV2Enabled */
+ ),
+ arrayOf(
+ "maxCurrent=3000000, maxVoltage=9000000 -> CHARGING_FAST",
+ Optional.of(3000000),
+ Optional.of(9000000),
+ CHARGING_FAST,
+ true /* chargingStringV2Enabled */
+ ),
+ arrayOf(
+ "maxCurrent=2200000, maxVoltage=9000000 -> CHARGING_REGULAR",
+ Optional.of(2200000),
+ Optional.of(9000000),
+ CHARGING_REGULAR,
+ true /* chargingStringV2Enabled */
),
)
}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index e2af631..65c5708 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -69,6 +69,219 @@
visibility: ["//visibility:private"],
}
+filegroup {
+ name: "SystemUI-tests-robofiles",
+ srcs: [
+ "tests/src/**/*.kt",
+ "tests/src/**/*.java",
+ ],
+ visibility: ["//visibility:private"],
+}
+
+// We are running robolectric tests in the tests directory as well as
+// multivalent tests. If you add a test, and it doesn't run in robolectric,
+// it should be added to this exclusion list. go/multivalent-tests
+filegroup {
+ name: "SystemUI-tests-broken-robofiles",
+ srcs: [
+ "tests/src/**/*DeviceOnlyTest.java",
+ "tests/src/**/*DeviceOnlyTest.kt",
+ "tests/src/**/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt",
+ "tests/src/**/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepositoryImplForDeviceTest.kt",
+ "tests/src/**/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt",
+ "tests/src/**/systemui/controls/management/ControlsFavoritingActivityTest.kt",
+ "tests/src/**/systemui/controls/management/ControlsProviderSelectorActivityTest.kt",
+ "tests/src/**/systemui/controls/start/ControlsStartableTest.kt",
+ "tests/src/**/systemui/haptics/slider/SliderStateTrackerTest.kt",
+ "tests/src/**/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinatorTest.kt",
+ "tests/src/**/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt",
+ "tests/src/**/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt",
+ "tests/src/**/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt",
+ "tests/src/**/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt",
+ "tests/src/**/systemui/keyguard/ResourceTrimmerTest.kt",
+ "tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt",
+ "tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt",
+ "tests/src/**/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt",
+ "tests/src/**/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherCoreStartableTest.kt",
+ "tests/src/**/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt",
+ "tests/src/**/systemui/qs/tileimpl/QSTileViewImplTest.kt",
+ "tests/src/**/systemui/qs/tiles/DeviceControlsTileTest.kt",
+ "tests/src/**/systemui/screenshot/ActionExecutorTest.kt",
+ "tests/src/**/systemui/screenshot/ActionIntentCreatorTest.kt",
+ "tests/src/**/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt",
+ "tests/src/**/systemui/screenshot/TakeScreenshotServiceTest.kt",
+ "tests/src/**/systemui/statusbar/commandline/CommandRegistryTest.kt",
+ "tests/src/**/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt",
+ "tests/src/**/systemui/statusbar/notification/icon/IconManagerTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt",
+ "tests/src/**/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt",
+ "tests/src/**/systemui/statusbar/policy/BatteryStateNotifierTest.kt",
+ "tests/src/**/systemui/statusbar/policy/FlashlightControllerImplTest.kt",
+ "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt",
+ "tests/src/**/systemui/stylus/StylusUsiPowerStartableTest.kt",
+ "tests/src/**/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt",
+ "tests/src/**/keyguard/ClockEventControllerTest.kt",
+ "tests/src/**/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt",
+ "tests/src/**/keyguard/LegacyLockIconViewControllerBaseTest.kt",
+ "tests/src/**/keyguard/LegacyLockIconViewControllerTest.java",
+ "tests/src/**/systemui/animation/TransitionAnimatorTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/BluetoothAutoOnRepositoryTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogRepositoryTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt",
+ "tests/src/**/systemui/broadcast/UserBroadcastDispatcherTest.kt",
+ "tests/src/**/systemui/charging/WiredChargingRippleControllerTest.kt",
+ "tests/src/**/systemui/clipboardoverlay/ClipboardModelTest.kt",
+ "tests/src/**/systemui/controls/controller/AuxiliaryPersistenceWrapperTest.kt",
+ "tests/src/**/systemui/controls/controller/ControlsBindingControllerImplTest.kt",
+ "tests/src/**/systemui/controls/controller/ControlsControllerImplTest.kt",
+ "tests/src/**/systemui/controls/controller/DeletionJobServiceTest.kt",
+ "tests/src/**/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt",
+ "tests/src/**/systemui/controls/ui/ControlsUiControllerImplTest.kt",
+ "tests/src/**/systemui/controls/ui/ControlViewHolderTest.kt",
+ "tests/src/**/systemui/controls/ui/SelectionItemTest.kt",
+ "tests/src/**/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt",
+ "tests/src/**/systemui/media/controls/ui/animation/AnimationBindHandlerTest.kt",
+ "tests/src/**/systemui/media/controls/ui/animation/ColorSchemeTransitionTest.kt",
+ "tests/src/**/systemui/media/controls/ui/animation/MetadataAnimationHandlerTest.kt",
+ "tests/src/**/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt",
+ "tests/src/**/systemui/media/controls/ui/controller/MediaControlPanelTest.kt",
+ "tests/src/**/systemui/media/controls/ui/controller/MediaViewControllerTest.kt",
+ "tests/src/**/systemui/media/controls/ui/drawable/SquigglyProgressTest.kt",
+ "tests/src/**/systemui/media/controls/ui/MediaPlayerDataTest.kt",
+ "tests/src/**/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt",
+ "tests/src/**/systemui/navigationbar/gestural/BackPanelControllerTest.kt",
+ "tests/src/**/systemui/notetask/NoteTaskControllerTest.kt",
+ "tests/src/**/systemui/notetask/NoteTaskInitializerTest.kt",
+ "tests/src/**/systemui/power/domain/interactor/PowerInteractorTest.kt",
+ "tests/src/**/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt",
+ "tests/src/**/systemui/privacy/PrivacyItemControllerTest.kt",
+ "tests/src/**/systemui/qs/external/CustomTileStatePersisterTest.kt",
+ "tests/src/**/systemui/qs/external/TileRequestDialogTest.kt",
+ "tests/src/**/systemui/qs/external/TileServiceRequestControllerTest.kt",
+ "tests/src/**/systemui/qs/tileimpl/TilesStatesTextTest.kt",
+ "tests/src/**/systemui/qs/tiles/AlarmTileTest.kt",
+ "tests/src/**/systemui/qs/tiles/BluetoothTileTest.kt",
+ "tests/src/**/systemui/screenshot/ScreenshotPolicyImplTest.kt",
+ "tests/src/**/systemui/settings/DisplayTrackerImplTest.kt",
+ "tests/src/**/systemui/settings/UserFileManagerImplTest.kt",
+ "tests/src/**/systemui/settings/UserTrackerImplReceiveTest.kt",
+ "tests/src/**/systemui/settings/UserTrackerImplTest.kt",
+ "tests/src/**/systemui/shade/GlanceableHubContainerControllerTest.kt",
+ "tests/src/**/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt",
+ "tests/src/**/systemui/shade/NotificationsQSContainerControllerTest.kt",
+ "tests/src/**/systemui/shade/ShadeExpansionStateManagerTest.kt",
+ "tests/src/**/systemui/shade/ShadeHeaderControllerTest.kt",
+ "tests/src/**/systemui/shade/transition/LargeScreenShadeInterpolatorImplTest.kt",
+ "tests/src/**/systemui/statusbar/commandline/CommandParserTest.kt",
+ "tests/src/**/systemui/statusbar/connectivity/MobileStateTest.kt",
+ "tests/src/**/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt",
+ "tests/src/**/systemui/statusbar/gesture/GenericGestureDetectorTest.kt",
+ "tests/src/**/systemui/statusbar/LightRevealScrimTest.kt",
+ "tests/src/**/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt",
+ "tests/src/**/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt",
+ "tests/src/**/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt",
+ "tests/src/**/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt",
+ "tests/src/**/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt",
+ "tests/src/**/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt",
+ "tests/src/**/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt",
+ "tests/src/**/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt",
+ "tests/src/**/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt",
+ "tests/src/**/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt",
+ "tests/src/**/systemui/statusbar/notification/RoundableTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt",
+ "tests/src/**/systemui/statusbar/notification/row/TextPrecomputerTest.kt",
+ "tests/src/**/systemui/statusbar/phone/FoldStateListenerTest.kt",
+ "tests/src/**/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt",
+ "tests/src/**/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt",
+ "tests/src/**/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt",
+ "tests/src/**/systemui/statusbar/policy/VariableDateViewControllerTest.kt",
+ "tests/src/**/systemui/statusbar/policy/WalletControllerImplTest.kt",
+ "tests/src/**/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt",
+ "tests/src/**/systemui/stylus/StylusUsiPowerUiTest.kt",
+ "tests/src/**/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt",
+ "tests/src/**/keyguard/KeyguardUpdateMonitorTest.java",
+ "tests/src/**/keyguard/LegacyLockIconViewControllerBaseTest.java",
+ "tests/src/**/keyguard/CarrierTextManagerTest.java",
+ "tests/src/**/systemui/ScreenDecorationsTest.java",
+ "tests/src/**/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
+ "tests/src/**/systemui/shared/system/RemoteTransitionTest.java",
+ "tests/src/**/systemui/navigationbar/NavigationBarControllerImplTest.java",
+ "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt",
+ "tests/src/**/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt",
+ "tests/src/**/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt",
+ "tests/src/**/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt",
+ "tests/src/**/systemui/DisplayCutoutBaseViewTest.kt",
+ "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java",
+ "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java",
+ "tests/src/**/systemui/qs/tiles/HotspotTileTest.java",
+ "tests/src/**/systemui/qs/external/TileLifecycleManagerTest.java",
+ "tests/src/**/systemui/recents/OverviewProxyServiceTest.kt",
+ "tests/src/**/systemui/stylus/StylusManagerTest.kt",
+ "tests/src/**/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java",
+ "tests/src/**/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java",
+ "tests/src/**/systemui/statusbar/policy/BatteryControllerStartableTest.java",
+ "tests/src/**/systemui/statusbar/policy/BatteryControllerTest.java",
+ "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt",
+ "tests/src/**/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt",
+ "tests/src/**/systemui/statusbar/KeyboardShortcutsReceiverTest.java",
+ "tests/src/**/systemui/wmshell/BubblesTest.java",
+ "tests/src/**/systemui/biometrics/AuthRippleControllerTest.kt",
+ "tests/src/**/keyguard/KeyguardAbsKeyInputViewControllerTest.java",
+ "tests/src/**/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java",
+ "tests/src/**/systemui/clipboardoverlay/ClipboardListenerTest.java",
+ "tests/src/**/systemui/doze/DozeScreenStateTest.java",
+ "tests/src/**/systemui/keyguard/WorkLockActivityControllerTest.java",
+ "tests/src/**/systemui/media/dialog/MediaOutputControllerTest.java",
+ "tests/src/**/systemui/navigationbar/NavigationBarTest.java",
+ "tests/src/**/systemui/power/PowerNotificationWarningsTest.java",
+ "tests/src/**/systemui/power/PowerUITest.java",
+ "tests/src/**/systemui/qs/QSFooterViewControllerTest.java",
+ "tests/src/**/systemui/qs/QSImplTest.java",
+ "tests/src/**/systemui/qs/QSSecurityFooterTest.java",
+ "tests/src/**/systemui/qs/tileimpl/QSTileImplTest.java",
+ "tests/src/**/systemui/qs/tiles/QuickAccessWalletTileTest.java",
+ "tests/src/**/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java",
+ "tests/src/**/systemui/shared/plugins/PluginActionManagerTest.java",
+ "tests/src/**/systemui/statusbar/CommandQueueTest.java",
+ "tests/src/**/systemui/statusbar/connectivity/CallbackHandlerTest.java",
+ "tests/src/**/systemui/statusbar/connectivity/NetworkControllerBaseTest.java",
+ "tests/src/**/systemui/statusbar/KeyguardIndicationControllerTest.java",
+ "tests/src/**/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java",
+ "tests/src/**/systemui/statusbar/phone/ScrimControllerTest.java",
+ "tests/src/**/systemui/statusbar/policy/RotationLockControllerImplTest.java",
+ "tests/src/**/systemui/statusbar/policy/SecurityControllerTest.java",
+ "tests/src/**/systemui/toast/ToastUITest.java",
+ "tests/src/**/systemui/statusbar/connectivity/NetworkControllerDataTest.java",
+ "tests/src/**/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java",
+ "tests/src/**/systemui/statusbar/connectivity/NetworkControllerSignalTest.java",
+ "tests/src/**/systemui/statusbar/connectivity/NetworkControllerWifiTest.java",
+ ],
+ visibility: ["//visibility:private"],
+}
+
//Create a library to expose SystemUI's resources to other modules.
android_library {
name: "SystemUI-res",
@@ -433,6 +646,21 @@
plugins: ["dagger2-compiler"],
}
+java_library {
+ name: "RoboTestLibraries",
+ static_libs: [
+ "dagger2",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.core_core-animation-testing",
+ "androidx.test.ext.junit",
+ "inline-mockito-robolectric-prebuilt",
+ "platform-parametric-runner-lib",
+ "SystemUICustomizationTestUtils",
+ "kotlin-test",
+ "kosmos",
+ ],
+}
+
android_robolectric_test {
name: "SystemUiRoboTests",
srcs: [
@@ -442,14 +670,40 @@
":SystemUI-tests-multivalent",
],
static_libs: [
- "dagger2",
- "androidx.test.uiautomator_uiautomator",
- "androidx.core_core-animation-testing",
- "androidx.test.ext.junit",
- "inline-mockito-robolectric-prebuilt",
- "platform-parametric-runner-lib",
- "SystemUICustomizationTestUtils",
- "kosmos",
+ "RoboTestLibraries",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ "truth",
+ ],
+
+ upstream: true,
+
+ instrumentation_for: "SystemUIRobo-stub",
+ java_resource_dirs: ["tests/robolectric/config"],
+ plugins: [
+ "dagger2-compiler",
+ ],
+}
+
+// in-place tests which use Robolectric in the tests directory
+// instead of multivalentTests
+android_robolectric_test {
+ name: "SystemUiRoboTestsInplace",
+ srcs: [
+ "tests/robolectric/src/**/*.kt",
+ "tests/robolectric/src/**/*.java",
+ ":SystemUI-tests-utils",
+ ":SystemUI-tests-multivalent",
+ ":SystemUI-tests-robofiles",
+ ],
+ exclude_srcs: [
+ ":SystemUI-tests-broken-robofiles",
+ ],
+ static_libs: [
+ "RoboTestLibraries",
],
libs: [
"android.test.runner",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index b3aa7e1..24d6413 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -26,13 +26,6 @@
}
flag {
- name: "refactor_keyguard_dismiss_intent"
- namespace: "systemui"
- description: "Update how keyguard dismiss intents are stored."
- bug: "275069969"
-}
-
-flag {
name: "notification_heads_up_cycling"
namespace: "systemui"
@@ -372,13 +365,6 @@
}
flag {
- name: "media_in_scene_container"
- namespace: "systemui"
- description: "Enable media in the scene container framework"
- bug: "296122467"
-}
-
-flag {
name: "pss_task_switcher"
namespace: "systemui"
description: "Enable the task switcher feature for partial screen sharing"
@@ -852,3 +838,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "communal_bouncer_do_not_modify_plugin_open"
+ namespace: "systemui"
+ description: "do not modify notification shade when handling bouncer expansion."
+ bug: "338252661"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
index 9ad0fc5..fd79f62 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
@@ -191,14 +191,20 @@
// so we have to take the optical insets into account.
ghostedView.getLocationOnScreen(ghostedViewLocation)
val insets = backgroundInsets
- state.top = ghostedViewLocation[1] + insets.top
+ val boundCorrections: Rect =
+ if (ghostedView is LaunchableView) {
+ ghostedView.getPaddingForLaunchAnimation()
+ } else {
+ Rect()
+ }
+ state.top = ghostedViewLocation[1] + insets.top + boundCorrections.top
state.bottom =
ghostedViewLocation[1] + (ghostedView.height * ghostedView.scaleY).roundToInt() -
- insets.bottom
- state.left = ghostedViewLocation[0] + insets.left
+ insets.bottom + boundCorrections.bottom
+ state.left = ghostedViewLocation[0] + insets.left + boundCorrections.left
state.right =
ghostedViewLocation[0] + (ghostedView.width * ghostedView.scaleX).roundToInt() -
- insets.right
+ insets.right + boundCorrections.right
}
override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt
index da6ccaa..330ab0f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt
@@ -16,6 +16,7 @@
package com.android.systemui.animation
+import android.graphics.Rect
import android.view.View
/** A view that can expand/launch into an app or a dialog. */
@@ -41,6 +42,9 @@
/** Perform an action when the activity launch animation ends */
fun onActivityLaunchAnimationEnd() {}
+
+ /** Provide an optional correction applied to the visible area during a launch animation */
+ fun getPaddingForLaunchAnimation(): Rect = Rect()
}
/** A delegate that can be used by views to make the implementation of [LaunchableView] easier. */
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index dff9b3b..a592aa9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -24,7 +24,11 @@
import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
import android.widget.FrameLayout
import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.AnimatedVisibilityScope
+import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.BorderStroke
@@ -83,10 +87,13 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.scale
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ColorMatrix
+import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.pointer.motionEventSpy
@@ -289,23 +296,21 @@
removeEnabled = removeButtonEnabled
)
}
+ if (currentPopup == PopupType.CtaTile) {
+ PopupOnDismissCtaTile(viewModel::onHidePopup)
+ }
- if (currentPopup != null) {
- when (currentPopup) {
- PopupType.CtaTile -> {
- PopupOnDismissCtaTile(viewModel::onHidePopup)
- }
- PopupType.CustomizeWidgetButton -> {
- ButtonToEditWidgets(
- onClick = {
- viewModel.onHidePopup()
- viewModel.onOpenWidgetEditor(selectedKey.value)
- },
- onHide = { viewModel.onHidePopup() }
- )
- }
- null -> {}
- }
+ AnimatedVisibility(
+ visible = currentPopup == PopupType.CustomizeWidgetButton,
+ modifier = Modifier.fillMaxSize()
+ ) {
+ ButtonToEditWidgets(
+ onClick = {
+ viewModel.onHidePopup()
+ viewModel.onOpenWidgetEditor(selectedKey.value)
+ },
+ onHide = { viewModel.onHidePopup() }
+ )
}
if (viewModel is CommunalViewModel && dialogFactory != null) {
@@ -654,30 +659,67 @@
}
}
+@OptIn(ExperimentalAnimationApi::class)
@Composable
-private fun ButtonToEditWidgets(
+private fun AnimatedVisibilityScope.ButtonToEditWidgets(
onClick: () -> Unit,
onHide: () -> Unit,
) {
- Popup(alignment = Alignment.TopCenter, offset = IntOffset(0, 40), onDismissRequest = onHide) {
+ Popup(
+ alignment = Alignment.TopCenter,
+ offset = IntOffset(0, 40),
+ onDismissRequest = onHide,
+ ) {
val colors = LocalAndroidColorScheme.current
Button(
modifier =
- Modifier.height(56.dp).background(colors.secondary, RoundedCornerShape(50.dp)),
+ Modifier.height(56.dp)
+ .graphicsLayer { transformOrigin = TransformOrigin(0f, 0f) }
+ .animateEnterExit(
+ enter =
+ fadeIn(
+ initialAlpha = 0f,
+ animationSpec = tween(durationMillis = 500, easing = LinearEasing)
+ ),
+ exit =
+ fadeOut(
+ animationSpec = tween(durationMillis = 500, easing = LinearEasing)
+ )
+ )
+ .background(colors.secondary, RoundedCornerShape(50.dp)),
onClick = onClick,
) {
- Icon(
- imageVector = Icons.Outlined.Widgets,
- contentDescription = stringResource(R.string.button_to_configure_widgets_text),
- tint = colors.onSecondary,
- modifier = Modifier.size(20.dp)
- )
- Spacer(modifier = Modifier.size(8.dp))
- Text(
- text = stringResource(R.string.button_to_configure_widgets_text),
- style = MaterialTheme.typography.titleSmall,
- color = colors.onSecondary,
- )
+ Row(
+ modifier =
+ Modifier.animateEnterExit(
+ enter =
+ fadeIn(
+ animationSpec =
+ tween(
+ durationMillis = 167,
+ delayMillis = 500,
+ easing = LinearEasing
+ )
+ ),
+ exit =
+ fadeOut(
+ animationSpec = tween(durationMillis = 167, easing = LinearEasing)
+ )
+ )
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.Widgets,
+ contentDescription = stringResource(R.string.button_to_configure_widgets_text),
+ tint = colors.onSecondary,
+ modifier = Modifier.size(20.dp)
+ )
+ Spacer(modifier = Modifier.size(8.dp))
+ Text(
+ text = stringResource(R.string.button_to_configure_widgets_text),
+ style = MaterialTheme.typography.titleSmall,
+ color = colors.onSecondary
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 985d3a1..6e987bd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -65,7 +65,6 @@
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.NestedScrollBehavior
import com.android.compose.animation.scene.SceneScope
-import com.android.compose.animation.scene.SceneTransitionLayoutState
import com.android.compose.modifiers.height
import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight
import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius
@@ -157,6 +156,7 @@
fun SceneScope.NotificationScrollingStack(
viewModel: NotificationsPlaceholderViewModel,
maxScrimTop: () -> Float,
+ shouldPunchHoleBehindScrim: Boolean,
modifier: Modifier = Modifier,
) {
val density = LocalDensity.current
@@ -233,7 +233,8 @@
// in step with the transition so that it is 0 when it completes.
if (
scrimOffset.value < 0 &&
- layoutState.isTransitioning(from = Scenes.Shade, to = Scenes.Gone)
+ layoutState.isTransitioning(from = Scenes.Shade, to = Scenes.Gone) ||
+ layoutState.isTransitioning(from = Scenes.Shade, to = Scenes.Lockscreen)
) {
IntOffset(x = 0, y = (scrimOffset.value * expansionFraction).roundToInt())
} else {
@@ -246,7 +247,7 @@
scrimCornerRadius,
screenCornerRadius,
{ expansionFraction },
- layoutState.isNotificationScrimTransitioning(),
+ shouldPunchHoleBehindScrim,
)
.let { scrimRounding.value.toRoundedCornerShape(it) }
clip = true
@@ -270,18 +271,20 @@
) {
// Creates a cutout in the background scrim in the shape of the notifications scrim.
// Only visible when notif scrim alpha < 1, during shade expansion.
- Spacer(
- modifier =
- Modifier.fillMaxSize().drawBehind {
- drawRect(Color.Black, blendMode = BlendMode.DstOut)
- }
- )
+ if (shouldPunchHoleBehindScrim) {
+ Spacer(
+ modifier =
+ Modifier.fillMaxSize().drawBehind {
+ drawRect(Color.Black, blendMode = BlendMode.DstOut)
+ }
+ )
+ }
Box(
modifier =
Modifier.fillMaxSize()
.graphicsLayer {
alpha =
- if (layoutState.isNotificationScrimTransitioning()) {
+ if (shouldPunchHoleBehindScrim) {
(expansionFraction / EXPANSION_FOR_MAX_SCRIM_ALPHA).coerceAtMost(1f)
} else 1f
}
@@ -429,13 +432,6 @@
)
}
-private fun SceneTransitionLayoutState.isNotificationScrimTransitioning(): Boolean {
- return isTransitioningBetween(Scenes.Gone, Scenes.Shade) ||
- isTransitioningBetween(Scenes.Lockscreen, Scenes.Shade) ||
- isTransitioningBetween(Scenes.Gone, Scenes.QuickSettings) ||
- isTransitioningBetween(Scenes.Lockscreen, Scenes.QuickSettings)
-}
-
private const val TAG = "FlexiNotifs"
private val DEBUG_STACK_COLOR = Color(1f, 0f, 0f, 0.2f)
private val DEBUG_HUN_COLOR = Color(0f, 0f, 1f, 0.2f)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 62619f5..b33ea78 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -61,6 +61,7 @@
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.TransitionState
import com.android.compose.animation.scene.animateSceneFloatAsState
+import com.android.compose.modifiers.thenIf
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight
@@ -155,15 +156,22 @@
qsSceneAdapter = viewModel.qsSceneAdapter
)
+ val shouldPunchHoleBehindScrim =
+ layoutState.isTransitioningBetween(Scenes.Gone, Scenes.QuickSettings) ||
+ layoutState.isTransitioningBetween(Scenes.Lockscreen, Scenes.QuickSettings)
+
// TODO(b/280887232): implement the real UI.
Box(
modifier =
- modifier.fillMaxSize().graphicsLayer {
- // Render the scene to an offscreen buffer so that BlendMode.DstOut only clears this
- // scene (and not the one under it) during a scene transition.
- compositingStrategy = CompositingStrategy.Offscreen
- alpha = contentAlpha
- }
+ modifier
+ .fillMaxSize()
+ .graphicsLayer { alpha = contentAlpha }
+ .thenIf(shouldPunchHoleBehindScrim) {
+ // Render the scene to an offscreen buffer so that BlendMode.DstOut only clears
+ // this
+ // scene (and not the one under it) during a scene transition.
+ Modifier.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
+ }
) {
val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
val screenHeight = LocalRawScreenHeight.current
@@ -313,6 +321,7 @@
NotificationScrollingStack(
viewModel = notificationsPlaceholderViewModel,
maxScrimTop = { screenHeight },
+ shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim,
modifier =
Modifier.fillMaxWidth().offset { IntOffset(x = 0, y = screenHeight.roundToInt()) },
)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 4c656b0..19c5800c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -16,6 +16,7 @@
import com.android.systemui.scene.ui.composable.transitions.lockscreenToQuickSettingsTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToShadeTransition
import com.android.systemui.scene.ui.composable.transitions.shadeToQuickSettingsTransition
+import com.android.systemui.shade.ui.composable.Shade
/**
* Comprehensive definition of all transitions between scenes in [SceneContainer].
@@ -73,10 +74,14 @@
// Scene overscroll
+ overscroll(Scenes.Gone, Orientation.Vertical) {}
overscroll(Scenes.Bouncer, Orientation.Vertical) {
translate(Bouncer.Elements.Content, y = { absoluteDistance })
}
overscroll(Scenes.Shade, Orientation.Vertical) {
- translate(Notifications.Elements.NotificationScrim, y = { absoluteDistance })
+ translate(
+ Notifications.Elements.NotificationScrim,
+ y = { Shade.Dimensions.ScrimOverscrollLimit }
+ )
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
index a9e5be9..8cd357e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
@@ -1,10 +1,15 @@
package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
+import com.android.compose.animation.scene.UserActionDistance
+import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ui.composable.ShadeHeader
import kotlin.time.Duration.Companion.milliseconds
@@ -12,6 +17,18 @@
durationScale: Double = 1.0,
) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
+ distance =
+ object : UserActionDistance {
+ override fun UserActionDistanceScope.absoluteDistance(
+ fromSceneSize: IntSize,
+ orientation: Orientation,
+ ): Float {
+ val distance =
+ Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y
+ ?: return 0f
+ return fromSceneSize.height - distance
+ }
+ }
translate(Notifications.Elements.NotificationScrim, Edge.Bottom)
timestampRange(endMillis = 83) { fade(QuickSettings.Elements.FooterActions) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
index 2f59217..df47cba 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
@@ -16,11 +16,19 @@
package com.android.systemui.scene.ui.composable.transitions
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
+import com.android.compose.animation.scene.UserActionDistance
+import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ui.composable.Shade
import com.android.systemui.shade.ui.composable.ShadeHeader
import kotlin.time.Duration.Companion.milliseconds
@@ -28,6 +36,20 @@
durationScale: Double = 1.0,
) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
+ swipeSpec =
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
+ )
+ distance =
+ object : UserActionDistance {
+ override fun UserActionDistanceScope.absoluteDistance(
+ fromSceneSize: IntSize,
+ orientation: Orientation,
+ ): Float {
+ return Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y ?: 0f
+ }
+ }
fractionRange(start = .58f) {
fade(ShadeHeader.Elements.Clock)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index cda8059..3122b99 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -98,6 +98,8 @@
object Dimensions {
val ScrimCornerSize = 32.dp
val HorizontalPadding = 16.dp
+ const val ScrimOverscrollLimit = 100f
+ const val ScrimVisibilityThreshold = 5f
}
object Shapes {
@@ -195,12 +197,26 @@
) {
val maxNotifScrimTop = remember { mutableStateOf(0f) }
val tileSquishiness by
- animateSceneFloatAsState(value = 1f, key = QuickSettings.SharedValues.TilesSquishiness)
+ animateSceneFloatAsState(
+ value = 1f,
+ key = QuickSettings.SharedValues.TilesSquishiness,
+ canOverflow = false
+ )
val isClickable by viewModel.isClickable.collectAsState()
- // Render the scene to an offscreen buffer so that BlendMode.DstOut only clears this scene
- // (and not the one under it) during a scene transition.
- Box(modifier = modifier.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)) {
+ val shouldPunchHoleBehindScrim =
+ layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade) ||
+ layoutState.isTransitioningBetween(Scenes.Lockscreen, Scenes.Shade)
+
+ Box(
+ modifier =
+ modifier.thenIf(shouldPunchHoleBehindScrim) {
+ // Render the scene to an offscreen buffer so that BlendMode.DstOut only clears this
+ // scene
+ // (and not the one under it) during a scene transition.
+ Modifier.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
+ }
+ ) {
Box(
modifier =
Modifier.fillMaxSize()
@@ -231,10 +247,7 @@
Box(Modifier.element(QuickSettings.Elements.QuickQuickSettings)) {
QuickSettings(
viewModel.qsSceneAdapter,
- {
- (viewModel.qsSceneAdapter.qqsHeight * tileSquishiness)
- .roundToInt()
- },
+ { viewModel.qsSceneAdapter.qqsHeight },
isSplitShade = false,
squishiness = tileSquishiness,
)
@@ -254,6 +267,7 @@
NotificationScrollingStack(
viewModel = viewModel.notifications,
maxScrimTop = { maxNotifScrimTop.value },
+ shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim,
)
},
)
@@ -425,6 +439,7 @@
NotificationScrollingStack(
viewModel = viewModel.notifications,
maxScrimTop = { 0f },
+ shouldPunchHoleBehindScrim = false,
modifier =
Modifier.weight(1f)
.fillMaxHeight()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
index c73656e..f1cc71b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
@@ -16,9 +16,9 @@
package com.android.systemui.volume.panel.component.mediaoutput
-import com.android.systemui.volume.panel.component.mediaoutput.domain.MediaOutputAvailabilityCriteria
import com.android.systemui.volume.panel.component.mediaoutput.ui.composable.MediaOutputComponent
import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents
+import com.android.systemui.volume.panel.domain.AlwaysAvailableCriteria
import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent
import dagger.Binds
@@ -39,6 +39,6 @@
@IntoMap
@StringKey(VolumePanelComponents.MEDIA_OUTPUT)
fun bindComponentAvailabilityCriteria(
- criteria: MediaOutputAvailabilityCriteria
+ criteria: AlwaysAvailableCriteria
): ComponentAvailabilityCriteria
}
diff --git a/packages/SystemUI/docs/scene.md b/packages/SystemUI/docs/scene.md
index fb8a271..2f50bbd 100644
--- a/packages/SystemUI/docs/scene.md
+++ b/packages/SystemUI/docs/scene.md
@@ -62,7 +62,7 @@
NOTE: in case these instructions become stale and don't actually enable the
framework, please make sure `SceneContainerFlag.isEnabled` in the
-[`SceneContainerFlags.kt`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt)
+[`SceneContainerFlag.kt`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt)
file evalutes to `true`.
1. Set a collection of **aconfig flags** to `true` by running the following
@@ -74,10 +74,9 @@
$ adb shell device_config override systemui com.android.systemui.keyguard_wm_state_refactor true
$ adb shell device_config override systemui com.android.systemui.media_in_scene_container true
$ adb shell device_config override systemui com.android.systemui.migrate_clocks_to_blueprint true
- $ adb shell device_config override systemui com.android.systemui.notification_heads_up_refactor true
+ $ adb shell device_config override systemui com.android.systemui.notifications_heads_up_refactor true
$ adb shell device_config override systemui com.android.systemui.predictive_back_sysui true
$ adb shell device_config override systemui com.android.systemui.device_entry_udfps_refactor true
- $ adb shell device_config override systemui com.android.systemui.refactor_keyguard_dismiss_intent true
```
2. **Restart** System UI by issuing the following command:
```console
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index aa70c45..3554b8fb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -211,7 +211,6 @@
if (!SceneContainerFlag.isEnabled) {
mSetFlagsRule.disableFlags(
AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
- AConfigFlags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
index 3395268..630bcd6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.animation.AnimatorListenerAdapter;
@@ -163,6 +164,7 @@
* Ensures expansion only happens when touch down happens in valid part of the screen.
*/
@Test
+ @DisableFlags(Flags.FLAG_COMMUNAL_BOUNCER_DO_NOT_MODIFY_PLUGIN_OPEN)
public void testSessionStart() {
mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion, null);
@@ -193,7 +195,31 @@
2)).isTrue();
}
+
+ /**
+ * Ensures expansion only happens when touch down happens in valid part of the screen.
+ */
@Test
+ @EnableFlags(Flags.FLAG_COMMUNAL_BOUNCER_DO_NOT_MODIFY_PLUGIN_OPEN)
+ public void testSessionStart_doesNotModifyNotificationShadeWindow() {
+ mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion, null);
+
+ verify(mRegion).union(mRectCaptor.capture());
+ final Rect bounds = mRectCaptor.getValue();
+
+ final Rect expected = new Rect();
+
+ expected.set(0, Math.round(SCREEN_HEIGHT_PX * (1 - TOUCH_REGION)), SCREEN_WIDTH_PX,
+ SCREEN_HEIGHT_PX);
+
+ assertThat(bounds).isEqualTo(expected);
+
+ mTouchHandler.onSessionStart(mTouchSession);
+ verifyNoMoreInteractions(mNotificationShadeWindowController);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_COMMUNAL_BOUNCER_DO_NOT_MODIFY_PLUGIN_OPEN)
public void testSwipeUp_whenBouncerInitiallyShowing_reduceHeightWithExclusionRects() {
mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion,
new Rect(0, 0, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX));
@@ -213,6 +239,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_COMMUNAL_BOUNCER_DO_NOT_MODIFY_PLUGIN_OPEN)
public void testSwipeUp_exclusionRectAtTop_doesNotIntersectGestureArea() {
mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion,
new Rect(0, 0, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX / 4));
@@ -228,6 +255,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_COMMUNAL_BOUNCER_DO_NOT_MODIFY_PLUGIN_OPEN)
public void testSwipeUp_exclusionRectBetweenNormalAndMinimumSwipeArea() {
final int normalSwipeAreaTop = SCREEN_HEIGHT_PX
- Math.round(SCREEN_HEIGHT_PX * TOUCH_REGION);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt
index 5bf0f4b..692ffee 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt
@@ -36,7 +36,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -54,11 +53,6 @@
private val sysuiStatusBarStateController = kosmos.sysuiStatusBarStateController
private val underTest by lazy { kosmos.alternateBouncerToGoneTransitionViewModel }
- @Before
- fun setup() {
- mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)
- }
-
@Test
fun deviceEntryParentViewDisappear() =
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt
index 854a478..9fab603 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt
@@ -32,7 +32,6 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -48,11 +47,6 @@
private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
private val underTest by lazy { kosmos.alternateBouncerToPrimaryBouncerTransitionViewModel }
- @Before
- fun setup() {
- mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)
- }
-
@Test
fun deviceEntryParentViewDisappear() =
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
index ee217a6..fee18dd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
@@ -69,7 +69,6 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)
whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)
sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(false)
}
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 030aa24..2e1765a 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
@@ -23,6 +23,7 @@
import android.view.View
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.communalRepository
@@ -56,7 +57,6 @@
import org.junit.runner.RunWith
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
-import com.android.systemui.Flags as AConfigFlags
@SmallTest
@RunWith(ParameterizedAndroidJunit4::class)
@@ -95,7 +95,6 @@
mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
mSetFlagsRule.disableFlags(
AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
- AConfigFlags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT,
)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index 18e9009..278c90a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -55,7 +55,6 @@
@Before
fun setUp() {
- mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)
whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)
sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(false)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
index 9c0674d..bc57ce6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
@@ -245,6 +245,33 @@
assertThat(flowForUser2).isNotEqualTo(flowForUser1)
}
+ // Tests that a ServiceInfo that is returned by queryIntentServicesAsUser but shortly
+ // after uninstalled, doesn't crash SystemUI.
+ @Test
+ fun packageUninstalledAfterQuery_noCrash_noComponent() =
+ testScope.runTest {
+ val userId = 0
+ val resolveInfo =
+ ResolveInfo(TEST_COMPONENT, hasPermission = true, defaultEnabled = true)
+
+ val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+
+ whenever(
+ packageManager.queryIntentServicesAsUser(
+ matchIntent(),
+ matchFlags(),
+ eq(userId)
+ )
+ )
+ .thenReturn(listOf(resolveInfo))
+ whenever(packageManager.getComponentEnabledSetting(TEST_COMPONENT))
+ .thenThrow(IllegalArgumentException())
+ kosmos.fakePackageChangeRepository.notifyChange(PackageChangeModel.Empty)
+ runCurrent()
+
+ assertThat(componentNames).isEmpty()
+ }
+
companion object {
private val INTENT = Intent(TileService.ACTION_QS_TILE)
private val FLAGS =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt
deleted file mode 100644
index 96b4dae..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.volume.panel.component.mediaoutput.domain
-
-import android.media.AudioManager
-import android.testing.TestableLooper.RunWithLooper
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.testKosmos
-import com.android.systemui.volume.data.repository.audioRepository
-import com.android.systemui.volume.domain.interactor.audioModeInteractor
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-@RunWithLooper(setAsMainLooper = true)
-class MediaOutputAvailabilityCriteriaTest : SysuiTestCase() {
-
- private val kosmos = testKosmos()
-
- private lateinit var underTest: MediaOutputAvailabilityCriteria
-
- @Before
- fun setup() {
- underTest =
- MediaOutputAvailabilityCriteria(
- kosmos.audioModeInteractor,
- )
- }
-
- @Test
- fun notInCall_isAvailable_true() {
- with(kosmos) {
- testScope.runTest {
- audioRepository.setMode(AudioManager.MODE_NORMAL)
-
- val isAvailable by collectLastValue(underTest.isAvailable())
- runCurrent()
-
- assertThat(isAvailable).isTrue()
- }
- }
- }
-
- @Test
- fun inCall_isAvailable_false() {
- with(kosmos) {
- testScope.runTest {
- audioRepository.setMode(AudioManager.MODE_IN_CALL)
-
- val isAvailable by collectLastValue(underTest.isAvailable())
- runCurrent()
-
- assertThat(isAvailable).isFalse()
- }
- }
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt
index b5c5809..64c9429 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.volume.localMediaController
import com.android.systemui.volume.mediaControllerRepository
import com.android.systemui.volume.mediaOutputInteractor
+import com.android.systemui.volume.panel.shared.model.filterData
import com.android.systemui.volume.remoteMediaController
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -67,7 +68,8 @@
fun playbackInfo_returnsPlaybackInfo() {
with(kosmos) {
testScope.runTest {
- val session by collectLastValue(mediaOutputInteractor.defaultActiveMediaSession)
+ val session by
+ collectLastValue(mediaOutputInteractor.defaultActiveMediaSession.filterData())
runCurrent()
val info by collectLastValue(underTest.playbackInfo(session!!))
runCurrent()
@@ -81,7 +83,8 @@
fun playbackState_returnsPlaybackState() {
with(kosmos) {
testScope.runTest {
- val session by collectLastValue(mediaOutputInteractor.defaultActiveMediaSession)
+ val session by
+ collectLastValue(mediaOutputInteractor.defaultActiveMediaSession.filterData())
runCurrent()
val state by collectLastValue(underTest.playbackState(session!!))
runCurrent()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt
index 30524d9..49f82d4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt
@@ -30,6 +30,8 @@
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.domain.interactor.audioModeInteractor
+import com.android.systemui.volume.domain.interactor.audioOutputInteractor
import com.android.systemui.volume.localMediaController
import com.android.systemui.volume.localMediaRepository
import com.android.systemui.volume.mediaControllerRepository
@@ -64,6 +66,8 @@
testScope.backgroundScope,
mediaOutputActionsInteractor,
mediaDeviceSessionInteractor,
+ audioOutputInteractor,
+ audioModeInteractor,
mediaOutputInteractor,
uiEventLogger,
)
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 40d863d..dcdd4f0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1634,12 +1634,15 @@
<!-- Hint for accessibility. A stream name is a parameter. For example: double tap to unmute media [CHAR_LIMIT=NONE] -->
<string name="volume_panel_hint_unmute">unmute %s</string>
- <!-- Title with application label for media output settings. [CHAR LIMIT=20] -->
+ <!-- Title with application label for media output settings when there is media playing. [CHAR LIMIT=20] -->
<string name="media_output_label_title">Playing <xliff:g id="label" example="Music Player">%s</xliff:g> on</string>
<!-- Title for media output settings without media is playing. [CHAR LIMIT=20] -->
<string name="media_output_title_without_playing">Audio will play on</string>
+ <!-- Title for media output settings when there is an ongoing call in progress. [CHAR LIMIT=20] -->
+ <string name="media_output_title_ongoing_call">Calling on</string>
+
<!-- Name of special SystemUI debug settings -->
<string name="system_ui_tuner">System UI Tuner</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index 6e1b670..660f0db 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -68,6 +68,7 @@
import java.io.PrintWriter;
import java.util.Optional;
import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Supplier;
/**
@@ -199,6 +200,10 @@
return mContext;
}
+ /**
+ * We should pass single threaded executor (rather than {@link ThreadPoolExecutor}) as we will
+ * make binder calls on that executor and ordering is vital.
+ */
public void setBgExecutor(Executor bgExecutor) {
mBgExecutor = bgExecutor;
}
@@ -230,25 +235,22 @@
mListenersRegistered = true;
mBgExecutor.execute(() -> {
+ if (registerRotationWatcher) {
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .watchRotation(mRotationWatcher, DEFAULT_DISPLAY);
+ mRotationWatcherRegistered = true;
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "RegisterListeners for the display failed", e);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RegisterListeners caught a RemoteException", e);
+ }
+ }
final Intent intent = mContext.registerReceiver(mDockedReceiver,
new IntentFilter(Intent.ACTION_DOCK_EVENT));
mContext.getMainExecutor().execute(() -> updateDockedState(intent));
});
- if (registerRotationWatcher) {
- try {
- WindowManagerGlobal.getWindowManagerService()
- .watchRotation(mRotationWatcher, DEFAULT_DISPLAY);
- mRotationWatcherRegistered = true;
- } catch (IllegalArgumentException e) {
- mListenersRegistered = false;
- Log.w(TAG, "RegisterListeners for the display failed", e);
- } catch (RemoteException e) {
- Log.e(TAG, "RegisterListeners caught a RemoteException", e);
- return;
- }
- }
-
TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
}
@@ -265,17 +267,16 @@
} catch (IllegalArgumentException e) {
Log.e(TAG, "Docked receiver already unregistered", e);
}
- });
- if (mRotationWatcherRegistered) {
- try {
- WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(
- mRotationWatcher);
- } catch (RemoteException e) {
- Log.e(TAG, "UnregisterListeners caught a RemoteException", e);
- return;
+ if (mRotationWatcherRegistered) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(
+ mRotationWatcher);
+ } catch (RemoteException e) {
+ Log.e(TAG, "UnregisterListeners caught a RemoteException", e);
+ }
}
- }
+ });
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index b916fc2..91fb688 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -81,7 +81,6 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardWmStateRefactor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -304,7 +303,7 @@
*/
@Override
public void finish(int targetUserId) {
- if (!RefactorKeyguardDismissIntent.isEnabled()) {
+ if (!SceneContainerFlag.isEnabled()) {
// If there's a pending runnable because the user interacted with a widget
// and we're leaving keyguard, then run it.
boolean deferKeyguardDone = false;
@@ -614,7 +613,7 @@
* @param action callback to be invoked when keyguard disappear animation completes.
*/
public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
- if (RefactorKeyguardDismissIntent.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
return;
}
if (mCancelAction != null) {
@@ -908,7 +907,7 @@
mUiEventLogger.log(uiEvent, getSessionId());
}
- if (RefactorKeyguardDismissIntent.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
if (authenticatedWithPrimaryAuth) {
mPrimaryBouncerInteractor.get()
.notifyKeyguardAuthenticatedPrimaryAuth(targetUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index b8af59d..4c9af66 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -121,6 +121,9 @@
SystemProperties.getBoolean("debug.disable_screen_decorations", false);
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
+
+ private static final boolean sToolkitSetFrameRateReadOnly =
+ android.view.flags.Flags.toolkitSetFrameRateReadOnly();
private boolean mDebug = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
private int mDebugColor = Color.RED;
@@ -892,6 +895,10 @@
lp.width = MATCH_PARENT;
lp.height = MATCH_PARENT;
lp.setTitle("ScreenDecorHwcOverlay");
+ if (sToolkitSetFrameRateReadOnly) {
+ lp.setFrameRateBoostOnTouchEnabled(false);
+ lp.setFrameRatePowerSavingsBalanced(false);
+ }
lp.gravity = Gravity.TOP | Gravity.START;
if (!mDebug) {
lp.setColorMode(ActivityInfo.COLOR_MODE_A8);
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.java
index 85aeb27..019f498 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.java
@@ -254,7 +254,11 @@
mVelocityTracker = mVelocityTrackerFactory.obtain();
mTouchSession = session;
mVelocityTracker.clear();
- mNotificationShadeWindowController.setForcePluginOpen(true, this);
+
+ if (!Flags.communalBouncerDoNotModifyPluginOpen()) {
+ mNotificationShadeWindowController.setForcePluginOpen(true, this);
+ }
+
mScrimManager.addCallback(mScrimManagerCallback);
mCurrentScrimController = mScrimManager.getCurrentController();
@@ -265,7 +269,10 @@
}
mScrimManager.removeCallback(mScrimManagerCallback);
mCapture = null;
- mNotificationShadeWindowController.setForcePluginOpen(false, this);
+
+ if (!Flags.communalBouncerDoNotModifyPluginOpen()) {
+ mNotificationShadeWindowController.setForcePluginOpen(false, this);
+ }
});
session.registerGestureListener(mOnGestureListener);
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
index db2ec8f..ea8d7d7 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
@@ -189,7 +189,6 @@
durations?.get(1) ?: LongPressHapticBuilder.INVALID_DURATION,
effectDuration
)
- _postedActionType.value = ActionType.INITIALIZE_ANIMATOR
setState(State.IDLE)
return true
}
@@ -209,6 +208,5 @@
START_ANIMATOR,
REVERSE_ANIMATOR,
CANCEL_ANIMATOR,
- INITIALIZE_ANIMATOR,
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
index c591af2..c464ed1 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
@@ -57,6 +57,7 @@
qsLongPressEffect.clearActionType()
}
QSLongPressEffect.ActionType.LONG_PRESS -> {
+ tile.prepareForLaunch()
tile.performLongClick()
qsLongPressEffect.clearActionType()
}
@@ -66,8 +67,32 @@
qsLongPressEffect.clearActionType()
}
QSLongPressEffect.ActionType.START_ANIMATOR -> {
- if (effectAnimator?.isRunning == false) {
- effectAnimator?.start()
+ if (effectAnimator?.isRunning != true) {
+ effectAnimator =
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ this.duration =
+ qsLongPressEffect.effectDuration.toLong()
+ interpolator = AccelerateDecelerateInterpolator()
+
+ doOnStart {
+ qsLongPressEffect.handleAnimationStart()
+ }
+ addUpdateListener {
+ val value = animatedValue as Float
+ if (value == 0f) {
+ tile.bringToFront()
+ } else {
+ tile.updateLongPressEffectProperties(value)
+ }
+ }
+ doOnEnd {
+ qsLongPressEffect.handleAnimationComplete()
+ }
+ doOnCancel {
+ qsLongPressEffect.handleAnimationCancel()
+ }
+ start()
+ }
}
}
QSLongPressEffect.ActionType.REVERSE_ANIMATOR -> {
@@ -81,26 +106,6 @@
tile.resetLongPressEffectProperties()
effectAnimator?.cancel()
}
- QSLongPressEffect.ActionType.INITIALIZE_ANIMATOR -> {
- effectAnimator =
- ValueAnimator.ofFloat(0f, 1f).apply {
- this.duration =
- qsLongPressEffect.effectDuration.toLong()
- interpolator = AccelerateDecelerateInterpolator()
-
- doOnStart { qsLongPressEffect.handleAnimationStart() }
- addUpdateListener {
- val value = animatedValue as Float
- if (value == 0f) {
- tile.bringToFront()
- } else {
- tile.updateLongPressEffectProperties(value)
- }
- }
- doOnEnd { qsLongPressEffect.handleAnimationComplete() }
- doOnCancel { qsLongPressEffect.handleAnimationCancel() }
- }
- }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 6138330..3956901 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -76,4 +76,9 @@
@Binds fun trustRepository(impl: TrustRepositoryImpl): TrustRepository
@Binds fun keyguardClockRepository(impl: KeyguardClockRepositoryImpl): KeyguardClockRepository
+
+ @Binds
+ fun keyguardSmartspaceRepository(
+ impl: KeyguardSmartspaceRepositoryImpl
+ ): KeyguardSmartspaceRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
index afe9151..956125c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
@@ -16,19 +16,68 @@
package com.android.systemui.keyguard.data.repository
+import android.content.Context
+import android.provider.Settings
import android.view.View
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+interface KeyguardSmartspaceRepository {
+ val bcSmartspaceVisibility: StateFlow<Int>
+ val isWeatherEnabled: StateFlow<Boolean>
+ fun setBcSmartspaceVisibility(visibility: Int)
+}
@SysUISingleton
-class KeyguardSmartspaceRepository @Inject constructor() {
+class KeyguardSmartspaceRepositoryImpl
+@Inject
+constructor(
+ context: Context,
+ private val secureSettings: SecureSettings,
+ private val userTracker: UserTracker,
+ @Application private val applicationScope: CoroutineScope,
+) : KeyguardSmartspaceRepository {
private val _bcSmartspaceVisibility: MutableStateFlow<Int> = MutableStateFlow(View.GONE)
- val bcSmartspaceVisibility: StateFlow<Int> = _bcSmartspaceVisibility.asStateFlow()
+ override val bcSmartspaceVisibility: StateFlow<Int> = _bcSmartspaceVisibility.asStateFlow()
+ val defaultValue =
+ context.resources.getBoolean(
+ com.android.internal.R.bool.config_lockscreenWeatherEnabledByDefault
+ )
+ override val isWeatherEnabled: StateFlow<Boolean> =
+ secureSettings
+ .observerFlow(
+ names = arrayOf(Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED),
+ userId = userTracker.userId,
+ )
+ .onStart { emit(Unit) }
+ .map { getLockscreenWeatherEnabled() }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = getLockscreenWeatherEnabled()
+ )
- fun setBcSmartspaceVisibility(visibility: Int) {
+ override fun setBcSmartspaceVisibility(visibility: Int) {
_bcSmartspaceVisibility.value = visibility
}
+
+ private fun getLockscreenWeatherEnabled(): Boolean {
+ return secureSettings.getIntForUser(
+ Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED,
+ if (defaultValue) 1 else 0,
+ userTracker.userId
+ ) == 1
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractor.kt
index bb633b5..45a4b70a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractor.kt
@@ -28,6 +28,7 @@
private val keyguardSmartspaceRepository: KeyguardSmartspaceRepository,
) {
val bcSmartspaceVisibility: StateFlow<Int> = keyguardSmartspaceRepository.bcSmartspaceVisibility
+ val isWeatherEnabled: StateFlow<Boolean> = keyguardSmartspaceRepository.isWeatherEnabled
fun setBcSmartspaceVisibility(visibility: Int) {
keyguardSmartspaceRepository.setBcSmartspaceVisibility(visibility)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/RefactorKeyguardDismissIntent.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/RefactorKeyguardDismissIntent.kt
deleted file mode 100644
index a43eb71..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/RefactorKeyguardDismissIntent.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.shared
-
-import com.android.systemui.Flags
-import com.android.systemui.flags.FlagToken
-import com.android.systemui.flags.RefactorFlagUtils
-
-/** Helper for reading or using the refactor_keyguard_dismiss_intent flag. */
-@Suppress("NOTHING_TO_INLINE")
-object RefactorKeyguardDismissIntent {
- /** The aconfig flag name */
- const val FLAG_NAME = Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT
-
- /** A token used for dependency declaration */
- val token: FlagToken
- get() = FlagToken(FLAG_NAME, isEnabled)
-
- /** Is the refactor enabled */
- @JvmStatic
- inline val isEnabled
- get() = Flags.refactorKeyguardDismissIntent()
-
- /**
- * Called to ensure code is only run when the flag is enabled. This protects users from the
- * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
- * build to ensure that the refactor author catches issues in testing.
- */
- @JvmStatic
- inline fun isUnexpectedlyInLegacyMode() =
- RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
-
- /**
- * Called to ensure code is only run when the flag is disabled. This will throw an exception if
- * the flag is enabled to ensure that the refactor author catches issues in testing.
- */
- @JvmStatic
- inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index cccb93c..b0d45ed 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -25,6 +25,7 @@
import androidx.core.view.isInvisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launch
import com.android.systemui.common.ui.view.LongPressHandlingView
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
@@ -40,6 +41,7 @@
@ExperimentalCoroutinesApi
object DeviceEntryIconViewBinder {
+ private const val TAG = "DeviceEntryIconViewBinder"
/**
* Updates UI for:
@@ -82,22 +84,22 @@
// GONE => AOD transition (even though the view may not be visible until the middle
// of the transition.
repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch {
+ launch("$TAG#viewModel.isVisible") {
viewModel.isVisible.collect { isVisible ->
longPressHandlingView.isInvisible = !isVisible
}
}
- launch {
+ launch("$TAG#viewModel.isLongPressEnabled") {
viewModel.isLongPressEnabled.collect { isEnabled ->
longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
}
}
- launch {
+ launch("$TAG#viewModel.accessibilityDelegateHint") {
viewModel.accessibilityDelegateHint.collect { hint ->
view.accessibilityHintType = hint
}
}
- launch {
+ launch("$TAG#viewModel.useBackgroundProtection") {
viewModel.useBackgroundProtection.collect { useBackgroundProtection ->
if (useBackgroundProtection) {
bgView.visibility = View.VISIBLE
@@ -106,7 +108,7 @@
}
}
}
- launch {
+ launch("$TAG#viewModel.burnInOffsets") {
viewModel.burnInOffsets.collect { burnInOffsets ->
view.translationX = burnInOffsets.x.toFloat()
view.translationY = burnInOffsets.y.toFloat()
@@ -114,7 +116,9 @@
}
}
- launch { viewModel.deviceEntryViewAlpha.collect { alpha -> view.alpha = alpha } }
+ launch("$TAG#viewModel.deviceEntryViewAlpha") {
+ viewModel.deviceEntryViewAlpha.collect { alpha -> view.alpha = alpha }
+ }
}
}
@@ -122,7 +126,7 @@
repeatOnLifecycle(Lifecycle.State.STARTED) {
// Start with an empty state
fgIconView.setImageState(StateSet.NOTHING, /* merge */ false)
- launch {
+ launch("$TAG#fpIconView.viewModel") {
fgViewModel.viewModel.collect { viewModel ->
fgIconView.setImageState(
view.getIconState(viewModel.type, viewModel.useAodVariant),
@@ -144,8 +148,10 @@
bgView.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch { bgViewModel.alpha.collect { alpha -> bgView.alpha = alpha } }
- launch {
+ launch("$TAG#bgViewModel.alpha") {
+ bgViewModel.alpha.collect { alpha -> bgView.alpha = alpha }
+ }
+ launch("$TAG#bgViewModel.color") {
bgViewModel.color.collect { color ->
bgView.imageTintList = ColorStateList.valueOf(color)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt
index 93b3ba5..b293027 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt
@@ -20,8 +20,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
-import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
import com.android.systemui.log.core.LogLevel
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -40,7 +40,7 @@
) : CoreStartable {
override fun start() {
- if (!RefactorKeyguardDismissIntent.isEnabled) {
+ if (!SceneContainerFlag.isEnabled) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt
index f77d012..ac24591 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt
@@ -22,9 +22,9 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissInteractor
-import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
import com.android.systemui.keyguard.shared.model.KeyguardDone
import com.android.systemui.log.core.LogLevel
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -44,7 +44,7 @@
) : CoreStartable {
override fun start() {
- if (!RefactorKeyguardDismissIntent.isEnabled) {
+ if (!SceneContainerFlag.isEnabled) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index 9ec7a65..487c2e9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -42,10 +42,10 @@
val context: Context,
val keyguardClockViewModel: KeyguardClockViewModel,
val keyguardSmartspaceViewModel: KeyguardSmartspaceViewModel,
- val keyguardSmartspaceInteractor: KeyguardSmartspaceInteractor,
+ private val keyguardSmartspaceInteractor: KeyguardSmartspaceInteractor,
val smartspaceController: LockscreenSmartspaceController,
val keyguardUnlockAnimationController: KeyguardUnlockAnimationController,
- val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
+ private val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
) : KeyguardSection() {
private var smartspaceView: View? = null
private var weatherView: View? = null
@@ -61,12 +61,10 @@
weatherView = smartspaceController.buildAndConnectWeatherView(constraintLayout)
dateView = smartspaceController.buildAndConnectDateView(constraintLayout)
pastVisibility = smartspaceView?.visibility ?: View.GONE
- if (keyguardSmartspaceViewModel.isSmartspaceEnabled) {
- constraintLayout.addView(smartspaceView)
- if (keyguardSmartspaceViewModel.isDateWeatherDecoupled) {
- constraintLayout.addView(weatherView)
- constraintLayout.addView(dateView)
- }
+ constraintLayout.addView(smartspaceView)
+ if (keyguardSmartspaceViewModel.isDateWeatherDecoupled) {
+ constraintLayout.addView(weatherView)
+ constraintLayout.addView(dateView)
}
keyguardUnlockAnimationController.lockscreenSmartspace = smartspaceView
smartspaceVisibilityListener = OnGlobalLayoutListener {
@@ -205,13 +203,9 @@
constraintSet.apply {
val weatherVisibility =
- when (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) {
- true -> ConstraintSet.GONE
- false ->
- when (keyguardSmartspaceViewModel.isWeatherEnabled) {
- true -> ConstraintSet.VISIBLE
- false -> ConstraintSet.GONE
- }
+ when (keyguardSmartspaceViewModel.isWeatherVisible.value) {
+ true -> ConstraintSet.VISIBLE
+ false -> ConstraintSet.GONE
}
setVisibility(sharedR.id.weather_smartspace_view, weatherVisibility)
setAlpha(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
index 24429fa..e0a3af6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
@@ -19,11 +19,11 @@
import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
-import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.SysuiStatusBarStateController
import dagger.Lazy
@@ -48,7 +48,7 @@
) {
/** Common fade for scrim alpha values during *BOUNCER->GONE */
fun scrimAlpha(duration: Duration, fromState: KeyguardState): Flow<ScrimAlpha> {
- return if (RefactorKeyguardDismissIntent.isEnabled) {
+ return if (SceneContainerFlag.isEnabled) {
keyguardDismissActionInteractor
.get()
.willAnimateDismissActionOnLockscreen
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index 45dca99..e26b75f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -50,6 +50,7 @@
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
/** Models the UI state for the containing device entry icon & long-press handling view. */
@ExperimentalCoroutinesApi
@@ -110,27 +111,7 @@
)
}
- private val dozeAmount: Flow<Float> =
- combine(
- transitionInteractor.startedKeyguardTransitionStep,
- merge(
- transitionInteractor.transitionStepsFromState(KeyguardState.AOD).map {
- 1f - it.value
- },
- transitionInteractor.transitionStepsToState(KeyguardState.AOD).map { it.value }
- ),
- ) { startedKeyguardTransitionStep, aodTransitionAmount ->
- if (
- startedKeyguardTransitionStep.to == KeyguardState.AOD ||
- startedKeyguardTransitionStep.from == KeyguardState.AOD
- ) {
- aodTransitionAmount
- } else {
- // in case a new transition (ie: to occluded) cancels a transition to or from
- // aod, then we want to make sure the doze amount is still updated to 0
- 0f
- }
- }
+ private val dozeAmount: Flow<Float> = transitionInteractor.transitionValue(KeyguardState.AOD)
// Burn-in offsets that animate based on the transition amount to AOD
private val animatedBurnInOffsets: Flow<BurnInOffsets> =
combine(nonAnimatedBurnInOffsets, dozeAmount) { burnInOffsets, dozeAmount ->
@@ -141,54 +122,57 @@
)
}
- val deviceEntryViewAlpha: Flow<Float> =
+ val deviceEntryViewAlpha: StateFlow<Float> =
combine(
- transitionAlpha,
- alphaMultiplierFromShadeExpansion,
- ) { alpha, alphaMultiplier ->
- alpha * alphaMultiplier
- }
+ transitionAlpha,
+ alphaMultiplierFromShadeExpansion,
+ ) { alpha, alphaMultiplier ->
+ alpha * alphaMultiplier
+ }
+ .stateIn(scope = scope, started = SharingStarted.WhileSubscribed(), initialValue = 0f)
val useBackgroundProtection: StateFlow<Boolean> = isUdfpsSupported
val burnInOffsets: Flow<BurnInOffsets> =
- deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolled ->
- if (udfpsEnrolled) {
- combine(
- transitionInteractor.startedKeyguardTransitionStep.sample(
- shadeInteractor.isAnyFullyExpanded,
- ::Pair
- ),
- animatedBurnInOffsets,
- nonAnimatedBurnInOffsets,
- ) {
- (startedTransitionStep, shadeExpanded),
- animatedBurnInOffsets,
- nonAnimatedBurnInOffsets ->
- if (startedTransitionStep.to == KeyguardState.AOD) {
- when (startedTransitionStep.from) {
- KeyguardState.ALTERNATE_BOUNCER -> animatedBurnInOffsets
- KeyguardState.LOCKSCREEN ->
- if (shadeExpanded) {
- nonAnimatedBurnInOffsets
- } else {
- animatedBurnInOffsets
- }
- else -> nonAnimatedBurnInOffsets
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled
+ .flatMapLatest { udfpsEnrolled ->
+ if (udfpsEnrolled) {
+ combine(
+ transitionInteractor.startedKeyguardTransitionStep.sample(
+ shadeInteractor.isAnyFullyExpanded,
+ ::Pair
+ ),
+ animatedBurnInOffsets,
+ nonAnimatedBurnInOffsets,
+ ) {
+ (startedTransitionStep, shadeExpanded),
+ animatedBurnInOffsets,
+ nonAnimatedBurnInOffsets ->
+ if (startedTransitionStep.to == KeyguardState.AOD) {
+ when (startedTransitionStep.from) {
+ KeyguardState.ALTERNATE_BOUNCER -> animatedBurnInOffsets
+ KeyguardState.LOCKSCREEN ->
+ if (shadeExpanded) {
+ nonAnimatedBurnInOffsets
+ } else {
+ animatedBurnInOffsets
+ }
+ else -> nonAnimatedBurnInOffsets
+ }
+ } else if (startedTransitionStep.from == KeyguardState.AOD) {
+ when (startedTransitionStep.to) {
+ KeyguardState.LOCKSCREEN -> animatedBurnInOffsets
+ else -> BurnInOffsets(x = 0, y = 0, progress = 0f)
+ }
+ } else {
+ BurnInOffsets(x = 0, y = 0, progress = 0f)
}
- } else if (startedTransitionStep.from == KeyguardState.AOD) {
- when (startedTransitionStep.to) {
- KeyguardState.LOCKSCREEN -> animatedBurnInOffsets
- else -> BurnInOffsets(x = 0, y = 0, progress = 0f)
- }
- } else {
- BurnInOffsets(x = 0, y = 0, progress = 0f)
}
+ } else {
+ // If UDFPS isn't enrolled, we don't show any UI on AOD so there's no need
+ // to use burn in offsets at all
+ flowOf(BurnInOffsets(x = 0, y = 0, progress = 0f))
}
- } else {
- // If UDFPS isn't enrolled, we don't show any UI on AOD so there's no need
- // to use burn in offsets at all
- flowOf(BurnInOffsets(x = 0, y = 0, progress = 0f))
}
- }
+ .distinctUntilChanged()
private val isUnlocked: Flow<Boolean> =
keyguardInteractor.isKeyguardDismissible.flatMapLatest { isUnlocked ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index 1f544c1..198e9f2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -84,8 +84,8 @@
combine(
isLargeClockVisible,
currentClock,
- ) { isLargeClock, clock ->
- clock?.let { clock ->
+ ) { isLargeClock, currentClock ->
+ currentClock?.let { clock ->
val face = if (isLargeClock) clock.largeClock else clock.smallClock
face.config.hasCustomWeatherDataDisplay
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
index dc053aa..c0b1f95 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
@@ -26,6 +26,7 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -41,8 +42,8 @@
/** Whether the smartspace section is available in the build. */
val isSmartspaceEnabled: Boolean = smartspaceController.isEnabled()
/** Whether the weather area is available in the build. */
- // TODO(b/317891876): this should be a Flow as the value can change over time.
- val isWeatherEnabled: Boolean = smartspaceController.isWeatherEnabled()
+ private val isWeatherEnabled: StateFlow<Boolean> = smartspaceInteractor.isWeatherEnabled
+
/** Whether the data and weather areas are decoupled in the build. */
val isDateWeatherDecoupled: Boolean = smartspaceController.isDateWeatherDecoupled()
@@ -58,8 +59,10 @@
/** Whether the weather area should be visible. */
val isWeatherVisible: StateFlow<Boolean> =
- keyguardClockViewModel.hasCustomWeatherDataDisplay
- .map { clockIncludesCustomWeatherDisplay ->
+ combine(
+ isWeatherEnabled,
+ keyguardClockViewModel.hasCustomWeatherDataDisplay,
+ ) { isWeatherEnabled, clockIncludesCustomWeatherDisplay ->
isWeatherVisible(
clockIncludesCustomWeatherDisplay = clockIncludesCustomWeatherDisplay,
isWeatherEnabled = isWeatherEnabled,
@@ -72,7 +75,7 @@
isWeatherVisible(
clockIncludesCustomWeatherDisplay =
keyguardClockViewModel.hasCustomWeatherDataDisplay.value,
- isWeatherEnabled = isWeatherEnabled,
+ isWeatherEnabled = smartspaceInteractor.isWeatherEnabled.value,
)
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index a08a234..b1fa710 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -20,11 +20,11 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
-import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
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.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.SysuiStatusBarStateController
import dagger.Lazy
import javax.inject.Inject
@@ -80,7 +80,7 @@
/** Bouncer container alpha */
val bouncerAlpha: Flow<Float> =
- if (RefactorKeyguardDismissIntent.isEnabled) {
+ if (SceneContainerFlag.isEnabled) {
keyguardDismissActionInteractor
.get()
.willAnimateDismissActionOnLockscreen
@@ -104,7 +104,7 @@
/** Lockscreen alpha */
val lockscreenAlpha: Flow<Float> =
- if (RefactorKeyguardDismissIntent.isEnabled) {
+ if (SceneContainerFlag.isEnabled) {
keyguardDismissActionInteractor
.get()
.willAnimateDismissActionOnLockscreen
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
index c997617..bf80e18 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
@@ -70,8 +70,7 @@
// dispatcher to use. We don't want it to run on the Dispatchers.Default thread pool as
// default behavior. Instead, we want it to run on the view's UI thread since the user will
// presumably want to call view methods that require being called from said UI thread.
- val lifecycleCoroutineContext =
- Dispatchers.Main + createCoroutineTracingContext() + coroutineContext
+ val lifecycleCoroutineContext = MAIN_DISPATCHER_SINGLETON + coroutineContext
val traceName =
if (Compile.IS_DEBUG && coroutineTracing()) {
inferTraceSectionName()
@@ -205,17 +204,28 @@
StackWalker.getInstance().walk { stream ->
stream.filter(::isFrameInteresting).limit(5).findFirst()
}
- if (interestingFrame.isPresent) {
+ return if (interestingFrame.isPresent) {
val f = interestingFrame.get()
- return "${f.className}#${f.methodName}:${f.lineNumber} [$DEFAULT_TRACE_NAME]"
+ "${f.className}#${f.methodName}:${f.lineNumber} [$DEFAULT_TRACE_NAME]"
} else {
- return DEFAULT_TRACE_NAME
+ DEFAULT_TRACE_NAME
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_APP)
}
}
+/**
+ * Even though there is only has one usage of `Dispatchers.Main` in this file, we cache it in a
+ * top-level property so that we do not unnecessarily create new `CoroutineContext` objects for
+ * tracing on each call to [repeatWhenAttached]. It is okay to reuse a single instance of the
+ * tracing context because it is copied for its children.
+ *
+ * Also, ideally, we would use the injected `@Main CoroutineDispatcher`, but [repeatWhenAttached] is
+ * an extension function, and plumbing dagger-injected instances for static usage has little
+ * benefit.
+ */
+private val MAIN_DISPATCHER_SINGLETON = Dispatchers.Main + createCoroutineTracingContext()
private const val DEFAULT_TRACE_NAME = "repeatWhenAttached"
private const val CURRENT_CLASS_NAME = "com.android.systemui.lifecycle.RepeatWhenAttachedKt"
private const val JAVA_ADAPTER_CLASS_NAME = "com.android.systemui.util.kotlin.JavaAdapterKt"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index 4e77d13..6a6eba1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -51,8 +51,7 @@
fun isRemoteResumeAllowed() = featureFlags.isEnabled(Flags.MEDIA_REMOTE_RESUME)
/** Check whether to use scene framework */
- fun isSceneContainerEnabled() =
- SceneContainerFlag.isEnabled && MediaInSceneContainerFlag.isEnabled
+ fun isSceneContainerEnabled() = SceneContainerFlag.isEnabled
/** Check whether to use media refactor code */
fun isMediaControlsRefactorEnabled() = MediaControlsRefactorFlag.isEnabled
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaInSceneContainerFlag.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaInSceneContainerFlag.kt
deleted file mode 100644
index 77279f2..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaInSceneContainerFlag.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.media.controls.util
-
-import com.android.systemui.Flags
-import com.android.systemui.flags.FlagToken
-import com.android.systemui.flags.RefactorFlagUtils
-
-/** Helper for reading or using the media_in_scene_container flag state. */
-@Suppress("NOTHING_TO_INLINE")
-object MediaInSceneContainerFlag {
- /** The aconfig flag name */
- const val FLAG_NAME = Flags.FLAG_MEDIA_IN_SCENE_CONTAINER
-
- /** A token used for dependency declaration */
- val token: FlagToken
- get() = FlagToken(FLAG_NAME, isEnabled)
-
- /** Is the flag enabled? */
- @JvmStatic
- inline val isEnabled
- get() = Flags.mediaInSceneContainer()
-
- /**
- * Called to ensure code is only run when the flag is enabled. This protects users from the
- * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
- * build to ensure that the refactor author catches issues in testing.
- */
- @JvmStatic
- inline fun isUnexpectedlyInLegacyMode() =
- RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
-
- /**
- * Called to ensure code is only run when the flag is disabled. This will throw an exception if
- * the flag is enabled to ensure that the refactor author catches issues in testing.
- */
- @JvmStatic
- inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 042fb63f..4ee2db7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -75,10 +75,6 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- // set layer to make alpha animation of brightness slider nicer - otherwise elements
- // of slider are animated separately and it doesn't look good. See b/329244723
- setLayerType(LAYER_TYPE_HARDWARE, null);
-
mQSPanelContainer = findViewById(R.id.expanded_qs_scroll_view);
mQSPanel = findViewById(R.id.quick_settings_panel);
mHeader = findViewById(R.id.header);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
index 93021ba..cfcea98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
@@ -91,7 +91,15 @@
.queryIntentServicesAsUser(INTENT, FLAGS, userId)
.mapNotNull { it.serviceInfo }
.filter { it.permission == BIND_QUICK_SETTINGS_TILE }
- .filter { packageManager.isComponentActuallyEnabled(it) }
+ .filter {
+ try {
+ packageManager.isComponentActuallyEnabled(it)
+ } catch (e: IllegalArgumentException) {
+ // If the package is not found, it means it was uninstalled between query
+ // and now. So it's clearly not enabled.
+ false
+ }
+ }
.mapTo(mutableSetOf()) { it.componentName }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSLongPressProperties.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSLongPressProperties.kt
index a2ded6a..71cf9e6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSLongPressProperties.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSLongPressProperties.kt
@@ -22,8 +22,8 @@
* These properties are used during animation if a tile supports a long-press action.
*/
data class QSLongPressProperties(
- var xScale: Float,
- var yScale: Float,
+ var height: Float,
+ var width: Float,
var cornerRadius: Float,
var backgroundColor: Int,
var labelColor: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 40cf4a4..ca5b771 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -25,6 +25,7 @@
import android.content.res.Resources.ID_NULL
import android.graphics.Color
import android.graphics.PorterDuff
+import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.LayerDrawable
@@ -46,6 +47,7 @@
import android.widget.Switch
import android.widget.TextView
import androidx.annotation.VisibleForTesting
+import androidx.core.graphics.drawable.updateBounds
import com.android.app.tracing.traceSection
import com.android.settingslib.Utils
import com.android.systemui.Flags
@@ -62,7 +64,6 @@
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSIconViewImpl.QS_ANIM_LENGTH
import com.android.systemui.res.R
-import com.android.systemui.util.children
import kotlinx.coroutines.DisposableHandle
import java.util.Objects
@@ -83,6 +84,10 @@
const val UNAVAILABLE_ALPHA = 0.3f
@VisibleForTesting
internal const val TILE_STATE_RES_PREFIX = "tile_states_"
+ @VisibleForTesting
+ internal const val LONG_PRESS_EFFECT_WIDTH_SCALE = 1.1f
+ @VisibleForTesting
+ internal const val LONG_PRESS_EFFECT_HEIGHT_SCALE = 1.2f
}
private val icon: QSIconViewImpl = QSIconViewImpl(context)
@@ -180,6 +185,8 @@
private val locInScreen = IntArray(2)
/** Visuo-haptic long-press effects */
+ private var haveLongPressPropertiesBeenReset = true
+ private var paddingForLaunch = Rect()
private var initialLongPressProperties: QSLongPressProperties? = null
private var finalLongPressProperties: QSLongPressProperties? = null
private val colorEvaluator = ArgbEvaluator.getInstance()
@@ -326,7 +333,7 @@
private fun updateHeight() {
// TODO(b/332900989): Find a more robust way of resetting the tile if not reset by the
// launch animation.
- if (scaleX != 1f || scaleY != 1f) {
+ if (!haveLongPressPropertiesBeenReset && longPressEffect != null) {
// The launch animation of a long-press effect did not reset the long-press effect so
// we must do it here
resetLongPressEffectProperties()
@@ -632,7 +639,7 @@
)
}
showRippleEffect = false
- initializeLongPressProperties()
+ initializeLongPressProperties(measuredHeight, measuredWidth)
} else {
// Long-press effects might have been enabled before but the new state does not
// handle a long-press. In this case, we go back to the behaviour of a regular tile
@@ -765,8 +772,60 @@
override fun onActivityLaunchAnimationEnd() = resetLongPressEffectProperties()
+ fun prepareForLaunch() {
+ val startingHeight = initialLongPressProperties?.height?.toInt() ?: 0
+ val startingWidth = initialLongPressProperties?.width?.toInt() ?: 0
+ val deltaH = finalLongPressProperties?.height?.minus(startingHeight)?.toInt() ?: 0
+ val deltaW = finalLongPressProperties?.width?.minus(startingWidth)?.toInt() ?: 0
+ paddingForLaunch.left = -deltaW / 2
+ paddingForLaunch.top = -deltaH / 2
+ paddingForLaunch.right = deltaW / 2
+ paddingForLaunch.bottom = deltaH / 2
+ }
+
+ override fun getPaddingForLaunchAnimation(): Rect = paddingForLaunch
+
fun updateLongPressEffectProperties(effectProgress: Float) {
if (!isLongClickable || longPressEffect == null) return
+
+ if (haveLongPressPropertiesBeenReset) haveLongPressPropertiesBeenReset = false
+
+ // Dimensions change
+ val newHeight =
+ interpolateFloat(
+ effectProgress,
+ initialLongPressProperties?.height ?: 0f,
+ finalLongPressProperties?.height ?: 0f,
+ ).toInt()
+ val newWidth =
+ interpolateFloat(
+ effectProgress,
+ initialLongPressProperties?.width ?: 0f,
+ finalLongPressProperties?.width ?: 0f,
+ ).toInt()
+
+ val startingHeight = initialLongPressProperties?.height?.toInt() ?: 0
+ val startingWidth = initialLongPressProperties?.width?.toInt() ?: 0
+ val deltaH = (newHeight - startingHeight) / 2
+ val deltaW = (newWidth - startingWidth) / 2
+
+ background.updateBounds(
+ left = -deltaW,
+ top = -deltaH,
+ right = newWidth - deltaW,
+ bottom = newHeight - deltaH,
+ )
+
+ // Radius change
+ val newRadius =
+ interpolateFloat(
+ effectProgress,
+ initialLongPressProperties?.cornerRadius ?: 0f,
+ finalLongPressProperties?.cornerRadius ?: 0f,
+ )
+ changeCornerRadius(newRadius)
+
+ // Color change
setAllColors(
colorEvaluator.evaluate(
effectProgress,
@@ -802,32 +861,6 @@
finalLongPressProperties?.iconColor ?: 0,
) as Int,
)
-
- val newScaleX =
- interpolateFloat(
- effectProgress,
- initialLongPressProperties?.xScale ?: 1f,
- finalLongPressProperties?.xScale ?: 1f,
- )
- val newScaleY =
- interpolateFloat(
- effectProgress,
- initialLongPressProperties?.xScale ?: 1f,
- finalLongPressProperties?.xScale ?: 1f,
- )
- val newRadius =
- interpolateFloat(
- effectProgress,
- initialLongPressProperties?.cornerRadius ?: 0f,
- finalLongPressProperties?.cornerRadius ?: 0f,
- )
- scaleX = newScaleX
- scaleY = newScaleY
- for (child in children) {
- child.scaleX = 1f / newScaleX
- child.scaleY = 1f / newScaleY
- }
- changeCornerRadius(newRadius)
}
private fun unbindLongPressEffect() {
@@ -839,12 +872,12 @@
start + fraction * (end - start)
fun resetLongPressEffectProperties() {
- scaleY = 1f
- scaleX = 1f
- for (child in children) {
- child.scaleY = 1f
- child.scaleX = 1f
- }
+ background.updateBounds(
+ left = 0,
+ top = 0,
+ right = initialLongPressProperties?.width?.toInt() ?: 0,
+ bottom = initialLongPressProperties?.height?.toInt() ?: 0,
+ )
changeCornerRadius(resources.getDimensionPixelSize(R.dimen.qs_corner_radius).toFloat())
setAllColors(
getBackgroundColorForState(lastState, lastDisabledByPolicy),
@@ -854,13 +887,15 @@
getOverlayColorForState(lastState),
)
icon.setTint(icon.mIcon as ImageView, lastIconTint)
+ haveLongPressPropertiesBeenReset = true
}
- private fun initializeLongPressProperties() {
+ @VisibleForTesting
+ fun initializeLongPressProperties(startingHeight: Int, startingWidth: Int) {
initialLongPressProperties =
QSLongPressProperties(
- /* xScale= */1f,
- /* yScale= */1f,
+ height = startingHeight.toFloat(),
+ width = startingWidth.toFloat(),
resources.getDimensionPixelSize(R.dimen.qs_corner_radius).toFloat(),
getBackgroundColorForState(lastState),
getLabelColorForState(lastState),
@@ -872,8 +907,8 @@
finalLongPressProperties =
QSLongPressProperties(
- /* xScale= */1.1f,
- /* yScale= */1.2f,
+ height = LONG_PRESS_EFFECT_HEIGHT_SCALE * startingHeight,
+ width = LONG_PRESS_EFFECT_WIDTH_SCALE * startingWidth,
resources.getDimensionPixelSize(R.dimen.qs_corner_radius).toFloat() - 20,
getBackgroundColorForState(Tile.STATE_ACTIVE),
getLabelColorForState(Tile.STATE_ACTIVE),
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
index 234eda8..cf33c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
@@ -27,8 +27,6 @@
import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.ComposeLockscreen
-import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
-import com.android.systemui.media.controls.util.MediaInSceneContainerFlag
import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.phone.PredictiveBackSysUiFlag
@@ -44,12 +42,10 @@
ComposeLockscreen.isEnabled &&
KeyguardBottomAreaRefactor.isEnabled &&
KeyguardWmStateRefactor.isEnabled &&
- MediaInSceneContainerFlag.isEnabled &&
MigrateClocksToBlueprint.isEnabled &&
NotificationsHeadsUpRefactor.isEnabled &&
PredictiveBackSysUiFlag.isEnabled &&
- DeviceEntryUdfpsRefactor.isEnabled &&
- RefactorKeyguardDismissIntent.isEnabled
+ DeviceEntryUdfpsRefactor.isEnabled
// NOTE: Changes should also be made in getSecondaryFlags and @EnableSceneContainer
/** The main aconfig flag. */
@@ -61,12 +57,10 @@
ComposeLockscreen.token,
KeyguardBottomAreaRefactor.token,
KeyguardWmStateRefactor.token,
- MediaInSceneContainerFlag.token,
MigrateClocksToBlueprint.token,
NotificationsHeadsUpRefactor.token,
PredictiveBackSysUiFlag.token,
DeviceEntryUdfpsRefactor.token,
- RefactorKeyguardDismissIntent.token,
// NOTE: Changes should also be made in isEnabled and @EnableSceneContainer
)
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
index e051dab..92006a4 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
@@ -63,6 +63,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ setLayerType(LAYER_TYPE_HARDWARE, null);
mSlider = requireViewById(R.id.slider);
mSlider.setAccessibilityLabel(getContentDescription().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index ff5fdc6..851bfca 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -229,7 +229,9 @@
// the gesture area doesn't overlap with widgets.
// TODO(b/323035776): adjust gesture areaa for portrait mode
containerView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
+ // Run when the touch handling lifecycle is RESUMED, meaning the hub is visible and not
+ // occluded.
+ lifecycleRegistry.repeatOnLifecycle(Lifecycle.State.RESUMED) {
val exclusionRect =
Rect(
0,
@@ -242,12 +244,19 @@
}
}
+ // Listen to bouncer visibility directly as these flows become true as soon as any portion
+ // of the bouncers are visible when the transition starts. The keyguard transition state
+ // only changes once transitions are fully finished, which would mean touches during a
+ // transition to the bouncer would be incorrectly intercepted by the hub.
collectFlow(
containerView,
- keyguardTransitionInteractor.isFinishedInStateWhere(KeyguardState::isBouncerState),
+ or(
+ keyguardInteractor.primaryBouncerShowing,
+ keyguardInteractor.alternateBouncerShowing
+ ),
{
anyBouncerShowing = it
- updateLifecycleState()
+ updateTouchHandlingState()
}
)
collectFlow(
@@ -255,7 +264,7 @@
communalInteractor.isCommunalShowing,
{
hubShowing = it
- updateLifecycleState()
+ updateTouchHandlingState()
}
)
collectFlow(
@@ -263,7 +272,7 @@
and(shadeInteractor.isAnyFullyExpanded, not(shadeInteractor.isUserInteracting)),
{
shadeShowing = it
- updateLifecycleState()
+ updateTouchHandlingState()
}
)
collectFlow(containerView, keyguardInteractor.isDreaming, { isDreaming = it })
@@ -276,13 +285,22 @@
/**
* Updates the lifecycle stored by the [lifecycleRegistry] to control when the [touchMonitor]
* should listen for and intercept top and bottom swipes.
+ *
+ * Also clears gesture exclusion zones when the hub is occluded or gone.
*/
- private fun updateLifecycleState() {
+ private fun updateTouchHandlingState() {
val shouldInterceptGestures = hubShowing && !(shadeShowing || anyBouncerShowing)
if (shouldInterceptGestures) {
lifecycleRegistry.currentState = Lifecycle.State.RESUMED
} else {
+ // Hub is either occluded or no longer showing, turn off touch handling.
lifecycleRegistry.currentState = Lifecycle.State.STARTED
+
+ // Clear exclusion rects if the hub is not showing or is covered, so we don't interfere
+ // with back gestures when the bouncer or shade. We do this here instead of with
+ // repeatOnLifecycle as repeatOnLifecycle does not run when going from RESUMED back to
+ // STARTED, only when going from CREATED to STARTED.
+ communalContainerView!!.systemGestureExclusionRects = emptyList()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 403bece..4d4d177 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -3992,7 +3992,12 @@
mExpandLatencyTracking = false;
}
float maxPanelHeight = getMaxPanelTransitionDistance();
- if (mHeightAnimator == null) {
+ if (mHeightAnimator == null && !MigrateClocksToBlueprint.isEnabled()) {
+ // MigrateClocksToBlueprint - There is an edge case where swiping up slightly,
+ // and then swiping down will trigger overscroll logic. Even without this flag
+ // enabled, the notifications can then run into UDFPS. At this point it is
+ // safer to remove overscroll for this one case to prevent overlap.
+
// Split shade has its own overscroll logic
if (isTracking()) {
float overExpansionPixels = Math.max(0, h - maxPanelHeight);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 4d7dacd..7c1101b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -382,16 +382,16 @@
private void clearCurrentMediaNotificationSession() {
mMediaMetadata = null;
- if (mMediaController != null) {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
- + mMediaController.getPackageName());
- }
- mBackgroundExecutor.execute(() -> {
+ mBackgroundExecutor.execute(() -> {
+ if (mMediaController != null) {
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
+ + mMediaController.getPackageName());
+ }
mMediaController.unregisterCallback(mMediaListener);
mMediaController = null;
- });
- }
+ }
+ });
}
public interface MediaListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index 2f9c2f0..6909907 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -82,7 +82,7 @@
launch { viewModel.stackBottom.collect { view.setStackBottom(it) } }
launch { viewModel.scrolledToTop.collect { view.setScrolledToTop(it) } }
launch { viewModel.headsUpTop.collect { view.setHeadsUpTop(it) } }
- launch { viewModel.expandFraction.collect { view.setExpandFraction(it) } }
+ launch { viewModel.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) } }
launch { viewModel.isScrollable.collect { view.setScrollingEnabled(it) } }
launch { viewModel.isDozing.collect { isDozing -> view.setDozing(isDozing) } }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index f35d199..7301b87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -72,7 +72,6 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
-import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent;
import com.android.systemui.keyguard.shared.model.DismissAction;
import com.android.systemui.keyguard.shared.model.KeyguardDone;
import com.android.systemui.keyguard.shared.model.KeyguardState;
@@ -800,7 +799,7 @@
public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
boolean afterKeyguardGone, String message) {
- if (RefactorKeyguardDismissIntent.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
if (r == null) {
return;
}
@@ -852,7 +851,7 @@
return;
}
- if (!RefactorKeyguardDismissIntent.isEnabled()) {
+ if (!SceneContainerFlag.isEnabled()) {
mAfterKeyguardGoneAction = r;
mKeyguardGoneCancelAction = cancelAction;
mDismissActionWillAnimateOnKeyguard = r != null
@@ -920,7 +919,7 @@
* Adds a {@param runnable} to be executed after Keyguard is gone.
*/
public void addAfterKeyguardGoneRunnable(Runnable runnable) {
- if (RefactorKeyguardDismissIntent.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
if (runnable != null) {
mKeyguardDismissActionInteractor.get().runAfterKeyguardGone(runnable);
}
@@ -1112,7 +1111,7 @@
// We update the state (which will show the keyguard) only if an animation will run on
// the keyguard. If there is no animation, we wait before updating the state so that we
// go directly from bouncer to launcher/app.
- if (RefactorKeyguardDismissIntent.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
if (mKeyguardDismissActionInteractor.get().runDismissAnimationOnKeyguard()) {
updateStates();
}
@@ -1239,7 +1238,7 @@
}
private void executeAfterKeyguardGoneAction() {
- if (RefactorKeyguardDismissIntent.isEnabled()) {
+ if (SceneContainerFlag.isEnabled()) {
return;
}
if (mAfterKeyguardGoneAction != null) {
@@ -1629,8 +1628,8 @@
pw.println(" isBouncerShowing(): " + isBouncerShowing());
pw.println(" bouncerIsOrWillBeShowing(): " + primaryBouncerIsOrWillBeShowing());
pw.println(" Registered KeyguardViewManagerCallbacks:");
- pw.println(" refactorKeyguardDismissIntent enabled:"
- + RefactorKeyguardDismissIntent.isEnabled());
+ pw.println(" SceneContainerFlag enabled:"
+ + SceneContainerFlag.isEnabled());
for (KeyguardViewManagerCallback callback : mCallbacks) {
pw.println(" " + callback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
index 054116d..51c053e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
@@ -84,14 +84,15 @@
if (Flags.oemEnabledSatelliteFlag()) {
iconsInteractor.icons.aggregateOver(
selector = { intr ->
- combine(intr.isInService, intr.isEmergencyOnly) {
+ combine(intr.isInService, intr.isEmergencyOnly, intr.isNonTerrestrial) {
isInService,
- isEmergencyOnly ->
- !isInService && !isEmergencyOnly
+ isEmergencyOnly,
+ isNtn ->
+ !isInService && !(isEmergencyOnly || isNtn)
}
}
- ) { isOosAndIsNotEmergencyOnly ->
- isOosAndIsNotEmergencyOnly.all { it }
+ ) { isOosAndNotEmergencyOnlyOrSatellite ->
+ isOosAndNotEmergencyOnlyOrSatellite.all { it }
}
} else {
flowOf(false)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt
index ed44699..19d9c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt
@@ -32,6 +32,7 @@
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import com.android.systemui.volume.panel.shared.model.filterData
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
@@ -69,6 +70,7 @@
}
} else {
mediaOutputInteractor.defaultActiveMediaSession
+ .filterData()
.flatMapLatest {
localMediaRepositoryFactory
.create(it?.packageName)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteria.kt
deleted file mode 100644
index bac7d15..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteria.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.volume.panel.component.mediaoutput.domain
-
-import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
-import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
-import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
-
-/** Determines if the Media Output Volume Panel component is available. */
-@VolumePanelScope
-class MediaOutputAvailabilityCriteria
-@Inject
-constructor(
- private val audioModeInteractor: AudioModeInteractor,
-) : ComponentAvailabilityCriteria {
-
- override fun isAvailable(): Flow<Boolean> = audioModeInteractor.isOngoingCall.map { !it }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
index 83b8029..b974f90 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
@@ -28,6 +28,9 @@
import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSessions
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import com.android.systemui.volume.panel.shared.model.Result
+import com.android.systemui.volume.panel.shared.model.filterData
+import com.android.systemui.volume.panel.shared.model.wrapInResult
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
@@ -72,7 +75,7 @@
}
/** Returns the default [MediaDeviceSession] from [activeMediaDeviceSessions] */
- val defaultActiveMediaSession: StateFlow<MediaDeviceSession?> =
+ val defaultActiveMediaSession: StateFlow<Result<MediaDeviceSession?>> =
activeMediaControllers
.map {
when {
@@ -82,11 +85,13 @@
else -> null
}
}
+ .wrapInResult()
.flowOn(backgroundCoroutineContext)
- .stateIn(coroutineScope, SharingStarted.Eagerly, null)
+ .stateIn(coroutineScope, SharingStarted.Eagerly, Result.Loading())
private val localMediaRepository: SharedFlow<LocalMediaRepository> =
defaultActiveMediaSession
+ .filterData()
.map { it?.packageName }
.distinctUntilChanged()
.map { localMediaRepositoryFactory.create(it) }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
index d60d981..192e0ec 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
@@ -18,16 +18,21 @@
import android.content.Context
import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Color
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.res.R
+import com.android.systemui.volume.domain.interactor.AudioOutputInteractor
+import com.android.systemui.volume.domain.model.AudioOutputDevice
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputActionsInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.SessionWithPlaybackState
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import com.android.systemui.volume.panel.shared.model.Result
+import com.android.systemui.volume.panel.shared.model.filterData
+import com.android.systemui.volume.panel.shared.model.wrapInResult
import com.android.systemui.volume.panel.ui.VolumePanelUiEvent
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -35,6 +40,7 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapNotNull
@@ -50,25 +56,25 @@
@VolumePanelScope private val coroutineScope: CoroutineScope,
private val actionsInteractor: MediaOutputActionsInteractor,
private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
+ audioOutputInteractor: AudioOutputInteractor,
+ audioModeInteractor: AudioModeInteractor,
interactor: MediaOutputInteractor,
private val uiEventLogger: UiEventLogger,
) {
private val sessionWithPlaybackState: StateFlow<Result<SessionWithPlaybackState?>> =
interactor.defaultActiveMediaSession
+ .filterData()
.flatMapLatest { session ->
if (session == null) {
- flowOf(Result.Data<SessionWithPlaybackState?>(null))
+ flowOf(null)
} else {
mediaDeviceSessionInteractor.playbackState(session).mapNotNull { playback ->
- playback?.let {
- Result.Data<SessionWithPlaybackState?>(
- SessionWithPlaybackState(session, playback.isActive())
- )
- }
+ playback?.let { SessionWithPlaybackState(session, playback.isActive) }
}
}
}
+ .wrapInResult()
.stateIn(
coroutineScope,
SharingStarted.Eagerly,
@@ -76,23 +82,24 @@
)
val connectedDeviceViewModel: StateFlow<ConnectedDeviceViewModel?> =
- combine(sessionWithPlaybackState, interactor.currentConnectedDevice) {
- mediaDeviceSession,
- currentConnectedDevice ->
- if (mediaDeviceSession !is Result.Data) {
- return@combine null
- }
- ConnectedDeviceViewModel(
- if (mediaDeviceSession.data?.isPlaybackActive == true) {
- context.getString(
- R.string.media_output_label_title,
- mediaDeviceSession.data.session.appLabel
- )
- } else {
- context.getString(R.string.media_output_title_without_playing)
- },
- currentConnectedDevice?.name,
- )
+ combine(
+ sessionWithPlaybackState.filterData(),
+ audioModeInteractor.isOngoingCall,
+ audioOutputInteractor.currentAudioDevice.filter {
+ it !is AudioOutputDevice.Unknown
+ },
+ ) { mediaDeviceSession, isOngoingCall, currentConnectedDevice ->
+ val label =
+ when {
+ isOngoingCall -> context.getString(R.string.media_output_title_ongoing_call)
+ mediaDeviceSession?.isPlaybackActive == true ->
+ context.getString(
+ R.string.media_output_label_title,
+ mediaDeviceSession.session.appLabel
+ )
+ else -> context.getString(R.string.media_output_title_without_playing)
+ }
+ ConnectedDeviceViewModel(label, currentConnectedDevice.name)
}
.stateIn(
coroutineScope,
@@ -101,16 +108,16 @@
)
val deviceIconViewModel: StateFlow<DeviceIconViewModel?> =
- combine(sessionWithPlaybackState, interactor.currentConnectedDevice) {
+ combine(sessionWithPlaybackState.filterData(), audioOutputInteractor.currentAudioDevice) {
mediaDeviceSession,
currentConnectedDevice ->
- if (mediaDeviceSession !is Result.Data) {
- return@combine null
- }
val icon: Icon =
- currentConnectedDevice?.icon?.let { Icon.Loaded(it, null) }
+ currentConnectedDevice
+ .takeIf { currentConnectedDevice !is AudioOutputDevice.Unknown }
+ ?.icon
+ ?.let { Icon.Loaded(it, null) }
?: Icon.Resource(R.drawable.ic_media_home_devices, null)
- if (mediaDeviceSession.data?.isPlaybackActive == true) {
+ if (mediaDeviceSession?.isPlaybackActive == true) {
DeviceIconViewModel.IsPlaying(
icon = icon,
iconColor =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt
index ac8092c..fa40059 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt
@@ -25,6 +25,7 @@
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.isTheSameSession
import com.android.systemui.volume.panel.component.volume.domain.model.SliderType
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import com.android.systemui.volume.panel.shared.model.filterData
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
@@ -46,7 +47,7 @@
val volumePanelSliders: StateFlow<List<SliderType>> =
combineTransform(
mediaOutputInteractor.activeMediaDeviceSessions,
- mediaOutputInteractor.defaultActiveMediaSession,
+ mediaOutputInteractor.defaultActiveMediaSession.filterData(),
audioRepository.communicationDevice,
) { activeSessions, defaultSession, communicationDevice ->
coroutineScope {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
index 741f5cf..26d6a9a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
@@ -26,6 +26,7 @@
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.CastVolumeSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import com.android.systemui.volume.panel.shared.model.filterData
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -80,9 +81,13 @@
val isExpanded: StateFlow<Boolean> =
merge(
mutableIsExpanded,
- mediaOutputInteractor.defaultActiveMediaSession.flatMapLatest {
- if (it == null) flowOf(true)
- else mediaDeviceSessionInteractor.playbackState(it).map { it?.isActive != true }
+ mediaOutputInteractor.defaultActiveMediaSession.filterData().flatMapLatest { session
+ ->
+ if (session == null) flowOf(true)
+ else
+ mediaDeviceSessionInteractor.playbackState(session).map {
+ it?.isActive != true
+ }
},
)
.stateIn(scope, SharingStarted.Eagerly, false)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/shared/model/Result.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/shared/model/Result.kt
index 8793538..5daed99 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/shared/model/Result.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/shared/model/Result.kt
@@ -16,6 +16,10 @@
package com.android.systemui.volume.panel.shared.model
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapNotNull
+
/** Models a loadable result */
sealed interface Result<T> {
@@ -25,3 +29,9 @@
/** The data is loaded successfully */
data class Data<T>(val data: T) : Result<T>
}
+
+/** Wraps flow into [Result]. */
+fun <T> Flow<T>.wrapInResult(): Flow<Result<T>> = map { Result.Data(it) }
+
+/** Filters only [Result.Data] from the flow. */
+fun <T> Flow<Result<T>>.filterData(): Flow<T> = mapNotNull { it as? Result.Data<T> }.map { it.data }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt
new file mode 100644
index 0000000..a320845
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import android.provider.Settings
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth
+import kotlin.test.Test
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.MockitoAnnotations
+
+@RunWith(JUnit4::class)
+@SmallTest
+class KeyguardSmartspaceRepositoryImplTest : SysuiTestCase() {
+
+ private lateinit var scheduler: TestCoroutineScheduler
+ private lateinit var dispatcher: CoroutineDispatcher
+ private lateinit var scope: TestScope
+
+ private lateinit var underTest: KeyguardSmartspaceRepository
+ private lateinit var fakeSettings: FakeSettings
+ private lateinit var fakeUserTracker: FakeUserTracker
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ fakeSettings = FakeSettings()
+ fakeUserTracker = FakeUserTracker()
+ fakeSettings.userId = fakeUserTracker.userId
+ scheduler = TestCoroutineScheduler()
+ dispatcher = StandardTestDispatcher(scheduler)
+ scope = TestScope(dispatcher)
+ underTest =
+ KeyguardSmartspaceRepositoryImpl(
+ context = context,
+ secureSettings = fakeSettings,
+ userTracker = fakeUserTracker,
+ applicationScope = scope.backgroundScope,
+ )
+ }
+
+ @Test
+ fun testWeatherEnabled_true() =
+ scope.runTest {
+ fakeSettings.putInt(Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED, 1)
+ val value = collectLastValue(underTest.isWeatherEnabled)
+ Truth.assertThat(value()).isEqualTo(true)
+ }
+
+ @Test
+ fun testWeatherEnabled_false() =
+ scope.runTest {
+ fakeSettings.putInt(Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED, 0)
+
+ val value = collectLastValue(underTest.isWeatherEnabled)
+ Truth.assertThat(value()).isEqualTo(false)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
index 8eccde7..be10b82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
@@ -64,6 +64,7 @@
private val clockShouldBeCentered = MutableStateFlow(false)
private val hasCustomWeatherDataDisplay = MutableStateFlow(false)
+ private val isWeatherVisibleFlow = MutableStateFlow(false)
@Before
fun setup() {
@@ -89,7 +90,7 @@
.thenReturn(hasCustomWeatherDataDisplay)
whenever(keyguardClockViewModel.clockShouldBeCentered).thenReturn(clockShouldBeCentered)
whenever(keyguardSmartspaceViewModel.isSmartspaceEnabled).thenReturn(true)
-
+ whenever(keyguardSmartspaceViewModel.isWeatherVisible).thenReturn(isWeatherVisibleFlow)
constraintSet = ConstraintSet()
}
@@ -124,7 +125,6 @@
@Test
fun testConstraintsWhenNotHasCustomWeatherDataDisplay() {
whenever(keyguardSmartspaceViewModel.isDateWeatherDecoupled).thenReturn(true)
- hasCustomWeatherDataDisplay.value = false
underTest.addViews(constraintLayout)
underTest.applyConstraints(constraintSet)
assertWeatherSmartspaceConstrains(constraintSet)
@@ -149,13 +149,12 @@
@Test
fun testNormalDateWeatherVisibility() {
- hasCustomWeatherDataDisplay.value = false
- whenever(keyguardSmartspaceViewModel.isWeatherEnabled).thenReturn(true)
+ isWeatherVisibleFlow.value = true
underTest.addViews(constraintLayout)
underTest.applyConstraints(constraintSet)
assertThat(constraintSet.getVisibility(weatherView.id)).isEqualTo(VISIBLE)
- whenever(keyguardSmartspaceViewModel.isWeatherEnabled).thenReturn(false)
+ isWeatherVisibleFlow.value = false
underTest.applyConstraints(constraintSet)
assertThat(constraintSet.getVisibility(weatherView.id)).isEqualTo(GONE)
assertThat(constraintSet.getVisibility(dateView.id)).isEqualTo(VISIBLE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt
new file mode 100644
index 0000000..78f4dcc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
+import com.android.systemui.keyguard.data.repository.keyguardClockRepository
+import com.android.systemui.keyguard.data.repository.keyguardSmartspaceRepository
+import com.android.systemui.keyguard.shared.model.ClockSize
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Answers
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardSmartspaceViewModelTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+ val testScope = kosmos.testScope
+ val underTest = kosmos.keyguardSmartspaceViewModel
+ val res = context.resources
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var clockController: ClockController
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ kosmos.fakeKeyguardClockRepository.setCurrentClock(clockController)
+ }
+
+ @Test
+ fun testWhenWeatherEnabled_notCustomWeatherDataDisplay_isWeatherVisible_shouldBeTrue() =
+ testScope.runTest {
+ val isWeatherVisible by collectLastValue(underTest.isWeatherVisible)
+ whenever(clockController.largeClock.config.hasCustomWeatherDataDisplay)
+ .thenReturn(false)
+
+ with(kosmos) {
+ keyguardSmartspaceRepository.setIsWeatherEnabled(true)
+ keyguardClockRepository.setClockSize(ClockSize.LARGE)
+ }
+
+ assertThat(isWeatherVisible).isEqualTo(true)
+ }
+
+ @Test
+ fun testWhenWeatherEnabled_hasCustomWeatherDataDisplay_isWeatherVisible_shouldBeFalse() =
+ testScope.runTest {
+ val isWeatherVisible by collectLastValue(underTest.isWeatherVisible)
+ whenever(clockController.largeClock.config.hasCustomWeatherDataDisplay).thenReturn(true)
+
+ with(kosmos) {
+ keyguardSmartspaceRepository.setIsWeatherEnabled(true)
+ keyguardClockRepository.setClockSize(ClockSize.LARGE)
+ }
+
+ assertThat(isWeatherVisible).isEqualTo(false)
+ }
+
+ @Test
+ fun testWhenWeatherEnabled_notCustomWeatherDataDisplay_notIsWeatherVisible_shouldBeFalse() =
+ testScope.runTest {
+ val isWeatherVisible by collectLastValue(underTest.isWeatherVisible)
+ whenever(clockController.largeClock.config.hasCustomWeatherDataDisplay)
+ .thenReturn(false)
+
+ with(kosmos) {
+ keyguardSmartspaceRepository.setIsWeatherEnabled(false)
+ keyguardClockRepository.setClockSize(ClockSize.LARGE)
+ }
+
+ assertThat(isWeatherVisible).isEqualTo(false)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
index ecbd0f5..b5ef8c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tileimpl
import android.content.Context
+import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.service.quicksettings.Tile
import android.testing.AndroidTestingRunner
@@ -474,6 +475,31 @@
assertThat(tileView.isLongPressEffectInitialized).isFalse()
}
+ @Test
+ fun onPrepareForLaunch_paddingForLaunchAnimationIsConfigured() {
+ val startingWidth = 100
+ val startingHeight = 50
+ val deltaWidth = (QSTileViewImpl.LONG_PRESS_EFFECT_WIDTH_SCALE - 1f) * startingWidth
+ val deltaHeight = (QSTileViewImpl.LONG_PRESS_EFFECT_HEIGHT_SCALE - 1f) * startingHeight
+
+ // GIVEN that long-press effect properties are initialized
+ tileView.initializeLongPressProperties(startingHeight, startingWidth)
+
+ // WHEN the tile is preparing for the launch animation
+ tileView.prepareForLaunch()
+
+ // THE animation padding corresponds to the tile's growth due to the effect
+ val padding = tileView.getPaddingForLaunchAnimation()
+ assertThat(padding).isEqualTo(
+ Rect(
+ -deltaWidth.toInt() / 2,
+ -deltaHeight.toInt() / 2,
+ deltaWidth.toInt() / 2,
+ deltaHeight.toInt() / 2,
+ )
+ )
+ }
+
class FakeTileView(
context: Context,
collapsed: Boolean,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 19b137c..99204e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -33,6 +33,7 @@
import com.android.systemui.ambient.touch.TouchHandler
import com.android.systemui.ambient.touch.TouchMonitor
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
+import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.communal.data.repository.FakeCommunalRepository
import com.android.systemui.communal.data.repository.fakeCommunalRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
@@ -42,10 +43,8 @@
import com.android.systemui.communal.util.CommunalColors
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.andSceneContainer
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
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.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -238,11 +237,7 @@
goToScene(CommunalScenes.Communal)
// Bouncer is visible.
- fakeKeyguardTransitionRepository.sendTransitionSteps(
- KeyguardState.GLANCEABLE_HUB,
- KeyguardState.PRIMARY_BOUNCER,
- testScope
- )
+ fakeKeyguardBouncerRepository.setPrimaryShow(true)
testableLooper.processAllMessages()
// Touch events are not intercepted.
@@ -368,11 +363,7 @@
goToScene(CommunalScenes.Communal)
// Bouncer is visible.
- fakeKeyguardTransitionRepository.sendTransitionSteps(
- KeyguardState.GLANCEABLE_HUB,
- KeyguardState.PRIMARY_BOUNCER,
- testScope
- )
+ fakeKeyguardBouncerRepository.setPrimaryShow(true)
testableLooper.processAllMessages()
assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
@@ -387,11 +378,7 @@
goToScene(CommunalScenes.Communal)
// Bouncer is visible.
- fakeKeyguardTransitionRepository.sendTransitionSteps(
- KeyguardState.GLANCEABLE_HUB,
- KeyguardState.ALTERNATE_BOUNCER,
- testScope
- )
+ fakeKeyguardBouncerRepository.setAlternateVisible(true)
testableLooper.processAllMessages()
assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
@@ -452,6 +439,53 @@
}
}
+ @Test
+ fun gestureExclusionZone_unsetWhenShadeOpen() =
+ with(kosmos) {
+ testScope.runTest {
+ goToScene(CommunalScenes.Communal)
+
+ // Shade shows up.
+ shadeTestUtil.setQsExpansion(1.0f)
+ testableLooper.processAllMessages()
+
+ // Exclusion rects are unset.
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
+ }
+ }
+
+ @Test
+ fun gestureExclusionZone_unsetWhenBouncerOpen() =
+ with(kosmos) {
+ testScope.runTest {
+ goToScene(CommunalScenes.Communal)
+
+ // Bouncer is visible.
+ fakeKeyguardBouncerRepository.setPrimaryShow(true)
+ testableLooper.processAllMessages()
+
+ // Exclusion rects are unset.
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
+ }
+ }
+
+ @Test
+ fun gestureExclusionZone_unsetWhenHubClosed() =
+ with(kosmos) {
+ testScope.runTest {
+ goToScene(CommunalScenes.Communal)
+
+ // Exclusion rect is set.
+ assertThat(containerView.systemGestureExclusionRects).hasSize(1)
+
+ // Leave the hub.
+ goToScene(CommunalScenes.Blank)
+
+ // Exclusion rect is unset.
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
+ }
+ }
+
private fun initAndAttachContainerView() {
containerView = View(context)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index e38e31d..6b3c005 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -187,8 +187,7 @@
when(mBouncerViewDelegate.getBackCallback()).thenReturn(mBouncerViewDelegateBackCallback);
mSetFlagsRule.disableFlags(
com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR,
- com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
- com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT
+ com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
);
when(mNotificationShadeWindowController.getWindowRootView())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
index c4ab943..405e3ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
@@ -250,7 +250,7 @@
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_twoConnectionsOos_yes() =
+ fun areAllConnectionsOutOfService_twoConnectionsOos_nonNtn_yes() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -258,11 +258,13 @@
val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2)
- // WHEN all of the connections are OOS
+ // WHEN all of the connections are OOS and none are NTN
i1.isInService.value = false
i1.isEmergencyOnly.value = false
+ i1.isNonTerrestrial.value = false
i2.isInService.value = false
i2.isEmergencyOnly.value = false
+ i2.isNonTerrestrial.value = false
// THEN the value is propagated to this interactor
assertThat(latest).isTrue()
@@ -270,7 +272,31 @@
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_oneConnectionOos_yes() =
+ fun areAllConnectionsOutOfService_twoConnectionsOos_oneNtn_no() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+ // GIVEN, 2 connections
+ val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+ val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2)
+
+ // WHEN all of the connections are OOS and one is NTN
+ i1.isInService.value = false
+ i1.isEmergencyOnly.value = false
+ i1.isNonTerrestrial.value = false
+ i2.isInService.value = false
+ i2.isEmergencyOnly.value = false
+
+ // sub2 is non terrestrial, consider it connected for the sake of the iconography
+ i2.isNonTerrestrial.value = true
+
+ // THEN the value is propagated to this interactor
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun areAllConnectionsOutOfService_oneConnectionOos_nonNtn_yes() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -280,6 +306,7 @@
// WHEN all of the connections are OOS
i1.isInService.value = false
i1.isEmergencyOnly.value = false
+ i1.isNonTerrestrial.value = false
// THEN the value is propagated to this interactor
assertThat(latest).isTrue()
@@ -287,7 +314,25 @@
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_oneConnectionInService_no() =
+ fun areAllConnectionsOutOfService_oneConnectionOos_ntn_yes() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+ // GIVEN, 1 connection
+ val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+
+ // WHEN all of the connections are OOS
+ i1.isInService.value = false
+ i1.isEmergencyOnly.value = false
+ i1.isNonTerrestrial.value = true
+
+ // THEN the value is propagated to this interactor
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun areAllConnectionsOutOfService_oneConnectionInService_nonNtn_no() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -296,6 +341,7 @@
// WHEN all of the connections are NOT OOS
i1.isInService.value = true
+ i1.isNonTerrestrial.value = false
// THEN the value is propagated to this interactor
assertThat(latest).isFalse()
@@ -303,7 +349,24 @@
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_twoConnectionsOneInService_no() =
+ fun areAllConnectionsOutOfService_oneConnectionInService_ntn_no() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+ // GIVEN, 1 connection
+ val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+
+ // WHEN all of the connections are NOT OOS
+ i1.isInService.value = true
+ i1.isNonTerrestrial.value = true
+
+ // THEN the value is propagated to this interactor
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun areAllConnectionsOutOfService_twoConnectionsOneInService_nonNtn_no() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -313,7 +376,9 @@
// WHEN at least 1 connection is NOT OOS.
i1.isInService.value = false
+ i1.isNonTerrestrial.value = false
i2.isInService.value = true
+ i2.isNonTerrestrial.value = false
// THEN the value is propagated to this interactor
assertThat(latest).isFalse()
@@ -321,7 +386,7 @@
@Test
@EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
- fun areAllConnectionsOutOfService_twoConnectionsInService_no() =
+ fun areAllConnectionsOutOfService_twoConnectionsInService_nonNtn_no() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
index e83205c5..1107971 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
@@ -21,11 +21,9 @@
import com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR
import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
-import com.android.systemui.Flags.FLAG_MEDIA_IN_SCENE_CONTAINER
import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
import com.android.systemui.Flags.FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR
import com.android.systemui.Flags.FLAG_PREDICTIVE_BACK_SYSUI
-import com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT
import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
/**
@@ -36,13 +34,11 @@
FLAG_COMPOSE_LOCKSCREEN,
FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR,
FLAG_KEYGUARD_WM_STATE_REFACTOR,
- FLAG_MEDIA_IN_SCENE_CONTAINER,
FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR,
FLAG_PREDICTIVE_BACK_SYSUI,
FLAG_SCENE_CONTAINER,
FLAG_DEVICE_ENTRY_UDFPS_REFACTOR,
- FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT,
)
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSmartspaceRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSmartspaceRepository.kt
new file mode 100644
index 0000000..42cb150
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSmartspaceRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import android.view.View.GONE
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class FakeKeyguardSmartspaceRepository : KeyguardSmartspaceRepository {
+
+ private val _bcSmartspaceVisibility = MutableStateFlow(GONE)
+ override val bcSmartspaceVisibility: StateFlow<Int> = _bcSmartspaceVisibility
+ private val _isWeatherEnabled = MutableStateFlow(true)
+ override val isWeatherEnabled: StateFlow<Boolean> = _isWeatherEnabled
+
+ override fun setBcSmartspaceVisibility(visibility: Int) {
+ _bcSmartspaceVisibility.value = visibility
+ }
+
+ fun setIsWeatherEnabled(isEnabled: Boolean) {
+ _isWeatherEnabled.value = isEnabled
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryKosmos.kt
index dc7103f..2949452 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryKosmos.kt
@@ -18,4 +18,4 @@
import com.android.systemui.kosmos.Kosmos
-val Kosmos.keyguardSmartspaceRepository by Kosmos.Fixture { KeyguardSmartspaceRepository() }
+val Kosmos.keyguardSmartspaceRepository by Kosmos.Fixture { FakeKeyguardSmartspaceRepository() }
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 3337419..e06f400 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -155,6 +155,31 @@
visibility: ["//frameworks/base"],
}
+cc_library_shared {
+ name: "libravenwood_runtime",
+ host_supported: true,
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wthread-safety",
+ ],
+
+ srcs: [
+ "runtime-helper-src/jni/*.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libnativehelper",
+ "libutils",
+ "libcutils",
+ ],
+ visibility: ["//frameworks/base"],
+}
+
// For collecting the *stats.csv files in a known directory under out/host/linux-x86/testcases/.
// The "test" just shows the available stats filenames.
sh_test_host {
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodClassLoadHook.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodClassLoadHook.java
index 7dc197e..7a3142b 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodClassLoadHook.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodClassLoadHook.java
@@ -28,8 +28,10 @@
* Add this with a fully-specified method name (e.g. {@code "com.package.Class.methodName"})
* of a callback to get a callback at the class load time.
*
- * The method must be {@code public static} with a single argument that takes
- * {@link Class}.
+ * The method must be {@code public static} with a single argument that takes {@link Class}.
+ *
+ * Typically, this is used with {@link #LIBANDROID_LOADING_HOOK}, which will load the necessary
+ * native libraries.
*
* @hide
*/
@@ -37,4 +39,10 @@
@Retention(RetentionPolicy.CLASS)
public @interface RavenwoodClassLoadHook {
String value();
+
+ /**
+ * Class load hook that loads <code>libandroid_runtime</code>.
+ */
+ public static String LIBANDROID_LOADING_HOOK
+ = "com.android.platform.test.ravenwood.runtimehelper.ClassLoadHook.onClassLoaded";
}
diff --git a/ravenwood/bivalenttest/Android.bp b/ravenwood/bivalenttest/Android.bp
index a6b6ed9..2d94894 100644
--- a/ravenwood/bivalenttest/Android.bp
+++ b/ravenwood/bivalenttest/Android.bp
@@ -45,7 +45,6 @@
jni_libs: [
"libravenwoodbivalenttest_jni",
],
- sdk_version: "test_current",
auto_gen_config: true,
}
diff --git a/ravenwood/bivalenttest/AndroidTest.xml b/ravenwood/bivalenttest/AndroidTest.xml
index ac4695b..9e5dd11 100644
--- a/ravenwood/bivalenttest/AndroidTest.xml
+++ b/ravenwood/bivalenttest/AndroidTest.xml
@@ -25,5 +25,8 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.ravenwood.bivalenttest" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+
+ <!-- Need to use MODULE_LIBRARIES APIs, so no hidden API check. -->
+ <option name="hidden-api-checks" value="false" />
</test>
</configuration>
diff --git a/ravenwood/bivalenttest/jni/ravenwood_core_test_jni.cpp b/ravenwood/bivalenttest/jni/ravenwood_core_test_jni.cpp
index 83f756e..956d79c 100644
--- a/ravenwood/bivalenttest/jni/ravenwood_core_test_jni.cpp
+++ b/ravenwood/bivalenttest/jni/ravenwood_core_test_jni.cpp
@@ -15,19 +15,70 @@
*/
#include <nativehelper/JNIHelp.h>
+#include <atomic>
#include "jni.h"
#include "utils/Log.h"
#include "utils/misc.h"
+// JNI methods for RavenwoodJniTest
+
static jint add(JNIEnv* env, jclass clazz, jint a, jint b) {
return a + b;
}
-static const JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods_JniTest[] =
{
{ "add", "(II)I", (void*)add },
};
+// JNI methods for RavenwoodNativeAllocationRegistryTest
+std::atomic<int> numTotalAlloc = 0;
+
+class NarTestData {
+public:
+ NarTestData(jint v): value(v) {
+ numTotalAlloc++;
+ }
+
+ ~NarTestData() {
+ value = -1;
+ numTotalAlloc--;
+ }
+
+ volatile jint value;
+};
+
+static jlong NarTestData_nMalloc(JNIEnv* env, jclass clazz, jint value) {
+ NarTestData* p = new NarTestData(value);
+ return reinterpret_cast<jlong>(p);
+}
+
+static jint NarTestData_nGet(JNIEnv* env, jclass clazz, jlong ptr) {
+ NarTestData* p = reinterpret_cast<NarTestData*>(ptr);
+ return p->value;
+}
+
+static void NarTestData_free(jlong ptr) {
+ NarTestData* p = reinterpret_cast<NarTestData*>(ptr);
+ delete p;
+}
+
+static jlong NarTestData_nGetNativeFinalizer(JNIEnv* env, jclass clazz) {
+ return reinterpret_cast<jlong>(NarTestData_free);
+}
+
+static jint NarTestData_nGetTotalAlloc(JNIEnv* env, jclass clazz) {
+ return numTotalAlloc;
+}
+
+static const JNINativeMethod sMethods_NarTestData[] =
+{
+ { "nMalloc", "(I)J", (void*)NarTestData_nMalloc },
+ { "nGet", "(J)I", (void*)NarTestData_nGet },
+ { "nGetNativeFinalizer", "()J", (void*)NarTestData_nGetNativeFinalizer },
+ { "nGetTotalAlloc", "()I", (void*)NarTestData_nGetTotalAlloc },
+};
+
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
JNIEnv* env = NULL;
@@ -43,7 +94,13 @@
int res = jniRegisterNativeMethods(env,
"com/android/ravenwoodtest/bivalenttest/RavenwoodJniTest",
- sMethods, NELEM(sMethods));
+ sMethods_JniTest, NELEM(sMethods_JniTest));
+ if (res < 0) {
+ return res;
+ }
+ res = jniRegisterNativeMethods(env,
+ "com/android/ravenwoodtest/bivalenttest/RavenwoodNativeAllocationRegistryTest$Data",
+ sMethods_NarTestData, NELEM(sMethods_NarTestData));
if (res < 0) {
return res;
}
diff --git a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodJniTest.java b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodJniTest.java
index 59467e9..0cc2adc 100644
--- a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodJniTest.java
+++ b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodJniTest.java
@@ -29,6 +29,10 @@
@RunWith(AndroidJUnit4.class)
public final class RavenwoodJniTest {
static {
+ initializeJni();
+ }
+
+ public static void initializeJni() {
RavenwoodUtils.loadJniLibrary("ravenwoodbivalenttest_jni");
}
diff --git a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodNativeAllocationRegistryTest.java b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodNativeAllocationRegistryTest.java
new file mode 100644
index 0000000..415b467
--- /dev/null
+++ b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodNativeAllocationRegistryTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ravenwoodtest.bivalenttest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.platform.test.ravenwood.RavenwoodRule;
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import libcore.util.NativeAllocationRegistry;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodNativeAllocationRegistryTest {
+ private static final String TAG = RavenwoodNativeAllocationRegistryTest.class.getSimpleName();
+ static {
+ RavenwoodJniTest.initializeJni();
+ }
+
+ @Rule
+ public final RavenwoodRule mRavenwoodRule = new RavenwoodRule();
+
+ private static class Data {
+ private final long mNativePtr;
+
+ private static native long nMalloc(int value);
+ private static native int nGet(long ptr);
+ private static native long nGetNativeFinalizer();
+
+ public static native int nGetTotalAlloc();
+
+ public int get() {
+ return nGet(mNativePtr);
+ }
+
+ private static class NarHolder {
+ public static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(
+ Data.class.getClassLoader(), nGetNativeFinalizer());
+ }
+
+ public Data(int value) {
+ mNativePtr = nMalloc(value);
+ NarHolder.sRegistry.registerNativeAllocation(this, mNativePtr);
+ }
+ }
+
+ @Test
+ public void testNativeAllocationRegistry() {
+
+ final long timeoutTime = mRavenwoodRule.realCurrentTimeMillis() + 10_000;
+
+ final int startAlloc = Data.nGetTotalAlloc();
+
+ int totalAlloc = 0;
+
+ // Keep allocation new objects, until some get released.
+
+ while (true) {
+ for (int i = 0; i < 1000; i++) {
+ totalAlloc++;
+ Data d = new Data(i);
+ assertEquals(i, d.get());
+ }
+ System.gc();
+
+ final int currentAlloc = Data.nGetTotalAlloc() - startAlloc;
+ Log.i(TAG, "# of currently allocated objects=" + currentAlloc);
+
+ if (currentAlloc < totalAlloc) {
+ break; // Good, some objects have been released;
+ }
+ if (mRavenwoodRule.realCurrentTimeMillis() > timeoutTime) {
+ fail("No objects have been released before timeout");
+ }
+ }
+ }
+}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 21d8019..9d12f85 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -426,4 +426,15 @@
return ENABLE_OPTIONAL_VALIDATION;
}
}
+
+ /**
+ * Returns the "real" result from {@link System#currentTimeMillis()}.
+ *
+ * Currently, it's the same thing as calling {@link System#currentTimeMillis()},
+ * but this one is guaranteeed to return the real value, even when Ravenwood supports
+ * injecting a time to{@link System#currentTimeMillis()}.
+ */
+ public long realCurrentTimeMillis() {
+ return System.currentTimeMillis();
+ }
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
index 37ceac6..99ab327 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
@@ -26,6 +26,15 @@
private RavenwoodUtils() {
}
+ private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime";
+
+ // LibcoreRavenwoodUtils calls it with reflections.
+ public static void loadRavenwoodNativeRuntime() {
+ if (RavenwoodRule.isOnRavenwood()) {
+ RavenwoodUtils.loadJniLibrary(RAVENWOOD_NATIVE_RUNTIME_NAME);
+ }
+ }
+
/**
* Load a JNI library respecting {@code java.library.path}
* (which reflects {@code LD_LIBRARY_PATH}).
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index e951351b..773a89a 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -39,4 +39,8 @@
public static void validate(Statement base, Description description,
boolean enableOptionalValidation) {
}
+
+ public static long realCurrentTimeMillis() {
+ return System.currentTimeMillis();
+ }
}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
index 9057d16..96b7057 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
@@ -44,6 +44,14 @@
public static final String LIBANDROID_RUNTIME_NAME = "android_runtime";
+ /**
+ * Extra strings needed to pass to register_android_graphics_classes().
+ *
+ * `android.graphics.Graphics` is not actually a class, so we can't use the same initialization
+ * strategy than the "normal" classes. So we just hardcode it here.
+ */
+ public static final String GRAPHICS_EXTRA_INIT_PARAMS = ",android.graphics.Graphics";
+
private static String sInitialDir = new File("").getAbsolutePath();
static {
@@ -98,7 +106,6 @@
private static void loadFrameworkNativeCode() {
// This is called from class-initializers, so no synchronization is needed.
if (sLoadFrameworkNativeCodeCalled) {
- // This method has already been called before.s
return;
}
sLoadFrameworkNativeCodeCalled = true;
@@ -112,7 +119,8 @@
}
if (SKIP_LOADING_LIBANDROID) {
- log("Skip loading " + LIBANDROID_RUNTIME_NAME);
+ log("Skip loading native runtime.");
+ return;
}
// Make sure these properties are not set.
@@ -121,27 +129,39 @@
ensurePropertyNotSet(KEYBOARD_PATHS);
ensurePropertyNotSet(GRAPHICS_NATIVE_CLASSES);
- // Tell libandroid what JNI to use.
- final var jniClasses = getCoreNativeClassesToUse();
- if (jniClasses.isEmpty()) {
- log("No classes require JNI methods, skip loading " + LIBANDROID_RUNTIME_NAME);
+ // Load the libraries, if needed.
+ final var libanrdoidClasses = getClassesWithNativeMethods(sLibandroidClasses);
+ final var libhwuiClasses = getClassesWithNativeMethods(sLibhwuiClasses);
+ if (libanrdoidClasses.isEmpty() && libhwuiClasses.isEmpty()) {
+ log("No classes require JNI methods, skip loading native runtime.");
return;
}
- setProperty(CORE_NATIVE_CLASSES, jniClasses);
- setProperty(GRAPHICS_NATIVE_CLASSES, "");
+ setProperty(CORE_NATIVE_CLASSES, libanrdoidClasses);
+ setProperty(GRAPHICS_NATIVE_CLASSES, libhwuiClasses + GRAPHICS_EXTRA_INIT_PARAMS);
+ log("Loading " + LIBANDROID_RUNTIME_NAME + " for '" + libanrdoidClasses + "' and '"
+ + libhwuiClasses + "'");
RavenwoodUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME);
}
/**
- * Classes with native methods that are backed by `libandroid_runtime`.
+ * Classes with native methods that are backed by libandroid_runtime.
*
- * At runtime, we check if these classes have any methods, and if so, we'll have
- * `libandroid_runtime` register the native functions.
+ * See frameworks/base/core/jni/platform/host/HostRuntime.cpp
*/
- private static final Class<?>[] sClassesWithLibandroidNativeMethods = {
+ private static final Class<?>[] sLibandroidClasses = {
android.util.Log.class,
- android.os.Parcel.class,
+ };
+
+ /**
+ * Classes with native methods that are backed by libhwui.
+ *
+ * See frameworks/base/libs/hwui/apex/LayoutlibLoader.cpp
+ */
+ private static final Class<?>[] sLibhwuiClasses = {
+ android.graphics.Interpolator.class,
+ android.graphics.Matrix.class,
+ android.graphics.Path.class,
};
/**
@@ -157,17 +177,15 @@
}
/**
- * Create a list of classes as comma-separated that require JNI methods to be set up.
- *
- * <p>This list is used by frameworks/base/core/jni/LayoutlibLoader.cpp to decide
- * what JNI methods to set up.
+ * Create a list of classes as comma-separated that require JNI methods to be set up from
+ * a given class list, ignoring classes with no native methods.
*/
- private static String getCoreNativeClassesToUse() {
+ private static String getClassesWithNativeMethods(Class<?>[] classes) {
final var coreNativeClassesToLoad = new ArrayList<String>();
- for (var clazz : sClassesWithLibandroidNativeMethods) {
+ for (var clazz : classes) {
if (hasNativeMethod(clazz)) {
- log("Class %s has native methods", clazz);
+ log("Class %s has native methods", clazz.getCanonicalName());
coreNativeClassesToLoad.add(clazz.getName());
}
}
diff --git a/ravenwood/runtime-helper-src/jni/ravenwood_runtime.cpp b/ravenwood/runtime-helper-src/jni/ravenwood_runtime.cpp
new file mode 100644
index 0000000..8e3a21d
--- /dev/null
+++ b/ravenwood/runtime-helper-src/jni/ravenwood_runtime.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <nativehelper/JNIHelp.h>
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+
+typedef void (*FreeFunction)(void*);
+
+static void NativeAllocationRegistry_applyFreeFunction(JNIEnv*,
+ jclass,
+ jlong freeFunction,
+ jlong ptr) {
+ void* nativePtr = reinterpret_cast<void*>(static_cast<uintptr_t>(ptr));
+ FreeFunction nativeFreeFunction
+ = reinterpret_cast<FreeFunction>(static_cast<uintptr_t>(freeFunction));
+ nativeFreeFunction(nativePtr);
+}
+
+static const JNINativeMethod sMethods_NAR[] =
+{
+ { "applyFreeFunction", "(JJ)V", (void*)NativeAllocationRegistry_applyFreeFunction },
+};
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
+{
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ ALOGE("GetEnv failed!");
+ return result;
+ }
+ ALOG_ASSERT(env, "Could not retrieve the env!");
+
+ ALOGI("%s: JNI_OnLoad", __FILE__);
+
+ // Initialize the Ravenwood version of NativeAllocationRegistry.
+ // We don't use this JNI on the device side, but if we ever have to do, skip this part.
+#ifndef __ANDROID__
+ int res = jniRegisterNativeMethods(env, "libcore/util/NativeAllocationRegistry",
+ sMethods_NAR, NELEM(sMethods_NAR));
+ if (res < 0) {
+ return res;
+ }
+#endif
+
+ return JNI_VERSION_1_4;
+}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/ravenwood/LibcoreRavenwoodUtils.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/ravenwood/LibcoreRavenwoodUtils.java
new file mode 100644
index 0000000..839b62a
--- /dev/null
+++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/ravenwood/LibcoreRavenwoodUtils.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.ravenwood;
+
+public class LibcoreRavenwoodUtils {
+ private LibcoreRavenwoodUtils() {
+ }
+
+ public static void loadRavenwoodNativeRuntime() {
+ // TODO Stop using reflections.
+ // We need to call RavenwoodUtils.loadRavenwoodNativeRuntime(), but due to the build
+ // structure complexity, we can't refer to to this method directly from here,
+ // so let's use reflections for now...
+ try {
+ final var clazz = Class.forName("android.platform.test.ravenwood.RavenwoodUtils");
+ final var method = clazz.getMethod("loadRavenwoodNativeRuntime");
+ method.invoke(null);
+ } catch (Throwable th) {
+ throw new IllegalStateException("Failed to load Ravenwood native runtime", th);
+ }
+ }
+}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java
new file mode 100644
index 0000000..93861e8
--- /dev/null
+++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.util;
+
+import libcore.ravenwood.LibcoreRavenwoodUtils;
+
+import java.lang.ref.Cleaner;
+import java.lang.ref.Reference;
+
+/**
+ * Re-implementation of ART's NativeAllocationRegistry for Ravenwood.
+ * - We don't track the native allocation size on Ravenwood.
+ * - sun.misc.Cleaner isn't available on the desktop JVM, so we use java.lang.ref.Cleaner.
+ * (Should ART switch to java.lang.ref.Cleaner?)
+ */
+public class NativeAllocationRegistry {
+ static {
+ // Initialize the JNI method.
+ LibcoreRavenwoodUtils.loadRavenwoodNativeRuntime();
+ }
+
+ private final long mFreeFunction;
+ private static final Cleaner sCleaner = Cleaner.create();
+
+ public static NativeAllocationRegistry createNonmalloced(
+ ClassLoader classLoader, long freeFunction, long size) {
+ return new NativeAllocationRegistry(classLoader, freeFunction, size, false);
+ }
+
+ public static NativeAllocationRegistry createMalloced(
+ ClassLoader classLoader, long freeFunction, long size) {
+ return new NativeAllocationRegistry(classLoader, freeFunction, size, true);
+ }
+
+ public static NativeAllocationRegistry createMalloced(
+ ClassLoader classLoader, long freeFunction) {
+ return new NativeAllocationRegistry(classLoader, freeFunction, 0, true);
+ }
+
+ public NativeAllocationRegistry(ClassLoader classLoader, long freeFunction, long size) {
+ this(classLoader, freeFunction, size, size == 0);
+ }
+
+ private NativeAllocationRegistry(ClassLoader classLoader, long freeFunction, long size,
+ boolean mallocAllocation) {
+ if (size < 0) {
+ throw new IllegalArgumentException("Invalid native allocation size: " + size);
+ }
+ mFreeFunction = freeFunction;
+ }
+
+ public Runnable registerNativeAllocation(Object referent, long nativePtr) {
+ if (referent == null) {
+ throw new IllegalArgumentException("referent is null");
+ }
+ if (nativePtr == 0) {
+ throw new IllegalArgumentException("nativePtr is null");
+ }
+
+ final Runnable releaser = () -> {
+ applyFreeFunction(mFreeFunction, nativePtr);
+ };
+ sCleaner.register(referent, releaser);
+
+ // Ensure that cleaner doesn't get invoked before we enable it.
+ Reference.reachabilityFence(referent);
+ return releaser;
+ }
+
+ /**
+ * Calls {@code freeFunction}({@code nativePtr}).
+ */
+ public static native void applyFreeFunction(long freeFunction, long nativePtr);
+}
+
diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
index 243e224..e452299 100644
--- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
@@ -236,7 +236,11 @@
android.accounts.Account
+android.graphics.Bitmap$Config
android.graphics.Insets
+android.graphics.Interpolator
+android.graphics.Matrix
+android.graphics.Path
android.graphics.Point
android.graphics.PointF
android.graphics.Rect
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ad869a1..2bece6c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -852,7 +852,7 @@
}
private void registerBroadcastReceivers() {
- mPackageMonitor = new PackageMonitor() {
+ mPackageMonitor = new PackageMonitor(true) {
@Override
public void onSomePackagesChanged() {
if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 522aa67..e830523 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2292,11 +2292,32 @@
args.arg4 = requestId;
args.argi1 = widget.appWidgetId;
+ if (updateViews != null && updateViews.isLegacyListRemoteViews()) {
+ mCallbackHandler.obtainMessage(
+ CallbackHandler.MSG_NOTIFY_UPDATE_APP_WIDGET_DEFERRED,
+ args).sendToTarget();
+ return;
+ }
+
mCallbackHandler.obtainMessage(
CallbackHandler.MSG_NOTIFY_UPDATE_APP_WIDGET,
args).sendToTarget();
}
+ private void handleNotifyUpdateAppWidgetDeferred(Host host, IAppWidgetHost callbacks,
+ int appWidgetId, long requestId) {
+ try {
+ Slog.d(TAG, "Trying to notify widget update deferred for id: " + appWidgetId);
+ callbacks.updateAppWidgetDeferred(appWidgetId);
+ host.lastWidgetUpdateSequenceNo = requestId;
+ } catch (RemoteException re) {
+ synchronized (mLock) {
+ Slog.e(TAG, "Widget host dead: " + host.id, re);
+ host.callbacks = null;
+ }
+ }
+ }
+
private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
int appWidgetId, RemoteViews views, long requestId) {
try {
@@ -4277,6 +4298,7 @@
public static final int MSG_NOTIFY_PROVIDERS_CHANGED = 3;
public static final int MSG_NOTIFY_VIEW_DATA_CHANGED = 4;
public static final int MSG_NOTIFY_APP_WIDGET_REMOVED = 5;
+ public static final int MSG_NOTIFY_UPDATE_APP_WIDGET_DEFERRED = 6;
public CallbackHandler(Looper looper) {
super(looper, null, false);
@@ -4340,6 +4362,17 @@
handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId,
requestId);
} break;
+
+ case MSG_NOTIFY_UPDATE_APP_WIDGET_DEFERRED: {
+ SomeArgs args = (SomeArgs) message.obj;
+ Host host = (Host) args.arg1;
+ IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
+ long requestId = (Long) args.arg4;
+ final int appWidgetId = args.argi1;
+ args.recycle();
+
+ handleNotifyUpdateAppWidgetDeferred(host, callbacks, appWidgetId, requestId);
+ } break;
}
}
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 8ee560b..3ff0504 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -242,6 +242,7 @@
"com.android.sysprop.watchdog",
"securebox",
"apache-commons-math",
+ "battery_saver_flag_lib",
"notification_flags_lib",
"power_hint_flags_lib",
"biometrics_flags_lib",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c47e42d..1b59c18 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5034,7 +5034,7 @@
}
@Override
- public final void finishAttachApplication(long startSeq) {
+ public final void finishAttachApplication(long startSeq, long timestampApplicationOnCreateNs) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -5054,6 +5054,11 @@
} finally {
Binder.restoreCallingIdentity(origId);
}
+
+ if (android.app.Flags.appStartInfoTimestamps() && timestampApplicationOnCreateNs > 0) {
+ addStartInfoTimestampInternal(ApplicationStartInfo.START_TIMESTAMP_APPLICATION_ONCREATE,
+ timestampApplicationOnCreateNs, UserHandle.getUserId(uid), uid);
+ }
}
private void handleBindApplicationTimeoutSoft(ProcessRecord app, int softTimeoutMillis) {
@@ -10253,10 +10258,15 @@
mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, true,
ALLOW_NON_FULL, "addStartInfoTimestamp", null);
- final String packageName = Settings.getPackageNameForUid(mContext, callingUid);
+ addStartInfoTimestampInternal(key, timestampNs, userId, callingUid);
+ }
- mProcessList.getAppStartInfoTracker().addTimestampToStart(packageName,
- UserHandle.getUid(userId, UserHandle.getAppId(callingUid)), timestampNs, key);
+ private void addStartInfoTimestampInternal(int key, long timestampNs, int userId, int uid) {
+ mProcessList.getAppStartInfoTracker().addTimestampToStart(
+ Settings.getPackageNameForUid(mContext, uid),
+ UserHandle.getUid(userId, UserHandle.getAppId(uid)),
+ timestampNs,
+ key);
}
@Override
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index 94baf88..2285826 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
+import android.companion.virtual.VirtualDeviceManager;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -134,7 +135,7 @@
AppOpsManager.OpEventProxyInfo proxyInfo = null;
if (proxyUid != Process.INVALID_UID) {
proxyInfo = mAppOpsService.mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
- proxyAttributionTag);
+ proxyAttributionTag, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
}
AppOpsManager.NoteOpEvent existingEvent = mAccessEvents.get(key);
@@ -855,7 +856,7 @@
AppOpsManager.OpEventProxyInfo proxyInfo = null;
if (proxyUid != Process.INVALID_UID) {
proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
- proxyAttributionTag);
+ proxyAttributionTag, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
}
if (recycled != null) {
@@ -881,10 +882,11 @@
AppOpsManager.OpEventProxyInfo acquire(@IntRange(from = 0) int uid,
@Nullable String packageName,
- @Nullable String attributionTag) {
+ @Nullable String attributionTag,
+ @Nullable String deviceId) {
AppOpsManager.OpEventProxyInfo recycled = acquire();
if (recycled != null) {
- recycled.reinit(uid, packageName, attributionTag);
+ recycled.reinit(uid, packageName, attributionTag, deviceId);
return recycled;
}
diff --git a/services/core/java/com/android/server/biometrics/biometrics.aconfig b/services/core/java/com/android/server/biometrics/biometrics.aconfig
index 92fd9cb..712dcee 100644
--- a/services/core/java/com/android/server/biometrics/biometrics.aconfig
+++ b/services/core/java/com/android/server/biometrics/biometrics.aconfig
@@ -14,3 +14,10 @@
description: "This flag controls whether virtual HAL is used for testing instead of TestHal "
bug: "294254230"
}
+
+flag {
+ name: "mandatory_biometrics"
+ namespace: "biometrics_framework"
+ description: "This flag controls whether LSKF fallback is removed from biometric prompt when the phone is outside trusted locations"
+ bug: "322081563"
+}
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
index d494be5..e91de37 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
@@ -123,8 +123,7 @@
* Returns the system-gender to be backed up as a data-blob.
*/
public byte[] getSystemBackupPayload(int userId) {
- int gender = mGrammaticalGenderService.getSystemGrammaticalGender(mAttributionSource,
- userId);
+ int gender = mGrammaticalGenderService.getSystemGrammaticalGender(userId);
return intToByteArray(gender);
}
@@ -167,7 +166,7 @@
BackupManager.dataChanged(SYSTEM_BACKUP_PACKAGE_KEY);
}
- private byte[] convertToByteArray(HashMap<String, Integer> pkgGenderInfo) {
+ private static byte[] convertToByteArray(HashMap<String, Integer> pkgGenderInfo) {
try (final ByteArrayOutputStream out = new ByteArrayOutputStream();
final ObjectOutputStream objStream = new ObjectOutputStream(out)) {
objStream.writeObject(pkgGenderInfo);
@@ -178,22 +177,22 @@
}
}
- private byte[] intToByteArray(final int gender) {
+ private static byte[] intToByteArray(final int gender) {
ByteBuffer bb = ByteBuffer.allocate(4);
bb.putInt(gender);
return bb.array();
}
- private int convertByteArrayToInt(byte[] intBytes) {
+ private static int convertByteArrayToInt(byte[] intBytes) {
ByteBuffer byteBuffer = ByteBuffer.wrap(intBytes);
return byteBuffer.getInt();
}
- private HashMap<String, Integer> readFromByteArray(byte[] payload) {
+ private static HashMap<String, Integer> readFromByteArray(byte[] payload) {
HashMap<String, Integer> data = new HashMap<>();
- try (ByteArrayInputStream byteIn = new ByteArrayInputStream(payload);
- ObjectInputStream in = new ObjectInputStream(byteIn)) {
+ try (var byteIn = new ByteArrayInputStream(payload);
+ var in = new ObjectInputStream(byteIn)) {
data = (HashMap<String, Integer>) in.readObject();
} catch (IOException | ClassNotFoundException e) {
Log.e(TAG, "cannot convert payload to HashMap.", e);
@@ -205,10 +204,10 @@
private void cleanStagedDataForOldEntries() {
for (int i = 0; i < mCache.size(); i++) {
int userId = mCache.keyAt(i);
- StagedData stagedData = mCache.get(userId);
+ StagedData stagedData = mCache.valueAt(userId);
if (stagedData.mCreationTimeMillis
< mClock.millis() - STAGE_DATA_RETENTION_PERIOD.toMillis()) {
- mCache.remove(userId);
+ mCache.removeAt(i--);
}
}
}
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
index 2816d08..7eb971c 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
@@ -16,7 +16,6 @@
package com.android.server.grammaticalinflection;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Configuration;
@@ -41,7 +40,7 @@
public abstract void stageAndApplyRestoredPayload(byte[] payload, int userId);
/**
- * Get the current system grammatical gender of privileged application.
+ * Get the current system grammatical gender for the particular user.
*
* @return the value of grammatical gender
*
@@ -50,18 +49,25 @@
public abstract @Configuration.GrammaticalGender int getSystemGrammaticalGender(int userId);
/**
- * Retrieve the system grammatical gender.
+ * Get the final merged value of the global grammatical gender, user- or devsettings-set.
*
* @return the value of grammatical gender
*
*/
- public abstract @Configuration.GrammaticalGender int retrieveSystemGrammaticalGender(
- @NonNull Configuration configuration);
+ public abstract @Configuration.GrammaticalGender int mergedFinalSystemGrammaticalGender();
+
+ /**
+ * Get the grammatical gender from developer settings global override.
+ *
+ * @return the value of grammatical gender
+ */
+ public abstract
+ @Configuration.GrammaticalGender int getGrammaticalGenderFromDeveloperSettings();
/**
* Whether the package can get the system grammatical gender or not.
*/
- public abstract boolean canGetSystemGrammaticalGender(int uid, @Nullable String packageName);
+ public abstract boolean canGetSystemGrammaticalGender(int uid);
/**
@@ -74,4 +80,3 @@
*/
public abstract void applyRestoredSystemPayload(byte[] payload, int userId);
}
-
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
index 93a71b9..e242164 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
@@ -17,7 +17,6 @@
package com.android.server.grammaticalinflection;
import static android.app.Flags.systemTermsOfAddressEnabled;
-import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
import static com.android.server.grammaticalinflection.GrammaticalInflectionUtils.checkSystemGrammaticalGenderPermission;
@@ -43,6 +42,7 @@
import android.util.SparseIntArray;
import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
@@ -126,7 +126,7 @@
@Override
public void setSystemWideGrammaticalGender(int grammaticalGender, int userId) {
- isCallerAllowed();
+ enforceCallerPermissions();
GrammaticalInflectionService.this.setSystemWideGrammaticalGender(grammaticalGender,
userId);
}
@@ -138,18 +138,16 @@
+ " does not have READ_SYSTEM_GRAMMATICAL_GENDER permission.");
}
return checkSystemTermsOfAddressIsEnabled()
- ? GrammaticalInflectionService.this.getSystemGrammaticalGender(
- attributionSource, userId)
- : GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ ? GrammaticalInflectionService.this.getSystemGrammaticalGender(userId)
+ : Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
}
@Override
public int peekSystemGrammaticalGenderByUserId(AttributionSource attributionSource,
int userId) {
return canGetSystemGrammaticalGender(attributionSource)
- ? GrammaticalInflectionService.this.getSystemGrammaticalGender(
- attributionSource, userId)
- : GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ ? GrammaticalInflectionService.this.getSystemGrammaticalGender(userId)
+ : Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
}
@Override
@@ -163,11 +161,10 @@
private final class GrammaticalInflectionManagerInternalImpl
extends GrammaticalInflectionManagerInternal {
-
@Override
@Nullable
public byte[] getBackupPayload(int userId) {
- isCallerAllowed();
+ enforceCallerPermissions();
return mBackupHelper.getBackupPayload(userId);
}
@@ -179,7 +176,7 @@
@Override
@Nullable
public byte[] getSystemBackupPayload(int userId) {
- isCallerAllowed();
+ enforceCallerPermissions();
return mBackupHelper.getSystemBackupPayload(userId);
}
@@ -191,30 +188,35 @@
@Override
public int getSystemGrammaticalGender(int userId) {
return checkSystemTermsOfAddressIsEnabled()
- ? GrammaticalInflectionService.this.getSystemGrammaticalGender(
- mContext.getAttributionSource(), userId)
- : GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ ? GrammaticalInflectionService.this.getSystemGrammaticalGender(userId)
+ : Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
}
@Override
- public int retrieveSystemGrammaticalGender(Configuration configuration) {
+ public int mergedFinalSystemGrammaticalGender() {
int systemGrammaticalGender = getSystemGrammaticalGender(mContext.getUserId());
// Retrieve the grammatical gender from system property, set it into
// configuration which will get updated later if the grammatical gender raw value of
// current configuration is {@link Configuration#GRAMMATICAL_GENDER_UNDEFINED}.
- if (configuration.getGrammaticalGenderRaw()
- == Configuration.GRAMMATICAL_GENDER_UNDEFINED
- || systemGrammaticalGender <= Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) {
- systemGrammaticalGender = SystemProperties.getInt(GRAMMATICAL_GENDER_PROPERTY,
- Configuration.GRAMMATICAL_GENDER_UNDEFINED);
+ if (systemGrammaticalGender == Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) {
+ systemGrammaticalGender = getGrammaticalGenderFromDeveloperSettings();
}
- return systemGrammaticalGender;
+ return systemGrammaticalGender == Configuration.GRAMMATICAL_GENDER_UNDEFINED
+ ? Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED : systemGrammaticalGender;
}
@Override
- public boolean canGetSystemGrammaticalGender(int uid, String packageName) {
- AttributionSource attributionSource = new AttributionSource.Builder(
- uid).setPackageName(packageName).build();
+ public int getGrammaticalGenderFromDeveloperSettings() {
+ return SystemProperties.getInt(GRAMMATICAL_GENDER_PROPERTY,
+ Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED);
+ }
+
+ @Override
+ public boolean canGetSystemGrammaticalGender(int uid) {
+ if (uid == Process.SYSTEM_UID) {
+ return true;
+ }
+ var attributionSource = new AttributionSource.Builder(uid).build();
return GrammaticalInflectionService.this.canGetSystemGrammaticalGender(
attributionSource);
}
@@ -225,7 +227,7 @@
mActivityTaskManagerInternal.getApplicationConfig(appPackageName, userId);
if (appConfig == null || appConfig.mGrammaticalGender == null) {
- return GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ return Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
} else {
return appConfig.mGrammaticalGender;
}
@@ -239,9 +241,10 @@
userId);
if (!SystemProperties.getBoolean(GRAMMATICAL_INFLECTION_ENABLED, true)) {
- if (preValue != GRAMMATICAL_GENDER_NOT_SPECIFIED) {
+ if (preValue != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) {
Log.d(TAG, "Clearing the user's grammatical gender setting");
- updater.setGrammaticalGender(GRAMMATICAL_GENDER_NOT_SPECIFIED).commit();
+ updater.setGrammaticalGender(
+ Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED).commit();
}
return;
}
@@ -250,49 +253,48 @@
FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_GRAMMATICAL_INFLECTION_CHANGED,
FrameworkStatsLog.APPLICATION_GRAMMATICAL_INFLECTION_CHANGED__SOURCE_ID__OTHERS,
uid,
- gender != GRAMMATICAL_GENDER_NOT_SPECIFIED,
- preValue != GRAMMATICAL_GENDER_NOT_SPECIFIED);
+ gender != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED,
+ preValue != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED);
updater.setGrammaticalGender(gender).commit();
}
protected void setSystemWideGrammaticalGender(int grammaticalGender, int userId) {
- Trace.beginSection("GrammaticalInflectionService.setSystemWideGrammaticalGender");
- if (!GrammaticalInflectionManager.VALID_GRAMMATICAL_GENDER_VALUES.contains(
- grammaticalGender)) {
- throw new IllegalArgumentException("Unknown grammatical gender");
- }
-
- if (!checkSystemTermsOfAddressIsEnabled()) {
- if (grammaticalGender == GRAMMATICAL_GENDER_NOT_SPECIFIED) {
- return;
+ try {
+ if (!checkSystemTermsOfAddressIsEnabled()) {
+ return; // Nothing to do, and the flag can't get flipped at the runtime.
}
- Log.d(TAG, "Clearing the system grammatical gender setting");
- grammaticalGender = GRAMMATICAL_GENDER_NOT_SPECIFIED;
- }
- synchronized (mLock) {
+ Trace.beginSection("GrammaticalInflectionService.setSystemWideGrammaticalGender");
+ if (!GrammaticalInflectionManager.VALID_GRAMMATICAL_GENDER_VALUES.contains(
+ grammaticalGender)) {
+ throw new IllegalArgumentException("Unknown grammatical gender");
+ }
+
final File file = getGrammaticalGenderFile(userId);
- final AtomicFile atomicFile = new AtomicFile(file);
- FileOutputStream stream = null;
- try {
- stream = atomicFile.startWrite();
- stream.write(toXmlByteArray(grammaticalGender, stream));
- atomicFile.finishWrite(stream);
- mGrammaticalGenderCache.put(userId, grammaticalGender);
- } catch (IOException e) {
- Log.e(TAG, "Failed to write file " + atomicFile, e);
- if (stream != null) {
- atomicFile.failWrite(stream);
+ synchronized (mLock) {
+ final AtomicFile atomicFile = new AtomicFile(file);
+ FileOutputStream stream = null;
+ try {
+ stream = atomicFile.startWrite();
+ stream.write(toXmlByteArray(grammaticalGender, stream));
+ atomicFile.finishWrite(stream);
+ mGrammaticalGenderCache.put(userId, grammaticalGender);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to write file " + atomicFile, e);
+ if (stream != null) {
+ atomicFile.failWrite(stream);
+ }
+ throw new RuntimeException(e);
}
- throw new RuntimeException(e);
}
+ updateConfiguration(grammaticalGender, userId);
+ } finally {
+ Trace.endSection();
}
- updateConfiguration(grammaticalGender, userId);
- Trace.endSection();
}
- private void updateConfiguration(int grammaticalGender, int userId) {
+ private static void updateConfiguration(int grammaticalGender, int userId) {
try {
Configuration config = new Configuration();
int preValue = config.getGrammaticalGender();
@@ -301,54 +303,47 @@
FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_GRAMMATICAL_INFLECTION_CHANGED,
FrameworkStatsLog.SYSTEM_GRAMMATICAL_INFLECTION_CHANGED__SOURCE_ID__SYSTEM,
userId,
- grammaticalGender != GRAMMATICAL_GENDER_NOT_SPECIFIED,
- preValue != GRAMMATICAL_GENDER_NOT_SPECIFIED);
+ grammaticalGender != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED,
+ preValue != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED);
GrammaticalInflectionBackupHelper.notifyBackupManager();
} catch (RemoteException e) {
Log.w(TAG, "Can not update configuration", e);
}
}
- public int getSystemGrammaticalGender(AttributionSource attributionSource, int userId) {
- String packageName = attributionSource.getPackageName();
- if (packageName == null) {
- Log.d(TAG, "Package name is null.");
- return GRAMMATICAL_GENDER_NOT_SPECIFIED;
- }
-
+ /**
+ * Returns the system global grammatical gender value for the requested user.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
+ public int getSystemGrammaticalGender(int userId) {
synchronized (mLock) {
int grammaticalGender = mGrammaticalGenderCache.get(userId);
- return grammaticalGender < 0 ? GRAMMATICAL_GENDER_NOT_SPECIFIED : grammaticalGender;
+ return grammaticalGender < 0
+ ? Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED : grammaticalGender;
}
}
- private File getGrammaticalGenderFile(int userId) {
+ private static File getGrammaticalGenderFile(int userId) {
final File dir = new File(Environment.getDataSystemCeDirectory(userId),
TAG_GRAMMATICAL_INFLECTION);
return new File(dir, USER_SETTINGS_FILE_NAME);
}
- private byte[] toXmlByteArray(int grammaticalGender, FileOutputStream fileStream) {
-
- try {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- TypedXmlSerializer out = Xml.resolveSerializer(fileStream);
- out.setOutput(outputStream, StandardCharsets.UTF_8.name());
- out.startDocument(/* encoding= */ null, /* standalone= */ true);
- out.startTag(null, TAG_GRAMMATICAL_INFLECTION);
- out.attributeInt(null, ATTR_NAME, grammaticalGender);
- out.endTag(null, TAG_GRAMMATICAL_INFLECTION);
- out.endDocument();
-
- return outputStream.toByteArray();
- } catch (IOException e) {
- return null;
- }
+ private static byte[] toXmlByteArray(int grammaticalGender, FileOutputStream fileStream)
+ throws IOException {
+ var outputStream = new ByteArrayOutputStream();
+ TypedXmlSerializer out = Xml.resolveSerializer(fileStream);
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ out.startDocument(/* encoding= */ null, /* standalone= */ true);
+ out.startTag(null, TAG_GRAMMATICAL_INFLECTION);
+ out.attributeInt(null, ATTR_NAME, grammaticalGender);
+ out.endTag(null, TAG_GRAMMATICAL_INFLECTION);
+ out.endDocument();
+ return outputStream.toByteArray();
}
- private int getGrammaticalGenderFromXml(TypedXmlPullParser parser)
+ private static int getGrammaticalGenderFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
-
XmlUtils.nextElement(parser);
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
String tagName = parser.getName();
@@ -359,20 +354,20 @@
}
}
- return GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ return Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
}
- private void isCallerAllowed() {
+ private void enforceCallerPermissions() {
int callingUid = Binder.getCallingUid();
if (callingUid != Process.SYSTEM_UID && callingUid != Process.SHELL_UID
&& callingUid != Process.ROOT_UID) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_CONFIGURATION,
- "Caller must be system, shell, root or has CHANGE_CONFIGURATION permission.");
+ "Caller must be system, shell, root or hold CHANGE_CONFIGURATION permission.");
}
}
- private boolean checkSystemTermsOfAddressIsEnabled() {
+ private static boolean checkSystemTermsOfAddressIsEnabled() {
if (!systemTermsOfAddressEnabled()) {
Log.d(TAG, "The flag must be enabled to allow calling the API.");
return false;
@@ -387,25 +382,31 @@
@Override
public void onUserUnlocked(TargetUser user) {
+ if (!checkSystemTermsOfAddressIsEnabled()) {
+ return;
+ }
IoThread.getHandler().post(() -> {
- int userId = user.getUserIdentifier();
+ final int userId = user.getUserIdentifier();
final File file = getGrammaticalGenderFile(userId);
+ final int grammaticalGender;
synchronized (mLock) {
if (!file.exists()) {
Log.d(TAG, "User " + userId + " doesn't have the grammatical gender file.");
return;
}
- if (mGrammaticalGenderCache.indexOfKey(userId) < 0) {
- try (FileInputStream in = new FileInputStream(file)) {
- final TypedXmlPullParser parser = Xml.resolvePullParser(in);
- int grammaticalGender = getGrammaticalGenderFromXml(parser);
- mGrammaticalGenderCache.put(userId, grammaticalGender);
- updateConfiguration(grammaticalGender, userId);
- } catch (IOException | XmlPullParserException e) {
- Log.e(TAG, "Failed to parse XML configuration from " + file, e);
- }
+ if (mGrammaticalGenderCache.indexOfKey(userId) >= 0) {
+ return;
+ }
+ try (FileInputStream in = new FileInputStream(file)) {
+ final TypedXmlPullParser parser = Xml.resolvePullParser(in);
+ grammaticalGender = getGrammaticalGenderFromXml(parser);
+ mGrammaticalGenderCache.put(userId, grammaticalGender);
+ } catch (IOException | XmlPullParserException e) {
+ Log.e(TAG, "Failed to parse XML configuration from " + file, e);
+ return;
}
}
+ updateConfiguration(grammaticalGender, userId);
});
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index f6dfc9e..cd2c037 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -350,7 +350,7 @@
* {@link HdmiCecNetwork} only.
*
* @return CEC physical address of the device. The range of success address
- * is between 0x0000 and 0xFFFF. If failed it returns -1
+ * is between 0x0000 and 0xFFFE. If failed it returns INVALID_PHYSICAL_ADDRESS.
*/
@ServiceThreadOnly
int getPhysicalAddress() {
@@ -1315,7 +1315,7 @@
hdmiPortInfo[i] = new HdmiPortInfo.Builder(
portInfo.portId,
portInfo.type,
- portInfo.physicalAddress)
+ Short.toUnsignedInt(portInfo.physicalAddress))
.setCecSupported(portInfo.cecSupported)
.setMhlSupported(false)
.setArcSupported(portInfo.arcSupported)
@@ -1512,7 +1512,7 @@
hdmiPortInfo[i] = new HdmiPortInfo.Builder(
portInfo.portId,
portInfo.type,
- portInfo.physicalAddress)
+ Short.toUnsignedInt(portInfo.physicalAddress))
.setCecSupported(portInfo.cecSupported)
.setMhlSupported(false)
.setArcSupported(portInfo.arcSupported)
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 54e1217..d10e192 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -867,6 +867,60 @@
}
}
}, mServiceThreadExecutor);
+ mHdmiCecConfig.registerChangeListener(HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ new HdmiCecConfig.SettingChangeListener() {
+ @Override
+ public void onChange(String setting) {
+ reportFeatures(true);
+ }
+ },
+ mServiceThreadExecutor);
+ mHdmiCecConfig.registerChangeListener(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ new HdmiCecConfig.SettingChangeListener() {
+ @Override
+ public void onChange(String setting) {
+ reportFeatures(false);
+ }
+ },
+ mServiceThreadExecutor);
+ mHdmiCecConfig.registerChangeListener(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ new HdmiCecConfig.SettingChangeListener() {
+ @Override
+ public void onChange(String setting) {
+ reportFeatures(false);
+ }
+ },
+ mServiceThreadExecutor);
+ mHdmiCecConfig.registerChangeListener(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ new HdmiCecConfig.SettingChangeListener() {
+ @Override
+ public void onChange(String setting) {
+ reportFeatures(false);
+ }
+ },
+ mServiceThreadExecutor);
+ mHdmiCecConfig.registerChangeListener(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ new HdmiCecConfig.SettingChangeListener() {
+ @Override
+ public void onChange(String setting) {
+ reportFeatures(false);
+ }
+ },
+ mServiceThreadExecutor);
+ mHdmiCecConfig.registerChangeListener(
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU,
+ new HdmiCecConfig.SettingChangeListener() {
+ @Override
+ public void onChange(String setting) {
+ reportFeatures(false);
+ }
+ },
+ mServiceThreadExecutor);
if (isTvDevice()) {
mDeviceConfig.addOnPropertiesChangedListener(getContext().getMainExecutor(),
@@ -968,6 +1022,21 @@
}
}
+ /** Helper method for sending feature discovery command */
+ private void reportFeatures(boolean isTvDeviceSetting) {
+ // check if tv device is enabled for tv device specific RC profile setting
+ if (isTvDeviceSetting) {
+ if (isTvDeviceEnabled()) {
+ tv().reportFeatures();
+ }
+ } else { // check for source device setting
+ HdmiCecLocalDeviceSource source = isAudioSystemDevice() ? audioSystem() : playback();
+ if (source != null) {
+ source.reportFeatures();
+ }
+ }
+ }
+
/**
* Returns the initial power status used when the HdmiControlService starts.
*/
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
index 8949427..bf6633e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
@@ -124,8 +124,7 @@
return historySize(pw);
}
- getErrPrintWriter().println("Unhandled command: " + cmd);
- return 1;
+ return handleDefaultCommands(cmd);
}
private int deviceSelect(PrintWriter pw) throws RemoteException {
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index ef52d2a..e28939b 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -986,7 +986,7 @@
}
private void startTrackingPackageChanges() {
- final PackageMonitor monitor = new PackageMonitor() {
+ final PackageMonitor monitor = new PackageMonitor(true) {
@Override
public void onPackageUpdateStarted(@NonNull String packageName, int uid) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 44a200e..f86045b 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -471,11 +471,6 @@
return mBindingController.getSelectedMethodId();
}
- @GuardedBy("ImfLock.class")
- private void setSelectedMethodIdLocked(@Nullable String selectedMethodId) {
- mBindingController.setSelectedMethodId(selectedMethodId);
- }
-
/**
* The current binding sequence number, incremented every time there is
* a new bind performed.
@@ -816,6 +811,8 @@
}
} else if (stylusHandwritingEnabledUri.equals(uri)) {
InputMethodManager.invalidateLocalStylusHandwritingAvailabilityCaches();
+ InputMethodManager
+ .invalidateLocalConnectionlessStylusHandwritingAvailabilityCaches();
} else {
boolean enabledChanged = false;
String newEnabled = InputMethodSettingsRepository.get(mCurrentUserId)
@@ -934,6 +931,10 @@
*/
private ArrayList<String> mDataClearedPackages = new ArrayList<>();
+ private MyPackageMonitor() {
+ super(true);
+ }
+
@GuardedBy("ImfLock.class")
void clearKnownImePackageNamesLocked() {
mKnownImePackageNames.clear();
@@ -1526,6 +1527,20 @@
+ " currentUserId=" + mCurrentUserId);
}
+ // Clean up stuff for mCurrentUserId, which soon becomes the previous user.
+
+ // TODO(b/338461930): Check if this is still necessary or not.
+ onUnbindCurrentMethodByReset();
+
+ // Note that in b/197848765 we want to see if we can keep the binding alive for better
+ // profile switching.
+ mBindingController.unbindCurrentMethod();
+ // TODO(b/325515685): No need to do this once BindingController becomes per-user.
+ mBindingController.setSelectedMethodId(null);
+ unbindCurrentClientLocked(UnbindReason.SWITCH_USER);
+
+ // Hereafter we start initializing things for "newUserId".
+
maybeInitImeNavbarConfigLocked(newUserId);
// ContentObserver should be registered again when the user is changed
@@ -1547,10 +1562,6 @@
// IME for that user.
final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
- // The mSystemReady flag is set during boot phase,
- // and user switch would not happen at that time.
- resetCurrentMethodAndClientLocked(UnbindReason.SWITCH_USER);
-
final InputMethodSettings newSettings = InputMethodSettingsRepository.get(newUserId);
postInputMethodSettingUpdatedLocked(initialUserSwitch /* resetDefaultEnabledIme */);
if (TextUtils.isEmpty(newSettings.getSelectedInputMethod())) {
@@ -2497,8 +2508,9 @@
@GuardedBy("ImfLock.class")
void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) {
- setSelectedMethodIdLocked(null);
+ mBindingController.setSelectedMethodId(null);
// Callback before clean-up binding states.
+ // TODO(b/338461930): Check if this is still necessary or not.
onUnbindCurrentMethodByReset();
mBindingController.unbindCurrentMethod();
unbindCurrentClientLocked(unbindClientReason);
@@ -3077,7 +3089,7 @@
// mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
// because mCurMethodId is stored as a history in
// setSelectedInputMethodAndSubtypeLocked().
- setSelectedMethodIdLocked(id);
+ mBindingController.setSelectedMethodId(id);
if (mActivityManagerInternal.isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
@@ -3401,7 +3413,14 @@
mBindingController.setCurrentMethodVisible();
final IInputMethodInvoker curMethod = getCurMethodLocked();
ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
- if (curMethod != null) {
+ final boolean readyToDispatchToIme;
+ if (Flags.deferShowSoftInputUntilSessionCreation()) {
+ readyToDispatchToIme =
+ curMethod != null && mCurClient != null && mCurClient.mCurSession != null;
+ } else {
+ readyToDispatchToIme = curMethod != null;
+ }
+ if (readyToDispatchToIme) {
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_HAS_IME);
mCurStatsToken = null;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index 3bd0a9f..326ef7e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -98,7 +98,10 @@
final int size = imList.size();
mIms = new InputMethodInfo[size];
mSubtypeIds = new int[size];
- int checkedItem = 0;
+ // No items are checked by default. When we have a list of explicitly enabled subtypes,
+ // the implicit subtype is no longer listed, but if it is still the selected one,
+ // no items will be shown as checked.
+ int checkedItem = -1;
for (int i = 0; i < size; ++i) {
final ImeSubtypeListItem item = imList.get(i);
mIms[i] = item.mImi;
@@ -113,6 +116,12 @@
}
}
+ if (checkedItem == -1) {
+ Slog.w(TAG, "Switching menu shown with no item selected"
+ + ", IME id: " + preferredInputMethodId
+ + ", subtype index: " + preferredInputMethodSubtypeId);
+ }
+
if (mDialogWindowContext == null) {
mDialogWindowContext = new InputMethodDialogWindowContext();
}
diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
index 2c14532..c5e2bb8 100644
--- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
@@ -291,9 +291,15 @@
private void setOldSettingForBackworkCompatibility(boolean isActive) {
// Set the SECURE_FRP_MODE flag, for backward compatibility with clients who use it.
- // They should switch to calling #isFrpActive().
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.SECURE_FRP_MODE, isActive ? 1 : 0);
+ // They should switch to calling #isFrpActive(). Clear calling ID since this can happen
+ // during an app call.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.SECURE_FRP_MODE, isActive ? 1 : 0);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
}
private void setOemUnlockEnabledProperty(boolean oemUnlockEnabled) {
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 306f77d..3862b79 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -734,11 +734,11 @@
.addCategory(Intent.CATEGORY_BROWSABLE)
.build();
- /** SMS and MMS can be handled by the private profile or by the parent user. */
+ /** SMS and MMS are always handled in the main user. */
private static final DefaultCrossProfileIntentFilter SMS_MMS_PRIVATE_PROFILE =
new DefaultCrossProfileIntentFilter.Builder(
DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
- ONLY_IF_NO_MATCH_FOUND,
+ SKIP_CURRENT_PROFILE,
/* letsPersonalDataIntoProfile= */ false)
.addAction(Intent.ACTION_VIEW)
.addAction(Intent.ACTION_SENDTO)
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index b2c6c49..47ee1d0 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -513,7 +513,11 @@
// Legacy behavior to report appId as UID here.
// The final broadcasts will contain a per-user UID.
outInfo.mUid = ps.getAppId();
- outInfo.mIsAppIdRemoved = true;
+ // Only send Intent.ACTION_UID_REMOVED when flag & DELETE_KEEP_DATA is 0
+ // i.e. the mDataRemoved is true
+ if (outInfo.mDataRemoved) {
+ outInfo.mIsAppIdRemoved = true;
+ }
mPm.scheduleWritePackageRestrictions(user);
return;
}
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 2e67b2f..9ab6016 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -170,6 +170,7 @@
}
}
+ boolean isPendingRestoreBefore = false;
if (pkgSetting != null && oldSharedUserSetting != sharedUserSetting) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Package " + parsedPackage.getPackageName() + " shared user changed from "
@@ -178,6 +179,9 @@
+ " to "
+ (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>")
+ "; replacing with new");
+ // Preserve the value of isPendingRestore. We need to set it to the new PackageSetting
+ // if the value is true to restore the app
+ isPendingRestoreBefore = pkgSetting.isPendingRestore();
pkgSetting = null;
}
@@ -224,6 +228,11 @@
parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(),
newDomainSetId,
parsedPackage.getTargetSdkVersion(), parsedPackage.getRestrictUpdateHash());
+
+ // If isPendingRestore is true before, set the value true to the PackageSetting
+ if (isPendingRestoreBefore) {
+ pkgSetting.setPendingRestore(true);
+ }
} else {
// make a deep copy to avoid modifying any existing system state.
pkgSetting = new PackageSetting(pkgSetting);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 3f5ec06..82902d4 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -50,7 +50,6 @@
import android.content.pm.IPackageManager;
import android.content.pm.IShortcutService;
import android.content.pm.LauncherApps;
-import android.content.pm.LauncherApps.ShortcutChangeCallback;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -152,7 +151,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
@@ -322,11 +320,12 @@
private final Handler mHandler;
- private final CopyOnWriteArrayList<ShortcutChangeListener> mListeners =
- new CopyOnWriteArrayList<>();
+ @GuardedBy("mServiceLock")
+ private final ArrayList<ShortcutChangeListener> mListeners = new ArrayList<>(1);
- private final CopyOnWriteArrayList<ShortcutChangeCallback> mShortcutChangeCallbacks =
- new CopyOnWriteArrayList<>();
+ @GuardedBy("mServiceLock")
+ private final ArrayList<LauncherApps.ShortcutChangeCallback> mShortcutChangeCallbacks =
+ new ArrayList<>(1);
private final AtomicLong mRawLastResetTime = new AtomicLong(0);
@@ -1842,11 +1841,18 @@
@UserIdInt final int userId) {
return () -> {
try {
- if (!isUserUnlockedL(userId)) {
- return;
+ final ArrayList<ShortcutChangeListener> copy;
+ synchronized (mServiceLock) {
+ if (!isUserUnlockedL(userId)) {
+ return;
+ }
+
+ copy = new ArrayList<>(mListeners);
}
// Note onShortcutChanged() needs to be called with the system service permissions.
- mListeners.forEach(listener -> listener.onShortcutChanged(packageName, userId));
+ for (int i = copy.size() - 1; i >= 0; i--) {
+ copy.get(i).onShortcutChanged(packageName, userId);
+ }
} catch (Exception ignore) {
}
};
@@ -1861,17 +1867,22 @@
final UserHandle user = UserHandle.of(userId);
injectPostToHandler(() -> {
try {
- if (!isUserUnlockedL(userId)) {
- return;
+ final ArrayList<LauncherApps.ShortcutChangeCallback> copy;
+ synchronized (mServiceLock) {
+ if (!isUserUnlockedL(userId)) {
+ return;
+ }
+
+ copy = new ArrayList<>(mShortcutChangeCallbacks);
}
- mShortcutChangeCallbacks.forEach(callback -> {
+ for (int i = copy.size() - 1; i >= 0; i--) {
if (!CollectionUtils.isEmpty(changedList)) {
- callback.onShortcutsAddedOrUpdated(packageName, changedList, user);
+ copy.get(i).onShortcutsAddedOrUpdated(packageName, changedList, user);
}
if (!CollectionUtils.isEmpty(removedList)) {
- callback.onShortcutsRemoved(packageName, removedList, user);
+ copy.get(i).onShortcutsRemoved(packageName, removedList, user);
}
- });
+ }
} catch (Exception ignore) {
}
});
@@ -3414,13 +3425,17 @@
@Override
public void addListener(@NonNull ShortcutChangeListener listener) {
- mListeners.add(Objects.requireNonNull(listener));
+ synchronized (mServiceLock) {
+ mListeners.add(Objects.requireNonNull(listener));
+ }
}
@Override
public void addShortcutChangeCallback(
@NonNull LauncherApps.ShortcutChangeCallback callback) {
- mShortcutChangeCallbacks.add(Objects.requireNonNull(callback));
+ synchronized (mServiceLock) {
+ mShortcutChangeCallbacks.add(Objects.requireNonNull(callback));
+ }
}
@Override
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 98499417..deaa8d8 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -494,6 +494,7 @@
PhoneCarrierPrivilegesCallback(int phoneId) {
mPhoneId = phoneId;
}
+
@Override
public void onCarrierPrivilegesChanged(
@NonNull Set<String> privilegedPackageNames,
@@ -563,7 +564,11 @@
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("Permission_grant_default_permissions-" + userId);
- grantOrUpgradeDefaultRuntimePermissionsIfNeeded(userId);
+ if (mPackageManagerInternal.isPermissionUpgradeNeeded(userId)) {
+ grantOrUpgradeDefaultRuntimePermissions(userId);
+ updateUserSensitive(userId);
+ mPackageManagerInternal.updateRuntimePermissionsFingerprint(userId);
+ }
t.traceEnd();
final OnInitializedCallback callback;
@@ -595,59 +600,56 @@
}
}
- private void grantOrUpgradeDefaultRuntimePermissionsIfNeeded(@UserIdInt int userId) {
+ private void grantOrUpgradeDefaultRuntimePermissions(@UserIdInt int userId) {
if (PermissionManager.USE_ACCESS_CHECKING_SERVICE) {
return;
}
- if (DEBUG) Slog.i(LOG_TAG, "grantOrUpgradeDefaultPermsIfNeeded(" + userId + ")");
+ if (DEBUG) Slog.i(LOG_TAG, "grantOrUpgradeDefaultPerms(" + userId + ")");
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
- final PackageManagerInternal packageManagerInternal =
- LocalServices.getService(PackageManagerInternal.class);
- final PermissionManagerServiceInternal permissionManagerInternal =
- LocalServices.getService(PermissionManagerServiceInternal.class);
- if (packageManagerInternal.isPermissionUpgradeNeeded(userId)) {
- if (DEBUG) Slog.i(LOG_TAG, "defaultPermsWereGrantedSinceBoot(" + userId + ")");
+ // Now call into the permission controller to apply policy around permissions
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
- // Now call into the permission controller to apply policy around permissions
- final AndroidFuture<Boolean> future = new AndroidFuture<>();
-
- // We need to create a local manager that does not schedule work on the main
- // there as we are on the main thread and want to block until the work is
- // completed or we time out.
- final PermissionControllerManager permissionControllerManager =
- new PermissionControllerManager(
- getUserContext(getContext(), UserHandle.of(userId)),
- PermissionThread.getHandler());
- permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
- PermissionThread.getExecutor(), successful -> {
- if (successful) {
- future.complete(null);
- } else {
- // We are in an undefined state now, let us crash and have
- // rescue party suggest a wipe to recover to a good one.
- final String message = "Error granting/upgrading runtime permissions"
- + " for user " + userId;
- Slog.wtf(LOG_TAG, message);
- future.completeExceptionally(new IllegalStateException(message));
- }
- });
- try {
- t.traceBegin("Permission_callback_waiting-" + userId);
- future.get();
- } catch (InterruptedException | ExecutionException e) {
- throw new IllegalStateException(e);
- } finally {
- t.traceEnd();
- }
-
- permissionControllerManager.updateUserSensitive();
-
- packageManagerInternal.updateRuntimePermissionsFingerprint(userId);
+ // We need to create a local manager that does not schedule work on the main
+ // there as we are on the main thread and want to block until the work is
+ // completed or we time out.
+ final PermissionControllerManager permissionControllerManager =
+ new PermissionControllerManager(
+ getUserContext(getContext(), UserHandle.of(userId)),
+ PermissionThread.getHandler());
+ permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
+ PermissionThread.getExecutor(), successful -> {
+ if (successful) {
+ future.complete(null);
+ } else {
+ // We are in an undefined state now, let us crash and have
+ // rescue party suggest a wipe to recover to a good one.
+ final String message = "Error granting/upgrading runtime permissions"
+ + " for user " + userId;
+ Slog.wtf(LOG_TAG, message);
+ future.completeExceptionally(new IllegalStateException(message));
+ }
+ });
+ try {
+ t.traceBegin("Permission_callback_waiting-" + userId);
+ future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new IllegalStateException(e);
+ } finally {
+ t.traceEnd();
}
}
+ private void updateUserSensitive(@UserIdInt int userId) {
+ if (DEBUG) Slog.i(LOG_TAG, "updateUserSensitive(" + userId + ")");
+ final PermissionControllerManager permissionControllerManager =
+ new PermissionControllerManager(
+ getUserContext(getContext(), UserHandle.of(userId)),
+ PermissionThread.getHandler());
+ permissionControllerManager.updateUserSensitive();
+ }
+
private static @Nullable Context getUserContext(@NonNull Context context,
@Nullable UserHandle user) {
if (context.getUser().equals(user)) {
@@ -695,12 +697,10 @@
if (DEBUG) Slog.i(LOG_TAG, "synchronizePermissionsAndAppOpsForUser(" + userId + ")");
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
- final PackageManagerInternal packageManagerInternal = LocalServices.getService(
- PackageManagerInternal.class);
final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
getUserContext(getContext(), UserHandle.of(userId)));
t.traceBegin("Permission_synchronize_addPackages-" + userId);
- packageManagerInternal.forEachPackage(
+ mPackageManagerInternal.forEachPackage(
(pkg) -> synchronizer.addPackage(pkg.getPackageName()));
t.traceEnd();
t.traceBegin("Permission_syncPackages-" + userId);
@@ -1052,13 +1052,11 @@
* @param pkgName The package to add for later processing.
*/
void addPackage(@NonNull String pkgName) {
- PackageManagerInternal pmInternal =
- LocalServices.getService(PackageManagerInternal.class);
final PackageInfo pkgInfo;
final AndroidPackage pkg;
try {
pkgInfo = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
- pkg = pmInternal.getPackage(pkgName);
+ pkg = mPackageManagerInternal.getPackage(pkgName);
} catch (NameNotFoundException e) {
return;
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index bbb59ce..76cedd8 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -444,6 +444,9 @@
// Refer to autosuspend.h.
private boolean mHalAutoSuspendModeEnabled;
+ // True if the device uses auto-suspend mode.
+ private final boolean mUseAutoSuspend;
+
// True if interactive mode is enabled.
// Refer to power.h.
private boolean mHalInteractiveModeEnabled;
@@ -1203,6 +1206,9 @@
mPowerGroupWakefulnessChangeListener = new PowerGroupWakefulnessChangeListener();
+ mUseAutoSuspend = mContext.getResources().getBoolean(com.android.internal.R.bool
+ .config_useAutoSuspend);
+
// Save brightness values:
// Get float values from config.
// Store float if valid
@@ -3918,6 +3924,9 @@
@GuardedBy("mLock")
private void setHalAutoSuspendModeLocked(boolean enable) {
+ if (!mUseAutoSuspend) {
+ return;
+ }
if (enable != mHalAutoSuspendModeEnabled) {
if (DEBUG) {
Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
@@ -4661,6 +4670,7 @@
pw.println(" mEnhancedDischargePredictionIsPersonalized="
+ mEnhancedDischargePredictionIsPersonalized);
}
+ pw.println(" mUseAutoSuspend=" + mUseAutoSuspend);
pw.println(" mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled);
pw.println(" mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
diff --git a/services/core/java/com/android/server/power/batterysaver/Android.bp b/services/core/java/com/android/server/power/batterysaver/Android.bp
new file mode 100644
index 0000000..0b04345
--- /dev/null
+++ b/services/core/java/com/android/server/power/batterysaver/Android.bp
@@ -0,0 +1,14 @@
+aconfig_declarations {
+ name: "battery_saver_flag",
+ package: "com.android.server.power.batterysaver",
+ container: "system",
+ srcs: [
+ "*.aconfig",
+ ],
+}
+
+java_aconfig_library {
+ name: "battery_saver_flag_lib",
+ aconfig_declarations: "battery_saver_flag",
+ sdk_version: "system_current",
+}
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index c8cb92b..9a4c60d 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -29,6 +29,7 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.BatterySaverPolicyConfig;
+import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -97,6 +98,9 @@
private static final String TAG = "BatterySaverStateMachine";
private static final String DYNAMIC_MODE_NOTIF_CHANNEL_ID = "dynamic_mode_notification";
private static final String BATTERY_SAVER_NOTIF_CHANNEL_ID = "battery_saver_channel";
+ private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
+ private static final String EXTRA_SHOW_FRAGMENT_TITLE = ":settings:show_fragment_args";
+ private static final String PREFERENCE_KEY_BATTERY_SAVER_SCHEDULER = "battery_saver_schedule";
private static final int DYNAMIC_MODE_NOTIFICATION_ID = 1992;
private static final int STICKY_AUTO_DISABLED_NOTIFICATION_ID = 1993;
private final Object mLock;
@@ -831,7 +835,11 @@
// Handle triggering the notification to show/hide when appropriate
if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON
|| intReason == BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON) {
- triggerDynamicModeNotification();
+ if (Flags.updateAutoTurnOnNotificationStringAndAction()) {
+ triggerDynamicModeNotificationV2();
+ } else {
+ triggerDynamicModeNotification();
+ }
} else if (!enable) {
hideDynamicModeNotification();
}
@@ -862,6 +870,31 @@
}
@VisibleForTesting
+ void triggerDynamicModeNotificationV2() {
+ // The current lock is the PowerManager lock, which sits very low in the service lock
+ // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
+ runOnBgThread(() -> {
+ NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+ ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID,
+ R.string.dynamic_mode_notification_channel_name);
+
+ // The bundle is used for highlighting a settings item when launching the settings page.
+ final var highlightBundle = new Bundle(1 /* capacity */);
+ highlightBundle.putString(
+ EXTRA_FRAGMENT_ARG_KEY, PREFERENCE_KEY_BATTERY_SAVER_SCHEDULER);
+
+ manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID,
+ buildNotificationV2(DYNAMIC_MODE_NOTIF_CHANNEL_ID,
+ R.string.dynamic_mode_notification_title_v2,
+ R.string.dynamic_mode_notification_summary_v2,
+ Settings.ACTION_BATTERY_SAVER_SETTINGS,
+ 0L /* timeoutMs */,
+ highlightBundle),
+ UserHandle.ALL);
+ });
+ }
+
+ @VisibleForTesting
void triggerStickyDisabledNotification() {
if (!mBatterySaverTurnedOffNotificationEnabled) {
return;
@@ -915,6 +948,32 @@
.build();
}
+ private Notification buildNotificationV2(@NonNull String channelId, @StringRes int titleId,
+ @StringRes int summaryId, @NonNull String intentAction, long timeoutMs,
+ @NonNull Bundle highlightBundle) {
+ Resources res = mContext.getResources();
+ Intent intent = new Intent(intentAction)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ .putExtra(EXTRA_SHOW_FRAGMENT_TITLE, highlightBundle);
+
+ PendingIntent batterySaverIntent = PendingIntent.getActivity(
+ mContext, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
+ final String title = res.getString(titleId);
+ final String summary = res.getString(summaryId);
+
+ return new Notification.Builder(mContext, channelId)
+ .setSmallIcon(R.drawable.ic_battery)
+ .setContentTitle(title)
+ .setContentText(summary)
+ .setContentIntent(batterySaverIntent)
+ .setStyle(new Notification.BigTextStyle().bigText(summary))
+ .setOnlyAlertOnce(true)
+ .setAutoCancel(true)
+ .setTimeoutAfter(timeoutMs)
+ .build();
+ }
+
private void hideDynamicModeNotification() {
hideNotification(DYNAMIC_MODE_NOTIFICATION_ID);
}
diff --git a/services/core/java/com/android/server/power/batterysaver/flags.aconfig b/services/core/java/com/android/server/power/batterysaver/flags.aconfig
new file mode 100644
index 0000000..fa29dc1
--- /dev/null
+++ b/services/core/java/com/android/server/power/batterysaver/flags.aconfig
@@ -0,0 +1,12 @@
+package: "com.android.server.power.batterysaver"
+container: "system"
+
+flag {
+ name: "update_auto_turn_on_notification_string_and_action"
+ namespace: "battery_saver"
+ description: "Improve the string and hightligh settings item for battery saver auto-turn-on notification"
+ bug: "336960905"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
index 7126cb5..7c2ce64 100644
--- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -110,7 +110,7 @@
final EnabledComponentsObserver o = new EnabledComponentsObserver(context, settingName,
servicePermission, serviceName, lock, listeners);
- PackageMonitor packageMonitor = new PackageMonitor() {
+ PackageMonitor packageMonitor = new PackageMonitor(true) {
@Override
public void onSomePackagesChanged() {
o.onPackagesChanged();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index f1ba755..d20b3b2 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1346,6 +1346,10 @@
}
class MyPackageMonitor extends PackageMonitor {
+ private MyPackageMonitor() {
+ super(true);
+ }
+
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 7d057a9..e814f17 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7846,10 +7846,12 @@
@Override
void prepareSurfaces() {
+ final boolean isDecorSurfaceBoosted =
+ getTask() != null && getTask().isDecorSurfaceBoosted();
final boolean show = (isVisible()
// Ensure that the activity content is hidden when the decor surface is boosted to
// prevent UI redressing attack.
- && !getTask().isDecorSurfaceBoosted())
+ && !isDecorSurfaceBoosted)
|| isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS
| ANIMATION_TYPE_PREDICT_BACK);
@@ -9492,6 +9494,12 @@
return false;
}
+ @Override
+ protected boolean setOverrideGender(Configuration requestsTmpConfig, int gender) {
+ return WindowProcessController.applyConfigGenderOverride(
+ requestsTmpConfig, gender, mAtmService.mGrammaticalManagerInternal, getUid());
+ }
+
@VisibleForTesting
@Override
Rect getAnimationBounds(int appRootTaskClipMode) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index fc05d17..f3e1dfb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -949,7 +949,7 @@
}
configuration.setGrammaticalGender(
- mGrammaticalManagerInternal.retrieveSystemGrammaticalGender(configuration));
+ mGrammaticalManagerInternal.mergedFinalSystemGrammaticalGender());
synchronized (mGlobalLock) {
mForceResizableActivities = forceResizable;
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 31754bf..efd5202 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -534,8 +534,8 @@
nightMode);
boolean newLocalesSet = (locales != null) && setOverrideLocales(mRequestsTmpConfig,
locales);
- boolean newGenderSet = (gender != null) && setOverrideGender(mRequestsTmpConfig,
- gender);
+ boolean newGenderSet = setOverrideGender(mRequestsTmpConfig,
+ gender == null ? Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED : gender);
if (newNightModeSet || newLocalesSet || newGenderSet) {
onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
}
@@ -577,14 +577,11 @@
*
* @return true if the grammatical gender has been changed.
*/
- private boolean setOverrideGender(Configuration requestsTmpConfig,
+ protected boolean setOverrideGender(Configuration requestsTmpConfig,
@Configuration.GrammaticalGender int gender) {
- if (mRequestedOverrideConfiguration.getGrammaticalGender() == gender) {
- return false;
- } else {
- requestsTmpConfig.setGrammaticalGender(gender);
- return true;
- }
+ // Noop, only ActivityRecord and WindowProcessController have enough knowledge about the
+ // app to apply gender correctly.
+ return false;
}
public boolean isActivityTypeDream() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index da29998..2f37e88 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2030,12 +2030,11 @@
}
// Update directly because the app which will change the orientation of display is ready.
if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) {
- // Run rotation change on display thread. See Transition#shouldApplyOnDisplayThread().
- mWmService.mH.post(() -> {
- synchronized (mWmService.mGlobalLock) {
- sendNewConfiguration();
- }
- });
+ // If a transition is collecting, let the transition apply the rotation change on
+ // display thread. See Transition#shouldApplyOnDisplayThread().
+ if (!mTransitionController.isCollecting(this)) {
+ sendNewConfiguration();
+ }
return;
}
if (mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange()) {
diff --git a/services/core/java/com/android/server/wm/PackageConfigPersister.java b/services/core/java/com/android/server/wm/PackageConfigPersister.java
index 23127ac..9d597ea 100644
--- a/services/core/java/com/android/server/wm/PackageConfigPersister.java
+++ b/services/core/java/com/android/server/wm/PackageConfigPersister.java
@@ -169,6 +169,8 @@
LocaleOverlayHelper.combineLocalesIfOverlayExists(
modifiedRecord.mLocales, mAtm.getGlobalConfiguration().getLocales()),
modifiedRecord.mGrammaticalGender);
+ } else {
+ container.applyAppSpecificConfig(null, null, null);
}
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9b98380..56e5d76 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -43,12 +43,10 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
import static android.view.SurfaceControl.METADATA_TASK_ID;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
@@ -171,12 +169,10 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
-import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.RemoteAnimationAdapter;
import android.view.Surface;
import android.view.SurfaceControl;
-import android.view.TaskTransitionSpec;
import android.view.WindowManager;
import android.view.WindowManager.TransitionOldType;
import android.window.ITaskOrganizer;
@@ -641,8 +637,6 @@
mLastTaskSnapshotData = _lastSnapshotData != null
? _lastSnapshotData
: new PersistedTaskSnapshotData();
- // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
- setOrientation(SCREEN_ORIENTATION_UNSET);
affinityIntent = _affinityIntent;
affinity = _affinity;
rootAffinity = _rootAffinity;
@@ -2942,33 +2936,6 @@
return;
}
- /**
- * Account for specified insets to crop the animation bounds by to avoid the animation
- * occurring over "out of bounds" regions
- *
- * For example this is used to make sure the tasks are cropped to be fully above the expanded
- * taskbar when animating.
- *
- * TEMPORARY FIELD (b/202383002)
- * TODO: Remove once we use surfaceflinger rounded corners on tasks rather than taskbar overlays
- * or when shell transitions are fully enabled
- *
- * @param animationBounds The animation bounds to adjust to account for the custom spec insets.
- */
- void adjustAnimationBoundsForTransition(Rect animationBounds) {
- TaskTransitionSpec spec = mWmService.mTaskTransitionSpec;
- if (spec != null) {
- final InsetsState state =
- getDisplayContent().getInsetsStateController().getRawInsetsState();
- for (int i = state.sourceSize() - 1; i >= 0; i--) {
- final InsetsSource source = state.sourceAt(i);
- if (source.hasFlags(FLAG_INSETS_ROUNDED_CORNER)) {
- animationBounds.inset(source.calculateVisibleInsets(animationBounds));
- }
- }
- }
- }
-
void setDragResizing(boolean dragResizing) {
if (mDragResizing != dragResizing) {
// No need to check if allowed if it's leaving dragResize
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index a437914..d70ca02 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -44,7 +44,6 @@
import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION;
import static com.android.server.wm.AppTransition.isActivityTransitOld;
import static com.android.server.wm.AppTransition.isTaskFragmentTransitOld;
-import static com.android.server.wm.AppTransition.isTaskTransitOld;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
@@ -72,7 +71,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.ScreenOrientation;
import android.content.res.Configuration;
@@ -103,7 +101,6 @@
import android.view.SurfaceControl.Builder;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceSession;
-import android.view.TaskTransitionSpec;
import android.view.WindowManager;
import android.view.WindowManager.TransitionOldType;
import android.view.animation.Animation;
@@ -186,7 +183,7 @@
// The specified orientation for this window container.
// Shouldn't be accessed directly since subclasses can override getOverrideOrientation.
@ScreenOrientation
- private int mOverrideOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ private int mOverrideOrientation = SCREEN_ORIENTATION_UNSET;
/**
* The window container which decides its orientation since the last time
@@ -1683,8 +1680,6 @@
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
- // TODO: Maybe mOverrideOrientation should default to SCREEN_ORIENTATION_UNSET vs.
- // SCREEN_ORIENTATION_UNSPECIFIED?
final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND
? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET);
if (orientation == SCREEN_ORIENTATION_BEHIND) {
@@ -1700,7 +1695,7 @@
continue;
}
- if (wc.providesOrientation() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+ if (orientation != SCREEN_ORIENTATION_UNSPECIFIED || wc.providesOrientation()) {
// Use the orientation if the container can provide or requested an explicit
// orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)",
@@ -3148,9 +3143,6 @@
// Separate position and size for use in animators.
final Rect screenBounds = getAnimationBounds(appRootTaskClipMode);
mTmpRect.set(screenBounds);
- if (this.asTask() != null && isTaskTransitOld(transit)) {
- this.asTask().adjustAnimationBoundsForTransition(mTmpRect);
- }
getAnimationPosition(mTmpPoint);
mTmpRect.offsetTo(0, 0);
@@ -3285,10 +3277,6 @@
AnimationRunnerBuilder animationRunnerBuilder = new AnimationRunnerBuilder();
- if (isTaskTransitOld(transit) && getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
- animationRunnerBuilder.setTaskBackgroundColor(getTaskAnimationBackgroundColor());
- }
-
// Check if the animation requests to show background color for Activity and embedded
// TaskFragment.
final ActivityRecord activityRecord = asActivityRecord();
@@ -3342,18 +3330,6 @@
}
}
- private @ColorInt int getTaskAnimationBackgroundColor() {
- Context uiContext = mDisplayContent.getDisplayPolicy().getSystemUiContext();
- TaskTransitionSpec customSpec = mWmService.mTaskTransitionSpec;
- @ColorInt int defaultFallbackColor = uiContext.getColor(R.color.overview_background);
-
- if (customSpec != null && customSpec.backgroundColor != 0) {
- return customSpec.backgroundColor;
- }
-
- return defaultFallbackColor;
- }
-
final SurfaceAnimationRunner getSurfaceAnimationRunner() {
return mWmService.mSurfaceAnimationRunner;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b19f0be..feede01 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -20,7 +20,6 @@
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.INPUT_CONSUMER;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
-import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.MODIFY_TOUCH_MODE_STATE;
import static android.Manifest.permission.READ_FRAME_BUFFER;
@@ -295,7 +294,6 @@
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceSession;
-import android.view.TaskTransitionSpec;
import android.view.View;
import android.view.View.FocusDirection;
import android.view.ViewDebug;
@@ -763,11 +761,6 @@
*/
final Handler mAnimationHandler = new Handler(AnimationThread.getHandler().getLooper());
- /**
- * Used during task transitions to allow SysUI and launcher to customize task transitions.
- */
- TaskTransitionSpec mTaskTransitionSpec;
-
boolean mHardKeyboardAvailable;
WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
@@ -9932,24 +9925,6 @@
}
@Override
- public void setTaskTransitionSpec(TaskTransitionSpec spec) {
- if (!checkCallingPermission(MANAGE_ACTIVITY_TASKS, "setTaskTransitionSpec()")) {
- throw new SecurityException("Requires MANAGE_ACTIVITY_TASKS permission");
- }
-
- mTaskTransitionSpec = spec;
- }
-
- @Override
- public void clearTaskTransitionSpec() {
- if (!checkCallingPermission(MANAGE_ACTIVITY_TASKS, "clearTaskTransitionSpec()")) {
- throw new SecurityException("Requires MANAGE_ACTIVITY_TASKS permission");
- }
-
- mTaskTransitionSpec = null;
- }
-
- @Override
@RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
public void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
ITaskFpsCallback callback) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index fd1b5be..1c00fbb 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -84,6 +84,7 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
+import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal;
import com.android.server.wm.ActivityTaskManagerService.HotPath;
import java.io.IOException;
@@ -324,8 +325,6 @@
*/
private volatile int mActivityStateFlags = ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
- private final boolean mCanUseSystemGrammaticalGender;
-
public WindowProcessController(@NonNull ActivityTaskManagerService atm,
@NonNull ApplicationInfo info, String name, int uid, int userId, Object owner,
@NonNull WindowProcessListener listener) {
@@ -349,9 +348,6 @@
mUseFifoUiScheduling = com.android.window.flags.Flags.fifoPriorityForMajorUiProcesses()
&& (isSysUiPackage || mAtm.isCallerRecents(uid));
- mCanUseSystemGrammaticalGender = mAtm.mGrammaticalManagerInternal != null
- && mAtm.mGrammaticalManagerInternal.canGetSystemGrammaticalGender(mUid,
- mInfo.packageName);
onConfigurationChanged(atm.getGlobalConfiguration());
mAtm.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, mInfo.packageName);
}
@@ -1612,11 +1608,6 @@
return;
}
- if (mCanUseSystemGrammaticalGender) {
- config.setGrammaticalGender(
- mAtm.mGrammaticalManagerInternal.getSystemGrammaticalGender(mUserId));
- }
-
if (mPauseConfigurationDispatchCount > 0) {
mHasPendingConfigurationChange = true;
return;
@@ -2139,4 +2130,34 @@
void dumpDebug(ProtoOutputStream proto, long fieldId) {
mListener.dumpDebug(proto, fieldId);
}
+
+ @Override
+ protected boolean setOverrideGender(Configuration requestsTmpConfig, int gender) {
+ return applyConfigGenderOverride(requestsTmpConfig, gender,
+ mAtm.mGrammaticalManagerInternal, mUid);
+ }
+
+ static boolean applyConfigGenderOverride(@NonNull Configuration overrideConfig,
+ @Configuration.GrammaticalGender int override,
+ GrammaticalInflectionManagerInternal service, int uid) {
+ final boolean canGetSystemValue = service != null
+ && service.canGetSystemGrammaticalGender(uid);
+
+ // The priority here is as follows:
+ // - app-specific override if set
+ // - system value if allowed to see it
+ // - global configuration otherwise
+ final int targetValue = (override != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED)
+ ? override
+ : canGetSystemValue
+ ? Configuration.GRAMMATICAL_GENDER_UNDEFINED
+ : service != null
+ ? service.getGrammaticalGenderFromDeveloperSettings()
+ : Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ if (overrideConfig.getGrammaticalGenderRaw() == targetValue) {
+ return false;
+ }
+ overrideConfig.setGrammaticalGender(targetValue);
+ return true;
+ }
}
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 25c5db1..64cbb0d1 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -12,6 +12,7 @@
per-file com_android_server_Usb* = file:/services/usb/OWNERS
per-file com_android_server_Vibrator* = file:/services/core/java/com/android/server/vibrator/OWNERS
per-file com_android_server_accessibility_* = file:/services/accessibility/OWNERS
+per-file com_android_server_adb_* = file:/services/core/java/com/android/server/adb/OWNERS
per-file com_android_server_display_* = file:/services/core/java/com/android/server/display/OWNERS
per-file com_android_server_hdmi_* = file:/core/java/android/hardware/hdmi/OWNERS
per-file com_android_server_lights_* = file:/services/core/java/com/android/server/lights/OWNERS
diff --git a/services/core/jni/com_android_server_adb_AdbDebuggingManager.cpp b/services/core/jni/com_android_server_adb_AdbDebuggingManager.cpp
index 9c834aa..c7b6852 100644
--- a/services/core/jni/com_android_server_adb_AdbDebuggingManager.cpp
+++ b/services/core/jni/com_android_server_adb_AdbDebuggingManager.cpp
@@ -18,58 +18,22 @@
#define LOG_NDEBUG 0
-#include <algorithm>
#include <condition_variable>
#include <mutex>
#include <optional>
-#include <random>
-#include <string>
-#include <vector>
#include <adb/pairing/pairing_server.h>
#include <android-base/properties.h>
-#include <utils/Log.h>
-
+#include <jni.h>
#include <nativehelper/JNIHelp.h>
-#include "jni.h"
+#include <nativehelper/utils.h>
+#include <utils/Log.h>
namespace android {
// ----------------------------------------------------------------------------
namespace {
-template <class T, class N>
-class JSmartWrapper {
-public:
- JSmartWrapper(JNIEnv* env, T* jData) : mEnv(env), mJData(jData) {}
-
- virtual ~JSmartWrapper() = default;
-
- const N* data() const { return mRawData; }
-
- jsize size() const { return mSize; }
-
-protected:
- N* mRawData = nullptr;
- JNIEnv* mEnv = nullptr;
- T* mJData = nullptr;
- jsize mSize = 0;
-}; // JSmartWrapper
-
-class JStringUTFWrapper : public JSmartWrapper<jstring, const char> {
-public:
- explicit JStringUTFWrapper(JNIEnv* env, jstring* str) : JSmartWrapper(env, str) {
- mRawData = env->GetStringUTFChars(*str, NULL);
- mSize = env->GetStringUTFLength(*str);
- }
-
- virtual ~JStringUTFWrapper() {
- if (data()) {
- mEnv->ReleaseStringUTFChars(*mJData, mRawData);
- }
- }
-}; // JStringUTFWrapper
-
struct ServerDeleter {
void operator()(PairingServerCtx* p) { pairing_server_destroy(p); }
};
@@ -97,19 +61,19 @@
std::unique_ptr<PairingResultWaiter> sWaiter;
} // namespace
-static jint native_pairing_start(JNIEnv* env, jobject thiz, jstring guid, jstring password) {
+static jint native_pairing_start(JNIEnv* env, jobject thiz, jstring javaGuid, jstring javaPassword) {
// Server-side only sends its GUID on success.
- PeerInfo system_info = {};
- system_info.type = ADB_DEVICE_GUID;
- JStringUTFWrapper guidWrapper(env, &guid);
- memcpy(system_info.data, guidWrapper.data(), guidWrapper.size());
+ PeerInfo system_info = { .type = ADB_DEVICE_GUID };
- JStringUTFWrapper passwordWrapper(env, &password);
+ ScopedUtfChars guid = GET_UTF_OR_RETURN(env, javaGuid);
+ memcpy(system_info.data, guid.c_str(), guid.size());
+
+ ScopedUtfChars password = GET_UTF_OR_RETURN(env, javaPassword);
// Create the pairing server
sServer = PairingServerPtr(
- pairing_server_new_no_cert(reinterpret_cast<const uint8_t*>(passwordWrapper.data()),
- passwordWrapper.size(), &system_info, 0));
+ pairing_server_new_no_cert(reinterpret_cast<const uint8_t*>(password.c_str()),
+ password.size(), &system_info, 0));
sWaiter.reset(new PairingResultWaiter);
uint16_t port = pairing_server_start(sServer.get(), sWaiter->ResultCallback, sWaiter.get());
@@ -137,11 +101,16 @@
return JNI_FALSE;
}
- std::string peer_public_key = reinterpret_cast<char*>(sWaiter->peer_info_.data);
- // Write to PairingThread's member variables
+ // Create a Java string for the public key.
+ char* peer_public_key = reinterpret_cast<char*>(sWaiter->peer_info_.data);
+ jstring jpublickey = env->NewStringUTF(peer_public_key);
+ if (jpublickey == nullptr) {
+ return JNI_FALSE;
+ }
+
+ // Write to PairingThread.mPublicKey.
jclass clazz = env->GetObjectClass(thiz);
jfieldID mPublicKey = env->GetFieldID(clazz, "mPublicKey", "Ljava/lang/String;");
- jstring jpublickey = env->NewStringUTF(peer_public_key.c_str());
env->SetObjectField(thiz, mPublicKey, jpublickey);
return JNI_TRUE;
}
@@ -157,12 +126,9 @@
};
int register_android_server_AdbDebuggingManager(JNIEnv* env) {
- int res = jniRegisterNativeMethods(env,
- "com/android/server/adb/AdbDebuggingManager$PairingThread",
- gPairingThreadMethods, NELEM(gPairingThreadMethods));
- (void)res; // Faked use when LOG_NDEBUG.
- LOG_FATAL_IF(res < 0, "Unable to register native methods.");
- return 0;
+ return jniRegisterNativeMethods(env,
+ "com/android/server/adb/AdbDebuggingManager$PairingThread",
+ gPairingThreadMethods, NELEM(gPairingThreadMethods));
}
} /* namespace android */
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 4a8d73d2..07cda37 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -875,7 +875,7 @@
}
private void registerBroadcastReceivers() {
- PackageMonitor monitor = new PackageMonitor() {
+ PackageMonitor monitor = new PackageMonitor(true) {
/**
* Checks if the package contains a print service.
*
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
index a8b792e..80f7a06 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
@@ -197,7 +197,7 @@
+ Arrays.toString(invocation.getArguments()));
if (!wedge) {
if (mRealAms.mConstants.mEnableWaitForFinishAttachApplication) {
- mRealAms.finishAttachApplication(0);
+ mRealAms.finishAttachApplication(0, 0);
}
}
return null;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ProcessObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ProcessObserverTest.java
index 67be93b..89c67d5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ProcessObserverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ProcessObserverTest.java
@@ -200,7 +200,7 @@
Log.v(TAG, "Intercepting bindApplication() for "
+ Arrays.toString(invocation.getArguments()));
if (mRealAms.mConstants.mEnableWaitForFinishAttachApplication) {
- mRealAms.finishAttachApplication(0);
+ mRealAms.finishAttachApplication(0, 0);
}
return null;
}).when(thread).bindApplication(
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index 5c74a80..7f165e0 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -3241,6 +3241,48 @@
}
}
+ @Test
+ public void testHalAutoSuspendMode_enabledByConfiguration() {
+ AtomicReference<DisplayManagerInternal.DisplayPowerCallbacks> callback =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ callback.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).initPowerManagement(any(), any(), any());
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay))
+ .thenReturn(false);
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_useAutoSuspend))
+ .thenReturn(true);
+
+ createService();
+ startSystem();
+ callback.get().onDisplayStateChange(/* allInactive= */ true, /* allOff= */ true);
+
+ verify(mNativeWrapperMock).nativeSetAutoSuspend(true);
+ }
+
+ @Test
+ public void testHalAutoSuspendMode_disabledByConfiguration() {
+ AtomicReference<DisplayManagerInternal.DisplayPowerCallbacks> callback =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ callback.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).initPowerManagement(any(), any(), any());
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay))
+ .thenReturn(false);
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_useAutoSuspend))
+ .thenReturn(false);
+
+ createService();
+ startSystem();
+ callback.get().onDisplayStateChange(/* allInactive= */ true, /* allOff= */ true);
+
+ verify(mNativeWrapperMock, never()).nativeSetAutoSuspend(true);
+ }
+
private void setCachedUidProcState(int uid) {
mService.updateUidProcStateInternal(uid, PROCESS_STATE_TOP_SLEEPING);
}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 94a71be..753db12 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -279,7 +279,7 @@
test_module_config {
name: "FrameworksServicesTests_contentprotection",
base: "FrameworksServicesTests",
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
include_filters: ["com.android.server.contentprotection"],
exclude_annotations: FLAKY_AND_IGNORED,
}
@@ -287,7 +287,7 @@
test_module_config {
name: "FrameworksServicesTests_om",
base: "FrameworksServicesTests",
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
include_filters: ["com.android.server.om."],
exclude_annotations: FLAKY_AND_IGNORED,
}
@@ -296,7 +296,7 @@
test_module_config {
name: "FrameworksServicesTests_contexthub_presubmit",
base: "FrameworksServicesTests",
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
include_filters: ["com.android.server.location.contexthub."],
// TODO(ron): are these right, does it run anything?
include_annotations: ["android.platform.test.annotations.Presubmit"],
@@ -306,7 +306,7 @@
test_module_config {
name: "FrameworksServicesTests_contexthub_postsubmit",
base: "FrameworksServicesTests",
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
include_filters: ["com.android.server.location.contexthub."],
// TODO(ron): are these right, does it run anything?
include_annotations: ["android.platform.test.annotations.Postsubmit"],
@@ -317,7 +317,7 @@
test_module_config {
name: "FrameworksServicesTests_contentcapture",
base: "FrameworksServicesTests",
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
include_filters: ["com.android.server.contentcapture"],
exclude_annotations: FLAKY_AND_IGNORED,
}
@@ -325,7 +325,7 @@
test_module_config {
name: "FrameworksServicesTests_recoverysystem",
base: "FrameworksServicesTests",
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
include_filters: ["com.android.server.recoverysystem."],
exclude_annotations: ["androidx.test.filters.FlakyTest"],
}
@@ -334,7 +334,7 @@
test_module_config {
name: "FrameworksServicesTests_pm_presubmit",
base: "FrameworksServicesTests",
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
include_annotations: ["android.platform.test.annotations.Presubmit"],
include_filters: ["com.android.server.pm."],
exclude_annotations: FLAKY_AND_IGNORED,
@@ -343,7 +343,7 @@
test_module_config {
name: "FrameworksServicesTests_pm_postsubmit",
base: "FrameworksServicesTests",
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
include_annotations: ["android.platform.test.annotations.Postsubmit"],
include_filters: ["com.android.server.pm."],
exclude_annotations: FLAKY_AND_IGNORED,
@@ -353,6 +353,6 @@
test_module_config {
name: "FrameworksServicesTests_os",
base: "FrameworksServicesTests",
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
include_filters: ["com.android.server.os."],
}
diff --git a/services/tests/servicestests/src/com/android/server/autofill/OWNERS b/services/tests/servicestests/src/com/android/server/autofill/OWNERS
new file mode 100644
index 0000000..70106d1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/autofill/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/autofill/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java b/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
index af6f6f2..608b306 100644
--- a/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
+++ b/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
@@ -112,7 +112,7 @@
public void testSystemBackupPayload_returnsGender()
throws IOException, ClassNotFoundException {
doReturn(Configuration.GRAMMATICAL_GENDER_MASCULINE).when(mGrammaticalInflectionService)
- .getSystemGrammaticalGender(any(), eq(DEFAULT_USER_ID));
+ .getSystemGrammaticalGender(eq(DEFAULT_USER_ID));
int gender = convertByteArrayToInt(mBackupHelper.getSystemBackupPayload(DEFAULT_USER_ID));
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 902ffed..4faeea5 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -937,6 +937,94 @@
}
@Test
+ public void onHotplug_doNotSend_systemAudioModeRequestWithParameter(){
+ // Add a device to the network and assert that this device is included in the list of
+ // devices.
+ HdmiDeviceInfo infoAudioSystem = HdmiDeviceInfo.cecDeviceBuilder()
+ .setLogicalAddress(ADDR_AUDIO_SYSTEM)
+ .setPhysicalAddress(0x2000)
+ .setPortId(2)
+ .setDeviceType(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)
+ .setVendorId(0x1000)
+ .setDisplayName("Audio System")
+ .build();
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoAudioSystem);
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .hasSize(1);
+ mDeviceEventListeners.clear();
+ assertThat(mDeviceEventListeners.size()).isEqualTo(0);
+
+ // Connect port 2 (ARC port)
+ mNativeWrapper.setPortConnectionStatus(2, true);
+
+ // AVR connection
+ HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV);
+
+ mNativeWrapper.onCecMessage(initiateArc);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
+ ADDR_TV,
+ ADDR_AUDIO_SYSTEM);
+ // <Report ARC Initiated> should only be sent after SAD querying is done
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
+ // Finish querying SADs
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
+ mNativeWrapper.clearResultMessages();
+
+ // Audio System still acking polls. Allowing detection by HotplugDetectionAction
+ mNativeWrapper.setPollAddressResponse(ADDR_AUDIO_SYSTEM, SendMessageResult.SUCCESS);
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ // Hotplug event
+ mHdmiCecLocalDeviceTv.onHotplug(2, true);
+
+ // Audio System replies to <Give System Audio Mode> with <System Audio Mode Status>[On]
+ HdmiCecMessage reportSystemAudioModeOn =
+ HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ true);
+ mHdmiControlService.handleCecCommand(reportSystemAudioModeOn);
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ // Hotplug event when turn off the audio system
+ mHdmiCecLocalDeviceTv.onHotplug(2, false);
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ // Some audio systems (eg. Sony) might trigger 5V status from false to true when the
+ // devices are off
+ mHdmiCecLocalDeviceTv.onHotplug(2, true);
+
+ // Audio System replies to <Give System Audio Mode> with <System Audio Mode Status>
+ HdmiCecMessage reportSystemAudioMode =
+ HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ true);
+ mHdmiControlService.handleCecCommand(reportSystemAudioMode);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage systemAudioModeRequest = HdmiCecMessageBuilder.buildSystemAudioModeRequest(
+ mTvLogicalAddress, ADDR_AUDIO_SYSTEM, mTvPhysicalAddress, true);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(systemAudioModeRequest);
+ }
+
+ @Test
public void listenerInvokedIfPhysicalAddressReported() {
mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 1d3dacc..9a92c70 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -408,6 +408,60 @@
}
@Test
+ public void setRcProfileRootMenu_reportFeatureBroadcast() {
+ setRcProfileSourceDeviceTestHelper(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED);
+ }
+
+ @Test
+ public void setRcProfileSetupMenu_reportFeatureBroadcast() {
+ setRcProfileSourceDeviceTestHelper(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED);
+ }
+
+ @Test
+ public void setRcProfileContentMenu_reportFeatureBroadcast() {
+ setRcProfileSourceDeviceTestHelper(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED);
+ }
+
+ @Test
+ public void setRcProfileTopMenu_reportFeatureBroadcast() {
+ setRcProfileSourceDeviceTestHelper(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED);
+ }
+
+ @Test
+ public void setRcProfileMediaSensitiveMenu_reportFeatureBroadcast() {
+ setRcProfileSourceDeviceTestHelper(
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU,
+ HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED);
+ }
+
+ /** Helper method to test if feature discovery message sent given RCProfile change */
+ private void setRcProfileSourceDeviceTestHelper(final String setting, final int val) {
+ mNativeWrapper.clearResultMessages();
+
+ mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.HDMI_CEC_VERSION_2_0);
+ mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(setting, val);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage reportFeatures = ReportFeaturesMessage.build(Constants.ADDR_PLAYBACK_1,
+ HdmiControlManager.HDMI_CEC_VERSION_2_0,
+ Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
+ mPlaybackDeviceSpy.getRcProfile(), mPlaybackDeviceSpy.getRcFeatures(),
+ mPlaybackDeviceSpy.getDeviceFeatures());
+ assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
+ }
+
+ @Test
public void disableAndReenableCec_volumeControlReturnsToOriginalValue_enabled() {
int volumeControlEnabled = HdmiControlManager.VOLUME_CONTROL_ENABLED;
mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(volumeControlEnabled);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTvTest.java
index 920c376..eed9975 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTvTest.java
@@ -16,11 +16,14 @@
package com.android.server.hdmi;
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
+
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.os.Looper;
import android.os.test.TestLooper;
@@ -35,6 +38,7 @@
import org.junit.runners.JUnit4;
import java.util.Collections;
+import java.util.List;
/**
* TV specific tests for {@link HdmiControlService} class.
@@ -47,6 +51,7 @@
private static final String TAG = "HdmiControlServiceTvTest";
private HdmiControlService mHdmiControlService;
private HdmiCecController mHdmiCecController;
+ private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
private FakeNativeWrapper mNativeWrapper;
private HdmiEarcController mHdmiEarcController;
private FakeEarcNativeWrapper mEarcNativeWrapper;
@@ -90,6 +95,8 @@
mHdmiControlService.initService();
mTestLooper.dispatchAll();
+
+ mHdmiCecLocalDeviceTv = mHdmiControlService.tv();
}
@Test
@@ -139,4 +146,23 @@
assertThat(mHdmiControlService
.verifyPhysicalAddresses(HdmiUtils.buildMessage("4F:82:10"))).isFalse();
}
+
+ @Test
+ public void setRcProfileTv_reportFeatureBroadcast() {
+ mNativeWrapper.clearResultMessages();
+
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.HDMI_CEC_VERSION_2_0);
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ HdmiControlManager.RC_PROFILE_TV_NONE);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage reportFeatures = ReportFeaturesMessage.build(Constants.ADDR_TV,
+ HdmiControlManager.HDMI_CEC_VERSION_2_0, List.of(DEVICE_TV),
+ mHdmiCecLocalDeviceTv.getRcProfile(), mHdmiCecLocalDeviceTv.getRcFeatures(),
+ mHdmiCecLocalDeviceTv.getDeviceFeatures());
+ assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 1da5001..b0a3374 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -525,10 +525,13 @@
// The activity shouldn't start relaunching since it doesn't have any desk resources.
assertFalse(activity.isRelaunching());
+ // The activity configuration ui mode should match.
+ final var activityConfig = activity.getConfiguration();
+ assertEquals(newConfig.uiMode, activityConfig.uiMode);
// The configuration change is still sent to the activity, even if it doesn't relaunch.
final ActivityConfigurationChangeItem expected =
- ActivityConfigurationChangeItem.obtain(activity.token, newConfig,
+ ActivityConfigurationChangeItem.obtain(activity.token, activityConfig,
activity.getActivityWindowInfo());
verify(mClientLifecycleManager).scheduleTransactionItem(
eq(activity.app.getThread()), eq(expected));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 7356b43..27d9d13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1071,6 +1071,7 @@
@Test
public void testAllowsTopmostFullscreenOrientation() {
final DisplayContent dc = createNewDisplay();
+ assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, dc.getOrientation());
dc.getDisplayRotation().setFixedToUserRotation(
IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
@@ -1717,7 +1718,6 @@
// The display should be rotated after the launch is finished.
doReturn(false).when(app).isAnimating(anyInt(), anyInt());
mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app.token);
- waitHandlerIdle(mWm.mH);
mStatusBarWindow.finishSeamlessRotation(t);
mNavBarWindow.finishSeamlessRotation(t);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 87f26e5..c45c86c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -56,6 +56,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.res.Configuration;
import android.database.ContentObserver;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManagerGlobal;
@@ -86,6 +87,7 @@
import com.android.server.display.DisplayControl;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.firewall.IntentFirewall;
+import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal;
import com.android.server.input.InputManagerService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
@@ -208,6 +210,11 @@
setUpLocalServices();
setUpActivityTaskManagerService();
setUpWindowManagerService();
+
+ // We never load the system settings in the tests, thus need to setup the grammatical
+ // gender configuration explicitly.
+ mAtmService.getGlobalConfiguration().setGrammaticalGender(
+ Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED);
}
private void setUpSystemCore() {
@@ -337,6 +344,18 @@
};
when(umi.isUserVisible(anyInt())).thenAnswer(isUserVisibleAnswer);
when(umi.isUserVisible(anyInt(), anyInt())).thenAnswer(isUserVisibleAnswer);
+
+ final var gimi = mock(
+ GrammaticalInflectionManagerInternal.class, withSettings().stubOnly());
+ doReturn(Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED).when(
+ gimi).getGrammaticalGenderFromDeveloperSettings();
+ doReturn(Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED).when(
+ gimi).getSystemGrammaticalGender(anyInt());
+ doReturn(Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED).when(
+ gimi).mergedFinalSystemGrammaticalGender();
+ doReturn(false).when(gimi).canGetSystemGrammaticalGender(anyInt());
+ doReturn(gimi).when(
+ () -> LocalServices.getService(GrammaticalInflectionManagerInternal.class));
}
private void setUpActivityTaskManagerService() {
@@ -475,6 +494,7 @@
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
LocalServices.removeServiceForTest(UserManagerInternal.class);
LocalServices.removeServiceForTest(ImeTargetVisibilityPolicy.class);
+ LocalServices.removeServiceForTest(GrammaticalInflectionManagerInternal.class);
}
Description getDescription() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 48fc2dc..9f85acb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -565,36 +565,17 @@
@Test
public void testGetOrientation_childSpecified() {
- testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE,
- SCREEN_ORIENTATION_LANDSCAPE);
- testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET,
- SCREEN_ORIENTATION_UNSPECIFIED);
- }
-
- private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation,
- int expectedOrientation) {
final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
- final TestWindowContainer root = builder.setLayer(0).build();
+ final TestWindowContainer root = builder.build();
root.setFillsParent(true);
+ assertEquals(SCREEN_ORIENTATION_UNSET, root.getOrientation());
- builder.setIsVisible(childVisible);
+ final TestWindowContainer child = root.addChildWindow();
+ child.setFillsParent(true);
+ assertEquals(SCREEN_ORIENTATION_UNSET, root.getOrientation());
- if (childOrientation != SCREEN_ORIENTATION_UNSET) {
- builder.setOrientation(childOrientation);
- }
-
- final TestWindowContainer child1 = root.addChildWindow(builder);
- child1.setFillsParent(true);
-
- assertEquals(expectedOrientation, root.getOrientation());
- }
-
- @Test
- public void testGetOrientation_Unset() {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
- final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
- // Unspecified well because we didn't specify anything...
- assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
+ child.setOverrideOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
}
@Test
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index e5d7b40e..1d01420 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -2538,7 +2538,8 @@
}
}
- PackageMonitor mPackageMonitor = new PackageMonitor() {
+ PackageMonitor mPackageMonitor = new PackageMonitor(
+ /* supportsPackageRestartQuery= */ true) {
@Override
public boolean onHandleForceStop(Intent intent, String[] packages, int uid,
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7db4180..4c719dd 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -6007,7 +6007,7 @@
defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false);
defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, false);
- defaults.putInt(KEY_SUBSCRIBE_RETRY_DURATION_MILLIS_LONG, -1);
+ defaults.putLong(KEY_SUBSCRIBE_RETRY_DURATION_MILLIS_LONG, -1);
defaults.putBoolean(KEY_USE_SIP_URI_FOR_PRESENCE_SUBSCRIBE_BOOL, false);
defaults.putInt(KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT, 30 * 24 * 60 * 60);
defaults.putBoolean(KEY_RCS_REQUEST_FORBIDDEN_BY_SIP_489_BOOL, false);
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index b568f07..e6515f13 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -65,6 +65,7 @@
public final class PreciseDataConnectionState implements Parcelable {
private final @TransportType int mTransportType;
private final int mId;
+ private final int mNetId;
private final @DataState int mState;
private final @NetworkType int mNetworkType;
private final @DataFailureCause int mFailCause;
@@ -134,7 +135,7 @@
@ApnType int apnTypes, @NonNull String apn,
@Nullable LinkProperties linkProperties,
@DataFailureCause int failCause) {
- this(AccessNetworkConstants.TRANSPORT_TYPE_INVALID, -1, state, networkType,
+ this(AccessNetworkConstants.TRANSPORT_TYPE_INVALID, -1, -1, state, networkType,
linkProperties, failCause, new ApnSetting.Builder()
.setApnTypeBitmask(apnTypes)
.setApnName(apn)
@@ -158,13 +159,14 @@
* @param defaultQos If there is a valid QoS for the default bearer supporting this data call,
* (supported for LTE and NR), then this is specified. Otherwise it should be null.
*/
- private PreciseDataConnectionState(@TransportType int transportType, int id,
+ private PreciseDataConnectionState(@TransportType int transportType, int id, int netId,
@DataState int state, @NetworkType int networkType,
@Nullable LinkProperties linkProperties, @DataFailureCause int failCause,
@Nullable ApnSetting apnSetting, @Nullable Qos defaultQos,
@NetworkValidationStatus int networkValidationStatus) {
mTransportType = transportType;
mId = id;
+ mNetId = netId;
mState = state;
mNetworkType = networkType;
mLinkProperties = linkProperties;
@@ -182,6 +184,7 @@
private PreciseDataConnectionState(Parcel in) {
mTransportType = in.readInt();
mId = in.readInt();
+ mNetId = in.readInt();
mState = in.readInt();
mNetworkType = in.readInt();
mLinkProperties = in.readParcelable(
@@ -244,6 +247,14 @@
}
/**
+ * @return the current TelephonyNetworkAgent ID. {@code -1} if no network agent.
+ * @hide
+ */
+ public int getNetId() {
+ return mNetId;
+ }
+
+ /**
* @return The high-level state of this data connection.
*/
public @DataState int getState() {
@@ -363,6 +374,7 @@
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mTransportType);
out.writeInt(mId);
+ out.writeInt(mNetId);
out.writeInt(mState);
out.writeInt(mNetworkType);
out.writeParcelable(mLinkProperties, flags);
@@ -386,7 +398,7 @@
@Override
public int hashCode() {
- return Objects.hash(mTransportType, mId, mState, mNetworkType, mFailCause,
+ return Objects.hash(mTransportType, mId, mNetId, mState, mNetworkType, mFailCause,
mLinkProperties, mApnSetting, mDefaultQos, mNetworkValidationStatus);
}
@@ -398,6 +410,7 @@
PreciseDataConnectionState that = (PreciseDataConnectionState) o;
return mTransportType == that.mTransportType
&& mId == that.mId
+ && mNetId == that.mNetId
&& mState == that.mState
&& mNetworkType == that.mNetworkType
&& mFailCause == that.mFailCause
@@ -412,17 +425,18 @@
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append(" state: " + TelephonyUtils.dataStateToString(mState));
- sb.append(", transport: "
- + AccessNetworkConstants.transportTypeToString(mTransportType));
- sb.append(", id: " + mId);
- sb.append(", network type: " + TelephonyManager.getNetworkTypeName(mNetworkType));
- sb.append(", APN Setting: " + mApnSetting);
- sb.append(", link properties: " + mLinkProperties);
- sb.append(", default QoS: " + mDefaultQos);
- sb.append(", fail cause: " + DataFailCause.toString(mFailCause));
- sb.append(", network validation status: "
- + networkValidationStatusToString(mNetworkValidationStatus));
+ sb.append(" state: ").append(TelephonyUtils.dataStateToString(mState));
+ sb.append(", transport: ").append(
+ AccessNetworkConstants.transportTypeToString(mTransportType));
+ sb.append(", id: ").append(mId);
+ sb.append(", netId: ").append(mNetId);
+ sb.append(", network type: ").append(TelephonyManager.getNetworkTypeName(mNetworkType));
+ sb.append(", APN Setting: ").append(mApnSetting);
+ sb.append(", link properties: ").append(mLinkProperties);
+ sb.append(", default QoS: ").append(mDefaultQos);
+ sb.append(", fail cause: ").append(DataFailCause.toString(mFailCause));
+ sb.append(", network validation status: ").append(
+ networkValidationStatusToString(mNetworkValidationStatus));
return sb.toString();
}
@@ -463,6 +477,11 @@
*/
private int mId = -1;
+ /**
+ * The current TelephonyNetworkAgent ID. {@code -1} if no network agent.
+ */
+ private int mNetworkAgentId = -1;
+
/** The state of the data connection */
private @DataState int mState = TelephonyManager.DATA_UNKNOWN;
@@ -511,6 +530,17 @@
}
/**
+ * Set the id of the data connection.
+ *
+ * @param agentId The id of the data connection
+ * @return The builder
+ */
+ public @NonNull Builder setNetworkAgentId(int agentId) {
+ mNetworkAgentId = agentId;
+ return this;
+ }
+
+ /**
* Set the state of the data connection.
*
* @param state The state of the data connection
@@ -598,8 +628,8 @@
* @return The {@link PreciseDataConnectionState} instance
*/
public PreciseDataConnectionState build() {
- return new PreciseDataConnectionState(mTransportType, mId, mState, mNetworkType,
- mLinkProperties, mFailCause, mApnSetting, mDefaultQos,
+ return new PreciseDataConnectionState(mTransportType, mId, mNetworkAgentId, mState,
+ mNetworkType, mLinkProperties, mFailCause, mApnSetting, mDefaultQos,
mNetworkValidationStatus);
}
}
diff --git a/telephony/java/android/telephony/satellite/ISatelliteCommunicationAllowedStateCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteCommunicationAllowedStateCallback.aidl
new file mode 100644
index 0000000..a7eda48
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/ISatelliteCommunicationAllowedStateCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.satellite;
+
+/**
+ * Interface for satellite communication allowed state callback.
+ * @hide
+ */
+oneway interface ISatelliteCommunicationAllowedStateCallback {
+ /**
+ * Telephony does not guarantee that whenever there is a change in communication allowed
+ * state, this API will be called. Telephony does its best to detect the changes and notify
+ * its listners accordingly.
+ *
+ * @param allowed whether satellite communication state or not
+ */
+ void onSatelliteCommunicationAllowedStateChanged(in boolean isAllowed);
+}
diff --git a/telephony/java/android/telephony/satellite/SatelliteCommunicationAllowedStateCallback.java b/telephony/java/android/telephony/satellite/SatelliteCommunicationAllowedStateCallback.java
new file mode 100644
index 0000000..1a87020
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/SatelliteCommunicationAllowedStateCallback.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.satellite;
+
+import android.annotation.FlaggedApi;
+
+import com.android.internal.telephony.flags.Flags;
+
+
+/**
+ * A callback class for monitoring satellite communication allowed state changed events.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+public interface SatelliteCommunicationAllowedStateCallback {
+
+ /**
+ * Telephony does not guarantee that whenever there is a change in communication allowed state,
+ * this API will be called. Telephony does its best to detect the changes and notify its
+ * listeners accordingly.
+ *
+ * @param isAllowed {@code true} means satellite allow state is changed,
+ * {@code false} satellite allow state is not changed
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ void onSatelliteCommunicationAllowedStateChanged(boolean isAllowed);
+}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 40ad312..0bb5fd5 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -91,6 +91,11 @@
ISatelliteSupportedStateCallback> sSatelliteSupportedStateCallbackMap =
new ConcurrentHashMap<>();
+ private static final ConcurrentHashMap<SatelliteCommunicationAllowedStateCallback,
+ ISatelliteCommunicationAllowedStateCallback>
+ sSatelliteCommunicationAllowedStateCallbackMap =
+ new ConcurrentHashMap<>();
+
private final int mSubId;
/**
@@ -2393,7 +2398,89 @@
}
}
- @Nullable private static ITelephony getITelephony() {
+ /**
+ * Registers for the satellite communication allowed state changed.
+ *
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback to handle satellite communication allowed state changed event.
+ * @return The {@link SatelliteResult} result of the operation.
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @SatelliteResult
+ public int registerForCommunicationAllowedStateChanged(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull SatelliteCommunicationAllowedStateCallback callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ ISatelliteCommunicationAllowedStateCallback internalCallback =
+ new ISatelliteCommunicationAllowedStateCallback.Stub() {
+ @Override
+ public void onSatelliteCommunicationAllowedStateChanged(
+ boolean isAllowed) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> callback.onSatelliteCommunicationAllowedStateChanged(
+ isAllowed)));
+ }
+ };
+ sSatelliteCommunicationAllowedStateCallbackMap.put(callback, internalCallback);
+ return telephony.registerForCommunicationAllowedStateChanged(
+ mSubId, internalCallback);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("registerForCommunicationAllowedStateChanged() RemoteException: " + ex);
+ ex.rethrowAsRuntimeException();
+ }
+ return SATELLITE_RESULT_REQUEST_FAILED;
+ }
+
+ /**
+ * Unregisters for the satellite communication allowed state changed.
+ * If callback was not registered before, the request will be ignored.
+ *
+ * @param callback The callback that was passed to
+ * {@link #registerForCommunicationAllowedStateChanged(Executor,
+ * SatelliteCommunicationAllowedStateCallback)}
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ public void unregisterForCommunicationAllowedStateChanged(
+ @NonNull SatelliteCommunicationAllowedStateCallback callback) {
+ Objects.requireNonNull(callback);
+ ISatelliteCommunicationAllowedStateCallback internalCallback =
+ sSatelliteCommunicationAllowedStateCallbackMap.remove(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ if (internalCallback != null) {
+ telephony.unregisterForCommunicationAllowedStateChanged(mSubId,
+ internalCallback);
+ } else {
+ loge("unregisterForCommunicationAllowedStateChanged: No internal callback.");
+ }
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("unregisterForCommunicationAllowedStateChanged() RemoteException: " + ex);
+ ex.rethrowAsRuntimeException();
+ }
+ }
+
+ @Nullable
+ private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
.getTelephonyServiceManager()
.getTelephonyServiceRegisterer()
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index f25fc36..f591f40 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -69,6 +69,7 @@
import android.telephony.ims.aidl.IRcsConfigCallback;
import android.telephony.satellite.INtnSignalStrengthCallback;
import android.telephony.satellite.ISatelliteCapabilitiesCallback;
+import android.telephony.satellite.ISatelliteCommunicationAllowedStateCallback;
import android.telephony.satellite.ISatelliteDatagramCallback;
import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
import android.telephony.satellite.ISatelliteProvisionStateCallback;
@@ -3341,4 +3342,29 @@
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
void unregisterForSatelliteSupportedStateChanged(int subId,
in ISatelliteSupportedStateCallback callback);
+
+ /**
+ * Registers for satellite communication allowed state changed.
+ *
+ * @param subId The subId of the subscription to register for communication allowed state.
+ * @param callback The callback to handle the communication allowed state changed event.
+ *
+ * @return The {@link SatelliteError} result of the operation.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ int registerForCommunicationAllowedStateChanged(int subId,
+ in ISatelliteCommunicationAllowedStateCallback callback);
+
+ /**
+ * Unregisters for satellite communication allowed state.
+ * If callback was not registered before, the request will be ignored.
+ *
+ * @param subId The subId of the subscription to unregister for supported state changed.
+ * @param callback The callback that was passed to registerForCommunicationAllowedStateChanged.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void unregisterForCommunicationAllowedStateChanged(int subId,
+ in ISatelliteCommunicationAllowedStateCallback callback);
}
diff --git a/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
index 439cf13..1dc1037 100644
--- a/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
@@ -8,6 +8,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/tests/FlickerTests/AppClose/AndroidTestTemplate.xml b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
index 4b6224e..57a58c8 100644
--- a/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
@@ -8,6 +8,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
index 583bcb7..2cb86e0 100644
--- a/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
@@ -8,6 +8,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
index d6ae2b3..2cf85fa 100644
--- a/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
@@ -8,6 +8,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/tests/FlickerTests/IME/AndroidTestTemplate.xml b/tests/FlickerTests/IME/AndroidTestTemplate.xml
index 38442db..b93e1be 100644
--- a/tests/FlickerTests/IME/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/IME/AndroidTestTemplate.xml
@@ -8,6 +8,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- enable AOD -->
diff --git a/tests/FlickerTests/Notification/AndroidTestTemplate.xml b/tests/FlickerTests/Notification/AndroidTestTemplate.xml
index 4036858..9c6a17d3 100644
--- a/tests/FlickerTests/Notification/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/Notification/AndroidTestTemplate.xml
@@ -8,6 +8,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
index 797ca4e..ecbed28 100644
--- a/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
@@ -8,6 +8,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/tests/FlickerTests/Rotation/AndroidTestTemplate.xml b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
index b5ea739..1eacdfd 100644
--- a/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
@@ -8,6 +8,8 @@
<option name="isolated-storage" value="false"/>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on"/>
<!-- prevents the phone from restarting -->
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
index 23fa91c..2df3da6 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.testapp;
-import androidx.annotation.NonNull;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
@@ -103,18 +102,13 @@
}
private static SplitPairRule createSplitPairRules(@NonNull String layoutDirection) {
- final Set<SplitPairFilter> pairFilters = new HashSet<>();
- final SplitPairFilter activitiesPair = new SplitPairFilter(
- ActivityOptions.ActivityEmbedding.MainActivity.COMPONENT,
- ActivityOptions.ActivityEmbedding.SecondaryActivity.COMPONENT,
- null /* secondaryActivityIntentAction */);
- pairFilters.add(activitiesPair);
+ final Set<SplitPairFilter> pairFilters = getSplitPairFilters();
final SplitAttributes splitAttributes = new SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.SPLIT_TYPE_EQUAL)
.setLayoutDirection(parseLayoutDirection(layoutDirection))
.build();
// Setting thresholds to ALWAYS_ALLOW values to make it easy for running on all devices.
- final SplitPairRule rule = new SplitPairRule.Builder(pairFilters)
+ return new SplitPairRule.Builder(pairFilters)
.setDefaultSplitAttributes(splitAttributes)
.setMinWidthDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
.setMinHeightDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
@@ -122,7 +116,22 @@
.setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ALWAYS_ALLOW)
.setMaxAspectRatioInLandscape(EmbeddingAspectRatio.ALWAYS_ALLOW)
.build();
- return rule;
+ }
+
+ @NonNull
+ private static Set<SplitPairFilter> getSplitPairFilters() {
+ final Set<SplitPairFilter> pairFilters = new HashSet<>();
+ final SplitPairFilter mainAndSecondaryActivitiesPair = new SplitPairFilter(
+ ActivityOptions.ActivityEmbedding.MainActivity.COMPONENT,
+ ActivityOptions.ActivityEmbedding.SecondaryActivity.COMPONENT,
+ null /* secondaryActivityIntentAction */);
+ pairFilters.add(mainAndSecondaryActivitiesPair);
+ final SplitPairFilter mainAndTrampolineActivitiesPair = new SplitPairFilter(
+ ActivityOptions.ActivityEmbedding.MainActivity.COMPONENT,
+ ActivityOptions.ActivityEmbedding.TrampolineActivity.COMPONENT,
+ null /* secondaryActivityIntentAction */);
+ pairFilters.add(mainAndTrampolineActivitiesPair);
+ return pairFilters;
}
private static SplitPlaceholderRule createSplitPlaceholderRules(
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
index c0c60ef..d033389 100644
--- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
@@ -393,6 +393,7 @@
mEditText.setFocusableInTouchMode(false);
}
rootView.addView(mEditText, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ rootView.setFitsSystemWindows(true);
setContentView(rootView);
if (requestFocus) {