Merge "Revert "feat(multi finger multi tap): add Setting for control magnification enable gesture"" into main
diff --git a/Android.bp b/Android.bp
index 986a071..b5f7e99 100644
--- a/Android.bp
+++ b/Android.bp
@@ -695,12 +695,10 @@
"--hide CallbackInterface",
"--hide DeprecationMismatch",
"--hide HiddenSuperclass",
- "--hide HiddenTypeParameter",
"--hide MissingPermission",
"--hide RequiresPermission",
"--hide SdkConstant",
"--hide Todo",
- "--hide UnavailableSymbol",
"--hide-package android.audio.policy.configuration.V7_0",
"--hide-package com.android.server",
"--manifest $(location :frameworks-base-core-AndroidManifest.xml)",
diff --git a/core/api/current.txt b/core/api/current.txt
index cce8329..18001e8 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -33455,7 +33455,9 @@
method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
method public boolean hasUserRestriction(String);
method public boolean isAdminUser();
+ method @FlaggedApi("android.multiuser.support_communal_profile") public boolean isCommunalProfile();
method public boolean isDemoUser();
+ method @FlaggedApi("android.multiuser.support_communal_profile_nextgen") public boolean isForegroundUserAdmin();
method public static boolean isHeadlessSystemUserMode();
method public boolean isManagedProfile();
method public boolean isProfile();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 119e0ad..6062f79 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3875,6 +3875,7 @@
method public void setInstallAsInstantApp(boolean);
method public void setInstallAsVirtualPreload();
method public void setRequestDowngrade(boolean);
+ method @FlaggedApi("android.content.pm.rollback_lifetime") @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void setRollbackLifetimeMillis(long);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e130206..83b6880 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2148,7 +2148,9 @@
}
public final class BugreportParams {
+ field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL = 4; // 0x4
field @FlaggedApi("android.os.bugreport_mode_max_value") public static final int BUGREPORT_MODE_MAX_VALUE = 7; // 0x7
+ field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_MODE_ONBOARDING = 7; // 0x7
}
public class Build {
@@ -2355,6 +2357,7 @@
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getAliveUsers();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle getBootUser();
+ method @FlaggedApi("android.multiuser.support_communal_profile") @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getCommunalProfile();
method public int getMainDisplayIdAssignedToUser();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.Set<java.lang.String> getPreInstallableSystemPackages(@NonNull String);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public String getUserType();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ecbc9b1..9a19d8e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -8638,8 +8638,8 @@
}
}
- SyncNotedAppOp syncOp = mService.noteProxyOperation(op, attributionSource.asState(),
- collectionMode == COLLECT_ASYNC, message,
+ SyncNotedAppOp syncOp = mService.noteProxyOperationWithState(op,
+ attributionSource.asState(), collectionMode == COLLECT_ASYNC, message,
shouldCollectMessage, skipProxyOperation);
if (syncOp.getOpMode() == MODE_ALLOWED) {
@@ -9110,7 +9110,7 @@
}
}
- SyncNotedAppOp syncOp = mService.startProxyOperation(clientId, op,
+ SyncNotedAppOp syncOp = mService.startProxyOperationWithState(clientId, op,
attributionSource.asState(), false, collectionMode == COLLECT_ASYNC, message,
shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
proxiedAttributionFlags, attributionChainId);
@@ -9229,8 +9229,8 @@
public void finishProxyOp(@NonNull IBinder clientId, @NonNull String op,
@NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
try {
- mService.finishProxyOperation(clientId, strOpToOp(op), attributionSource.asState(),
- skipProxyOperation);
+ mService.finishProxyOperationWithState(
+ clientId, strOpToOp(op), attributionSource.asState(), skipProxyOperation);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 2d55403..545ba8e 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -26,6 +26,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.PasswordMetrics;
@@ -736,7 +737,7 @@
* @see #isKeyguardLocked()
*/
public boolean isDeviceLocked() {
- return isDeviceLocked(mContext.getUserId());
+ return isDeviceLocked(mContext.getUserId(), mContext.getDeviceId());
}
/**
@@ -746,8 +747,17 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean isDeviceLocked(int userId) {
+ return isDeviceLocked(userId, mContext.getDeviceId());
+ }
+
+ /**
+ * Per-user per-device version of {@link #isDeviceLocked()}.
+ *
+ * @hide
+ */
+ public boolean isDeviceLocked(@UserIdInt int userId, int deviceId) {
try {
- return mTrustManager.isDeviceLocked(userId, mContext.getAssociatedDisplayId());
+ return mTrustManager.isDeviceLocked(userId, deviceId);
} catch (RemoteException e) {
return false;
}
@@ -769,7 +779,7 @@
* @see #isKeyguardSecure()
*/
public boolean isDeviceSecure() {
- return isDeviceSecure(mContext.getUserId());
+ return isDeviceSecure(mContext.getUserId(), mContext.getDeviceId());
}
/**
@@ -779,8 +789,17 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isDeviceSecure(int userId) {
+ return isDeviceSecure(userId, mContext.getDeviceId());
+ }
+
+ /**
+ * Per-user per-device version of {@link #isDeviceSecure()}.
+ *
+ * @hide
+ */
+ public boolean isDeviceSecure(@UserIdInt int userId, int deviceId) {
try {
- return mTrustManager.isDeviceSecure(userId, mContext.getAssociatedDisplayId());
+ return mTrustManager.isDeviceSecure(userId, deviceId);
} catch (RemoteException e) {
return false;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3bde39c..bbc843b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -374,7 +374,7 @@
* that you take care of task management as described in the
* <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
* Stack</a> document. In particular, make sure to read the
- * <a href="{@docRoot}/training/notify-user/navigation">Start
+ * <a href="{@docRoot}training/notify-user/navigation">Start
* an Activity from a Notification</a> page for the correct ways to launch an application from a
* notification.
*/
@@ -5606,7 +5606,8 @@
contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
// Use different highlighted colors for conversations' unread count
if (p.mHighlightExpander) {
- pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor);
+ pillColor = Colors.flattenAlpha(
+ getColors(p).getTertiaryFixedDimAccentColor(), bgColor);
textColor = Colors.flattenAlpha(
getColors(p).getOnTertiaryAccentTextColor(), pillColor);
}
@@ -12835,6 +12836,9 @@
private int mSecondaryAccentColor = COLOR_INVALID;
private int mTertiaryAccentColor = COLOR_INVALID;
private int mOnTertiaryAccentTextColor = COLOR_INVALID;
+ private int mTertiaryFixedDimAccentColor = COLOR_INVALID;
+ private int mOnTertiaryFixedAccentTextColor = COLOR_INVALID;
+
private int mErrorColor = COLOR_INVALID;
private int mContrastColor = COLOR_INVALID;
private int mRippleAlpha = 0x33;
@@ -12892,7 +12896,7 @@
if (isColorized) {
if (rawColor == COLOR_DEFAULT) {
- int[] attrs = {R.attr.colorAccentSecondary};
+ int[] attrs = {R.attr.materialColorSecondary};
try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
mBackgroundColor = getColor(ta, 0, Color.WHITE);
}
@@ -12910,17 +12914,21 @@
mSecondaryAccentColor = mSecondaryTextColor;
mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor);
mOnTertiaryAccentTextColor = mBackgroundColor;
+ mTertiaryFixedDimAccentColor = mTertiaryAccentColor;
+ mOnTertiaryFixedAccentTextColor = mOnTertiaryAccentTextColor;
mErrorColor = mPrimaryTextColor;
mRippleAlpha = 0x33;
} else {
int[] attrs = {
- R.attr.colorSurface,
- R.attr.textColorPrimary,
- R.attr.textColorSecondary,
- R.attr.colorAccent,
- R.attr.colorAccentSecondary,
- R.attr.colorAccentTertiary,
- R.attr.textColorOnAccent,
+ R.attr.materialColorSurfaceContainerHigh,
+ R.attr.materialColorOnSurface,
+ R.attr.materialColorOnSurfaceVariant,
+ R.attr.materialColorPrimary,
+ R.attr.materialColorSecondary,
+ R.attr.materialColorTertiary,
+ R.attr.materialColorOnTertiary,
+ R.attr.materialColorTertiaryFixedDim,
+ R.attr.materialColorOnTertiaryFixed,
R.attr.colorError,
R.attr.colorControlHighlight
};
@@ -12932,8 +12940,10 @@
mSecondaryAccentColor = getColor(ta, 4, COLOR_INVALID);
mTertiaryAccentColor = getColor(ta, 5, COLOR_INVALID);
mOnTertiaryAccentTextColor = getColor(ta, 6, COLOR_INVALID);
- mErrorColor = getColor(ta, 7, COLOR_INVALID);
- mRippleAlpha = Color.alpha(getColor(ta, 8, 0x33ffffff));
+ mTertiaryFixedDimAccentColor = getColor(ta, 7, COLOR_INVALID);
+ mOnTertiaryFixedAccentTextColor = getColor(ta, 8, COLOR_INVALID);
+ mErrorColor = getColor(ta, 9, COLOR_INVALID);
+ mRippleAlpha = Color.alpha(getColor(ta, 10, 0x33ffffff));
}
mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
mBackgroundColor, nightMode);
@@ -12961,6 +12971,14 @@
ContrastColorUtil.resolvePrimaryColor(
ctx, mTertiaryAccentColor, nightMode), 0xFF);
}
+ if (mTertiaryFixedDimAccentColor == COLOR_INVALID) {
+ mTertiaryFixedDimAccentColor = mContrastColor;
+ }
+ if (mOnTertiaryFixedAccentTextColor == COLOR_INVALID) {
+ mOnTertiaryFixedAccentTextColor = ColorUtils.setAlphaComponent(
+ ContrastColorUtil.resolvePrimaryColor(
+ ctx, mTertiaryFixedDimAccentColor, nightMode), 0xFF);
+ }
if (mErrorColor == COLOR_INVALID) {
mErrorColor = mPrimaryTextColor;
}
@@ -13034,6 +13052,16 @@
return mOnTertiaryAccentTextColor;
}
+ /** @return the theme's tertiary fixed dim accent color for colored UI elements. */
+ public @ColorInt int getTertiaryFixedDimAccentColor() {
+ return mTertiaryFixedDimAccentColor;
+ }
+
+ /** @return the theme's text color to be used on the tertiary fixed accent color. */
+ public @ColorInt int getOnTertiaryFixedAccentTextColor() {
+ return mOnTertiaryFixedAccentTextColor;
+ }
+
/**
* @return the contrast-adjusted version of the color provided by the app, or the
* primary text color when colorized.
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index a5e5135..70c25ea 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -34,8 +34,8 @@
void unregisterTrustListener(in ITrustListener trustListener);
void reportKeyguardShowingChanged();
void setDeviceLockedForUser(int userId, boolean locked);
- boolean isDeviceLocked(int userId, int displayId);
- boolean isDeviceSecure(int userId, int displayId);
+ boolean isDeviceLocked(int userId, int deviceId);
+ boolean isDeviceSecure(int userId, int deviceId);
@EnforcePermission("TRUST_LISTENER")
boolean isTrustUsuallyManaged(int userId);
void unlockedByBiometricForUser(int userId, in BiometricSourceType source);
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index aefa55f..323592c 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1204,12 +1204,15 @@
/**
* This change id is the gatekeeper for all treatments that force a given min aspect ratio.
* Enabling this change will allow the following min aspect ratio treatments to be applied:
- * OVERRIDE_MIN_ASPECT_RATIO_MEDIUM
- * OVERRIDE_MIN_ASPECT_RATIO_LARGE
+ * <ul>
+ * <li>OVERRIDE_MIN_ASPECT_RATIO_MEDIUM
+ * <li>OVERRIDE_MIN_ASPECT_RATIO_LARGE
+ * </ul>
*
* If OVERRIDE_MIN_ASPECT_RATIO is applied, the min aspect ratio given in the app's manifest
* will be overridden to the largest enabled aspect ratio treatment unless the app's manifest
- * value is higher.
+ * value is higher. By default, this will only apply to activities with fixed portrait
+ * orientation if OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY is not explicitly disabled.
* @hide
*/
@ChangeId
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index cd8938d..cbb20e0 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2535,6 +2535,8 @@
public DataLoaderParams dataLoaderParams;
/** {@hide} */
public int rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
+ /** @hide */
+ public long rollbackLifetimeMillis = 0;
/** {@hide} */
public boolean forceQueryableOverride;
/** {@hide} */
@@ -2589,6 +2591,7 @@
dataLoaderParams = new DataLoaderParams(dataLoaderParamsParcel);
}
rollbackDataPolicy = source.readInt();
+ rollbackLifetimeMillis = source.readLong();
requireUserAction = source.readInt();
packageSource = source.readInt();
applicationEnabledSettingPersistent = source.readBoolean();
@@ -2621,6 +2624,7 @@
ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
ret.dataLoaderParams = dataLoaderParams;
ret.rollbackDataPolicy = rollbackDataPolicy;
+ ret.rollbackLifetimeMillis = rollbackLifetimeMillis;
ret.requireUserAction = requireUserAction;
ret.packageSource = packageSource;
ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent;
@@ -2902,12 +2906,7 @@
*/
@SystemApi
public void setEnableRollback(boolean enable) {
- if (enable) {
- installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
- } else {
- installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
- }
- rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
+ setEnableRollback(enable, PackageManager.ROLLBACK_DATA_POLICY_RESTORE);
}
/**
@@ -2931,10 +2930,36 @@
installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
} else {
installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
+ rollbackLifetimeMillis = 0;
}
rollbackDataPolicy = dataPolicy;
}
+ /**
+ * If rollback enabled for this session (via {@link #setEnableRollback}, set time
+ * after which rollback will no longer be possible
+ *
+ * <p>For multi-package installs, this value must be set on the parent session.
+ * Child session rollback lifetime will be ignored.
+ *
+ * @param lifetimeMillis time after which rollback expires
+ * @throws IllegalArgumentException if lifetimeMillis is negative or rollback is not
+ * enabled via setEnableRollback.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @FlaggedApi(Flags.FLAG_ROLLBACK_LIFETIME)
+ public void setRollbackLifetimeMillis(@DurationMillisLong long lifetimeMillis) {
+ if (lifetimeMillis < 0) {
+ throw new IllegalArgumentException("rollbackLifetimeMillis can't be negative.");
+ }
+ if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
+ throw new IllegalArgumentException(
+ "Can't set rollbackLifetimeMillis when rollback is not enabled");
+ }
+ rollbackLifetimeMillis = lifetimeMillis;
+ }
/**
* @deprecated use {@link #setRequestDowngrade(boolean)}.
@@ -3295,6 +3320,7 @@
pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
pw.printPair("dataLoaderParams", dataLoaderParams);
pw.printPair("rollbackDataPolicy", rollbackDataPolicy);
+ pw.printPair("rollbackLifetimeMillis", rollbackLifetimeMillis);
pw.printPair("applicationEnabledSettingPersistent",
applicationEnabledSettingPersistent);
pw.printHexPair("developmentInstallFlags", developmentInstallFlags);
@@ -3336,6 +3362,7 @@
dest.writeParcelable(null, flags);
}
dest.writeInt(rollbackDataPolicy);
+ dest.writeLong(rollbackLifetimeMillis);
dest.writeInt(requireUserAction);
dest.writeInt(packageSource);
dest.writeBoolean(applicationEnabledSettingPersistent);
@@ -3529,6 +3556,9 @@
/** {@hide} */
public int rollbackDataPolicy;
+ /** @hide */
+ public long rollbackLifetimeMillis;
+
/** {@hide} */
public int requireUserAction;
@@ -3596,6 +3626,7 @@
isCommitted = source.readBoolean();
isPreapprovalRequested = source.readBoolean();
rollbackDataPolicy = source.readInt();
+ rollbackLifetimeMillis = source.readLong();
createdMillis = source.readLong();
requireUserAction = source.readInt();
installerUid = source.readInt();
@@ -4220,6 +4251,7 @@
dest.writeBoolean(isCommitted);
dest.writeBoolean(isPreapprovalRequested);
dest.writeInt(rollbackDataPolicy);
+ dest.writeLong(rollbackLifetimeMillis);
dest.writeLong(createdMillis);
dest.writeInt(requireUserAction);
dest.writeInt(installerUid);
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 96609ad..9ad66ce 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -58,3 +58,11 @@
bug: "295827951"
is_fixed_read_only: true
}
+
+flag {
+ name: "rollback_lifetime"
+ namespace: "package_manager_service"
+ description: "Feature flag to enable custom rollback lifetime during install."
+ bug: "299670324"
+ is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 3ec239c..43cf97f 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -28,3 +28,10 @@
description: "Framework support for communal profile."
bug: "285426179"
}
+
+flag {
+ name: "support_communal_profile_nextgen"
+ namespace: "multiuser"
+ description: "Further framework support for communal profile, beyond the basics, for later releases."
+ bug: "285426179"
+}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index a40fb15..66e3c28 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -16,10 +16,12 @@
package android.net.vcn;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
import static com.android.internal.annotations.VisibleForTesting.Visibility;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -235,6 +237,9 @@
"mMinUdpPort4500NatTimeoutSeconds";
private final int mMinUdpPort4500NatTimeoutSeconds;
+ private static final String IS_SAFE_MODE_DISABLED_KEY = "mIsSafeModeDisabled";
+ private final boolean mIsSafeModeDisabled;
+
private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions";
@NonNull private final Set<Integer> mGatewayOptions;
@@ -247,6 +252,7 @@
@NonNull long[] retryIntervalsMs,
@IntRange(from = MIN_MTU_V6) int maxMtu,
@NonNull int minUdpPort4500NatTimeoutSeconds,
+ boolean isSafeModeDisabled,
@NonNull Set<Integer> gatewayOptions) {
mGatewayConnectionName = gatewayConnectionName;
mTunnelConnectionParams = tunnelConnectionParams;
@@ -255,6 +261,7 @@
mMaxMtu = maxMtu;
mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions));
+ mIsSafeModeDisabled = isSafeModeDisabled;
mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates);
if (mUnderlyingNetworkTemplates.isEmpty()) {
@@ -317,6 +324,7 @@
in.getInt(
MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY,
MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
+ mIsSafeModeDisabled = in.getBoolean(IS_SAFE_MODE_DISABLED_KEY);
validate();
}
@@ -483,6 +491,17 @@
}
/**
+ * Check whether safe mode is enabled
+ *
+ * @see Builder#enableSafeMode(boolean)
+ * @hide
+ */
+ @FlaggedApi(FLAG_SAFE_MODE_CONFIG)
+ public boolean isSafeModeEnabled() {
+ return !mIsSafeModeDisabled;
+ }
+
+ /**
* Checks if the given VCN gateway option is enabled.
*
* @param option the option to check.
@@ -528,6 +547,7 @@
result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
result.putInt(MAX_MTU_KEY, mMaxMtu);
result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds);
+ result.putBoolean(IS_SAFE_MODE_DISABLED_KEY, mIsSafeModeDisabled);
return result;
}
@@ -542,6 +562,7 @@
Arrays.hashCode(mRetryIntervalsMs),
mMaxMtu,
mMinUdpPort4500NatTimeoutSeconds,
+ mIsSafeModeDisabled,
mGatewayOptions);
}
@@ -559,6 +580,7 @@
&& Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
&& mMaxMtu == rhs.mMaxMtu
&& mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds
+ && mIsSafeModeDisabled == rhs.mIsSafeModeDisabled
&& mGatewayOptions.equals(rhs.mGatewayOptions);
}
@@ -577,6 +599,7 @@
@NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
private int mMaxMtu = DEFAULT_MAX_MTU;
private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;
+ private boolean mIsSafeModeDisabled = false;
@NonNull private final Set<Integer> mGatewayOptions = new ArraySet<>();
@@ -789,6 +812,28 @@
}
/**
+ * Enable/disable safe mode
+ *
+ * <p>If a VCN fails to provide connectivity within a system-provided timeout, it will enter
+ * safe mode. In safe mode, the VCN Network will be torn down and the system will restore
+ * connectivity by allowing underlying cellular networks to be used as default. At the same
+ * time, VCN will continue to retry until it succeeds.
+ *
+ * <p>When safe mode is disabled and VCN connection fails to provide connectivity, end users
+ * might not have connectivity, and may not have access to carrier-owned underlying
+ * networks.
+ *
+ * @param enabled whether safe mode should be enabled. Defaults to {@code true}
+ * @hide
+ */
+ @FlaggedApi(FLAG_SAFE_MODE_CONFIG)
+ @NonNull
+ public Builder enableSafeMode(boolean enabled) {
+ mIsSafeModeDisabled = !enabled;
+ return this;
+ }
+
+ /**
* Builds and validates the VcnGatewayConnectionConfig.
*
* @return an immutable VcnGatewayConnectionConfig instance
@@ -803,6 +848,7 @@
mRetryIntervalsMs,
mMaxMtu,
mMinUdpPort4500NatTimeoutSeconds,
+ mIsSafeModeDisabled,
mGatewayOptions);
}
}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 58def6e..960e84d 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -26,6 +26,7 @@
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.content.Context;
@@ -280,8 +281,8 @@
*
* <p>{@link BugreportManager} takes ownership of {@code bugreportFd}.
*
- * <p>The caller may only request to retrieve a given bugreport once. Subsequent calls will fail
- * with error code {@link BugreportCallback#BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE}.
+ * <p>The caller can reattempt to retrieve the bugreport multiple times if the user has not
+ * consented on previous attempts.
*
* @param bugreportFile the identifier for a bugreport that was previously generated for this
* caller using {@code startBugreport}.
@@ -294,6 +295,7 @@
@SystemApi
@RequiresPermission(Manifest.permission.DUMP)
@WorkerThread
+ @UserHandleAware
public void retrieveBugreport(
@NonNull String bugreportFile,
@NonNull ParcelFileDescriptor bugreportFd,
@@ -307,8 +309,10 @@
Preconditions.checkNotNull(callback);
DumpstateListener dsListener = new DumpstateListener(executor, callback, false, false);
mBinder.retrieveBugreport(Binder.getCallingUid(), mContext.getOpPackageName(),
+ mContext.getUserId(),
bugreportFd.getFileDescriptor(),
bugreportFile,
+ /* keepBugreportOnRetrieval = */ false,
dsListener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index e8ad303..8510084 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -20,6 +20,7 @@
import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.app.admin.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -128,6 +129,8 @@
*
* @hide
*/
+ @TestApi
+ @FlaggedApi(Flags.FLAG_ONBOARDING_BUGREPORT_V2_ENABLED)
public static final int BUGREPORT_MODE_ONBOARDING = IDumpstate.BUGREPORT_MODE_ONBOARDING;
/**
@@ -145,7 +148,8 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "BUGREPORT_FLAG_" }, value = {
BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA,
- BUGREPORT_FLAG_DEFER_CONSENT
+ BUGREPORT_FLAG_DEFER_CONSENT,
+ BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL
})
public @interface BugreportFlag {}
@@ -165,4 +169,20 @@
* String, ParcelFileDescriptor, Executor, BugreportManager.BugreportCallback)}.
*/
public static final int BUGREPORT_FLAG_DEFER_CONSENT = IDumpstate.BUGREPORT_FLAG_DEFER_CONSENT;
+
+ /**
+ * Flag for keeping a bugreport stored even after it has been retrieved via
+ * {@link BugreportManager#retrieveBugreport}.
+ *
+ * <p>This flag can only be used when {@link #BUGREPORT_FLAG_DEFER_CONSENT} is set.
+ * The bugreport may be retrieved multiple times using
+ * {@link BugreportManager#retrieveBugreport(
+ * String, ParcelFileDescriptor, Executor, BugreportManager.BugreportCallback)}.
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(Flags.FLAG_ONBOARDING_BUGREPORT_V2_ENABLED)
+ public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL =
+ IDumpstate.BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL;
}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 839c56f..330b992 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -137,6 +137,7 @@
boolean isUserVisible(int userId);
int[] getVisibleUsers();
int getMainDisplayIdAssignedToUser();
+ boolean isForegroundUserAdmin();
boolean isUserNameSet(int userId);
boolean hasRestrictedProfiles(int userId);
boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userId, in IntentSender target, int flags);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 72bc211..cc79ae3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2774,6 +2774,8 @@
* Returns the designated "communal profile" of the device, or {@code null} if there is none.
* @hide
*/
+ @FlaggedApi(android.multiuser.Flags.FLAG_SUPPORT_COMMUNAL_PROFILE)
+ @TestApi
@RequiresPermission(anyOf = {
Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS,
@@ -2791,16 +2793,33 @@
}
/**
+ * Checks if the context user is running in a communal profile.
+ *
+ * A communal profile is a {@link #isProfile() profile}, but instead of being associated with a
+ * particular parent user, it is communal to the device.
+ *
+ * @return whether the context user is a communal profile.
+ */
+ @FlaggedApi(android.multiuser.Flags.FLAG_SUPPORT_COMMUNAL_PROFILE)
+ @UserHandleAware(
+ requiresAnyOfPermissionsIfNotCallerProfileGroup = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.QUERY_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
+ public boolean isCommunalProfile() {
+ return isCommunalProfile(mUserId);
+ }
+
+ /**
* Returns {@code true} if the given user is the designated "communal profile" of the device.
* @hide
*/
@RequiresPermission(anyOf = {
- Manifest.permission.MANAGE_USERS,
- Manifest.permission.CREATE_USERS,
- Manifest.permission.QUERY_USERS})
- public boolean isCommunalProfile(@UserIdInt int userId) {
- final UserInfo user = getUserInfo(userId);
- return user != null && user.isCommunalProfile();
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.QUERY_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
+ private boolean isCommunalProfile(@UserIdInt int userId) {
+ return isUserTypeCommunalProfile(getProfileType(userId));
}
/**
@@ -2840,6 +2859,23 @@
}
/**
+ * Used to check if the user currently running in the <b>foreground</b> is an
+ * {@link #isAdminUser() admin} user.
+ *
+ * @return whether the foreground user is an admin user.
+ * @see #isAdminUser()
+ * @see #isUserForeground()
+ */
+ @FlaggedApi(android.multiuser.Flags.FLAG_SUPPORT_COMMUNAL_PROFILE_NEXTGEN)
+ public boolean isForegroundUserAdmin() {
+ try {
+ return mService.isForegroundUserAdmin();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns whether the context user is of the given user type.
*
* @param userType the name of the user's user type, e.g.
@@ -2997,7 +3033,7 @@
}
/**
- * Checks if the calling context user can have a restricted profile.
+ * Checks if the context user can have a restricted profile.
* @return whether the context user can have a restricted profile.
* @hide
*/
@@ -3101,11 +3137,11 @@
}
/**
- * Checks if the calling context user is running in a profile. A profile is a user that
+ * Checks if the context user is running in a profile. A profile is a user that
* typically has its own separate data but shares its UI with some parent user. For example, a
* {@link #isManagedProfile() managed profile} is a type of profile.
*
- * @return whether the caller is in a profile.
+ * @return whether the context user is in a profile.
*/
@UserHandleAware(
requiresAnyOfPermissionsIfNotCallerProfileGroup = {
@@ -5247,7 +5283,7 @@
/**
* Returns the parent of the profile which this method is called from
- * or null if called from a user that is not a profile.
+ * or null if it has no parent (e.g. if it is not a profile).
*
* @hide
*/
@@ -5269,7 +5305,7 @@
*
* @param user the handle of the user profile
*
- * @return the parent of the user or {@code null} if the user is not profile
+ * @return the parent of the user or {@code null} if the user has no parent
*
* @hide
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index be4693b..4da02f9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -11612,7 +11612,14 @@
Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
}
- surfaceSyncGroup.addTransaction(mPendingTransaction);
+ final Transaction t;
+ if (mHasPendingTransactions) {
+ t = new Transaction();
+ t.merge(mPendingTransaction);
+ } else {
+ t = null;
+ }
+
mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
@Override
public void onFrameDraw(long frame) {
@@ -11625,6 +11632,9 @@
"Received frameDrawingCallback syncResult=" + syncResult + " frameNum="
+ frame + ".");
}
+ if (t != null) {
+ mergeWithNextTransaction(t, frame);
+ }
// If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
// SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
diff --git a/core/java/android/window/TaskFragmentParentInfo.java b/core/java/android/window/TaskFragmentParentInfo.java
index 841354a..e6eeca4 100644
--- a/core/java/android/window/TaskFragmentParentInfo.java
+++ b/core/java/android/window/TaskFragmentParentInfo.java
@@ -35,17 +35,21 @@
private final boolean mVisible;
+ private final boolean mHasDirectActivity;
+
public TaskFragmentParentInfo(@NonNull Configuration configuration, int displayId,
- boolean visible) {
+ boolean visible, boolean hasDirectActivity) {
mConfiguration.setTo(configuration);
mDisplayId = displayId;
mVisible = visible;
+ mHasDirectActivity = hasDirectActivity;
}
public TaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
mConfiguration.setTo(info.getConfiguration());
mDisplayId = info.mDisplayId;
mVisible = info.mVisible;
+ mHasDirectActivity = info.mHasDirectActivity;
}
/** The {@link Configuration} of the parent Task */
@@ -68,6 +72,14 @@
}
/**
+ * Whether the parent Task has any direct child activity, which is not embedded in any
+ * TaskFragment, or not
+ */
+ public boolean hasDirectActivity() {
+ return mHasDirectActivity;
+ }
+
+ /**
* Returns {@code true} if the parameters which are important for task fragment
* organizers are equal between this {@link TaskFragmentParentInfo} and {@code that}.
* Note that this method is usually called with
@@ -80,7 +92,7 @@
return false;
}
return getWindowingMode() == that.getWindowingMode() && mDisplayId == that.mDisplayId
- && mVisible == that.mVisible;
+ && mVisible == that.mVisible && mHasDirectActivity == that.mHasDirectActivity;
}
@WindowConfiguration.WindowingMode
@@ -94,6 +106,7 @@
+ "config=" + mConfiguration
+ ", displayId=" + mDisplayId
+ ", visible=" + mVisible
+ + ", hasDirectActivity=" + mHasDirectActivity
+ "}";
}
@@ -114,7 +127,8 @@
final TaskFragmentParentInfo that = (TaskFragmentParentInfo) obj;
return mConfiguration.equals(that.mConfiguration)
&& mDisplayId == that.mDisplayId
- && mVisible == that.mVisible;
+ && mVisible == that.mVisible
+ && mHasDirectActivity == that.mHasDirectActivity;
}
@Override
@@ -122,6 +136,7 @@
int result = mConfiguration.hashCode();
result = 31 * result + mDisplayId;
result = 31 * result + (mVisible ? 1 : 0);
+ result = 31 * result + (mHasDirectActivity ? 1 : 0);
return result;
}
@@ -130,12 +145,14 @@
mConfiguration.writeToParcel(dest, flags);
dest.writeInt(mDisplayId);
dest.writeBoolean(mVisible);
+ dest.writeBoolean(mHasDirectActivity);
}
private TaskFragmentParentInfo(Parcel in) {
mConfiguration.readFromParcel(in);
mDisplayId = in.readInt();
mVisible = in.readBoolean();
+ mHasDirectActivity = in.readBoolean();
}
public static final Creator<TaskFragmentParentInfo> CREATOR =
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 584dd80..492e2ac 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -20,6 +20,7 @@
import android.app.AsyncNotedAppOp;
import android.app.SyncNotedAppOp;
import android.app.RuntimeAppOpAccessMessage;
+import android.content.AttributionSource;
import android.content.AttributionSourceState;
import android.content.pm.ParceledListSlice;
import android.os.Bundle;
@@ -32,10 +33,17 @@
import com.android.internal.app.IAppOpsStartedCallback;
import com.android.internal.app.MessageSamplingConfig;
+// AppOpsService AIDL interface.
+// PLEASE READ BEFORE MODIFYING THIS FILE.
+// Some methods in this interface or their transaction codes are mentioned in
+// frameworks/base/boot/hiddenapi/hiddenapi-unsupported.txt, meaning that we cannot change their
+// signature or ordering as they may be used by 3p apps.
+// Also, some methods are mentioned in native code, meaning that the numbering in
+// frameworks/native/libs/permission/include/binder/IAppOpsService.h must match the order here.
+// Please be careful to respect both these issues when modifying this file.
interface IAppOpsService {
- // These methods are also called by native code, so must
- // be kept in sync with frameworks/native/libs/permission/include/binder/IAppOpsService.h
- // and not be reordered
+ // These methods are also called by native code, so please be careful that the number in
+ // frameworks/native/libs/permission/include/binder/IAppOpsService.h matches the ordering here.
int checkOperation(int code, int uid, String packageName);
SyncNotedAppOp noteOperation(int code, int uid, String packageName, @nullable String attributionTag,
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage);
@@ -54,21 +62,21 @@
void setCameraAudioRestriction(int mode);
void startWatchingModeWithFlags(int op, String packageName, int flags,
IAppOpsCallback callback);
- // End of methods also called by native code.
- // Any new method exposed to native must be added after the last one, do not reorder
-
- SyncNotedAppOp noteProxyOperation(int code, in AttributionSourceState attributionSourceState,
+ // End of methods also called by native code (there may be more blocks like this of native
+ // methods later in this file).
+ // Deprecated, use noteProxyOperationWithState instead.
+ SyncNotedAppOp noteProxyOperation(int code, in AttributionSource attributionSource,
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
boolean skipProxyOperation);
+ // Deprecated, use startProxyOperationWithState instead.
SyncNotedAppOp startProxyOperation(IBinder clientId, int code,
- in AttributionSourceState attributionSourceState, boolean startIfModeDefault,
+ in AttributionSource attributionSource, boolean startIfModeDefault,
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
boolean skipProxyOperation, int proxyAttributionFlags, int proxiedAttributionFlags,
int attributionChainId);
- void finishProxyOperation(IBinder clientId, int code,
- in AttributionSourceState attributionSourceState, boolean skipProxyOperation);
-
- // Remaining methods are only used in Java.
+ // Deprecated, use finishProxyOperationWithState instead.
+ void finishProxyOperation(IBinder clientId, int code, in AttributionSource attributionSource,
+ boolean skipProxyOperation);
int checkPackage(int uid, String packageName);
RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage();
MessageSamplingConfig reportRuntimeAppOpAccessMessageAndGetConfig(String packageName,
@@ -127,8 +135,19 @@
List<AsyncNotedAppOp> extractAsyncOps(String packageName);
int checkOperationRaw(int code, int uid, String packageName, @nullable String attributionTag);
-
void reloadNonHistoricalState();
void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName, long version);
+
+ SyncNotedAppOp noteProxyOperationWithState(int code,
+ in AttributionSourceState attributionSourceStateState,
+ boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
+ boolean skipProxyOperation);
+ SyncNotedAppOp startProxyOperationWithState(IBinder clientId, int code,
+ in AttributionSourceState attributionSourceStateState, boolean startIfModeDefault,
+ boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
+ boolean skipProxyOperation, int proxyAttributionFlags, int proxiedAttributionFlags,
+ int attributionChainId);
+ void finishProxyOperationWithState(IBinder clientId, int code,
+ in AttributionSourceState attributionSourceStateState, boolean skipProxyOperation);
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 965277c..1c5f4f0 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -868,6 +868,11 @@
args.mPkgDataInfoList, args.mAllowlistedDataInfoList,
args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
+ // While `specializeAppProcess` sets the thread name on the process's main thread, this
+ // is distinct from the app process name which appears in stack traces, as the latter is
+ // sourced from the argument buffer of the Process class. Set the app process name here.
+ Zygote.setAppProcessName(args, TAG);
+
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 993e4e7..5fe086d 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -296,7 +296,6 @@
} else {
// child; result is a Runnable.
zygoteServer.setForkChild();
- Zygote.setAppProcessName(parsedArgs, TAG); // ??? Necessary?
return result;
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 8d11672..a3e0016 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1105,10 +1105,9 @@
@UnsupportedAppUsage
public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
- if (isSpecialUserId(userId)) {
- // For secure password storage (that is required for special users such as FRP), the
- // underlying storage also enforces the deadline. Since we cannot store settings
- // for special users, don't.
+ if (userId == USER_FRP) {
+ // For secure password storage (that is required for FRP), the underlying storage also
+ // enforces the deadline. Since we cannot store settings for the FRP user, don't.
return deadline;
}
mLockoutDeadlines.put(userId, deadline);
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index 03e9a6a..1b24efa 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -39,7 +39,7 @@
explicit VelocityTrackerState(const VelocityTracker::Strategy strategy);
void clear();
- void addMovement(const MotionEvent* event);
+ void addMovement(const MotionEvent& event);
// TODO(b/32830165): consider supporting an overload that supports computing velocity only for
// a subset of the supported axes.
void computeCurrentVelocity(int32_t units, float maxVelocity);
@@ -57,7 +57,7 @@
mVelocityTracker.clear();
}
-void VelocityTrackerState::addMovement(const MotionEvent* event) {
+void VelocityTrackerState::addMovement(const MotionEvent& event) {
mVelocityTracker.addMovement(event);
}
@@ -102,13 +102,13 @@
static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass clazz, jlong ptr,
jobject eventObj) {
const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj);
- if (!event) {
+ if (event == nullptr) {
LOG(WARNING) << "nativeAddMovement failed because MotionEvent was finalized.";
return;
}
VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
- state->addMovement(event);
+ state->addMovement(*event);
}
static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* env, jclass clazz,
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index a6830a6..c0c6e05 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -135,11 +135,12 @@
<drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
<drawable name="notification_template_divider">#29000000</drawable>
<drawable name="notification_template_divider_media">#29ffffff</drawable>
- <color name="notification_primary_text_color_light">@color/primary_text_default_material_light</color>
- <color name="notification_primary_text_color_dark">@color/primary_text_default_material_dark</color>
- <color name="notification_secondary_text_color_light">@color/primary_text_default_material_light</color>
+ <color name="notification_primary_text_color_light">@color/system_on_surface_light</color>
+ <color name="notification_primary_text_color_dark">@color/system_on_surface_dark</color>
+ <!-- Note that the primary and secondary notification text colors are, in fact, the same. -->
+ <color name="notification_secondary_text_color_light">@color/system_on_surface_light</color>
+ <color name="notification_secondary_text_color_dark">@color/system_on_surface_dark</color>
<item name="notification_secondary_text_disabled_alpha" format="float" type="dimen">0.38</item>
- <color name="notification_secondary_text_color_dark">@color/primary_text_default_material_dark</color>
<color name="notification_default_color_dark">#ddffffff</color>
<color name="notification_default_color_light">#a3202124</color>
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index 72969f7..37a499a 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -104,19 +104,15 @@
private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
private static final Path[] UI_TRACES_PREDUMPED = {
+ Paths.get("/data/misc/perfetto-traces/bugreport/systrace.pftrace"),
Paths.get("/data/misc/wmtrace/ime_trace_clients.winscope"),
Paths.get("/data/misc/wmtrace/ime_trace_managerservice.winscope"),
Paths.get("/data/misc/wmtrace/ime_trace_service.winscope"),
Paths.get("/data/misc/wmtrace/wm_trace.winscope"),
Paths.get("/data/misc/wmtrace/wm_log.winscope"),
- Paths.get("/data/misc/wmtrace/layers_trace.winscope"),
- Paths.get("/data/misc/wmtrace/transactions_trace.winscope"),
- Paths.get("/data/misc/wmtrace/transition_trace.winscope"),
+ Paths.get("/data/misc/wmtrace/wm_transition_trace.winscope"),
Paths.get("/data/misc/wmtrace/shell_transition_trace.winscope"),
};
- private static final Path[] UI_TRACES_GENERATED_DURING_BUGREPORT = {
- Paths.get("/data/misc/wmtrace/layers_trace_from_transactions.winscope"),
- };
private Handler mHandler;
private Executor mExecutor;
@@ -210,7 +206,7 @@
mBrm.preDumpUiData();
waitTillDumpstateExitedOrTimeout();
- List<File> expectedPreDumpedTraceFiles = copyFilesAsRoot(UI_TRACES_PREDUMPED);
+ List<File> expectedPreDumpedTraceFiles = copyFiles(UI_TRACES_PREDUMPED);
BugreportCallbackImpl callback = new BugreportCallbackImpl();
mBrm.startBugreport(mBugreportFd, null, fullWithUsePreDumpFlag(), mExecutor,
@@ -225,7 +221,6 @@
assertFdsAreClosed(mBugreportFd);
assertThatBugreportContainsFiles(UI_TRACES_PREDUMPED);
- assertThatBugreportContainsFiles(UI_TRACES_GENERATED_DURING_BUGREPORT);
List<File> actualPreDumpedTraceFiles = extractFilesFromBugreport(UI_TRACES_PREDUMPED);
assertThatAllFileContentsAreEqual(actualPreDumpedTraceFiles, expectedPreDumpedTraceFiles);
@@ -240,9 +235,9 @@
// In some corner cases, data dumped as part of the full bugreport could be the same as the
// pre-dumped data and this test would fail. Hence, here we create fake/artificial
// pre-dumped data that we know it won't match with the full bugreport data.
- createFilesWithFakeDataAsRoot(UI_TRACES_PREDUMPED, "system");
+ createFakeTraceFiles(UI_TRACES_PREDUMPED);
- List<File> preDumpedTraceFiles = copyFilesAsRoot(UI_TRACES_PREDUMPED);
+ List<File> preDumpedTraceFiles = copyFiles(UI_TRACES_PREDUMPED);
BugreportCallbackImpl callback = new BugreportCallbackImpl();
mBrm.startBugreport(mBugreportFd, null, full(), mExecutor,
@@ -257,7 +252,6 @@
assertFdsAreClosed(mBugreportFd);
assertThatBugreportContainsFiles(UI_TRACES_PREDUMPED);
- assertThatBugreportContainsFiles(UI_TRACES_GENERATED_DURING_BUGREPORT);
List<File> actualTraceFiles = extractFilesFromBugreport(UI_TRACES_PREDUMPED);
assertThatAllFileContentsAreDifferent(preDumpedTraceFiles, actualTraceFiles);
@@ -480,7 +474,32 @@
return f;
}
- private static void startPreDumpedUiTraces() {
+ private static void startPreDumpedUiTraces() throws Exception {
+ // Perfetto traces
+ String perfettoConfig =
+ "buffers: {\n"
+ + " size_kb: 2048\n"
+ + " fill_policy: RING_BUFFER\n"
+ + "}\n"
+ + "data_sources: {\n"
+ + " config {\n"
+ + " name: \"android.surfaceflinger.transactions\"\n"
+ + " }\n"
+ + "}\n"
+ + "bugreport_score: 10\n";
+ File tmp = createTempFile("tmp", ".cfg");
+ Files.write(perfettoConfig.getBytes(StandardCharsets.UTF_8), tmp);
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+ "install -m 644 -o root -g root "
+ + tmp.getAbsolutePath() + " /data/misc/perfetto-configs/bugreport-manager-test.cfg"
+ );
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+ "perfetto --background-wait"
+ + " --config /data/misc/perfetto-configs/bugreport-manager-test.cfg --txt"
+ + " --out /data/misc/perfetto-traces/not-used.perfetto-trace"
+ );
+
+ // Legacy traces
InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
"cmd input_method tracing start"
);
@@ -563,19 +582,24 @@
return extractedFile;
}
- private static void createFilesWithFakeDataAsRoot(Path[] paths, String owner) throws Exception {
+ private static void createFakeTraceFiles(Path[] paths) throws Exception {
File src = createTempFile("fake", ".data");
Files.write("fake data".getBytes(StandardCharsets.UTF_8), src);
for (Path path : paths) {
InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
- "install -m 611 -o " + owner + " -g " + owner
- + " " + src.getAbsolutePath() + " " + path.toString()
+ "install -m 644 -o system -g system "
+ + src.getAbsolutePath() + " " + path.toString()
);
}
+
+ // Dumpstate executes "perfetto --save-for-bugreport" as shell
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+ "chown shell:shell /data/misc/perfetto-traces/bugreport/systrace.pftrace"
+ );
}
- private static List<File> copyFilesAsRoot(Path[] paths) throws Exception {
+ private static List<File> copyFiles(Path[] paths) throws Exception {
ArrayList<File> files = new ArrayList<File>();
for (Path src : paths) {
File dst = createTempFile(src.getFileName().toString(), ".copy");
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 9430ba6..1577d9c1c1 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -859,6 +859,10 @@
assertEquals(cDay.getTertiaryAccentColor(), cNight.getTertiaryAccentColor());
assertEquals(cDay.getOnTertiaryAccentTextColor(),
cNight.getOnTertiaryAccentTextColor());
+ assertEquals(cDay.getTertiaryFixedDimAccentColor(),
+ cNight.getTertiaryFixedDimAccentColor());
+ assertEquals(cDay.getOnTertiaryFixedAccentTextColor(),
+ cNight.getOnTertiaryFixedAccentTextColor());
assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor());
assertEquals(cDay.getContrastColor(), cNight.getContrastColor());
assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha());
@@ -1832,6 +1836,8 @@
assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
assertThat(c.getTertiaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
assertThat(c.getOnTertiaryAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getTertiaryFixedDimAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getOnTertiaryFixedAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID);
assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID);
assertThat(c.getRippleAlpha()).isAtLeast(0x00);
@@ -1847,9 +1853,12 @@
// These colors are only used for emphasized buttons; they do not need contrast
assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1);
assertContrastIsAtLeast(c.getTertiaryAccentColor(), c.getBackgroundColor(), 1);
+ assertContrastIsAtLeast(c.getTertiaryFixedDimAccentColor(), c.getBackgroundColor(), 1);
// The text that is used within the accent color DOES need to have contrast
assertContrastIsAtLeast(c.getOnTertiaryAccentTextColor(), c.getTertiaryAccentColor(), 4.5);
+ assertContrastIsAtLeast(c.getOnTertiaryFixedAccentTextColor(),
+ c.getTertiaryFixedDimAccentColor(), 4.5);
}
private void resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor,
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 06b62f8..dd116b5 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -33,6 +33,7 @@
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.endsWith;
+import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -119,6 +120,11 @@
@Before
public void setUp() throws Exception {
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ assumeFalse("AccessibilityShortcutChooserActivity not supported on watch",
+ pm.hasSystemFeature(PackageManager.FEATURE_WATCH));
+
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mDevice.wakeUp();
when(mAccessibilityServiceInfo.getResolveInfo()).thenReturn(mResolveInfo);
@@ -138,7 +144,9 @@
@After
public void cleanUp() {
- mScenario.close();
+ if (mScenario != null) {
+ mScenario.close();
+ }
}
@Test
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 49606f0..7743ad5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -1763,6 +1763,15 @@
return;
}
+ if (container.isFinished()) {
+ return;
+ }
+
+ if (container.isOverlay()) {
+ updateOverlayContainer(wct, container);
+ return;
+ }
+
if (launchPlaceholderIfNecessary(wct, container)) {
// Placeholder was launched, the positions will be updated when the activity is added
// to the secondary container.
@@ -1783,6 +1792,25 @@
updateSplitContainerIfNeeded(splitContainer, wct, null /* splitAttributes */);
}
+
+ @VisibleForTesting
+ // Suppress GuardedBy warning because lint ask to mark this method as
+ // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
+ @SuppressWarnings("GuardedBy")
+ @GuardedBy("mLock")
+ void updateOverlayContainer(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentContainer container) {
+ final TaskContainer taskContainer = container.getTaskContainer();
+ // Dismiss the overlay container if it's the only container in the task and there's no
+ // direct activity in the parent task.
+ if (taskContainer.getTaskFragmentContainers().size() == 1
+ && !taskContainer.hasDirectActivity()) {
+ container.finish(false /* shouldFinishDependent */, mPresenter, wct, this);
+ }
+
+ // TODO(b/295805054): Add the logic to update overlay container
+ }
+
/**
* Updates {@link SplitContainer} with the given {@link SplitAttributes} if the
* {@link SplitContainer} is the top most and not finished. If passed {@link SplitAttributes}
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 9e53380..eeb3ccf 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -75,6 +75,8 @@
private boolean mIsVisible;
+ private boolean mHasDirectActivity;
+
/**
* TaskFragments that the organizer has requested to be closed. They should be removed when
* the organizer receives
@@ -102,8 +104,9 @@
mConfiguration = taskProperties.getConfiguration();
mDisplayId = taskProperties.getDisplayId();
// Note that it is always called when there's a new Activity is started, which implies
- // the host task is visible.
+ // the host task is visible and has an activity in the task.
mIsVisible = true;
+ mHasDirectActivity = true;
}
int getTaskId() {
@@ -118,6 +121,10 @@
return mIsVisible;
}
+ boolean hasDirectActivity() {
+ return mHasDirectActivity;
+ }
+
@NonNull
TaskProperties getTaskProperties() {
return new TaskProperties(mDisplayId, mConfiguration);
@@ -127,6 +134,7 @@
mConfiguration.setTo(info.getConfiguration());
mDisplayId = info.getDisplayId();
mIsVisible = info.isVisible();
+ mHasDirectActivity = info.hasDirectActivity();
}
/**
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 405f0b2..e74d5fb 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
@@ -58,6 +58,7 @@
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentParentInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -413,6 +414,33 @@
.isEqualTo(overlayContainer);
}
+ @Test
+ public void testUpdateContainer_dontInvokeUpdateOverlayForNonOverlayContainer() {
+ TaskFragmentContainer taskFragmentContainer = createMockTaskFragmentContainer(mActivity);
+
+ mSplitController.updateContainer(mTransaction, taskFragmentContainer);
+ verify(mSplitController, never()).updateOverlayContainer(any(), any());
+ }
+
+ @Test
+ public void testUpdateOverlayContainer_dismissOverlayIfNeeded() {
+ TaskFragmentContainer overlayContainer = createTestOverlayContainer(TASK_ID, "test");
+
+ mSplitController.updateOverlayContainer(mTransaction, overlayContainer);
+
+ final TaskContainer taskContainer = overlayContainer.getTaskContainer();
+ assertThat(taskContainer.getTaskFragmentContainers()).containsExactly(overlayContainer);
+
+ taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(Configuration.EMPTY,
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
+
+ mSplitController.updateOverlayContainer(mTransaction, overlayContainer);
+
+ assertWithMessage("The overlay must be dismissed since there's no activity"
+ + " in the task and other taskFragment.")
+ .that(taskContainer.getTaskFragmentContainers()).isEmpty();
+ }
+
/**
* A simplified version of {@link SplitController.ActivityStartMonitor
* #createOrUpdateOverlayTaskFragmentIfNeeded}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 96839c5..02031a6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -1139,7 +1139,7 @@
public void testOnTransactionReady_taskFragmentParentInfoChanged() {
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
final TaskFragmentParentInfo parentInfo = new TaskFragmentParentInfo(Configuration.EMPTY,
- DEFAULT_DISPLAY, true);
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */);
transaction.addChange(new TaskFragmentTransaction.Change(
TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
.setTaskId(TASK_ID)
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index 2188996..e3f5169 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -79,14 +79,14 @@
configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
- DEFAULT_DISPLAY, true /* visible */));
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
assertEquals(WINDOWING_MODE_MULTI_WINDOW,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
- DEFAULT_DISPLAY, true /* visible */));
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
assertEquals(WINDOWING_MODE_FREEFORM,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
@@ -106,13 +106,13 @@
configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
- DEFAULT_DISPLAY, true /* visible */));
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
assertFalse(taskContainer.isInPictureInPicture());
configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
- DEFAULT_DISPLAY, true /* visible */));
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
assertTrue(taskContainer.isInPictureInPicture());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index ca2c3b4..293b660 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -146,13 +146,13 @@
});
}
};
+ // If the remote is actually in the same process, then make a copy of parameters since
+ // remote impls assume that they have to clean-up native references.
+ final SurfaceControl.Transaction remoteStartT =
+ copyIfLocal(startTransaction, remote.getRemoteTransition());
+ final TransitionInfo remoteInfo =
+ remoteStartT == startTransaction ? info : info.localRemoteCopy();
try {
- // If the remote is actually in the same process, then make a copy of parameters since
- // remote impls assume that they have to clean-up native references.
- final SurfaceControl.Transaction remoteStartT =
- copyIfLocal(startTransaction, remote.getRemoteTransition());
- final TransitionInfo remoteInfo =
- remoteStartT == startTransaction ? info : info.localRemoteCopy();
handleDeath(remote.asBinder(), finishCallback);
remote.getRemoteTransition().startAnimation(transition, remoteInfo, remoteStartT, cb);
// assume that remote will apply the start transaction.
@@ -160,6 +160,10 @@
Transitions.setRunningRemoteTransitionDelegate(remote.getAppThread());
} catch (RemoteException e) {
Log.e(Transitions.TAG, "Error running remote transition.", e);
+ if (remoteStartT != startTransaction) {
+ remoteStartT.close();
+ }
+ startTransaction.apply();
unhandleDeath(remote.asBinder(), finishCallback);
mRequestedRemotes.remove(transition);
mMainExecutor.execute(() -> finishCallback.onTransitionFinished(null /* wct */));
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index e28ad67..200d4ef 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -502,7 +502,7 @@
* <td colspan="4"><strong>BDS</strong></td>
* <td colspan="3"><strong>GAL</strong></td>
* <td><strong>SBAS</strong></td>
- * <td><strong>IRNSS</strong></td>
+ * <td><strong>NavIC</strong></td>
* </tr>
* <tr>
* <td><strong>State Flag</strong></td>
@@ -1528,17 +1528,17 @@
* <p>Similar to the Attribute field described in RINEX 4.00, e.g., in Tables 9-16 (see
* https://igs.org/wg/rinex/#documents-formats).
*
- * <p>Returns "A" for GALILEO E1A, GALILEO E6A, IRNSS L5A SPS, IRNSS SA SPS, GLONASS G1a L1OCd,
+ * <p>Returns "A" for GALILEO E1A, GALILEO E6A, NavIC L5A SPS, NavIC SA SPS, GLONASS G1a L1OCd,
* GLONASS G2a L2CSI.
*
- * <p>Returns "B" for GALILEO E1B, GALILEO E6B, IRNSS L5B RS (D), IRNSS SB RS (D), GLONASS G1a
+ * <p>Returns "B" for GALILEO E1B, GALILEO E6B, NavIC L5B RS (D), NavIC SB RS (D), GLONASS G1a
* L1OCp, GLONASS G2a L2OCp, QZSS L1Sb.
*
* <p>Returns "C" for GPS L1 C/A, GPS L2 C/A, GLONASS G1 C/A, GLONASS G2 C/A, GALILEO E1C,
- * GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C RS (P), IRNSS SC RS (P).
+ * GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, NavIC L5C RS (P), NavIC SC RS (P).
*
* <p>Returns "D" for GPS L2 (L1(C/A) + (P2-P1) (semi-codeless)), QZSS L5S(I), BDS B1C Data,
- * BDS B2a Data, BDS B2b Data, BDS B2 (B2a+B2b) Data, BDS B3a Data.
+ * BDS B2a Data, BDS B2b Data, BDS B2 (B2a+B2b) Data, BDS B3a Data, NavIC L1 Data.
*
* <p>Returns “E” for QZSS L1 C/B, QZSS L6E.
*
@@ -1553,7 +1553,7 @@
* <p>Returns "N" for GPS L1 codeless, GPS L2 codeless.
*
* <p>Returns "P" for GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P, BDS B1C Pilot, BDS B2a Pilot,
- * BDS B2b Pilot, BDS B2 (B2a+B2b) Pilot, BDS B3a Pilot, QZSS L5S(Q).
+ * BDS B2b Pilot, BDS B2 (B2a+B2b) Pilot, BDS B3a Pilot, QZSS L5S(Q), NavIC L1 Pilot.
*
* <p>Returns "Q" for GPS L5 Q, GLONASS G3 Q, GALILEO E5a Q, GALILEO E5b Q, GALILEO E5a+b Q,
* SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
@@ -1567,7 +1567,8 @@
* GLONASS G2a L2CSI+L2OCp, GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO
* E5b (I+Q), GALILEO E5a+b (I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C
* (M+L), QZSS L5 (I+Q), QZSS L6 (D+P), BDS B1 (I+Q), BDS B1C Data+Pilot, BDS B2a Data+Pilot,
- * BDS B2 (I+Q), BDS B2 (B2a+B2b) Data+Pilot, BDS B3 (I+Q), IRNSS L5 (B+C), IRNSS S (B+C).
+ * BDS B2 (I+Q), BDS B2 (B2a+B2b) Data+Pilot, BDS B3 (I+Q), NavIC L5 (B+C), NavIC S (B+C),
+ * NavIC L1 Data+Pilot.
*
* <p>Returns "Y" for GPS L1Y, GPS L2Y.
*
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index c9cfa67..386534b 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -34,3 +34,10 @@
description: "Fallbacks to the default handling for volume adjustment when media session has fixed volume handling and its app is in the foreground and setting a media controller."
bug: "293743975"
}
+
+flag {
+ namespace: "media_solutions"
+ name: "enable_waiting_state_for_system_session_creation_request"
+ description: "Introduces a waiting state for the session creation request and prevents it from early failing when the selectedRoute from the bluetooth stack doesn't match the pending request route id."
+ bug: "307723189"
+}
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index 10c880d..24efbd1 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -158,26 +158,6 @@
in @nullable IMediaProjection projection);
/**
- * Notifies system server that we are handling a particular state during the consent flow.
- *
- * <p>Only used for emitting atoms.
- *
- * @param hostUid The uid of the process requesting consent to capture, may be an app or
- * SystemUI.
- * @param state The state that SystemUI is handling during the consent flow.
- * Must be a valid
- * state defined in the MediaProjectionState enum.
- * @param sessionCreationSource Only set if the state is MEDIA_PROJECTION_STATE_INITIATED.
- * Indicates the entry point for requesting the permission. Must be
- * a valid state defined
- * in the SessionCreationSource enum.
- */
- @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
- @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
- + ".permission.MANAGE_MEDIA_PROJECTION)")
- oneway void notifyPermissionRequestStateChange(int hostUid, int state, int sessionCreationSource);
-
- /**
* Notifies system server that the permission request was initiated.
*
* <p>Only used for emitting atoms.
@@ -208,6 +188,19 @@
oneway void notifyPermissionRequestDisplayed(int hostUid);
/**
+ * Notifies system server that the permission request was cancelled.
+ *
+ * <p>Only used for emitting atoms.
+ *
+ * @param hostUid The uid of the process requesting consent to capture, may be an app or
+ * SystemUI.
+ */
+ @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ + ".permission.MANAGE_MEDIA_PROJECTION)")
+ oneway void notifyPermissionRequestCancelled(int hostUid);
+
+ /**
* Notifies system server that the app selector was displayed.
*
* <p>Only used for emitting atoms.
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 477e61d..f0fa6c5 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -336,7 +336,10 @@
return result
}
- private fun parseCredentialEntryFromSlice(slice: Slice): CredentialEntry? {
+ /**
+ * @hide
+ */
+ fun parseCredentialEntryFromSlice(slice: Slice): CredentialEntry? {
try {
when (slice.spec?.type) {
TYPE_PASSWORD_CREDENTIAL -> return PasswordCredentialEntry.fromSlice(slice)!!
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index d35dcb5..81cbd5a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -23,6 +23,8 @@
import android.credentials.GetCandidateCredentialsException
import android.credentials.GetCandidateCredentialsResponse
import android.credentials.GetCredentialRequest
+import android.credentials.ui.GetCredentialProviderData
+import android.graphics.drawable.Icon
import android.os.Bundle
import android.os.CancellationSignal
import android.os.OutcomeReceiver
@@ -42,6 +44,9 @@
import org.json.JSONException
import android.widget.inline.InlinePresentationSpec
import androidx.autofill.inline.v1.InlineSuggestionUi
+import androidx.credentials.provider.CustomCredentialEntry
+import androidx.credentials.provider.PasswordCredentialEntry
+import androidx.credentials.provider.PublicKeyCredentialEntry
import com.android.credentialmanager.GetFlowUtils
import com.android.credentialmanager.getflow.CredentialEntryInfo
import com.android.credentialmanager.getflow.ProviderDisplayInfo
@@ -110,6 +115,34 @@
)
}
+ private fun getEntryToIconMap(
+ candidateProviderDataList: MutableList<GetCredentialProviderData>
+ ): Map<String, Icon> {
+ val entryIconMap: MutableMap<String, Icon> = mutableMapOf()
+ candidateProviderDataList.forEach { provider ->
+ provider.credentialEntries.forEach { entry ->
+ val credentialEntry = GetFlowUtils.parseCredentialEntryFromSlice(entry.slice)
+ when (credentialEntry) {
+ is PasswordCredentialEntry -> {
+ entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
+ }
+ is PublicKeyCredentialEntry -> {
+ entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
+ }
+ is CustomCredentialEntry -> {
+ entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
+ }
+ }
+ }
+ }
+ return entryIconMap
+ }
+
+ private fun getDefaultIcon(): Icon {
+ return Icon.createWithResource(
+ this, com.android.credentialmanager.R.drawable.ic_other_sign_in_24)
+ }
+
private fun convertToFillResponse(
getCredResponse: GetCandidateCredentialsResponse,
filLRequest: FillRequest
@@ -120,6 +153,8 @@
if (providerList.isEmpty()) {
return null
}
+ val entryIconMap: Map<String, Icon> =
+ getEntryToIconMap(getCredResponse.candidateProviderDataList)
var totalEntryCount = 0
providerList.forEach { provider ->
totalEntryCount += provider.credentialEntryList.size
@@ -174,6 +209,10 @@
val sliceBuilder = InlineSuggestionUi
.newContentBuilder(pendingIntent)
.setTitle(credentialEntry.userName)
+ val icon: Icon =
+ entryIconMap[credentialEntry.entryKey + credentialEntry.entrySubkey]
+ ?: getDefaultIcon()
+ sliceBuilder.setStartIcon(icon)
inlinePresentation = InlinePresentation(
sliceBuilder.build().slice, spec, /* pinned= */ false)
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index c9540c7..8bdbee3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -26,7 +26,6 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerManager;
-import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
@@ -202,10 +201,10 @@
}
private static void setBatterySaverConfirmationAcknowledged(Context context) {
- Secure.putIntForUser(context.getContentResolver(),
- Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1, UserHandle.USER_CURRENT);
- Secure.putIntForUser(context.getContentResolver(),
- Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1, UserHandle.USER_CURRENT);
+ Secure.putInt(context.getContentResolver(),
+ Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1);
+ Secure.putInt(context.getContentResolver(),
+ Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1);
}
/**
diff --git a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml
index 015e9f9..d1b8a06 100644
--- a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml
+++ b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml
@@ -14,8 +14,9 @@
~ limitations under the License
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<item android:state_selected="true"
- android:color="?android:attr/colorAccent" />
+ android:color="?androidprv:attr/materialColorOnSurfaceVariant" />
<item android:color="@color/notification_guts_priority_button_bg_stroke_color" />
</selector>
diff --git a/packages/SystemUI/res/color/notification_guts_priority_contents.xml b/packages/SystemUI/res/color/notification_guts_priority_contents.xml
index 42f0189..cc8c25a 100644
--- a/packages/SystemUI/res/color/notification_guts_priority_contents.xml
+++ b/packages/SystemUI/res/color/notification_guts_priority_contents.xml
@@ -14,8 +14,9 @@
~ limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<item android:state_selected="true"
- android:color="?android:attr/colorAccent" />
+ android:color="?androidprv:attr/materialColorOnSurfaceVariant" />
<item android:color="@color/notification_guts_priority_button_content_color" />
</selector>
diff --git a/packages/SystemUI/res/color/remote_input_hint.xml b/packages/SystemUI/res/color/remote_input_hint.xml
index 7fe58db..0d90ee6 100644
--- a/packages/SystemUI/res/color/remote_input_hint.xml
+++ b/packages/SystemUI/res/color/remote_input_hint.xml
@@ -14,6 +14,7 @@
~ limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="?android:attr/textColorPrimary" android:alpha=".6" />
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/materialColorOnSurfaceVariant" android:alpha=".6" />
</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/remote_input_send.xml b/packages/SystemUI/res/color/remote_input_send.xml
index 4dcd3dd..0acc66b 100644
--- a/packages/SystemUI/res/color/remote_input_send.xml
+++ b/packages/SystemUI/res/color/remote_input_send.xml
@@ -15,7 +15,8 @@
~ limitations under the License
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:color="?android:attr/colorAccent" android:alpha=".3" />
- <item android:color="?android:attr/colorAccent" />
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:state_enabled="false" android:color="?androidprv:attr/materialColorPrimary" android:alpha=".3" />
+ <item android:color="?androidprv:attr/materialColorPrimary" />
</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/remote_input_text.xml b/packages/SystemUI/res/color/remote_input_text.xml
index 13bb1d7..bf2c198 100644
--- a/packages/SystemUI/res/color/remote_input_text.xml
+++ b/packages/SystemUI/res/color/remote_input_text.xml
@@ -15,7 +15,8 @@
~ limitations under the License
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" android:alpha=".6" />
- <item android:color="?android:attr/textColorPrimary" />
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:state_enabled="false" android:color="?androidprv:attr/materialColorOnSurfaceVariant" android:alpha=".6" />
+ <item android:color="?androidprv:attr/materialColorOnSurfaceVariant" />
</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml
index e626675..b959737 100644
--- a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml
+++ b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml
@@ -26,7 +26,7 @@
<padding
android:left="20dp"
android:right="20dp" />
- <solid android:color="?androidprv:attr/colorSurface" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
</shape>
</inset>
</item>
diff --git a/packages/SystemUI/res/drawable/notification_guts_bg.xml b/packages/SystemUI/res/drawable/notification_guts_bg.xml
index bd9394b..84e2231 100644
--- a/packages/SystemUI/res/drawable/notification_guts_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_guts_bg.xml
@@ -17,7 +17,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <solid android:color="?androidprv:attr/colorSurface" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
<!--The radius is 1dp smaller than the notification one, to avoid aliasing bugs on the corners -->
<corners android:radius="1dp" />
</shape>
diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml
index 3eaa618..355e75d 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg.xml
@@ -20,7 +20,7 @@
android:color="?android:attr/colorControlHighlight">
<item>
<shape>
- <solid android:color="?androidprv:attr/colorSurface" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
</shape>
</item>
<item>
diff --git a/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml b/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml
index 535b354..45d1a53 100644
--- a/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml
+++ b/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml
@@ -14,12 +14,13 @@
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?android:attr/colorBackgroundFloating" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceDim" />
<stroke
android:width="@dimen/remote_input_view_text_stroke"
- android:color="?android:attr/colorAccent"/>
+ android:color="?androidprv:attr/materialColorPrimary"/>
<padding
android:bottom="0dp"
android:left="12dp"
diff --git a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
index 8b34080..06bed00 100644
--- a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
+++ b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
@@ -15,11 +15,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
- android:fillColor="@color/notification_section_clear_all_btn_color"
+ android:fillColor="?androidprv:attr/materialColorOnSurfaceVariant"
android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7267L16.2734 24.6667L20 20.94L23.7267 24.6667L24.6667 23.7267L20.94 20L24.6667 16.2733Z"/>
</vector>
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
index bddcb6a..cf301c9 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
@@ -79,7 +79,4 @@
android:tint="@color/accent_tint_color_selector"
android:soundEffectsEnabled="false" />
</LinearLayout>
-
- <include layout="@layout/volume_dnd_icon"/>
-
</FrameLayout>
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index 3b70dc0..5ce2601 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -70,12 +70,6 @@
android:tint="?android:attr/textColorPrimary"
android:layout_gravity="center"
android:soundEffectsEnabled="false" />
-
- <include layout="@layout/volume_dnd_icon"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/volume_dialog_stream_padding"
- android:layout_marginTop="6dp"/>
</FrameLayout>
<LinearLayout
diff --git a/packages/SystemUI/res/layout/bluetooth_device_item.xml b/packages/SystemUI/res/layout/bluetooth_device_item.xml
index 6d77943..08eccbb 100644
--- a/packages/SystemUI/res/layout/bluetooth_device_item.xml
+++ b/packages/SystemUI/res/layout/bluetooth_device_item.xml
@@ -44,10 +44,9 @@
android:paddingTop="10dp"
android:maxLines="1"
android:ellipsize="end"
- app:layout_constraintWidth_percent="0.7"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@+id/bluetooth_device_icon"
- app:layout_constraintEnd_toStartOf="@+id/gear_icon"
+ app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintBottom_toTopOf="@+id/bluetooth_device_summary"
android:gravity="center_vertical"
android:textSize="14sp" />
@@ -60,34 +59,35 @@
android:paddingBottom="10dp"
android:maxLines="1"
android:ellipsize="end"
- app:layout_constraintWidth_percent="0.7"
app:layout_constraintTop_toBottomOf="@+id/bluetooth_device_name"
app:layout_constraintStart_toEndOf="@+id/bluetooth_device_icon"
- app:layout_constraintEnd_toStartOf="@+id/gear_icon"
+ app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintBottom_toBottomOf="parent"
android:gravity="center_vertical" />
+ <androidx.constraintlayout.widget.Guideline
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/guideline"
+ app:layout_constraintGuide_percent="0.8"
+ android:orientation="vertical"/>
+
<View
android:id="@+id/gear_icon"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@string/accessibility_bluetooth_device_settings_gear"
- app:layout_constraintStart_toEndOf="@+id/bluetooth_device_name"
- app:layout_constraintEnd_toEndOf="@+id/gear_icon_image"
+ app:layout_constraintStart_toEndOf="@+id/guideline"
+ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<ImageView
android:id="@+id/gear_icon_image"
- android:src="@drawable/ic_settings_24dp"
- android:contentDescription="@string/accessibility_bluetooth_device_settings_gear"
android:layout_width="0dp"
android:layout_height="24dp"
- app:layout_constraintStart_toEndOf="@+id/bluetooth_device_name"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
+ android:src="@drawable/ic_settings_24dp"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintWidth_percent="0.3"
- android:gravity="center_vertical"
- android:paddingStart="10dp" />
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
index 5d986e0..c11a18b 100644
--- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
@@ -51,147 +51,160 @@
android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toTopOf="@id/bluetooth_toggle_title"
+ app:layout_constraintBottom_toTopOf="@+id/scroll_view"
app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_title" />
- <TextView
- android:id="@+id/bluetooth_toggle_title"
- style="@style/BluetoothTileDialog.Device"
- android:layout_width="0dp"
- android:layout_height="64dp"
- android:maxLines="1"
- android:ellipsize="end"
- android:gravity="center_vertical"
- android:layout_marginTop="4dp"
- android:text="@string/turn_on_bluetooth"
- android:clickable="false"
- android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
- android:textSize="16sp"
- app:layout_constraintEnd_toStartOf="@+id/bluetooth_toggle"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_subtitle" />
-
- <Switch
- android:id="@+id/bluetooth_toggle"
- style="@style/BluetoothTileDialog.Device"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:gravity="center|center_vertical"
- android:paddingEnd="24dp"
- android:layout_marginTop="10dp"
- android:contentDescription="@string/turn_on_bluetooth"
- android:switchMinWidth="@dimen/settingslib_switch_track_width"
- android:theme="@style/MainSwitch.Settingslib"
- android:thumb="@drawable/settingslib_thumb_selector"
- android:track="@drawable/settingslib_track_selector"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@+id/bluetooth_toggle_title"
- app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_subtitle" />
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/device_list"
+ <androidx.core.widget.NestedScrollView
+ android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:nestedScrollingEnabled="false"
- android:overScrollMode="never"
- android:scrollbars="vertical"
+ app:layout_constrainedHeight="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/bluetooth_toggle"
- app:layout_constraintBottom_toTopOf="@+id/see_all_text" />
-
- <androidx.constraintlayout.widget.Group
- android:id="@+id/see_all_layout_group"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- app:constraint_referenced_ids="ic_arrow,see_all_text" />
-
- <ImageView
- android:id="@+id/ic_arrow"
- android:layout_marginStart="36dp"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:importantForAccessibility="no"
- android:gravity="center_vertical"
- android:src="@drawable/ic_arrow_forward"
- app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/see_all_text"
- app:layout_constraintTop_toBottomOf="@id/device_list" />
-
- <TextView
- android:id="@+id/see_all_text"
- style="@style/BluetoothTileDialog.Device"
- android:layout_width="0dp"
- android:layout_height="64dp"
- android:maxLines="1"
- android:ellipsize="end"
- android:gravity="center_vertical"
- android:layout_marginStart="0dp"
- android:paddingStart="20dp"
- android:text="@string/see_all_bluetooth_devices"
- android:textSize="14sp"
- android:textAppearance="@style/TextAppearance.Dialog.Title"
- app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
- app:layout_constraintStart_toEndOf="@+id/ic_arrow"
- app:layout_constraintTop_toBottomOf="@id/device_list"
- app:layout_constraintEnd_toEndOf="parent" />
-
- <androidx.constraintlayout.widget.Group
- android:id="@+id/pair_new_device_layout_group"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- app:constraint_referenced_ids="ic_add,pair_new_device_text" />
-
- <ImageView
- android:id="@+id/ic_add"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_marginStart="36dp"
- android:gravity="center_vertical"
- android:importantForAccessibility="no"
- android:src="@drawable/ic_add"
- app:layout_constraintBottom_toTopOf="@id/done_button"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/pair_new_device_text"
- app:layout_constraintTop_toBottomOf="@id/see_all_text"
- android:tint="?android:attr/textColorPrimary" />
-
- <TextView
- android:id="@+id/pair_new_device_text"
- style="@style/BluetoothTileDialog.Device"
- android:layout_width="0dp"
- android:layout_height="64dp"
- android:maxLines="1"
- android:ellipsize="end"
- android:gravity="center_vertical"
- android:layout_marginStart="0dp"
- android:paddingStart="20dp"
- android:text="@string/pair_new_bluetooth_devices"
- android:textSize="14sp"
- android:textAppearance="@style/TextAppearance.Dialog.Title"
- app:layout_constraintBottom_toTopOf="@id/done_button"
- app:layout_constraintStart_toEndOf="@+id/ic_add"
- app:layout_constraintTop_toBottomOf="@id/see_all_text"
- app:layout_constraintEnd_toEndOf="parent" />
-
- <Button
- android:id="@+id/done_button"
- style="@style/Widget.Dialog.Button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/dialog_bottom_padding"
- android:layout_marginEnd="@dimen/dialog_side_padding"
- android:layout_marginStart="@dimen/dialog_side_padding"
- android:clickable="true"
- android:ellipsize="end"
- android:focusable="true"
- android:maxLines="1"
- android:text="@string/inline_done_button"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/pair_new_device_text" />
+ app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_subtitle">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/scroll_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:id="@+id/bluetooth_toggle_title"
+ android:layout_width="0dp"
+ android:layout_height="64dp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:gravity="start|center_vertical"
+ android:paddingEnd="0dp"
+ android:paddingStart="36dp"
+ android:text="@string/turn_on_bluetooth"
+ android:clickable="false"
+ android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+ android:textSize="16sp"
+ app:layout_constraintEnd_toStartOf="@+id/bluetooth_toggle"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/device_list"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <Switch
+ android:id="@+id/bluetooth_toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:gravity="start|center_vertical"
+ android:paddingEnd="40dp"
+ android:contentDescription="@string/turn_on_bluetooth"
+ android:switchMinWidth="@dimen/settingslib_switch_track_width"
+ android:theme="@style/MainSwitch.Settingslib"
+ android:thumb="@drawable/settingslib_thumb_selector"
+ android:track="@drawable/settingslib_track_selector"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/bluetooth_toggle_title"
+ app:layout_constraintBottom_toTopOf="@+id/device_list"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/device_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/bluetooth_toggle"
+ app:layout_constraintBottom_toTopOf="@+id/see_all_text" />
+
+ <androidx.constraintlayout.widget.Group
+ android:id="@+id/see_all_layout_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ app:constraint_referenced_ids="ic_arrow,see_all_text" />
+
+ <ImageView
+ android:id="@+id/ic_arrow"
+ android:layout_marginStart="36dp"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:importantForAccessibility="no"
+ android:gravity="center_vertical"
+ android:src="@drawable/ic_arrow_forward"
+ app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/see_all_text"
+ app:layout_constraintTop_toBottomOf="@id/device_list" />
+
+ <TextView
+ android:id="@+id/see_all_text"
+ style="@style/BluetoothTileDialog.Device"
+ android:layout_width="0dp"
+ android:layout_height="64dp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:gravity="center_vertical"
+ android:layout_marginStart="0dp"
+ android:paddingStart="20dp"
+ android:text="@string/see_all_bluetooth_devices"
+ android:textSize="14sp"
+ android:textAppearance="@style/TextAppearance.Dialog.Title"
+ app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
+ app:layout_constraintStart_toEndOf="@+id/ic_arrow"
+ app:layout_constraintTop_toBottomOf="@id/device_list"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+ <androidx.constraintlayout.widget.Group
+ android:id="@+id/pair_new_device_layout_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ app:constraint_referenced_ids="ic_add,pair_new_device_text" />
+
+ <ImageView
+ android:id="@+id/ic_add"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginStart="36dp"
+ android:gravity="center_vertical"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_add"
+ app:layout_constraintBottom_toTopOf="@id/done_button"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/pair_new_device_text"
+ app:layout_constraintTop_toBottomOf="@id/see_all_text"
+ android:tint="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:id="@+id/pair_new_device_text"
+ style="@style/BluetoothTileDialog.Device"
+ android:layout_width="0dp"
+ android:layout_height="64dp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:gravity="center_vertical"
+ android:layout_marginStart="0dp"
+ android:paddingStart="20dp"
+ android:text="@string/pair_new_bluetooth_devices"
+ android:textSize="14sp"
+ android:textAppearance="@style/TextAppearance.Dialog.Title"
+ app:layout_constraintStart_toEndOf="@+id/ic_add"
+ app:layout_constraintTop_toBottomOf="@id/see_all_text"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+ <Button
+ android:id="@+id/done_button"
+ style="@style/Widget.Dialog.Button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/dialog_bottom_padding"
+ android:layout_marginEnd="@dimen/dialog_side_padding"
+ android:layout_marginStart="@dimen/dialog_side_padding"
+ android:clickable="true"
+ android:ellipsize="end"
+ android:focusable="true"
+ android:maxLines="1"
+ android:text="@string/inline_done_button"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/pair_new_device_text"
+ app:layout_constraintBottom_toBottomOf="parent" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notif_half_shelf.xml b/packages/SystemUI/res/layout/notif_half_shelf.xml
index c70f8e2..68c8dd9 100644
--- a/packages/SystemUI/res/layout/notif_half_shelf.xml
+++ b/packages/SystemUI/res/layout/notif_half_shelf.xml
@@ -16,6 +16,7 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/half_shelf_dialog"
android:orientation="vertical"
android:layout_width="wrap_content"
@@ -65,7 +66,7 @@
android:gravity="center_vertical|start"
android:ellipsize="end"
android:maxLines="2"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="16sp"
/>
diff --git a/packages/SystemUI/res/layout/notif_half_shelf_row.xml b/packages/SystemUI/res/layout/notif_half_shelf_row.xml
index 190f999..9ef342c 100644
--- a/packages/SystemUI/res/layout/notif_half_shelf_row.xml
+++ b/packages/SystemUI/res/layout/notif_half_shelf_row.xml
@@ -16,6 +16,7 @@
<com.android.systemui.statusbar.notification.row.ChannelRow
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/half_shelf_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -59,7 +60,7 @@
android:ellipsize="end"
android:maxLines="1"
android:fontFamily="@*android:string/config_headlineFontFamily"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
android:textSize="16sp"
/>
@@ -74,7 +75,7 @@
android:maxLines="1"
android:layout_below="@id/channel_name"
android:fontFamily="@*android:string/config_bodyFontFamily"
- android:textColor="?android:attr/textColorSecondary"
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
android:textSize="14sp"
/>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/notification_children_divider.xml b/packages/SystemUI/res/layout/notification_children_divider.xml
index eb74306..13e24a9 100644
--- a/packages/SystemUI/res/layout/notification_children_divider.xml
+++ b/packages/SystemUI/res/layout/notification_children_divider.xml
@@ -17,7 +17,8 @@
<com.android.systemui.statusbar.AlphaOptimizedView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/notification_more_divider"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_divider_height"
- android:background="@color/notification_divider_color" />
+ android:background="?androidprv:attr/materialColorOnSurfaceVariant" />
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 4f6e88c..3a752c8 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -17,6 +17,7 @@
<com.android.systemui.statusbar.notification.row.NotificationConversationInfo
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/notification_guts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -173,7 +174,7 @@
android:contentDescription="@string/notification_more_settings"
android:background="@drawable/ripple_drawable_20dp"
android:src="@drawable/ic_settings"
- android:tint="?android:attr/colorAccent"
+ android:tint="?androidprv:attr/materialColorPrimary"
android:layout_alignParentEnd="true" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 852db1b..19a3f2f 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -17,6 +17,7 @@
<com.android.systemui.statusbar.notification.row.NotificationInfo
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/notification_guts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -102,7 +103,7 @@
android:contentDescription="@string/notification_app_settings"
android:src="@drawable/ic_info"
android:layout_toStartOf="@id/info"
- android:tint="@color/notification_guts_link_icon_tint"/>
+ android:tint="?androidprv:attr/materialColorPrimary"/>
<ImageButton
android:id="@+id/info"
android:layout_width="@dimen/notification_importance_toggle_size"
@@ -111,7 +112,7 @@
android:contentDescription="@string/notification_more_settings"
android:background="@drawable/ripple_drawable_20dp"
android:src="@drawable/ic_settings"
- android:tint="?android:attr/colorAccent"
+ android:tint="?androidprv:attr/materialColorPrimary"
android:layout_alignParentEnd="true" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index 8b53680..6e541a7 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -23,7 +23,7 @@
android:orientation="vertical"
android:paddingTop="2dp"
android:paddingBottom="2dp"
- android:background="?androidprv:attr/colorSurface"
+ android:background="?androidprv:attr/materialColorSurfaceContainerHigh"
android:theme="@style/Theme.SystemUI">
<RelativeLayout
@@ -38,7 +38,7 @@
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:paddingStart="@*android:dimen/notification_content_margin_end"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
android:paddingEnd="4dp"/>
<ImageView
diff --git a/packages/SystemUI/res/layout/notification_snooze_option.xml b/packages/SystemUI/res/layout/notification_snooze_option.xml
index d42cc02..fa6f965 100644
--- a/packages/SystemUI/res/layout/notification_snooze_option.xml
+++ b/packages/SystemUI/res/layout/notification_snooze_option.xml
@@ -16,10 +16,11 @@
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
android:layout_height="@*android:dimen/notification_headerless_min_height"
android:layout_marginStart="@*android:dimen/notification_content_margin_end"
android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
android:gravity="center_vertical"
android:textSize="14sp"
- android:textColor="?android:attr/textColorSecondary"/>
\ No newline at end of file
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index c1bac31..72424a13 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -41,7 +41,7 @@
android:layout_height="wrap_content"
>
<com.android.systemui.statusbar.notification.row.FooterViewButton
- style="@style/TextAppearance.NotificationSectionHeaderButton"
+ style="@style/TextAppearance.NotificationFooterButton"
android:id="@+id/manage_text"
android:layout_width="wrap_content"
android:layout_height="48dp"
@@ -54,12 +54,11 @@
app:layout_constraintEnd_toStartOf="@id/dismiss_text"
android:background="@drawable/notif_footer_btn_background"
android:focusable="true"
- android:textColor="@color/notif_pill_text"
android:contentDescription="@string/manage_notifications_history_text"
android:text="@string/manage_notifications_history_text"
/>
<com.android.systemui.statusbar.notification.row.FooterViewButton
- style="@style/TextAppearance.NotificationSectionHeaderButton"
+ style="@style/TextAppearance.NotificationFooterButton"
android:id="@+id/dismiss_text"
android:layout_width="wrap_content"
android:layout_height="48dp"
@@ -70,7 +69,6 @@
app:layout_constraintStart_toEndOf="@id/manage_text"
android:background="@drawable/notif_footer_btn_background"
android:focusable="true"
- android:textColor="@color/notif_pill_text"
android:contentDescription="@string/accessibility_clear_all"
android:text="@string/clear_all_notifications_text"
/>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index c4d8d55..53abe87 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -40,7 +40,7 @@
android:layout_weight="1">
<TextView
- style="@style/TextAppearance.NotificationSectionHeaderButton"
+ style="@style/TextAppearance.NotificationSectionHeaderLabel"
android:id="@+id/header_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 6a192d4..39a1f1f 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -69,12 +69,6 @@
android:tint="?android:attr/textColorPrimary"
android:layout_gravity="center"
android:soundEffectsEnabled="false" />
-
- <include layout="@layout/volume_dnd_icon"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/volume_dialog_stream_padding"
- android:layout_marginTop="6dp"/>
</FrameLayout>
<LinearLayout
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index c9256ae..f35de05 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -62,7 +62,6 @@
android:background="@null"
android:layoutDirection="ltr"
android:rotation="270" />
- <include layout="@layout/volume_dnd_icon"/>
</FrameLayout>
<com.android.keyguard.AlphaOptimizedImageButton
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 99311e3..d9385c7 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -33,7 +33,7 @@
<!-- The color of the text inside a notification -->
<color name="notification_primary_text_color">@*android:color/notification_primary_text_color_dark</color>
- <color name="notif_pill_text">@color/material_dynamic_neutral95</color>
+ <color name="notif_pill_text">@android:color/system_on_surface_dark</color>
<color name="notification_guts_link_icon_tint">@color/GM2_grey_500</color>
<color name="notification_guts_sub_text_color">@color/GM2_grey_300</color>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e942258..0620355 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -115,7 +115,7 @@
<!-- Chosen so fill over background matches single tone -->
<color name="dark_mode_qs_icon_color_dual_tone_fill">#99000000</color>
- <color name="notif_pill_text">@color/material_dynamic_neutral10</color>
+ <color name="notif_pill_text">@android:color/system_on_surface_light</color>
<!-- Keyboard shortcuts colors -->
<color name="ksh_application_group_color">#fff44336</color>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4c41ca4..4c520444 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -466,7 +466,7 @@
<string name="accessibility_bluetooth_device_icon">Bluetooth device icon</string>
<!-- Content description of the bluetooth device settings gear icon. [CHAR LIMIT=NONE] -->
- <string name="accessibility_bluetooth_device_settings_gear">Bluetooth device settings gear</string>
+ <string name="accessibility_bluetooth_device_settings_gear">Click to configure device detail</string>
<!-- Content description of the battery when battery state is unknown for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_battery_unknown">Battery percentage unknown.</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 084cb88..7ce530f 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -597,34 +597,34 @@
<style name="TextAppearance.NotificationImportanceChannel">
<item name="android:textSize">@dimen/notification_importance_channel_text</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
- <item name="android:textColor">@color/notification_guts_header_text_color</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
<item name="android:textSize">@dimen/notification_importance_channel_text</item>
</style>
<style name="TextAppearance.NotificationImportanceChannelGroup">
<item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">@color/notification_guts_header_text_color</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
<item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
</style>
<style name="TextAppearance.NotificationImportanceApp">
<item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">@color/notification_guts_sub_text_color</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
<item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
</style>
<style name="TextAppearance.NotificationImportanceHeader">
<item name="android:textSize">@dimen/notification_importance_header_text</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">@color/notification_guts_header_text_color</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
<style name="TextAppearance.NotificationImportanceDetail">
<item name="android:textSize">@dimen/notification_importance_description_text</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
- <item name="android:textColor">@color/notification_guts_sub_text_color</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
<item name="android:gravity">center</item>
</style>
@@ -636,9 +636,27 @@
</style>
<style
+ name="TextAppearance.NotificationSectionHeaderLabel"
+ parent="@android:style/Widget.DeviceDefault.Button.Borderless">
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:minWidth">0dp</item>
+ </style>
+
+ <style
name="TextAppearance.NotificationSectionHeaderButton"
parent="@android:style/Widget.DeviceDefault.Button.Borderless">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:minWidth">0dp</item>
+ </style>
+
+ <style
+ name="TextAppearance.NotificationFooterButton"
+ parent="@android:style/Widget.DeviceDefault.Button.Borderless">
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">14sp</item>
<item name="android:minWidth">0dp</item>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 584357b..0bd4859 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -1461,8 +1461,7 @@
mDragView.setColorFilter(filter);
}
- @VisibleForTesting
- void setBounceEffectDuration(int duration) {
+ private void setBounceEffectDuration(int duration) {
mBounceEffectDuration = duration;
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 06ec17f..f4a9f73 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -406,6 +406,10 @@
// TODO(b/301610137): Tracking bug
@JvmField val NEW_NETWORK_SLICE_UI = unreleasedFlag("new_network_slice_ui", teamfood = true)
+ // TODO(b/308138154): Tracking bug
+ val FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS =
+ releasedFlag("filter_provisioning_network_subscriptions")
+
// TODO(b/265892345): Tracking Bug
val PLUG_IN_STATUS_BAR_CHIP = releasedFlag("plug_in_status_bar_chip")
@@ -479,7 +483,7 @@
val MEDIA_REMOTE_RESUME = unreleasedFlag("media_remote_resume")
// TODO(b/304506662): Tracking Bug
- val MEDIA_DEVICE_NAME_FIX = unreleasedFlag("media_device_name_fix", teamfood = true)
+ val MEDIA_DEVICE_NAME_FIX = releasedFlag("media_device_name_fix")
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag("simulate_dock_through_charging")
@@ -618,7 +622,7 @@
/** TODO(b/295143676): Tracking bug. When enable, captures a screenshot for each display. */
@JvmField
- val MULTI_DISPLAY_SCREENSHOT = unreleasedFlag("multi_display_screenshot", teamfood = true)
+ val MULTI_DISPLAY_SCREENSHOT = releasedFlag("multi_display_screenshot")
// 1400 - columbus
// TODO(b/254512756): Tracking Bug
@@ -722,7 +726,7 @@
@JvmField val KEYBOARD_BACKLIGHT_INDICATOR = releasedFlag("keyboard_backlight_indicator")
// TODO(b/277192623): Tracking Bug
- @JvmField val KEYBOARD_EDUCATION = unreleasedFlag("keyboard_education", teamfood = true)
+ @JvmField val KEYBOARD_EDUCATION = releasedFlag("keyboard_education")
// TODO(b/277201412): Tracking Bug
@JvmField
@@ -768,7 +772,8 @@
@JvmField val PRECOMPUTED_TEXT = releasedFlag("precomputed_text")
// TODO(b/302087895): Tracking Bug
- @JvmField val CALL_LAYOUT_ASYNC_SET_DATA = unreleasedFlag("call_layout_async_set_data")
+ @JvmField val CALL_LAYOUT_ASYNC_SET_DATA =
+ unreleasedFlag("call_layout_async_set_data", teamfood = true)
// TODO(b/302144438): Tracking Bug
@JvmField val DECOUPLE_REMOTE_INPUT_DELEGATE_AND_CALLBACK_UPDATE =
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index aecfdaa..e768f16 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -91,7 +91,7 @@
@SysUISingleton
@NotifInflationLog
public static LogBuffer provideNotifInflationLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifInflationLog", 100);
+ return factory.create("NotifInflationLog", 250);
}
/** Provides a logging buffer for notification interruption calculations. */
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt
index 1962119..98a3896 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt
@@ -16,7 +16,6 @@
package com.android.systemui.mediaprojection
import android.media.projection.IMediaProjectionManager
-import android.os.Process
import android.os.RemoteException
import android.util.Log
import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_APP as METRICS_CREATION_SOURCE_APP
@@ -66,6 +65,19 @@
}
/**
+ * Request to log that the permission request was cancelled.
+ *
+ * @param hostUid The UID of the package that initiates MediaProjection.
+ */
+ fun notifyProjectionRequestCancelled(hostUid: Int) {
+ try {
+ service.notifyPermissionRequestCancelled(hostUid)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Error notifying server of projection cancelled", e)
+ }
+ }
+
+ /**
* Request to log that the app selector was displayed.
*
* @param hostUid The UID of the package that initiates MediaProjection.
@@ -78,47 +90,6 @@
}
}
- /**
- * Request to log that the permission request moved to the given state.
- *
- * Should not be used for the initialization state, since that should use {@link
- * MediaProjectionMetricsLogger#notifyProjectionInitiated(Int)} and pass the
- * sessionCreationSource.
- */
- fun notifyPermissionProgress(state: Int) {
- // TODO validate state is valid
- notifyToServer(state, SessionCreationSource.UNKNOWN)
- }
-
- /**
- * Notifies system server that we are handling a particular state during the consent flow.
- *
- * Only used for emitting atoms.
- *
- * @param state The state that SystemUI is handling during the consent flow. Must be a valid
- * state defined in the MediaProjectionState enum.
- * @param sessionCreationSource Only set if the state is MEDIA_PROJECTION_STATE_INITIATED.
- * Indicates the entry point for requesting the permission. Must be a valid state defined in
- * the SessionCreationSource enum.
- */
- private fun notifyToServer(state: Int, sessionCreationSource: SessionCreationSource) {
- Log.v(TAG, "FOO notifyToServer of state $state and source $sessionCreationSource")
- try {
- service.notifyPermissionRequestStateChange(
- Process.myUid(),
- state,
- sessionCreationSource.toMetricsConstant()
- )
- } catch (e: RemoteException) {
- Log.e(
- TAG,
- "Error notifying server of permission flow state $state from source " +
- "$sessionCreationSource",
- e
- )
- }
- }
-
companion object {
const val TAG = "MediaProjectionMetricsLogger"
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
index 04d5566..50e9e751 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
@@ -210,6 +210,10 @@
reviewGrantedConsentRequired,
/* projection= */ null
)
+ if (isFinishing) {
+ // Only log dismissed when actually finishing, and not when changing configuration.
+ controller.onSelectorDismissed()
+ }
}
activityLauncher.destroy()
controller.destroy()
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
index 67ef119..575e198 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
@@ -18,7 +18,6 @@
import android.content.ComponentName
import android.os.UserHandle
-import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED as STATE_APP_SELECTOR_DISPLAYED
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.mediaprojection.appselector.data.RecentTask
import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
@@ -76,6 +75,10 @@
scope.cancel()
}
+ fun onSelectorDismissed() {
+ logger.notifyProjectionRequestCancelled(hostUid)
+ }
+
private suspend fun refreshForegroundTaskThumbnails(tasks: List<RecentTask>) {
coroutineScope {
val thumbnails: List<Deferred<ThumbnailData?>> =
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
index 8b437c3..eea369f 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
@@ -32,6 +32,7 @@
import androidx.annotation.DrawableRes
import androidx.annotation.LayoutRes
import androidx.annotation.StringRes
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -40,16 +41,31 @@
context: Context,
private val screenShareOptions: List<ScreenShareOption>,
private val appName: String?,
+ private val hostUid: Int,
+ private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
@DrawableRes private val dialogIconDrawable: Int? = null,
- @ColorRes private val dialogIconTint: Int? = null
+ @ColorRes private val dialogIconTint: Int? = null,
) : SystemUIDialog(context), AdapterView.OnItemSelectedListener {
private lateinit var dialogTitle: TextView
private lateinit var startButton: TextView
private lateinit var cancelButton: TextView
private lateinit var warning: TextView
private lateinit var screenShareModeSpinner: Spinner
+ private var hasCancelBeenLogged: Boolean = false
var selectedScreenShareOption: ScreenShareOption = screenShareOptions.first()
+ override fun dismiss() {
+ super.dismiss()
+
+ // Dismiss can be called multiple times and we only want to log once.
+ if (hasCancelBeenLogged) {
+ return
+ }
+
+ mediaProjectionMetricsLogger.notifyProjectionRequestCancelled(hostUid)
+ hasCancelBeenLogged = true
+ }
+
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index f7cc589..eacfa57 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -222,13 +222,19 @@
// the correct screen width when in split screen.
Context dialogContext = getApplicationContext();
if (isPartialScreenSharingEnabled()) {
- mDialog = new MediaProjectionPermissionDialog(dialogContext, getMediaProjectionConfig(),
+ mDialog = new MediaProjectionPermissionDialog(
+ dialogContext,
+ getMediaProjectionConfig(),
() -> {
MediaProjectionPermissionDialog dialog =
(MediaProjectionPermissionDialog) mDialog;
ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption();
grantMediaProjectionPermission(selectedOption.getMode());
- }, () -> finish(RECORD_CANCEL, /* projection= */ null), appName);
+ },
+ () -> finish(RECORD_CANCEL, /* projection= */ null),
+ appName,
+ mUid,
+ mMediaProjectionMetricsLogger);
} else {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(dialogContext,
R.style.Theme_SystemUI_Dialog)
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
index b9bafd4..cff22b0 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.media.projection.MediaProjectionConfig
import android.os.Bundle
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.res.R
/** Dialog to select screen recording options */
@@ -26,12 +27,16 @@
mediaProjectionConfig: MediaProjectionConfig?,
private val onStartRecordingClicked: Runnable,
private val onCancelClicked: Runnable,
- private val appName: String?
+ private val appName: String?,
+ hostUid: Int,
+ mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
) :
BaseScreenSharePermissionDialog(
context,
createOptionList(context, appName, mediaProjectionConfig),
- appName
+ appName,
+ hostUid,
+ mediaProjectionMetricsLogger
) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
index 4096226..7b4b557 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
@@ -78,7 +78,10 @@
super.onCreate(savedInstanceState)
uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN)
- setContentView(LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null))
+ LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null).apply {
+ accessibilityPaneTitle = context.getText(R.string.accessibility_desc_quick_settings)
+ setContentView(this)
+ }
toggleView = requireViewById(R.id.bluetooth_toggle)
subtitleTextView = requireViewById(R.id.bluetooth_tile_dialog_subtitle) as TextView
@@ -114,14 +117,22 @@
}
internal fun onBluetoothStateUpdated(isEnabled: Boolean, subtitleResId: Int) {
- toggleView.isChecked = isEnabled
+ toggleView.apply {
+ isChecked = isEnabled
+ setEnabled(true)
+ alpha = ENABLED_ALPHA
+ }
subtitleTextView.text = context.getString(subtitleResId)
}
private fun setupToggle() {
toggleView.isChecked = bluetoothToggleInitialValue
- toggleView.setOnCheckedChangeListener { _, isChecked ->
+ toggleView.setOnCheckedChangeListener { view, isChecked ->
mutableBluetoothStateToggle.value = isChecked
+ view.apply {
+ isEnabled = false
+ alpha = DISABLED_ALPHA
+ }
logger.logBluetoothState(BluetoothStateStage.USER_TOGGLED, isChecked.toString())
uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TOGGLE_CLICKED)
}
@@ -225,5 +236,7 @@
const val ACTION_PREVIOUSLY_CONNECTED_DEVICE =
"com.android.settings.PREVIOUSLY_CONNECTED_DEVICE"
const val ACTION_PAIR_NEW_DEVICE = "android.settings.BLUETOOTH_PAIRING_SETTINGS"
+ const val DISABLED_ALPHA = 0.3f
+ const val ENABLED_ALPHA = 1f
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index ea1205a..05f125f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -163,8 +163,7 @@
}
mMediaProjectionMetricsLogger.notifyProjectionInitiated(
- mUserContextProvider.getUserContext().getUserId(),
- SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
+ getHostUid(), SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
return flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)
? new ScreenRecordPermissionDialog(
@@ -174,7 +173,8 @@
/* controller= */ this,
activityStarter,
mUserContextProvider,
- onStartRecordingClicked)
+ onStartRecordingClicked,
+ mMediaProjectionMetricsLogger)
: new ScreenRecordDialog(
context,
/* controller= */ this,
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index f2e94e9..e7481cc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -66,8 +66,10 @@
private Switch mAudioSwitch;
private Spinner mOptions;
- public ScreenRecordDialog(Context context, RecordingController controller,
- UserContextProvider userContextProvider, @Nullable Runnable onStartRecordingClicked) {
+ public ScreenRecordDialog(Context context,
+ RecordingController controller,
+ UserContextProvider userContextProvider,
+ @Nullable Runnable onStartRecordingClicked) {
super(context);
mController = controller;
mUserContextProvider = userContextProvider;
@@ -89,7 +91,6 @@
TextView cancelBtn = findViewById(R.id.button_cancel);
cancelBtn.setOnClickListener(v -> dismiss());
-
TextView startBtn = findViewById(R.id.button_start);
startBtn.setOnClickListener(v -> {
if (mOnStartRecordingClicked != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
index 3b3aa53..f74234b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -33,6 +33,7 @@
import android.widget.Switch
import androidx.annotation.LayoutRes
import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity
import com.android.systemui.mediaprojection.permission.BaseScreenSharePermissionDialog
import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN
@@ -50,12 +51,15 @@
private val controller: RecordingController,
private val activityStarter: ActivityStarter,
private val userContextProvider: UserContextProvider,
- private val onStartRecordingClicked: Runnable?
+ private val onStartRecordingClicked: Runnable?,
+ mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
) :
BaseScreenSharePermissionDialog(
context,
createOptionList(),
appName = null,
+ hostUid = hostUid,
+ mediaProjectionMetricsLogger,
R.drawable.ic_screenrecord,
R.color.screenrecord_icon_color
) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 33c42e0..ab015ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -72,10 +72,10 @@
return findViewById(R.id.no_notifications_footer);
}
- public void setTextColor(@ColorInt int color) {
- mEmptyText.setTextColor(color);
- mEmptyFooterText.setTextColor(color);
- mEmptyFooterText.setCompoundDrawableTintList(ColorStateList.valueOf(color));
+ public void setTextColors(@ColorInt int onSurface, @ColorInt int onSurfaceVariant) {
+ mEmptyText.setTextColor(onSurfaceVariant);
+ mEmptyFooterText.setTextColor(onSurface);
+ mEmptyFooterText.setCompoundDrawableTintList(ColorStateList.valueOf(onSurface));
}
public void setText(@StringRes int text) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index ba91654..9c51e3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -234,26 +234,24 @@
*/
public void updateColors() {
Resources.Theme theme = mContext.getTheme();
- final @ColorInt int textColor = getResources().getColor(R.color.notif_pill_text, theme);
+ final @ColorInt int onSurface = Utils.getColorAttrDefaultColor(mContext,
+ com.android.internal.R.attr.materialColorOnSurface);
+ final @ColorInt int scHigh = Utils.getColorAttrDefaultColor(mContext,
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh);
final Drawable clearAllBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
final Drawable manageBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
// TODO(b/282173943): Remove redundant tinting once Resources are thread-safe
- final @ColorInt int buttonBgColor =
- Utils.getColorAttrDefaultColor(mContext, com.android.internal.R.attr.colorSurface);
- final ColorFilter bgColorFilter = new PorterDuffColorFilter(buttonBgColor, SRC_ATOP);
- if (buttonBgColor != 0) {
+ final ColorFilter bgColorFilter = new PorterDuffColorFilter(scHigh, SRC_ATOP);
+ if (scHigh != 0) {
clearAllBg.setColorFilter(bgColorFilter);
manageBg.setColorFilter(bgColorFilter);
}
mClearAllButton.setBackground(clearAllBg);
- mClearAllButton.setTextColor(textColor);
+ mClearAllButton.setTextColor(onSurface);
mManageButton.setBackground(manageBg);
- mManageButton.setTextColor(textColor);
- final @ColorInt int labelTextColor =
- Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
- mSeenNotifsFooterTextView.setTextColor(labelTextColor);
- mSeenNotifsFooterTextView.setCompoundDrawableTintList(
- ColorStateList.valueOf(labelTextColor));
+ mManageButton.setTextColor(onSurface);
+ mSeenNotifsFooterTextView.setTextColor(onSurface);
+ mSeenNotifsFooterTextView.setCompoundDrawableTintList(ColorStateList.valueOf(onSurface));
}
private void updateResources() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
new file mode 100644
index 0000000..4ef80e3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.interruption
+
+import com.android.internal.logging.UiEventLogger.UiEventEnum
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+
+/**
+ * A reason why visual interruptions might be suppressed.
+ *
+ * @see VisualInterruptionCondition
+ * @see VisualInterruptionFilter
+ */
+enum class VisualInterruptionType {
+ /* HUN when awake */
+ PEEK,
+
+ /* HUN when dozing */
+ PULSE,
+
+ /* Bubble */
+ BUBBLE
+}
+
+/**
+ * A reason why visual interruptions might be suppressed.
+ *
+ * @see VisualInterruptionCondition
+ * @see VisualInterruptionFilter
+ */
+sealed interface VisualInterruptionSuppressor {
+ /** The type(s) of interruption that this suppresses. */
+ val types: Set<VisualInterruptionType>
+
+ /** A human-readable string to be logged to explain why this suppressed an interruption. */
+ val reason: String
+
+ /** An optional UiEvent ID to be recorded when this suppresses an interruption. */
+ val uiEventId: UiEventEnum?
+}
+
+/** A reason why visual interruptions might be suppressed regardless of the notification. */
+abstract class VisualInterruptionCondition(
+ override val types: Set<VisualInterruptionType>,
+ override val reason: String,
+ override val uiEventId: UiEventEnum? = null
+) : VisualInterruptionSuppressor {
+ /** @return true if these interruptions should be suppressed right now. */
+ abstract fun shouldSuppress(): Boolean
+}
+
+/** A reason why visual interruptions might be suppressed based on the notification. */
+abstract class VisualInterruptionFilter(
+ override val types: Set<VisualInterruptionType>,
+ override val reason: String,
+ override val uiEventId: UiEventEnum? = null
+) : VisualInterruptionSuppressor {
+ /**
+ * @param entry the notification to consider suppressing
+ * @return true if these interruptions should be suppressed for this notification right now
+ */
+ abstract fun shouldSuppress(entry: NotificationEntry): Boolean
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 661768d..8f1e59d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -121,7 +121,7 @@
private void updateColors() {
mNormalColor = Utils.getColorAttrDefaultColor(mContext,
- com.android.internal.R.attr.colorSurface);
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh);
mTintedRippleColor = mContext.getColor(
R.color.notification_ripple_tinted_color);
mNormalRippleColor = mContext.getColor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
index 892a635..da8c4dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
@@ -28,7 +28,6 @@
import androidx.annotation.ColorInt;
-import com.android.internal.util.ContrastColorUtil;
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.CrossFadeHelper;
@@ -98,8 +97,8 @@
private void resolveThemeTextColors() {
try (TypedArray ta = mContext.getTheme().obtainStyledAttributes(
android.R.style.Theme_DeviceDefault_DayNight, new int[]{
- android.R.attr.textColorPrimary,
- android.R.attr.textColorSecondary
+ com.android.internal.R.attr.materialColorOnSurface,
+ com.android.internal.R.attr.materialColorOnSurfaceVariant
})) {
if (ta != null) {
mPrimaryTextColor = ta.getColor(0, mPrimaryTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 62b268b..14593cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -65,10 +65,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.notification.ConversationIconFactory;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
+import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -336,10 +336,11 @@
Drawable person = mIconFactory.getBaseIconDrawable(mShortcutInfo);
if (person == null) {
person = mContext.getDrawable(R.drawable.ic_person).mutate();
- TypedArray ta = mContext.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
- int colorAccent = ta.getColor(0, 0);
+ TypedArray ta = mContext.obtainStyledAttributes(
+ new int[]{com.android.internal.R.attr.materialColorPrimary});
+ int colorPrimary = ta.getColor(0, 0);
ta.recycle();
- person.setTint(colorAccent);
+ person.setTint(colorPrimary);
}
ImageView image = findViewById(R.id.conversation_icon);
image.setImageDrawable(person);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index ff5b9cb..cdf178e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -326,7 +326,8 @@
if (customBackgroundColor != 0) {
return customBackgroundColor;
}
- return Utils.getColorAttr(mView.getContext(), android.R.attr.colorBackground)
+ return Utils.getColorAttr(mView.getContext(),
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh)
.getDefaultColor();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index a929e4f..0236fc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1362,7 +1362,7 @@
Resources.Theme theme = new ContextThemeWrapper(mContext,
com.android.internal.R.style.Theme_DeviceDefault_DayNight).getTheme();
try (TypedArray ta = theme.obtainStyledAttributes(
- new int[]{com.android.internal.R.attr.colorAccent})) {
+ new int[]{com.android.internal.R.attr.materialColorPrimary})) {
color = ta.getColor(0, color);
}
mHybridGroupManager.setOverflowNumberColor(mOverflowNumber, color);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index fd064ee..cfc433a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -244,10 +244,10 @@
}
}
- fun setHeaderForegroundColor(@ColorInt color: Int) {
- peopleHeaderView?.setForegroundColor(color)
- silentHeaderView?.setForegroundColor(color)
- alertingHeaderView?.setForegroundColor(color)
+ fun setHeaderForegroundColors(@ColorInt onSurface: Int, @ColorInt onSurfaceVariant: Int) {
+ peopleHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ silentHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ alertingHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1e9cfa8..8babcc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -344,7 +344,7 @@
private boolean mAnimateNextBackgroundTop;
private boolean mAnimateNextBackgroundBottom;
private boolean mAnimateNextSectionBoundsChange;
- private int mBgColor;
+ private @ColorInt int mBgColor;
private float mDimAmount;
private ValueAnimator mDimAnimator;
private final ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
@@ -647,8 +647,8 @@
mSections = mSectionsManager.createSectionsForBuckets();
mAmbientState = Dependency.get(AmbientState.class);
- mBgColor = Utils.getColorAttr(mContext, android.R.attr.colorBackgroundFloating)
- .getDefaultColor();
+ mBgColor = Utils.getColorAttr(mContext,
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh).getDefaultColor();
int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
mSplitShadeMinContentHeight = res.getDimensionPixelSize(
@@ -790,8 +790,8 @@
}
void updateBgColor() {
- mBgColor = Utils.getColorAttr(mContext, android.R.attr.colorBackgroundFloating)
- .getDefaultColor();
+ mBgColor = Utils.getColorAttr(mContext,
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh).getDefaultColor();
updateBackgroundDimming();
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
@@ -4421,14 +4421,19 @@
}
/**
- * Update colors of "dismiss" and "empty shade" views.
+ * Update colors of section headers, shade footer, and empty shade views.
*/
void updateDecorViews() {
- final @ColorInt int textColor =
- Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
- mSectionsManager.setHeaderForegroundColor(textColor);
+ final @ColorInt int onSurface = Utils.getColorAttrDefaultColor(
+ mContext, com.android.internal.R.attr.materialColorOnSurface);
+ final @ColorInt int onSurfaceVariant = Utils.getColorAttrDefaultColor(
+ mContext, com.android.internal.R.attr.materialColorOnSurfaceVariant);
+
+ mSectionsManager.setHeaderForegroundColors(onSurface, onSurfaceVariant);
+
mFooterView.updateColors();
- mEmptyShadeView.setTextColor(textColor);
+
+ mEmptyShadeView.setTextColors(onSurface, onSurfaceVariant);
}
void goToFullShade(long delay) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index 722c28c..5c1149b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -132,8 +132,8 @@
mLabelView.setText(resId);
}
- void setForegroundColor(@ColorInt int color) {
- mLabelView.setTextColor(color);
- mClearAllButton.setImageTintList(ColorStateList.valueOf(color));
+ void setForegroundColors(@ColorInt int onSurface, @ColorInt int onSurfaceVariant) {
+ mLabelView.setTextColor(onSurface);
+ mClearAllButton.setImageTintList(ColorStateList.valueOf(onSurfaceVariant));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 744d70e..3e753a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1505,8 +1505,9 @@
private void updateThemeColors() {
if (mScrimBehind == null) return;
int background = Utils.getColorAttr(mScrimBehind.getContext(),
- android.R.attr.colorBackgroundFloating).getDefaultColor();
- int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
+ com.android.internal.R.attr.materialColorSurfaceDim).getDefaultColor();
+ int accent = Utils.getColorAttr(mScrimBehind.getContext(),
+ com.android.internal.R.attr.materialColorPrimary).getDefaultColor();
mColors.setMainColor(background);
mColors.setSecondaryColor(accent);
final boolean isBackgroundLight = !ContrastColorUtil.isColorDark(background);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
index a033e1d..66ac17e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
@@ -20,6 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.annotation.ColorInt;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
@@ -28,6 +29,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.settingslib.Utils;
import com.android.systemui.res.R;
import com.android.wm.shell.animation.Interpolators;
@@ -49,8 +51,9 @@
}
void updateColor() {
- int textColor = getResources().getColor(R.color.notif_pill_text, mContext.getTheme());
- setTextColor(textColor);
+ final @ColorInt int onSurface = Utils.getColorAttrDefaultColor(mContext,
+ com.android.internal.R.attr.materialColorOnSurface);
+ setTextColor(onSurface);
setBackground(getResources().getDrawable(R.drawable.rounded_bg_full, mContext.getTheme()));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
index 27f6df4..d9d909a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.model
import android.os.ParcelUuid
+import android.telephony.SubscriptionManager.ProfileClass
/**
* SystemUI representation of [SubscriptionInfo]. Currently we only use two fields on the
@@ -37,4 +38,7 @@
/** Text representing the name for this connection */
val carrierName: String,
+
+ /** Allow us to filter out PROVISIONING profiles. See [SubscriptionInfo.getProfileClass] */
+ @ProfileClass val profileClass: Int
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index c7987e2..205dc1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.util.Log
import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.MobileMappings
@@ -96,6 +97,7 @@
subscriptionId = subId,
isOpportunistic = false,
carrierName = DEFAULT_CARRIER_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
)
.also { subscriptionInfoCache[subId] = it }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index ecb80f2..2caf33b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -408,6 +408,7 @@
isOpportunistic = isOpportunistic,
groupUuid = groupUuid,
carrierName = carrierName.toString(),
+ profileClass = profileClass,
)
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 62150e9..dad4093 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -19,10 +19,13 @@
import android.content.Context
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
@@ -121,6 +124,7 @@
userSetupRepo: UserSetupRepository,
@Application private val scope: CoroutineScope,
private val context: Context,
+ private val featureFlagsClassic: FeatureFlagsClassic,
) : MobileIconsInteractor {
// Weak reference lookup for created interactors
@@ -163,6 +167,20 @@
mobileConnectionsRepo.subscriptions
/**
+ * Any filtering that we can do based purely on the info of each subscription. Currently this
+ * only applies the ProfileClass-based filter, but if we need other they can go here
+ */
+ private val subscriptionsBasedFilteredSubs =
+ unfilteredSubscriptions.map { subs -> applyProvisioningFilter(subs) }.distinctUntilChanged()
+
+ private fun applyProvisioningFilter(subs: List<SubscriptionModel>): List<SubscriptionModel> =
+ if (!featureFlagsClassic.isEnabled(FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS)) {
+ subs
+ } else {
+ subs.filter { it.profileClass != PROFILE_CLASS_PROVISIONING }
+ }
+
+ /**
* Generally, SystemUI wants to show iconography for each subscription that is listed by
* [SubscriptionManager]. However, in the case of opportunistic subscriptions, we want to only
* show a single representation of the pair of subscriptions. The docs define opportunistic as:
@@ -177,48 +195,15 @@
*/
override val filteredSubscriptions: Flow<List<SubscriptionModel>> =
combine(
- unfilteredSubscriptions,
+ subscriptionsBasedFilteredSubs,
mobileConnectionsRepo.activeMobileDataSubscriptionId,
connectivityRepository.vcnSubId,
) { unfilteredSubs, activeId, vcnSubId ->
- // Based on the old logic,
- if (unfilteredSubs.size != 2) {
- return@combine unfilteredSubs
- }
-
- val info1 = unfilteredSubs[0]
- val info2 = unfilteredSubs[1]
-
- // Filtering only applies to subscriptions in the same group
- if (info1.groupUuid == null || info1.groupUuid != info2.groupUuid) {
- return@combine unfilteredSubs
- }
-
- // If both subscriptions are primary, show both
- if (!info1.isOpportunistic && !info2.isOpportunistic) {
- return@combine unfilteredSubs
- }
-
- // NOTE: at this point, we are now returning a single SubscriptionInfo
-
- // If carrier required, always show the icon of the primary subscription.
- // Otherwise, show whichever subscription is currently active for internet.
- if (carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) {
- // return the non-opportunistic info
- return@combine if (info1.isOpportunistic) listOf(info2) else listOf(info1)
- } else {
- // It's possible for the subId of the VCN to disagree with the active subId in
- // cases where the system has tried to switch but found no connection. In these
- // scenarios, VCN will always have the subId that we want to use, so use that
- // value instead of the activeId reported by telephony
- val subIdToKeep = vcnSubId ?: activeId
-
- return@combine if (info1.subscriptionId == subIdToKeep) {
- listOf(info1)
- } else {
- listOf(info2)
- }
- }
+ filterSubsBasedOnOpportunistic(
+ unfilteredSubs,
+ activeId,
+ vcnSubId,
+ )
}
.distinctUntilChanged()
.logDiffsForTable(
@@ -229,6 +214,51 @@
)
.stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
+ private fun filterSubsBasedOnOpportunistic(
+ subList: List<SubscriptionModel>,
+ activeId: Int?,
+ vcnSubId: Int?,
+ ): List<SubscriptionModel> {
+ // Based on the old logic,
+ if (subList.size != 2) {
+ return subList
+ }
+
+ val info1 = subList[0]
+ val info2 = subList[1]
+
+ // Filtering only applies to subscriptions in the same group
+ if (info1.groupUuid == null || info1.groupUuid != info2.groupUuid) {
+ return subList
+ }
+
+ // If both subscriptions are primary, show both
+ if (!info1.isOpportunistic && !info2.isOpportunistic) {
+ return subList
+ }
+
+ // NOTE: at this point, we are now returning a single SubscriptionInfo
+
+ // If carrier required, always show the icon of the primary subscription.
+ // Otherwise, show whichever subscription is currently active for internet.
+ if (carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) {
+ // return the non-opportunistic info
+ return if (info1.isOpportunistic) listOf(info2) else listOf(info1)
+ } else {
+ // It's possible for the subId of the VCN to disagree with the active subId in
+ // cases where the system has tried to switch but found no connection. In these
+ // scenarios, VCN will always have the subId that we want to use, so use that
+ // value instead of the activeId reported by telephony
+ val subIdToKeep = vcnSubId ?: activeId
+
+ return if (info1.subscriptionId == subIdToKeep) {
+ listOf(info1)
+ } else {
+ listOf(info2)
+ }
+ }
+ }
+
/**
* Copied from the old pipeline. We maintain a 2s period of time where we will keep the
* validated bit from the old active network (A) while data is changing to the new one (B).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index ceed81a..4864fb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -130,7 +130,7 @@
private ImageView mDelete;
private ImageView mDeleteBg;
private boolean mColorized;
- private int mTint;
+ private int mLastBackgroundColor;
private boolean mResetting;
@Nullable
private RevealParams mRevealParams;
@@ -181,10 +181,9 @@
mEditorActionHandler = new EditorActionHandler();
mUiEventLogger = Dependency.get(UiEventLogger.class);
TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{
- com.android.internal.R.attr.colorAccent,
- com.android.internal.R.attr.colorSurface,
+ com.android.internal.R.attr.materialColorSurfaceDim,
});
- mTint = ta.getColor(0, 0);
+ mLastBackgroundColor = ta.getColor(0, 0);
ta.recycle();
}
@@ -210,9 +209,9 @@
* @param backgroundColor colorized notification color
*/
public void setBackgroundTintColor(final int backgroundColor, boolean colorized) {
- if (colorized == mColorized && backgroundColor == mTint) return;
+ if (colorized == mColorized && backgroundColor == mLastBackgroundColor) return;
mColorized = colorized;
- mTint = backgroundColor;
+ mLastBackgroundColor = backgroundColor;
final int editBgColor;
final int deleteBgColor;
final int deleteFgColor;
@@ -237,8 +236,8 @@
hintColor = mContext.getColor(R.color.remote_input_hint);
deleteFgColor = textColor.getDefaultColor();
try (TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{
- com.android.internal.R.attr.colorSurfaceHighlight,
- com.android.internal.R.attr.colorSurfaceVariant
+ com.android.internal.R.attr.materialColorSurfaceDim,
+ com.android.internal.R.attr.materialColorSurfaceVariant
})) {
editBgColor = ta.getColor(0, backgroundColor);
deleteBgColor = ta.getColor(1, Color.GRAY);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 0ff308e..280c66a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -99,7 +99,6 @@
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -256,7 +255,6 @@
private CaptionsToggleImageButton mODICaptionsIcon;
private View mSettingsView;
private ImageButton mSettingsIcon;
- private FrameLayout mZenIcon;
private final List<VolumeRow> mRows = new ArrayList<>();
private ConfigurableTexts mConfigurableTexts;
private final SparseBooleanArray mDynamic = new SparseBooleanArray();
@@ -633,7 +631,6 @@
mRinger = mDialog.findViewById(R.id.ringer);
if (mRinger != null) {
mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
- mZenIcon = mRinger.findViewById(R.id.dnd_icon);
}
mSelectedRingerIcon = mDialog.findViewById(R.id.volume_new_ringer_active_icon);
@@ -847,7 +844,6 @@
if (stream == STREAM_ACCESSIBILITY) {
row.header.setFilters(new InputFilter[] {new InputFilter.LengthFilter(13)});
}
- row.dndIcon = row.view.findViewById(R.id.dnd_icon);
row.slider = row.view.findViewById(R.id.volume_row_slider);
row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
row.number = row.view.findViewById(R.id.volume_number);
@@ -1791,27 +1787,13 @@
}
/**
- * Toggles enable state of views in a VolumeRow (not including seekbar or icon)
- * Hides/shows zen icon
- * @param enable whether to enable volume row views and hide dnd icon
- */
- private void enableVolumeRowViewsH(VolumeRow row, boolean enable) {
- boolean showDndIcon = !enable;
- row.dndIcon.setVisibility(showDndIcon ? VISIBLE : GONE);
- }
-
- /**
* Toggles enable state of footer/ringer views
- * Hides/shows zen icon
- * @param enable whether to enable ringer views and hide dnd icon
+ * @param enable whether to enable ringer views
*/
private void enableRingerViewsH(boolean enable) {
if (mRingerIcon != null) {
mRingerIcon.setEnabled(enable);
}
- if (mZenIcon != null) {
- mZenIcon.setVisibility(enable ? GONE : VISIBLE);
- }
}
private void trimObsoleteH() {
@@ -1937,9 +1919,11 @@
// update icon
final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted;
final int iconRes;
- if (isRingVibrate) {
+ if (zenMuted) {
+ iconRes = com.android.internal.R.drawable.ic_qs_dnd;
+ } else if (isRingVibrate) {
iconRes = R.drawable.ic_volume_ringer_vibrate;
- } else if (isRingSilent || zenMuted) {
+ } else if (isRingSilent) {
iconRes = row.iconMuteRes;
} else if (ss.routedToBluetooth) {
if (isVoiceCallStream) {
@@ -2011,7 +1995,6 @@
if (zenMuted) {
row.tracking = false;
}
- enableVolumeRowViewsH(row, !zenMuted);
// update slider
final boolean enableSlider = !zenMuted;
@@ -2582,7 +2565,6 @@
private ObjectAnimator anim; // slider progress animation for non-touch-related updates
private int animTargetProgress;
private int lastAudibleLevel = 1;
- private FrameLayout dndIcon;
void setIcon(int iconRes, Resources.Theme theme) {
if (icon != null) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
index ac40ba6..603d548 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -21,7 +21,6 @@
import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.flags.Flags.MIGRATE_KEYGUARD_STATUS_VIEW;
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
@@ -58,7 +57,6 @@
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore;
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
@@ -144,7 +142,6 @@
public void setup() {
MockitoAnnotations.initMocks(this);
- setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
mFakeDateView.setTag(R.id.tag_smartspace_view, new Object());
mFakeWeatherView.setTag(R.id.tag_smartspace_view, new Object());
mFakeSmartspaceView.setTag(R.id.tag_smartspace_view, new Object());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MockMagnificationAnimationCallback.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MockMagnificationAnimationCallback.java
deleted file mode 100644
index 89389b0..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MockMagnificationAnimationCallback.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.accessibility;
-
-import android.os.RemoteException;
-import android.view.accessibility.IRemoteMagnificationAnimationCallback;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class MockMagnificationAnimationCallback extends IRemoteMagnificationAnimationCallback.Stub {
-
- private final CountDownLatch mCountDownLatch;
- private final AtomicInteger mSuccessCount;
- private final AtomicInteger mFailedCount;
-
- MockMagnificationAnimationCallback(CountDownLatch countDownLatch) {
- mCountDownLatch = countDownLatch;
- mSuccessCount = new AtomicInteger();
- mFailedCount = new AtomicInteger();
- }
-
- public int getSuccessCount() {
- return mSuccessCount.get();
- }
-
- public int getFailedCount() {
- return mFailedCount.get();
- }
-
- @Override
- public void onResult(boolean success) throws RemoteException {
- if (success) {
- mSuccessCount.getAndIncrement();
- } else {
- mFailedCount.getAndIncrement();
- }
- // It should be put at the last line to avoid making CountDownLatch#await passed without
- // updating values.
- mCountDownLatch.countDown();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index f15164e..284c273 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -35,7 +35,6 @@
import android.os.Handler;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
@@ -68,7 +67,6 @@
@LargeTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
@Rule
@@ -135,7 +133,9 @@
@After
public void tearDown() throws Exception {
- mController.deleteWindowMagnification();
+ mInstrumentation.runOnMainSync(() -> {
+ mController.deleteWindowMagnification();
+ });
}
@Test
@@ -170,8 +170,7 @@
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY, null);
+ enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY);
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
}
@@ -179,10 +178,11 @@
@Test
public void enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback()
throws RemoteException {
- mWindowMagnificationAnimationController.enableWindowMagnification(1,
+ enableWindowMagnificationAndWaitAnimating(
+ mWaitAnimationDuration, /* targetScale= */ 1.0f,
DEFAULT_CENTER_X, DEFAULT_CENTER_Y, mAnimationCallback);
- verify(mSpyController).enableWindowMagnificationInternal(1, DEFAULT_CENTER_X,
+ verify(mSpyController).enableWindowMagnificationInternal(1.0f, DEFAULT_CENTER_X,
DEFAULT_CENTER_Y, 0f, 0f);
verify(mAnimationCallback).onResult(true);
}
@@ -196,13 +196,15 @@
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
- Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY, mAnimationCallback2);
- mCurrentScale.set(mController.getScale());
- mCurrentCenterX.set(mController.getCenterX());
- mCurrentCenterY.set(mController.getCenterY());
- advanceTimeBy(mWaitAnimationDuration);
+ resetMockObjects();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY, mAnimationCallback2);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ advanceTimeBy(mWaitAnimationDuration);
+ });
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
mScaleCaptor.capture(),
@@ -224,9 +226,8 @@
enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
mAnimationCallback);
- mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
+ enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, Float.NaN,
Float.NaN, Float.NaN, mAnimationCallback2);
- advanceTimeBy(mWaitAnimationDuration);
// The callback in 2nd enableWindowMagnification will return true
verify(mAnimationCallback2).onResult(true);
@@ -245,12 +246,14 @@
final float targetCenterY = DEFAULT_CENTER_Y + 100;
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY, mAnimationCallback);
- mCurrentScale.set(mController.getScale());
- mCurrentCenterX.set(mController.getCenterX());
- mCurrentCenterY.set(mController.getCenterY());
- advanceTimeBy(mWaitAnimationDuration);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY, mAnimationCallback);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ advanceTimeBy(mWaitAnimationDuration);
+ });
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
mScaleCaptor.capture(),
@@ -279,12 +282,14 @@
final float targetCenterY = DEFAULT_CENTER_Y + 100;
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY, mAnimationCallback);
- mCurrentScale.set(mController.getScale());
- mCurrentCenterX.set(mController.getCenterX());
- mCurrentCenterY.set(mController.getCenterY());
- advanceTimeBy(mWaitAnimationDuration);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY, mAnimationCallback);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ advanceTimeBy(mWaitAnimationDuration);
+ });
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
mScaleCaptor.capture(),
@@ -314,8 +319,7 @@
final float targetCenterY = DEFAULT_CENTER_Y + 100;
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY, null);
+ enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY);
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
assertEquals(WindowMagnificationAnimationController.STATE_DISABLED,
@@ -333,8 +337,7 @@
final float targetCenterY = DEFAULT_CENTER_Y + 100;
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY, null);
+ enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY);
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
verify(mAnimationCallback).onResult(false);
@@ -347,9 +350,8 @@
mAnimationCallback);
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
- Float.NaN, Float.NaN, mAnimationCallback2);
- advanceTimeBy(mWaitAnimationDuration);
+ enableWindowMagnificationAndWaitAnimating(
+ mWaitAnimationDuration, Float.NaN, Float.NaN, Float.NaN, mAnimationCallback2);
verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
anyFloat());
@@ -368,20 +370,25 @@
final float targetCenterY = DEFAULT_CENTER_Y + 100;
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY, mAnimationCallback2);
- mCurrentScale.set(mController.getScale());
- mCurrentCenterX.set(mController.getCenterX());
- mCurrentCenterY.set(mController.getCenterY());
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY, mAnimationCallback2);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ });
// Current spec shouldn't match given spec.
verify(mAnimationCallback2, never()).onResult(anyBoolean());
verify(mAnimationCallback).onResult(false);
- // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it is
- // using SystemClock in reverse() (b/305731398). Therefore, we call end() on the animator
- // directly to verify the result of animation is correct instead of querying the animation
- // frame at a specific timing.
- mValueAnimator.end();
+
+ mInstrumentation.runOnMainSync(() -> {
+ // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it
+ // is using SystemClock in reverse() (b/305731398). Therefore, we call end() on the
+ // animator directly to verify the result of animation is correct instead of querying
+ // the animation frame at a specific timing.
+ mValueAnimator.end();
+ });
verify(mSpyController).enableWindowMagnificationInternal(
mScaleCaptor.capture(),
@@ -410,8 +417,7 @@
final float targetCenterY = DEFAULT_CENTER_Y + 100;
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY, null);
+ enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY);
verify(mAnimationCallback).onResult(false);
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
@@ -425,9 +431,8 @@
mAnimationCallback);
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
+ enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, Float.NaN,
Float.NaN, Float.NaN, mAnimationCallback2);
- advanceTimeBy(mWaitAnimationDuration);
verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
anyFloat());
@@ -445,12 +450,14 @@
final float targetCenterY = DEFAULT_CENTER_Y + 100;
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY, mAnimationCallback2);
- mCurrentScale.set(mController.getScale());
- mCurrentCenterX.set(mController.getCenterX());
- mCurrentCenterY.set(mController.getCenterY());
- advanceTimeBy(mWaitAnimationDuration);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY, mAnimationCallback2);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ advanceTimeBy(mWaitAnimationDuration);
+ });
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
mScaleCaptor.capture(),
@@ -471,25 +478,26 @@
final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
- windowBounds.exactCenterX(), windowBounds.exactCenterY(),
- offsetRatio, offsetRatio, mAnimationCallback);
- advanceTimeBy(mWaitAnimationDuration);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
+ windowBounds.exactCenterX(), windowBounds.exactCenterY(),
+ offsetRatio, offsetRatio, mAnimationCallback);
+ advanceTimeBy(mWaitAnimationDuration);
+ });
- // We delay the time of verifying to wait for the measurement and layout of the view
- mHandler.postDelayed(() -> {
- final View attachedView = mWindowManager.getAttachedView();
- assertNotNull(attachedView);
- final Rect mirrorViewBound = new Rect();
- final View mirrorView = attachedView.findViewById(R.id.surface_view);
- assertNotNull(mirrorView);
- mirrorView.getBoundsOnScreen(mirrorViewBound);
+ // Wait for Rects update
+ waitForIdleSync();
+ final View attachedView = mWindowManager.getAttachedView();
+ assertNotNull(attachedView);
+ final Rect mirrorViewBound = new Rect();
+ final View mirrorView = attachedView.findViewById(R.id.surface_view);
+ assertNotNull(mirrorView);
+ mirrorView.getBoundsOnScreen(mirrorViewBound);
- assertEquals((int) (offsetRatio * mirrorViewBound.width() / 2),
- (int) (mirrorViewBound.exactCenterX() - windowBounds.exactCenterX()));
- assertEquals((int) (offsetRatio * mirrorViewBound.height() / 2),
- (int) (mirrorViewBound.exactCenterY() - windowBounds.exactCenterY()));
- }, 100);
+ assertEquals((int) (offsetRatio * mirrorViewBound.width() / 2),
+ (int) (mirrorViewBound.exactCenterX() - windowBounds.exactCenterX()));
+ assertEquals((int) (offsetRatio * mirrorViewBound.height() / 2),
+ (int) (mirrorViewBound.exactCenterY() - windowBounds.exactCenterY()));
}
@Test
@@ -498,9 +506,11 @@
final float targetCenterY = DEFAULT_CENTER_Y + 100;
enableWindowMagnificationWithoutAnimation();
- mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
- targetCenterX, targetCenterY, mAnimationCallback);
- advanceTimeBy(mWaitAnimationDuration);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+ targetCenterX, targetCenterY, mAnimationCallback);
+ advanceTimeBy(mWaitAnimationDuration);
+ });
verify(mAnimationCallback).onResult(true);
verify(mAnimationCallback, never()).onResult(false);
@@ -512,15 +522,17 @@
throws RemoteException {
enableWindowMagnificationWithoutAnimation();
- mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
- DEFAULT_CENTER_X + 10, DEFAULT_CENTER_Y + 10, mAnimationCallback);
- mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
- DEFAULT_CENTER_X + 20, DEFAULT_CENTER_Y + 20, mAnimationCallback);
- mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
- DEFAULT_CENTER_X + 30, DEFAULT_CENTER_Y + 30, mAnimationCallback);
- mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
- DEFAULT_CENTER_X + 40, DEFAULT_CENTER_Y + 40, mAnimationCallback2);
- advanceTimeBy(mWaitAnimationDuration);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+ DEFAULT_CENTER_X + 10, DEFAULT_CENTER_Y + 10, mAnimationCallback);
+ mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+ DEFAULT_CENTER_X + 20, DEFAULT_CENTER_Y + 20, mAnimationCallback);
+ mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+ DEFAULT_CENTER_X + 30, DEFAULT_CENTER_Y + 30, mAnimationCallback);
+ mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+ DEFAULT_CENTER_X + 40, DEFAULT_CENTER_Y + 40, mAnimationCallback2);
+ advanceTimeBy(mWaitAnimationDuration);
+ });
// only the last one callback will return true
verify(mAnimationCallback2).onResult(true);
@@ -538,9 +550,11 @@
enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
mAnimationCallback);
- mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
- targetCenterX, targetCenterY, mAnimationCallback2);
- advanceTimeBy(mWaitAnimationDuration);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+ targetCenterX, targetCenterY, mAnimationCallback2);
+ advanceTimeBy(mWaitAnimationDuration);
+ });
// The callback in moveWindowMagnifierToPosition will return true
verify(mAnimationCallback2).onResult(true);
@@ -556,9 +570,11 @@
enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
mAnimationCallback);
- mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
- Float.NaN, Float.NaN, mAnimationCallback2);
- advanceTimeBy(mWaitAnimationDuration);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+ Float.NaN, Float.NaN, mAnimationCallback2);
+ advanceTimeBy(mWaitAnimationDuration);
+ });
// The callback in moveWindowMagnifierToPosition will return true
verify(mAnimationCallback2).onResult(true);
@@ -584,6 +600,7 @@
throws RemoteException {
enableWindowMagnificationWithoutAnimation();
+ resetMockObjects();
deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
@@ -625,16 +642,18 @@
mAnimationCallback);
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.deleteWindowMagnification(
- mAnimationCallback2);
- mCurrentScale.set(mController.getScale());
- mCurrentCenterX.set(mController.getCenterX());
- mCurrentCenterY.set(mController.getCenterY());
- // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it is
- // using SystemClock in reverse() (b/305731398). Therefore, we call end() on the animator
- // directly to verify the result of animation is correct instead of querying the animation
- // frame at a specific timing.
- mValueAnimator.end();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.deleteWindowMagnification(
+ mAnimationCallback2);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it
+ // is using SystemClock in reverse() (b/305731398). Therefore, we call end() on the
+ // animator directly to verify the result of animation is correct instead of querying
+ // the animation frame at a specific timing.
+ mValueAnimator.end();
+ });
verify(mSpyController).enableWindowMagnificationInternal(
mScaleCaptor.capture(),
@@ -661,7 +680,7 @@
mAnimationCallback);
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.deleteWindowMagnification(null);
+ deleteWindowMagnificationWithoutAnimation();
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
verify(mAnimationCallback).onResult(false);
@@ -673,6 +692,7 @@
deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
mAnimationCallback);
+ resetMockObjects();
deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback2);
verify(mSpyController).enableWindowMagnificationInternal(
@@ -710,8 +730,7 @@
final float offsetY =
(float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE)
+ 1.0f;
-
- mController.moveWindowMagnifier(offsetX, offsetY);
+ mInstrumentation.runOnMainSync(()-> mController.moveWindowMagnifier(offsetX, offsetY));
verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y + offsetY);
@@ -726,8 +745,8 @@
final float offsetY =
(float) Math.floor(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE)
- 1.0f;
-
- mController.moveWindowMagnifier(offsetX, offsetY);
+ mInstrumentation.runOnMainSync(() ->
+ mController.moveWindowMagnifier(offsetX, offsetY));
verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y);
@@ -742,8 +761,10 @@
(float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE);
// while diagonal scrolling enabled,
// should move with both offsetX and offsetY without regrading offsetY/offsetX
- mController.setDiagonalScrolling(true);
- mController.moveWindowMagnifier(offsetX, offsetY);
+ mInstrumentation.runOnMainSync(() -> {
+ mController.setDiagonalScrolling(true);
+ mController.moveWindowMagnifier(offsetX, offsetY);
+ });
verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y + offsetY);
@@ -755,9 +776,11 @@
final float targetCenterY = DEFAULT_CENTER_Y + 100;
enableWindowMagnificationWithoutAnimation();
- mController.moveWindowMagnifierToPosition(targetCenterX, targetCenterY,
- mAnimationCallback);
- advanceTimeBy(mWaitAnimationDuration);
+ mInstrumentation.runOnMainSync(() -> {
+ mController.moveWindowMagnifierToPosition(targetCenterX, targetCenterY,
+ mAnimationCallback);
+ advanceTimeBy(mWaitAnimationDuration);
+ });
verifyFinalSpec(DEFAULT_SCALE, targetCenterX, targetCenterY);
}
@@ -774,24 +797,49 @@
}
private void enableWindowMagnificationWithoutAnimation() {
- Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
- DEFAULT_CENTER_X, DEFAULT_CENTER_Y, null);
+ enableWindowMagnificationWithoutAnimation(
+ DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+ }
+
+ private void enableWindowMagnificationWithoutAnimation(
+ float targetScale, float targetCenterX, float targetCenterY) {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.enableWindowMagnification(
+ targetScale, targetCenterX, targetCenterY, null);
+ });
}
private void enableWindowMagnificationAndWaitAnimating(long duration,
@Nullable IRemoteMagnificationAnimationCallback callback) {
- Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
- DEFAULT_CENTER_X, DEFAULT_CENTER_Y, callback);
- advanceTimeBy(duration);
+ enableWindowMagnificationAndWaitAnimating(
+ duration, DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y, callback);
+ }
+
+ private void enableWindowMagnificationAndWaitAnimating(
+ long duration,
+ float targetScale,
+ float targetCenterX,
+ float targetCenterY,
+ @Nullable IRemoteMagnificationAnimationCallback callback) {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.enableWindowMagnification(
+ targetScale, targetCenterX, targetCenterY, callback);
+ advanceTimeBy(duration);
+ });
+ }
+
+ private void deleteWindowMagnificationWithoutAnimation() {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.deleteWindowMagnification(null);
+ });
}
private void deleteWindowMagnificationAndWaitAnimating(long duration,
@Nullable IRemoteMagnificationAnimationCallback callback) {
- resetMockObjects();
- mWindowMagnificationAnimationController.deleteWindowMagnification(callback);
- advanceTimeBy(duration);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationAnimationController.deleteWindowMagnification(callback);
+ advanceTimeBy(duration);
+ });
}
private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 86ae517..06421db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -45,6 +45,7 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
@@ -53,6 +54,7 @@
import android.animation.ValueAnimator;
import android.annotation.IdRes;
+import android.annotation.Nullable;
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -89,6 +91,7 @@
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.AnimatorTestRule;
import com.android.systemui.model.SysUiState;
import com.android.systemui.res.R;
import com.android.systemui.settings.FakeDisplayTracker;
@@ -102,6 +105,7 @@
import org.junit.Assume;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -111,8 +115,6 @@
import org.mockito.MockitoAnnotations;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@LargeTest
@@ -120,12 +122,10 @@
@RunWith(AndroidTestingRunner.class)
public class WindowMagnificationControllerTest extends SysuiTestCase {
+ @Rule
+ public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
+
private static final int LAYOUT_CHANGE_TIMEOUT_MS = 5000;
- // The duration couldn't too short, otherwise the animation check on bounce effect
- // won't work in expectation. (b/299537784)
- private static final int BOUNCE_EFFECT_DURATION_MS = 2000;
- private static final long ANIMATION_DURATION_MS = 300;
- private final long mWaitingAnimationPeriod = 2 * ANIMATION_DURATION_MS;
@Mock
private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
@Mock
@@ -134,11 +134,16 @@
private WindowMagnifierCallback mWindowMagnifierCallback;
@Mock
IRemoteMagnificationAnimationCallback mAnimationCallback;
+ @Mock
+ IRemoteMagnificationAnimationCallback mAnimationCallback2;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
@Mock
private SecureSettings mSecureSettings;
+ private long mWaitAnimationDuration;
+ private long mWaitBounceEffectDuration;
+
private Handler mHandler;
private TestableWindowManager mWindowManager;
private SysUiState mSysUiState;
@@ -194,6 +199,13 @@
mResources.getConfiguration().orientation = ORIENTATION_PORTRAIT;
}
+ // Using the animation duration in WindowMagnificationAnimationController for testing.
+ mWaitAnimationDuration = mResources.getInteger(
+ com.android.internal.R.integer.config_longAnimTime);
+ // Using the bounce effect duration in WindowMagnificationController for testing.
+ mWaitBounceEffectDuration = mResources.getInteger(
+ com.android.internal.R.integer.config_shortAnimTime);
+
mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
mContext, mValueAnimator);
mWindowMagnificationController =
@@ -208,7 +220,6 @@
mSysUiState,
() -> mWindowSessionSpy,
mSecureSettings);
- mWindowMagnificationController.setBounceEffectDuration(BOUNCE_EFFECT_DURATION_MS);
verify(mMirrorWindowControl).setWindowDelegate(
any(MirrorWindowControl.MirrorWindowDelegate.class));
@@ -281,9 +292,9 @@
/* magnificationFrameOffsetRatioY= */ 0,
Mockito.mock(IRemoteMagnificationAnimationCallback.class));
});
+ advanceTimeBy(LAYOUT_CHANGE_TIMEOUT_MS);
- verify(mSfVsyncFrameProvider,
- timeout(LAYOUT_CHANGE_TIMEOUT_MS).atLeast(2)).postFrameCallback(any());
+ verify(mSfVsyncFrameProvider, atLeast(2)).postFrameCallback(any());
}
@Test
@@ -401,14 +412,12 @@
@Test
public void moveWindowMagnifierToPositionWithAnimation_expectedValuesAndInvokeCallback()
- throws InterruptedException {
+ throws RemoteException {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN, 0, 0, null);
});
- final CountDownLatch countDownLatch = new CountDownLatch(1);
- final MockMagnificationAnimationCallback animationCallback =
- new MockMagnificationAnimationCallback(countDownLatch);
+
final ArgumentCaptor<Rect> sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class);
verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
.onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
@@ -417,12 +426,12 @@
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.moveWindowMagnifierToPosition(
- targetCenterX, targetCenterY, animationCallback);
+ targetCenterX, targetCenterY, mAnimationCallback);
});
+ advanceTimeBy(mWaitAnimationDuration);
- assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
- assertEquals(1, animationCallback.getSuccessCount());
- assertEquals(0, animationCallback.getFailedCount());
+ verify(mAnimationCallback, times(1)).onResult(eq(true));
+ verify(mAnimationCallback, never()).onResult(eq(false));
verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
.onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
assertEquals(mWindowMagnificationController.getCenterX(),
@@ -435,14 +444,12 @@
@Test
public void moveWindowMagnifierToPositionMultipleTimes_expectedValuesAndInvokeCallback()
- throws InterruptedException {
+ throws RemoteException {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN, 0, 0, null);
});
- final CountDownLatch countDownLatch = new CountDownLatch(4);
- final MockMagnificationAnimationCallback animationCallback =
- new MockMagnificationAnimationCallback(countDownLatch);
+
final ArgumentCaptor<Rect> sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class);
verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
.onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
@@ -451,20 +458,20 @@
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.moveWindowMagnifierToPosition(
- centerX + 10, centerY + 10, animationCallback);
+ centerX + 10, centerY + 10, mAnimationCallback);
mWindowMagnificationController.moveWindowMagnifierToPosition(
- centerX + 20, centerY + 20, animationCallback);
+ centerX + 20, centerY + 20, mAnimationCallback);
mWindowMagnificationController.moveWindowMagnifierToPosition(
- centerX + 30, centerY + 30, animationCallback);
+ centerX + 30, centerY + 30, mAnimationCallback);
mWindowMagnificationController.moveWindowMagnifierToPosition(
- centerX + 40, centerY + 40, animationCallback);
+ centerX + 40, centerY + 40, mAnimationCallback2);
});
+ advanceTimeBy(mWaitAnimationDuration);
- assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
// only the last one callback will return true
- assertEquals(1, animationCallback.getSuccessCount());
+ verify(mAnimationCallback2).onResult(eq(true));
// the others will return false
- assertEquals(3, animationCallback.getFailedCount());
+ verify(mAnimationCallback, times(3)).onResult(eq(false));
verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
.onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
assertEquals(mWindowMagnificationController.getCenterX(),
@@ -1078,27 +1085,16 @@
final View mirrorView = mWindowManager.getAttachedView();
- final long timeout = SystemClock.uptimeMillis() + 5000;
final AtomicDouble maxScaleX = new AtomicDouble();
- final Runnable onAnimationFrame = new Runnable() {
- @Override
- public void run() {
- // For some reason the fancy way doesn't compile...
-// maxScaleX.getAndAccumulate(mirrorView.getScaleX(), Math::max);
- final double oldMax = maxScaleX.get();
- final double newMax = Math.max(mirrorView.getScaleX(), oldMax);
- assertTrue(maxScaleX.compareAndSet(oldMax, newMax));
+ advanceTimeBy(mWaitBounceEffectDuration, /* runnableOnEachRefresh= */ () -> {
+ // For some reason the fancy way doesn't compile...
+ // maxScaleX.getAndAccumulate(mirrorView.getScaleX(), Math::max);
+ final double oldMax = maxScaleX.get();
+ final double newMax = Math.max(mirrorView.getScaleX(), oldMax);
+ assertTrue(maxScaleX.compareAndSet(oldMax, newMax));
+ });
- if (SystemClock.uptimeMillis() < timeout) {
- mirrorView.postOnAnimation(this);
- }
- }
- };
- mirrorView.postOnAnimation(onAnimationFrame);
-
- waitForIdleSync();
-
- ReferenceTestUtils.waitForCondition(() -> maxScaleX.get() > 1.0);
+ assertTrue(maxScaleX.get() > 1.0);
}
@Test
@@ -1455,4 +1451,23 @@
return newRotation;
}
+ // advance time based on the device frame refresh rate
+ private void advanceTimeBy(long timeDelta) {
+ advanceTimeBy(timeDelta, /* runnableOnEachRefresh= */ null);
+ }
+
+ // advance time based on the device frame refresh rate, and trigger runnable on each refresh
+ private void advanceTimeBy(long timeDelta, @Nullable Runnable runnableOnEachRefresh) {
+ final float frameRate = mContext.getDisplay().getRefreshRate();
+ final int timeSlot = (int) (1000 / frameRate);
+ int round = (int) Math.ceil((double) timeDelta / timeSlot);
+ for (; round >= 0; round--) {
+ mInstrumentation.runOnMainSync(() -> {
+ mAnimatorTestRule.advanceTimeBy(timeSlot);
+ if (runnableOnEachRefresh != null) {
+ runnableOnEachRefresh.run();
+ }
+ });
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index daa6070..3da7261 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -19,8 +19,6 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -89,7 +87,6 @@
@Before
public void setUp() throws Exception {
- setFlagDefaults(mSetFlagsRule);
MockitoAnnotations.initMocks(this);
mContextWrapper = new ContextWrapper(mContext) {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
index 5666435..fd258e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.accessibility.floatingmenu;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -58,7 +56,6 @@
@Before
public void setUp() throws Exception {
- setFlagDefaults(mSetFlagsRule);
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
mock(SecureSettings.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
index e832940..2e75480 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.accessibility.floatingmenu;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
@@ -77,7 +75,6 @@
@Before
public void setUp() throws Exception {
- setFlagDefaults(mSetFlagsRule);
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
stubWindowManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
index e8192c4..34a2e87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.accessibility.floatingmenu;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
import static com.google.common.truth.Truth.assertThat;
import android.content.res.Resources;
@@ -45,7 +43,6 @@
@Before
public void setUp() throws Exception {
- setFlagDefaults(mSetFlagsRule);
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
mMenuViewAppearance = new MenuViewAppearance(mContext, windowManager);
mMenuEduTooltipView = new MenuEduTooltipView(mContext, mMenuViewAppearance);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
index 62cb9a0..4ac18d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
@@ -19,8 +19,6 @@
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
@@ -74,7 +72,6 @@
@Before
public void setUp() {
- setFlagDefaults(mSetFlagsRule);
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
stubWindowManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
index 3248753..f0a497d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
@@ -18,8 +18,6 @@
import static android.view.View.OVER_SCROLL_NEVER;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -82,7 +80,6 @@
@Before
public void setUp() throws Exception {
- setFlagDefaults(mSetFlagsRule);
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
mock(SecureSettings.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
index 03a4ba7..31824ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
@@ -19,8 +19,6 @@
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.systemBars;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -75,7 +73,6 @@
@Before
public void setUp() throws Exception {
- setFlagDefaults(mSetFlagsRule);
final WindowManager wm = mContext.getSystemService(WindowManager.class);
doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
mWindowManager).getMaximumWindowMetrics();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index 76094c1..0f1364d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -23,7 +23,6 @@
import static android.view.WindowInsets.Type.systemBars;
import static com.android.systemui.accessibility.floatingmenu.MenuViewLayer.LayerIndex;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
import static com.google.common.truth.Truth.assertThat;
@@ -122,7 +121,6 @@
@Before
public void setUp() throws Exception {
- setFlagDefaults(mSetFlagsRule);
final Rect mDisplayBounds = new Rect();
mDisplayBounds.set(/* left= */ 0, /* top= */ 0, DISPLAY_WINDOW_WIDTH,
DISPLAY_WINDOW_HEIGHT);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index b9fd5d0f..5cd0fd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -18,8 +18,6 @@
import static android.app.UiModeManager.MODE_NIGHT_YES;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
@@ -69,7 +67,6 @@
@Before
public void setUp() throws Exception {
- setFlagDefaults(mSetFlagsRule);
mUiModeManager = mContext.getSystemService(UiModeManager.class);
mNightMode = mUiModeManager.getNightMode();
mUiModeManager.setNightMode(MODE_NIGHT_YES);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/FlagUtils.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/FlagUtils.java
deleted file mode 100644
index c7bb0f5..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/FlagUtils.java
+++ /dev/null
@@ -1,36 +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.accessibility.utils;
-
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
-import android.platform.test.flag.junit.SetFlagsRule;
-
-import com.android.systemui.Flags;
-
-public class FlagUtils {
- /**
- * Populates a setFlagsRule with every SystemUI a11y feature flag.
- * This function should be updated when new flags are added.
- *
- * @param setFlagsRule set flags rule from the test environment.
- */
- public static void setFlagDefaults(SetFlagsRule setFlagsRule) {
- setFlagDefault(setFlagsRule, Flags.FLAG_FLOATING_MENU_OVERLAPS_NAV_BARS_FLAG);
- setFlagDefault(setFlagsRule, Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/SetFlagsRuleExtensions.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/SetFlagsRuleExtensions.kt
index f4d2cfd..f4f05d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/SetFlagsRuleExtensions.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/SetFlagsRuleExtensions.kt
@@ -18,52 +18,7 @@
import android.platform.test.flag.junit.SetFlagsRule
-/**
- * Set the given flag's value to the real value for the current build configuration. This prevents
- * test code from crashing because it is reading an unspecified flag value.
- *
- * REMINDER: You should always test your code with your flag in both configurations, so generally
- * you should be explicitly enabling or disabling your flag. This method is for situations where the
- * flag needs to be read (e.g. in the class constructor), but its value shouldn't affect the actual
- * test cases. In those cases, it's mildly safer to use this method than to hard-code `false` or
- * `true` because then at least if you're wrong, and the flag value *does* matter, you'll notice
- * when the flag is flipped and tests start failing.
- */
-fun SetFlagsRule.setFlagDefault(flagName: String) {
- if (getFlagDefault(flagName)) {
- enableFlags(flagName)
- } else {
- disableFlags(flagName)
- }
-}
-
-/**
- * Set the given flag to an explicit value, or, if null, to the real value for the current build
- * configuration. This allows for convenient provisioning in tests where certain tests don't care
- * what the value is (`setFlagValue(FLAG_FOO, null)`), and others want an explicit value.
- */
-fun SetFlagsRule.setFlagValue(name: String, value: Boolean?) {
- when (value) {
- null -> setFlagDefault(name)
- true -> enableFlags(name)
- false -> disableFlags(name)
- }
-}
-
-// NOTE: This code uses reflection to gain access to private members of aconfig generated
-// classes (in the same way SetFlagsRule does internally) because this is the only way to get
-// at the underlying information and read the current value of the flag.
-// If aconfig had flag constants with accessible default values, this would be unnecessary.
-private fun getFlagDefault(name: String): Boolean {
- val flagPackage = name.substringBeforeLast(".")
- val featureFlagsImplClass = Class.forName("$flagPackage.FeatureFlagsImpl")
- val featureFlagsImpl = featureFlagsImplClass.getConstructor().newInstance()
- val flagMethodName = name.substringAfterLast(".").snakeToCamelCase()
- val flagGetter = featureFlagsImplClass.getDeclaredMethod(flagMethodName)
- return flagGetter.invoke(featureFlagsImpl) as Boolean
-}
-
-private fun String.snakeToCamelCase(): String {
- val pattern = "_[a-z]".toRegex()
- return replace(pattern) { it.value.last().uppercase() }
+/** Set the given flag to an explicit value. */
+fun SetFlagsRule.setFlagValue(name: String, value: Boolean) {
+ if (value) enableFlags(name) else disableFlags(name)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
index fd1e2c7..da448aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
@@ -74,6 +74,15 @@
}
@Test
+ fun notifyProjectionCancelled_forwardsToServiceWithMetricsValue() {
+ val hostUid = 123
+
+ logger.notifyProjectionRequestCancelled(hostUid)
+
+ verify(service).notifyPermissionRequestCancelled(hostUid)
+ }
+
+ @Test
fun notifyAppSelectorDisplayed_forwardsToService() {
val hostUid = 654
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
index 5255f71..44798ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
@@ -4,7 +4,6 @@
import android.os.UserHandle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED as STATE_APP_SELECTOR_DISPLAYED
import com.android.systemui.SysuiTestCase
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.mediaprojection.appselector.data.RecentTask
@@ -214,7 +213,7 @@
@Test
fun init_firstStart_logsAppSelectorDisplayed() {
val hostUid = 123456789
- val controller = createController(isFirstStart = true, hostUid)
+ val controller = createController(isFirstStart = true, hostUid)
controller.init()
@@ -231,6 +230,15 @@
verify(logger, never()).notifyAppSelectorDisplayed(hostUid)
}
+ @Test
+ fun onSelectorDismissed_logsProjectionRequestCancelled() {
+ val hostUid = 123
+
+ createController(hostUid = hostUid).onSelectorDismissed()
+
+ verify(logger).notifyProjectionRequestCancelled(hostUid)
+ }
+
private fun givenCaptureAllowed(isAllow: Boolean) {
whenever(policyResolver.isScreenCaptureAllowed(any(), any())).thenReturn(isAllow)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index c439cfe..49049bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.screenrecord;
+import static android.os.Process.myUid;
+
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertFalse;
@@ -31,8 +33,8 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.os.Looper;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
@@ -60,6 +62,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
/**
* Tests for exception handling and bitmap configuration in adding smart actions to Screenshot
* Notification.
@@ -117,10 +120,6 @@
// starting, and notifies listeners.
@Test
public void testCancelCountdown() {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
mController.startCountdown(100, 10, null, null);
assertTrue(mController.isStarting());
@@ -137,10 +136,6 @@
// Test that when recording is started, the start intent is sent and listeners are notified.
@Test
public void testStartRecording() throws PendingIntent.CanceledException {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
PendingIntent startIntent = Mockito.mock(PendingIntent.class);
mController.startCountdown(0, 0, startIntent, null);
@@ -151,10 +146,6 @@
// Test that when recording is stopped, the stop intent is sent and listeners are notified.
@Test
public void testStopRecording() throws PendingIntent.CanceledException {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
PendingIntent startIntent = Mockito.mock(PendingIntent.class);
PendingIntent stopIntent = Mockito.mock(PendingIntent.class);
@@ -182,10 +173,6 @@
// Test that broadcast will update state
@Test
public void testUpdateStateBroadcast() {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
// When a recording has started
PendingIntent startIntent = Mockito.mock(PendingIntent.class);
mController.startCountdown(0, 0, startIntent, null);
@@ -211,10 +198,6 @@
// Test that switching users will stop an ongoing recording
@Test
public void testUserChange() {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
// If we are recording
PendingIntent startIntent = Mockito.mock(PendingIntent.class);
PendingIntent stopIntent = Mockito.mock(PendingIntent.class);
@@ -231,10 +214,6 @@
@Test
public void testPoliciesFlagDisabled_screenCapturingNotAllowed_returnsNullDevicePolicyDialog() {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, true);
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, false);
when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(true);
@@ -247,10 +226,6 @@
@Test
public void testPartialScreenSharingDisabled_returnsLegacyDialog() {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, false);
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, false);
@@ -262,10 +237,6 @@
@Test
public void testPoliciesFlagEnabled_screenCapturingNotAllowed_returnsDevicePolicyDialog() {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, true);
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, true);
when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(true);
@@ -278,10 +249,6 @@
@Test
public void testPoliciesFlagEnabled_screenCapturingAllowed_returnsNullDevicePolicyDialog() {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, true);
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, true);
when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false);
@@ -294,9 +261,6 @@
@Test
public void testPoliciesFlagEnabled_screenCapturingAllowed_logsProjectionInitiated() {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, true);
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, true);
when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false);
@@ -306,7 +270,7 @@
verify(mMediaProjectionMetricsLogger)
.notifyProjectionInitiated(
- TEST_USER_ID,
+ /* hostUid= */ myUid(),
SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
index bf12d7d..fd38139 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
@@ -26,6 +26,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity
import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN
import com.android.systemui.mediaprojection.permission.SINGLE_APP
@@ -41,7 +42,6 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito
import org.mockito.Mockito.eq
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@@ -57,6 +57,7 @@
@Mock private lateinit var userContextProvider: UserContextProvider
@Mock private lateinit var flags: FeatureFlags
@Mock private lateinit var onStartRecordingClicked: Runnable
+ @Mock private lateinit var mediaProjectionMetricsLogger: MediaProjectionMetricsLogger
private lateinit var dialog: ScreenRecordPermissionDialog
@@ -72,7 +73,8 @@
controller,
starter,
userContextProvider,
- onStartRecordingClicked
+ onStartRecordingClicked,
+ mediaProjectionMetricsLogger,
)
dialog.onCreate(null)
whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true)
@@ -149,6 +151,28 @@
assertThat(dialog.isShowing).isFalse()
}
+ @Test
+ fun showDialog_cancelClickedMultipleTimes_projectionRequestCancelledIsLoggedOnce() {
+ dialog.show()
+
+ clickOnCancel()
+ clickOnCancel()
+
+ verify(mediaProjectionMetricsLogger).notifyProjectionRequestCancelled(TEST_HOST_UID)
+ }
+
+ @Test
+ fun dismissDialog_dismissCalledMultipleTimes_projectionRequestCancelledIsLoggedOnce() {
+ dialog.show()
+
+ TestableLooper.get(this).runWithLooper {
+ dialog.dismiss()
+ dialog.dismiss()
+ }
+
+ verify(mediaProjectionMetricsLogger).notifyProjectionRequestCancelled(TEST_HOST_UID)
+ }
+
private fun clickOnCancel() {
dialog.requireViewById<View>(android.R.id.button2).performClick()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index df38f93..f98267b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.shade.ui.viewmodel
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -151,12 +152,14 @@
subscriptionId = 1,
isOpportunistic = false,
carrierName = "Carrier 1",
+ profileClass = PROFILE_CLASS_UNSET,
)
private val SUB_2 =
SubscriptionModel(
subscriptionId = 2,
isOpportunistic = false,
carrierName = "Carrier 2",
+ profileClass = PROFILE_CLASS_UNSET,
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index a4c12f6..2bee7b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar;
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -43,7 +41,6 @@
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository;
import com.android.systemui.statusbar.domain.interactor.SilentNotificationStatusIconsVisibilityInteractor;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -72,7 +69,6 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
mListener = new NotificationListener(
mContext,
mNotificationManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
index e81207e..428574b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
@@ -63,11 +63,11 @@
@Before
fun setUp() {
initMocks(this)
- setUp(NotificationIconContainerRefactor.FLAG_NAME to null)
entry = NotificationEntryBuilder().setSection(section).build()
+ setUpWithFlags()
}
- private fun setUp(vararg flags: Pair<String, Boolean?>) {
+ private fun setUpWithFlags(vararg flags: Pair<String, Boolean>) {
flags.forEach { (name, value) -> mSetFlagsRule.setFlagValue(name, value) }
reset(pipeline)
coordinator =
@@ -84,14 +84,14 @@
@Test
fun testUpdateNotificationIcons() {
- setUp(NotificationIconContainerRefactor.FLAG_NAME to false)
+ setUpWithFlags(NotificationIconContainerRefactor.FLAG_NAME to false)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(notificationIconAreaController).updateNotificationIcons(eq(listOf(entry)))
}
@Test
fun testSetRenderedListOnInteractor() {
- setUp(NotificationIconContainerRefactor.FLAG_NAME to true)
+ setUpWithFlags(NotificationIconContainerRefactor.FLAG_NAME to true)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(renderListInteractor).setRenderedList(eq(listOf(entry)))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
index cbb0894..947bcfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
@@ -2,7 +2,6 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE
@@ -19,7 +18,30 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class NotificationInterruptStateProviderWrapperTest : SysuiTestCase() {
+class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() {
+ override val provider: VisualInterruptionDecisionProvider
+ get() =
+ NotificationInterruptStateProviderWrapper(
+ NotificationInterruptStateProviderImpl(
+ context.contentResolver,
+ powerManager,
+ ambientDisplayConfiguration,
+ batteryController,
+ statusBarStateController,
+ keyguardStateController,
+ headsUpManager,
+ logger,
+ mainHandler,
+ flags,
+ keyguardNotificationVisibilityProvider,
+ uiEventLogger,
+ userTracker,
+ deviceProvisionedController
+ )
+ .also { it.mUseHeadsUp = true }
+ )
+
+ // Tests of internals of the wrapper:
@Test
fun decisionOfTrue() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
new file mode 100644
index 0000000..6f4bbd5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -0,0 +1,221 @@
+package com.android.systemui.statusbar.notification.interruption
+
+import android.app.ActivityManager
+import android.app.Notification
+import android.app.Notification.BubbleMetadata
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_MUTABLE
+import android.content.Intent
+import android.content.pm.UserInfo
+import android.graphics.drawable.Icon
+import android.hardware.display.FakeAmbientDisplayConfiguration
+import android.os.Handler
+import android.os.PowerManager
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.statusbar.FakeStatusBarStateController
+import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.utils.leaks.FakeBatteryController
+import com.android.systemui.utils.leaks.LeakCheckedTest
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.`when` as whenever
+
+abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() {
+ private val leakCheck = LeakCheckedTest.SysuiLeakCheck()
+
+ protected val ambientDisplayConfiguration = FakeAmbientDisplayConfiguration(context)
+ protected val batteryController = FakeBatteryController(leakCheck)
+ protected val deviceProvisionedController: DeviceProvisionedController = mock()
+ protected val flags: NotifPipelineFlags = mock()
+ protected val headsUpManager: HeadsUpManager = mock()
+ protected val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider =
+ mock()
+ protected val keyguardStateController: KeyguardStateController = mock()
+ protected val logger: NotificationInterruptLogger = mock()
+ protected val mainHandler: Handler = mock()
+ protected val powerManager: PowerManager = mock()
+ protected val statusBarStateController = FakeStatusBarStateController()
+ protected val uiEventLogger = UiEventLoggerFake()
+ protected val userTracker = FakeUserTracker()
+
+ protected abstract val provider: VisualInterruptionDecisionProvider
+
+ @Before
+ fun setUp() {
+ val user = UserInfo(ActivityManager.getCurrentUser(), "Current user", /* flags = */ 0)
+ userTracker.set(listOf(user), /* currentUserIndex = */ 0)
+
+ whenever(headsUpManager.isSnoozed(any())).thenReturn(false)
+ whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any()))
+ .thenReturn(false)
+ }
+
+ @Test
+ fun testShouldPeek() {
+ ensureStateForPeek()
+
+ assertTrue(provider.makeUnloggedHeadsUpDecision(createPeekEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldPulse() {
+ ensureStateForPulse()
+
+ assertTrue(provider.makeUnloggedHeadsUpDecision(createPulseEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldFsi_awake() {
+ ensureStateForAwakeFsi()
+
+ assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldFsi_dreaming() {
+ ensureStateForDreamingFsi()
+
+ assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldFsi_keyguard() {
+ ensureStateForKeyguardFsi()
+
+ assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldBubble() {
+ assertTrue(provider.makeAndLogBubbleDecision(createBubbleEntry()).shouldInterrupt)
+ }
+
+ private fun ensureStateForPeek() {
+ whenever(powerManager.isScreenOn).thenReturn(true)
+ statusBarStateController.dozing = false
+ statusBarStateController.dreaming = false
+ }
+
+ private fun ensureStateForPulse() {
+ ambientDisplayConfiguration.fakePulseOnNotificationEnabled = true
+ batteryController.setIsAodPowerSave(false)
+ statusBarStateController.dozing = true
+ }
+
+ private fun ensureStateForAwakeFsi() {
+ whenever(powerManager.isInteractive).thenReturn(false)
+ statusBarStateController.dreaming = false
+ statusBarStateController.state = SHADE
+ }
+
+ private fun ensureStateForDreamingFsi() {
+ whenever(powerManager.isInteractive).thenReturn(true)
+ statusBarStateController.dreaming = true
+ statusBarStateController.state = SHADE
+ }
+
+ private fun ensureStateForKeyguardFsi() {
+ whenever(powerManager.isInteractive).thenReturn(true)
+ statusBarStateController.dreaming = false
+ statusBarStateController.state = KEYGUARD
+ }
+
+ private fun createNotif(
+ hasFsi: Boolean = false,
+ bubbleMetadata: BubbleMetadata? = null
+ ): Notification {
+ return Notification.Builder(context, TEST_CHANNEL_ID)
+ .apply {
+ setContentTitle(TEST_CONTENT_TITLE)
+ setContentText(TEST_CONTENT_TEXT)
+
+ if (hasFsi) {
+ setFullScreenIntent(mock(), /* highPriority = */ true)
+ }
+
+ if (bubbleMetadata != null) {
+ setBubbleMetadata(bubbleMetadata)
+ }
+ }
+ .setContentTitle(TEST_CONTENT_TITLE)
+ .setContentText(TEST_CONTENT_TEXT)
+ .build()
+ }
+
+ private fun createBubbleMetadata(): BubbleMetadata {
+ val pendingIntent =
+ PendingIntent.getActivity(
+ context,
+ /* requestCode = */ 0,
+ Intent().setPackage(context.packageName),
+ FLAG_MUTABLE
+ )
+
+ val icon = Icon.createWithResource(context.resources, R.drawable.android)
+
+ return BubbleMetadata.Builder(pendingIntent, icon).build()
+ }
+
+ private fun createEntry(
+ notif: Notification,
+ importance: Int = IMPORTANCE_DEFAULT,
+ canBubble: Boolean? = null
+ ): NotificationEntry {
+ return NotificationEntryBuilder()
+ .apply {
+ setPkg(TEST_PACKAGE)
+ setOpPkg(TEST_PACKAGE)
+ setTag(TEST_TAG)
+ setChannel(NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance))
+ setNotification(notif)
+ setImportance(importance)
+
+ if (canBubble != null) {
+ setCanBubble(canBubble)
+ }
+ }
+ .build()
+ }
+
+ private fun createPeekEntry() = createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH)
+
+ private fun createPulseEntry() =
+ createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH).also {
+ modifyRanking(it).setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build()
+ }
+
+ private fun createFsiEntry() =
+ createEntry(notif = createNotif(hasFsi = true), importance = IMPORTANCE_HIGH)
+
+ private fun createBubbleEntry() =
+ createEntry(
+ notif = createNotif(bubbleMetadata = createBubbleMetadata()),
+ importance = IMPORTANCE_HIGH,
+ canBubble = true
+ )
+}
+
+private const val TEST_CONTENT_TITLE = "Test Content Title"
+private const val TEST_CONTENT_TEXT = "Test content text"
+private const val TEST_CHANNEL_ID = "test_channel"
+private const val TEST_CHANNEL_NAME = "Test Channel"
+private const val TEST_PACKAGE = "test_package"
+private const val TEST_TAG = "test_tag"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
index ccef1d5..9b9cb82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
@@ -61,8 +61,9 @@
else -> null
} as T?
}
- mNormalColor =
- Utils.getColorAttrDefaultColor(mContext, com.android.internal.R.attr.colorSurface)
+
+ mNormalColor = Utils.getColorAttrDefaultColor(mContext,
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 8f36d4f..033c96a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -19,8 +19,6 @@
import static android.view.View.GONE;
import static android.view.WindowInsets.Type.ime;
-import static com.android.systemui.Flags.FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR;
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.RUBBER_BAND_FACTOR_NORMAL;
@@ -167,11 +165,6 @@
mFeatureFlags.setDefault(Flags.NOTIFICATION_SHELF_REFACTOR);
mFeatureFlags.setDefault(Flags.NEW_AOD_TRANSITION);
mFeatureFlags.setDefault(Flags.UNCLEARED_TRANSIENT_HUN_FIX);
- // Some tests in this file test the FooterView. Since we're refactoring the FooterView
- // business logic out of the NSSL, the behavior tested in this file will eventually be
- // tested directly in the new FooterView stack. For now, we just want to make sure that the
- // old behavior is preserved when the flag is off.
- setFlagDefault(mSetFlagsRule, FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR);
// Inject dependencies before initializing the layout
mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 6478a3e..05fd6d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -21,7 +21,6 @@
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
@@ -164,7 +163,6 @@
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
@@ -337,7 +335,6 @@
mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI, false);
// Set default value to avoid IllegalStateException.
mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
- setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
// For the Shade to respond to Back gesture, we must enable the event routing
mFeatureFlags.set(Flags.WM_SHADE_ALLOW_BACK_GESTURE, true);
// For the Shade to animate during the Back gesture, we must enable the animation flag.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 19215e3..53cb8a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -54,7 +52,6 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -107,7 +104,6 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
mDozeServiceHost = new DozeServiceHost(mDozeLog, mPowerManager, mWakefullnessLifecycle,
mStatusBarStateController, mDeviceProvisionedController, mFeatureFlags,
mHeadsUpManager, mBatteryController, mScrimController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 1fad2a2..c1ef1ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -48,7 +46,6 @@
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.policy.Clock;
@@ -92,7 +89,6 @@
@Before
public void setUp() throws Exception {
allowTestableLooperAsMainThread();
- setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
mTestHelper = new NotificationTestHelper(
mContext,
mDependency,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
index 92e40df..c24d9ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.verify;
@@ -30,7 +28,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.SetFlagsRuleExtensionsKt;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
index 2b28562..62d8f7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
@@ -20,23 +20,18 @@
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.setFlagDefault
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.Mockito.`when` as whenever
-/**
- * Tests for {@link NotificationIconContainer}.
- */
+/** Tests for {@link NotificationIconContainer}. */
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
@@ -44,15 +39,12 @@
private val iconContainer = NotificationIconContainer(context, /* attrs= */ null)
- @Before
- fun setup() {
- mSetFlagsRule.setFlagDefault(NotificationIconContainerRefactor.FLAG_NAME)
- }
-
@Test
fun calculateWidthFor_zeroIcons_widthIsZero() {
- assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 0f),
- /* actual= */ 0f)
+ assertEquals(
+ /* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 0f),
+ /* actual= */ 0f
+ )
}
@Test
@@ -61,8 +53,10 @@
iconContainer.setActualPaddingEnd(10f)
iconContainer.setIconSize(10)
- assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f),
- /* actual= */ 30f)
+ assertEquals(
+ /* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f),
+ /* actual= */ 30f
+ )
}
@Test
@@ -71,8 +65,10 @@
iconContainer.setActualPaddingEnd(10f)
iconContainer.setIconSize(10)
- assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f),
- /* actual= */ 60f)
+ assertEquals(
+ /* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f),
+ /* actual= */ 60f
+ )
}
@Test
@@ -80,8 +76,10 @@
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
iconContainer.setIconSize(10)
- assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f),
- /* actual= */ 60f)
+ assertEquals(
+ /* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f),
+ /* actual= */ 60f
+ )
}
@Test
@@ -214,112 +212,121 @@
@Test
fun shouldForceOverflow_appearingAboveSpeedBump_true() {
- val forceOverflow = iconContainer.shouldForceOverflow(
+ val forceOverflow =
+ iconContainer.shouldForceOverflow(
/* i= */ 1,
/* speedBumpIndex= */ 0,
/* iconAppearAmount= */ 1f,
/* maxVisibleIcons= */ 5
- )
+ )
assertTrue(forceOverflow)
}
@Test
fun shouldForceOverflow_moreThanMaxVisible_true() {
- val forceOverflow = iconContainer.shouldForceOverflow(
+ val forceOverflow =
+ iconContainer.shouldForceOverflow(
/* i= */ 10,
/* speedBumpIndex= */ 11,
/* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5
- )
+ )
assertTrue(forceOverflow)
}
@Test
fun shouldForceOverflow_belowSpeedBumpAndLessThanMaxVisible_false() {
- val forceOverflow = iconContainer.shouldForceOverflow(
+ val forceOverflow =
+ iconContainer.shouldForceOverflow(
/* i= */ 0,
/* speedBumpIndex= */ 11,
/* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5
- )
+ )
assertFalse(forceOverflow)
}
@Test
fun isOverflowing_lastChildXLessThanLayoutEnd_false() {
- val isOverflowing = iconContainer.isOverflowing(
+ val isOverflowing =
+ iconContainer.isOverflowing(
/* isLastChild= */ true,
/* translationX= */ 0f,
/* layoutEnd= */ 10f,
/* iconSize= */ 2f,
- )
+ )
assertFalse(isOverflowing)
}
-
@Test
fun isOverflowing_lastChildXEqualToLayoutEnd_true() {
- val isOverflowing = iconContainer.isOverflowing(
+ val isOverflowing =
+ iconContainer.isOverflowing(
/* isLastChild= */ true,
/* translationX= */ 10f,
/* layoutEnd= */ 10f,
/* iconSize= */ 2f,
- )
+ )
assertTrue(isOverflowing)
}
@Test
fun isOverflowing_lastChildXGreaterThanDotX_true() {
- val isOverflowing = iconContainer.isOverflowing(
+ val isOverflowing =
+ iconContainer.isOverflowing(
/* isLastChild= */ true,
/* translationX= */ 9f,
/* layoutEnd= */ 10f,
/* iconSize= */ 2f,
- )
+ )
assertTrue(isOverflowing)
}
@Test
fun isOverflowing_lastChildXGreaterThanLayoutEnd_true() {
- val isOverflowing = iconContainer.isOverflowing(
+ val isOverflowing =
+ iconContainer.isOverflowing(
/* isLastChild= */ true,
/* translationX= */ 20f,
/* layoutEnd= */ 10f,
/* iconSize= */ 2f,
- )
+ )
assertTrue(isOverflowing)
}
@Test
fun isOverflowing_notLastChildXLessThanDotX_false() {
- val isOverflowing = iconContainer.isOverflowing(
+ val isOverflowing =
+ iconContainer.isOverflowing(
/* isLastChild= */ false,
/* translationX= */ 0f,
/* layoutEnd= */ 10f,
/* iconSize= */ 2f,
- )
+ )
assertFalse(isOverflowing)
}
@Test
fun isOverflowing_notLastChildXGreaterThanDotX_true() {
- val isOverflowing = iconContainer.isOverflowing(
+ val isOverflowing =
+ iconContainer.isOverflowing(
/* isLastChild= */ false,
/* translationX= */ 20f,
/* layoutEnd= */ 10f,
/* iconSize= */ 2f,
- )
+ )
assertTrue(isOverflowing)
}
@Test
fun isOverflowing_notLastChildXEqualToDotX_true() {
- val isOverflowing = iconContainer.isOverflowing(
+ val isOverflowing =
+ iconContainer.isOverflowing(
/* isLastChild= */ false,
/* translationX= */ 8f,
/* layoutEnd= */ 10f,
/* iconSize= */ 2f,
- )
+ )
assertTrue(isOverflowing)
}
@@ -335,4 +342,4 @@
whenever(iconView.notification).thenReturn(sbn)
return iconView
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 4d4f33b..9b6940e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -18,6 +18,7 @@
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -249,11 +250,13 @@
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_1_ID)
whenever(it.carrierName).thenReturn(SUB_1_NAME)
+ whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
}
private val MODEL_1 =
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = SUB_1_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
)
private const val SUB_2_ID = 2
@@ -262,11 +265,13 @@
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_2_ID)
whenever(it.carrierName).thenReturn(SUB_2_NAME)
+ whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
}
private val MODEL_2 =
SubscriptionModel(
subscriptionId = SUB_2_ID,
carrierName = SUB_2_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index 1c21ebe..787a266 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -19,6 +19,7 @@
import android.net.ConnectivityManager
import android.telephony.ServiceState
import android.telephony.SignalStrength
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
@@ -88,6 +89,7 @@
SubscriptionModel(
subscriptionId = SUB_ID,
carrierName = DEFAULT_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
)
)
@@ -737,7 +739,7 @@
private companion object {
const val SUB_ID = 42
- private val DEFAULT_NAME = "default name"
+ private const val DEFAULT_NAME = "default name"
private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
private const val SEP = "-"
private const val BUFFER_SEPARATOR = "|"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index ba64265..a90bd48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -32,13 +32,13 @@
import android.telephony.ServiceState.STATE_IN_SERVICE
import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.DataActivityListener
import android.telephony.TelephonyCallback.ServiceStateListener
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
import android.telephony.TelephonyManager
-import android.telephony.TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED
import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
@@ -132,6 +132,7 @@
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = DEFAULT_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
)
)
@@ -677,6 +678,7 @@
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = DEFAULT_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
)
assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
@@ -686,6 +688,7 @@
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = updatedName,
+ profileClass = PROFILE_CLASS_UNSET,
)
assertThat(latest?.name).isEqualTo(updatedName)
@@ -980,9 +983,9 @@
companion object {
private const val SUB_1_ID = 1
- private val DEFAULT_NAME = "Fake Mobile Network"
+ private const val DEFAULT_NAME = "Fake Mobile Network"
private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
- private val SEP = "-"
+ private const val SEP = "-"
private const val SPN = "testSpn"
private const val PLMN = "testPlmn"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 18ba6c4..936c58e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -31,6 +31,7 @@
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
@@ -1223,12 +1224,14 @@
whenever(it.subscriptionId).thenReturn(SUB_1_ID)
whenever(it.groupUuid).thenReturn(GROUP_1)
whenever(it.carrierName).thenReturn(SUB_1_NAME)
+ whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
}
private val MODEL_1 =
SubscriptionModel(
subscriptionId = SUB_1_ID,
groupUuid = GROUP_1,
carrierName = SUB_1_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
)
// Subscription 2
@@ -1240,12 +1243,14 @@
whenever(it.subscriptionId).thenReturn(SUB_2_ID)
whenever(it.groupUuid).thenReturn(GROUP_2)
whenever(it.carrierName).thenReturn(SUB_2_NAME)
+ whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
}
private val MODEL_2 =
SubscriptionModel(
subscriptionId = SUB_2_ID,
groupUuid = GROUP_2,
carrierName = SUB_2_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
)
// Subs 3 and 4 are considered to be in the same group ------------------------------------
@@ -1257,6 +1262,7 @@
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_3_ID_GROUPED)
whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
+ whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
}
// Subscription 4
@@ -1265,6 +1271,7 @@
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_4_ID_GROUPED)
whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
+ whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
}
// Subs 3 and 4 are considered to be in the same group ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1279,9 +1286,14 @@
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_CM_ID)
whenever(it.carrierName).thenReturn(SUB_CM_NAME)
+ whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
}
private val MODEL_CM =
- SubscriptionModel(subscriptionId = SUB_CM_ID, carrierName = SUB_CM_NAME)
+ SubscriptionModel(
+ subscriptionId = SUB_CM_ID,
+ carrierName = SUB_CM_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
+ )
private val WIFI_INFO_CM =
mock<WifiInfo>().apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index e2f9119..20d5c5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.telephony.CellSignalStrength
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
@@ -65,6 +66,7 @@
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = DEFAULT_NAME,
+ profileClass = PROFILE_CLASS_UNSET,
)
)
@@ -649,9 +651,9 @@
private const val SUB_1_ID = 1
- private val DEFAULT_NAME = "test default name"
+ private const val DEFAULT_NAME = "test default name"
private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
- private val DERIVED_NAME = "test derived name"
+ private const val DERIVED_NAME = "test derived name"
private val DERIVED_NAME_MODEL = NetworkNameModel.IntentDerived(DERIVED_NAME)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index b4c7578..2060288 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -17,10 +17,16 @@
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.os.ParcelUuid
+import android.telephony.SubscriptionManager
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
@@ -57,6 +63,10 @@
private lateinit var connectionsRepository: FakeMobileConnectionsRepository
private val userSetupRepository = FakeUserSetupRepository()
private val mobileMappingsProxy = FakeMobileMappingsProxy()
+ private val flags =
+ FakeFeatureFlagsClassic().apply {
+ set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+ }
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
@@ -99,6 +109,7 @@
userSetupRepository,
testScope.backgroundScope,
context,
+ flags,
)
}
@@ -318,6 +329,123 @@
}
@Test
+ fun filteredSubscriptions_doesNotFilterProvisioningWhenFlagIsFalse() =
+ testScope.runTest {
+ // GIVEN the flag is false
+ flags.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false)
+
+ // GIVEN 1 sub that is in PROFILE_CLASS_PROVISIONING
+ val sub1 =
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ isOpportunistic = false,
+ carrierName = "Carrier 1",
+ profileClass = PROFILE_CLASS_PROVISIONING,
+ )
+
+ connectionsRepository.setSubscriptions(listOf(sub1))
+
+ // WHEN filtering is applied
+ val latest by collectLastValue(underTest.filteredSubscriptions)
+
+ // THEN the provisioning sub is still present (unfiltered)
+ assertThat(latest).isEqualTo(listOf(sub1))
+ }
+
+ @Test
+ fun filteredSubscriptions_filtersOutProvisioningSubs() =
+ testScope.runTest {
+ val sub1 =
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ isOpportunistic = false,
+ carrierName = "Carrier 1",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
+ val sub2 =
+ SubscriptionModel(
+ subscriptionId = SUB_2_ID,
+ isOpportunistic = false,
+ carrierName = "Carrier 2",
+ profileClass = SubscriptionManager.PROFILE_CLASS_PROVISIONING,
+ )
+
+ connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+
+ val latest by collectLastValue(underTest.filteredSubscriptions)
+
+ assertThat(latest).isEqualTo(listOf(sub1))
+ }
+
+ /** Note: I'm not sure if this will ever be the case, but we can test it at least */
+ @Test
+ fun filteredSubscriptions_filtersOutProvisioningSubsBeforeOpportunistic() =
+ testScope.runTest {
+ // This is a contrived test case, where the active subId is the one that would
+ // also be filtered by opportunistic filtering.
+
+ // GIVEN grouped, opportunistic subscriptions
+ val groupUuid = ParcelUuid(UUID.randomUUID())
+ val sub1 =
+ SubscriptionModel(
+ subscriptionId = 1,
+ isOpportunistic = true,
+ groupUuid = groupUuid,
+ carrierName = "Carrier 1",
+ profileClass = PROFILE_CLASS_PROVISIONING,
+ )
+
+ val sub2 =
+ SubscriptionModel(
+ subscriptionId = 2,
+ isOpportunistic = true,
+ groupUuid = groupUuid,
+ carrierName = "Carrier 2",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
+
+ // GIVEN active subId is 1
+ connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+ connectionsRepository.setActiveMobileDataSubscriptionId(1)
+
+ // THEN filtering of provisioning subs takes place first, and we result in sub2
+
+ val latest by collectLastValue(underTest.filteredSubscriptions)
+
+ assertThat(latest).isEqualTo(listOf(sub2))
+ }
+
+ @Test
+ fun filteredSubscriptions_groupedPairAndNonProvisioned_groupedFilteringStillHappens() =
+ testScope.runTest {
+ // Grouped filtering only happens when the list of subs is length 2. In this case
+ // we'll show that filtering of provisioning subs happens before, and thus grouped
+ // filtering happens even though the unfiltered list is length 3
+ val (sub1, sub3) =
+ createSubscriptionPair(
+ subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+ opportunistic = Pair(true, true),
+ grouped = true,
+ )
+
+ val sub2 =
+ SubscriptionModel(
+ subscriptionId = 2,
+ isOpportunistic = true,
+ groupUuid = null,
+ carrierName = "Carrier 2",
+ profileClass = PROFILE_CLASS_PROVISIONING,
+ )
+
+ connectionsRepository.setSubscriptions(listOf(sub1, sub2, sub3))
+ connectionsRepository.setActiveMobileDataSubscriptionId(1)
+
+ val latest by collectLastValue(underTest.filteredSubscriptions)
+
+ assertThat(latest).isEqualTo(listOf(sub1))
+ }
+
+ @Test
fun activeDataConnection_turnedOn() =
testScope.runTest {
CONNECTION_1.setDataEnabled(true)
@@ -806,7 +934,8 @@
subscriptionId = subscriptionIds.first,
isOpportunistic = opportunistic.first,
groupUuid = groupUuid,
- carrierName = "Carrier ${subscriptionIds.first}"
+ carrierName = "Carrier ${subscriptionIds.first}",
+ profileClass = PROFILE_CLASS_UNSET,
)
val sub2 =
@@ -814,7 +943,8 @@
subscriptionId = subscriptionIds.second,
isOpportunistic = opportunistic.second,
groupUuid = groupUuid,
- carrierName = "Carrier ${opportunistic.second}"
+ carrierName = "Carrier ${opportunistic.second}",
+ profileClass = PROFILE_CLASS_UNSET,
)
return Pair(sub1, sub2)
@@ -824,12 +954,20 @@
private const val SUB_1_ID = 1
private val SUB_1 =
- SubscriptionModel(subscriptionId = SUB_1_ID, carrierName = "Carrier $SUB_1_ID")
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = "Carrier $SUB_1_ID",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, mock())
private const val SUB_2_ID = 2
private val SUB_2 =
- SubscriptionModel(subscriptionId = SUB_2_ID, carrierName = "Carrier $SUB_2_ID")
+ SubscriptionModel(
+ subscriptionId = SUB_2_ID,
+ carrierName = "Carrier $SUB_2_ID",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, mock())
private const val SUB_3_ID = 3
@@ -838,7 +976,8 @@
subscriptionId = SUB_3_ID,
isOpportunistic = true,
groupUuid = ParcelUuid(UUID.randomUUID()),
- carrierName = "Carrier $SUB_3_ID"
+ carrierName = "Carrier $SUB_3_ID",
+ profileClass = PROFILE_CLASS_UNSET,
)
private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, mock())
@@ -848,7 +987,8 @@
subscriptionId = SUB_4_ID,
isOpportunistic = true,
groupUuid = ParcelUuid(UUID.randomUUID()),
- carrierName = "Carrier $SUB_4_ID"
+ carrierName = "Carrier $SUB_4_ID",
+ profileClass = PROFILE_CLASS_UNSET,
)
private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, mock())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
index 1d5487f..6a69d1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
@@ -70,7 +70,11 @@
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
private val connectivityRepository = FakeConnectivityRepository()
- private val flags = FakeFeatureFlagsClassic().also { it.set(Flags.NEW_NETWORK_SLICE_UI, false) }
+ private val flags =
+ FakeFeatureFlagsClassic().also {
+ it.set(Flags.NEW_NETWORK_SLICE_UI, false)
+ it.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+ }
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
@Mock private lateinit var constants: ConnectivityConstants
@@ -114,6 +118,7 @@
FakeUserSetupRepository(),
testScope.backgroundScope,
context,
+ flags,
)
interactor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index c831e62..b39fc5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -82,7 +82,11 @@
@Mock private lateinit var tableLogBuffer: TableLogBuffer
@Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
- private val flags = FakeFeatureFlagsClassic().also { it.set(Flags.NEW_NETWORK_SLICE_UI, false) }
+ private val flags =
+ FakeFeatureFlagsClassic().also {
+ it.set(Flags.NEW_NETWORK_SLICE_UI, false)
+ it.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+ }
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
@@ -120,6 +124,7 @@
FakeUserSetupRepository(),
testScope.backgroundScope,
context,
+ flags,
)
interactor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index f3e334e..f029152 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.TelephonyIcons
@@ -102,6 +103,7 @@
subscriptionId = 1,
isOpportunistic = false,
carrierName = "Carrier 1",
+ profileClass = PROFILE_CLASS_UNSET,
),
)
assertThat(latest).isEqualTo(listOf(1))
@@ -112,16 +114,19 @@
subscriptionId = 2,
isOpportunistic = false,
carrierName = "Carrier 2",
+ profileClass = PROFILE_CLASS_UNSET,
),
SubscriptionModel(
subscriptionId = 5,
isOpportunistic = true,
carrierName = "Carrier 5",
+ profileClass = PROFILE_CLASS_UNSET,
),
SubscriptionModel(
subscriptionId = 7,
isOpportunistic = true,
carrierName = "Carrier 7",
+ profileClass = PROFILE_CLASS_UNSET,
),
)
assertThat(latest).isEqualTo(listOf(2, 5, 7))
@@ -335,18 +340,21 @@
subscriptionId = 1,
isOpportunistic = false,
carrierName = "Carrier 1",
+ profileClass = PROFILE_CLASS_UNSET,
)
private val SUB_2 =
SubscriptionModel(
subscriptionId = 2,
isOpportunistic = false,
carrierName = "Carrier 2",
+ profileClass = PROFILE_CLASS_UNSET,
)
private val SUB_3 =
SubscriptionModel(
subscriptionId = 3,
isOpportunistic = false,
carrierName = "Carrier 3",
+ profileClass = PROFILE_CLASS_UNSET,
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
index c935dbb..8405fb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
@@ -22,6 +22,8 @@
import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
import com.android.systemui.common.shared.model.Text
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
import com.android.systemui.res.R
@@ -75,6 +77,11 @@
private val mobileConnectionRepository =
FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer)
+ private val flags =
+ FakeFeatureFlagsClassic().also {
+ it.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+ }
+
private val internet = context.getString(R.string.quick_settings_internet_label)
@Before
@@ -101,6 +108,7 @@
userSetupRepo,
testScope.backgroundScope,
context,
+ flags,
)
underTest =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index c4c7472..7456e00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -26,6 +26,8 @@
import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
@@ -40,6 +42,9 @@
import android.app.KeyguardManager;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.os.SystemClock;
import android.provider.Settings;
@@ -52,6 +57,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
+import android.widget.ImageButton;
import androidx.test.core.view.MotionEventBuilder;
import androidx.test.filters.SmallTest;
@@ -90,6 +96,7 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
import java.util.function.Predicate;
@SmallTest
@@ -757,6 +764,86 @@
foundCaptionLog);
}
+ @Test
+ public void turnOnDnD_volumeSliderIconChangesToDnd() {
+ State state = createShellState();
+ state.zenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
+
+ mDialog.onStateChangedH(state);
+ mTestableLooper.processAllMessages();
+
+ boolean foundDnDIcon = findDndIconAmongVolumeRows();
+ assertTrue(foundDnDIcon);
+ }
+
+ @Test
+ public void turnOffDnD_volumeSliderIconIsNotDnd() {
+ State state = createShellState();
+ state.zenMode = Settings.Global.ZEN_MODE_OFF;
+
+ mDialog.onStateChangedH(state);
+ mTestableLooper.processAllMessages();
+
+ boolean foundDnDIcon = findDndIconAmongVolumeRows();
+ assertFalse(foundDnDIcon);
+ }
+
+ /**
+ * @return true if at least one volume row has the DND icon
+ */
+ private boolean findDndIconAmongVolumeRows() {
+ ViewGroup volumeDialogRows = mDialog.getDialogView().findViewById(R.id.volume_dialog_rows);
+ assumeNotNull(volumeDialogRows);
+ Drawable expected = getContext().getDrawable(com.android.internal.R.drawable.ic_qs_dnd);
+ boolean foundDnDIcon = false;
+ final int rowCount = volumeDialogRows.getChildCount();
+ // we don't make assumptions about the position of the dnd row
+ for (int i = 0; i < rowCount && !foundDnDIcon; i++) {
+ View volumeRow = volumeDialogRows.getChildAt(i);
+ ImageButton rowIcon = volumeRow.findViewById(R.id.volume_row_icon);
+ assertNotNull(rowIcon);
+
+ // VolumeDialogImpl changes tint and alpha in a private method, so we clear those here.
+ rowIcon.setImageTintList(null);
+ rowIcon.setAlpha(0xFF);
+
+ Drawable actual = rowIcon.getDrawable();
+ foundDnDIcon |= areDrawablesEqual(expected, actual);
+ }
+ return foundDnDIcon;
+ }
+
+ private boolean areDrawablesEqual(Drawable drawable1, Drawable drawable2) {
+ int size = 100;
+ Bitmap bm1 = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Bitmap bm2 = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+
+ Canvas canvas1 = new Canvas(bm1);
+ Canvas canvas2 = new Canvas(bm2);
+
+ drawable1.setBounds(0, 0, size, size);
+ drawable2.setBounds(0, 0, size, size);
+
+ drawable1.draw(canvas1);
+ drawable2.draw(canvas2);
+
+ boolean areBitmapsEqual = areBitmapsEqual(bm1, bm2);
+ bm1.recycle();
+ bm2.recycle();
+ return areBitmapsEqual;
+ }
+
+ private boolean areBitmapsEqual(Bitmap a, Bitmap b) {
+ if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) return false;
+ int w = a.getWidth();
+ int h = a.getHeight();
+ int[] aPix = new int[w * h];
+ int[] bPix = new int[w * h];
+ a.getPixels(aPix, 0, w, 0, 0, w, h);
+ b.getPixels(bPix, 0, w, 0, 0, w, h);
+ return Arrays.equals(aPix, bPix);
+ }
+
@After
public void teardown() {
// Detailed logs to track down timeout issues in b/299491332
diff --git a/packages/SystemUI/tests/utils/src/android/hardware/display/FakeAmbientDisplayConfiguration.kt b/packages/SystemUI/tests/utils/src/android/hardware/display/FakeAmbientDisplayConfiguration.kt
new file mode 100644
index 0000000..cdd0ff7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/android/hardware/display/FakeAmbientDisplayConfiguration.kt
@@ -0,0 +1,68 @@
+package android.hardware.display
+
+import android.content.Context
+
+class FakeAmbientDisplayConfiguration(context: Context) : AmbientDisplayConfiguration(context) {
+ var fakePulseOnNotificationEnabled = true
+
+ override fun pulseOnNotificationEnabled(user: Int) = fakePulseOnNotificationEnabled
+
+ override fun pulseOnNotificationAvailable() = TODO("Not yet implemented")
+
+ override fun pickupGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun dozePickupSensorAvailable() = TODO("Not yet implemented")
+
+ override fun tapGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun tapSensorAvailable() = TODO("Not yet implemented")
+
+ override fun doubleTapGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun doubleTapSensorAvailable() = TODO("Not yet implemented")
+
+ override fun quickPickupSensorEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun screenOffUdfpsEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun wakeScreenGestureAvailable() = TODO("Not yet implemented")
+
+ override fun wakeLockScreenGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun wakeDisplayGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun getWakeLockScreenDebounce() = TODO("Not yet implemented")
+
+ override fun doubleTapSensorType() = TODO("Not yet implemented")
+
+ override fun tapSensorTypeMapping() = TODO("Not yet implemented")
+
+ override fun longPressSensorType() = TODO("Not yet implemented")
+
+ override fun udfpsLongPressSensorType() = TODO("Not yet implemented")
+
+ override fun quickPickupSensorType() = TODO("Not yet implemented")
+
+ override fun pulseOnLongPressEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun alwaysOnEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun alwaysOnAvailable() = TODO("Not yet implemented")
+
+ override fun alwaysOnAvailableForUser(user: Int) = TODO("Not yet implemented")
+
+ override fun ambientDisplayComponent() = TODO("Not yet implemented")
+
+ override fun accessibilityInversionEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun ambientDisplayAvailable() = TODO("Not yet implemented")
+
+ override fun dozeSuppressed(user: Int) = TODO("Not yet implemented")
+
+ override fun disableDozeSettings(userId: Int) = TODO("Not yet implemented")
+
+ override fun disableDozeSettings(shouldDisableNonUserConfigurable: Boolean, userId: Int) =
+ TODO("Not yet implemented")
+
+ override fun restoreDozeSettings(userId: Int) = TODO("Not yet implemented")
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index e6e6b7b..29e737e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -15,7 +15,7 @@
*/
package com.android.systemui;
-import static com.android.systemui.Flags.FLAG_EXAMPLE_FLAG;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -65,7 +65,7 @@
new AndroidXAnimatorIsolationRule();
@Rule
- public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
@Rule
public SysuiTestableContext mContext = new SysuiTestableContext(
@@ -88,9 +88,6 @@
if (isRobolectricTest()) {
mContext = mContext.createDefaultDisplayContext();
}
- // Set the value of a single gantry flag inside the com.android.systemui package to
- // ensure all flags in that package are faked (and thus require a value to be set).
- mSetFlagsRule.disableFlags(FLAG_EXAMPLE_FLAG);
mSysuiDependency = new SysuiTestDependency(mContext, shouldFailOnLeakedReceiver());
mDependency = mSysuiDependency.install();
mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt
new file mode 100644
index 0000000..19fdb6d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt
@@ -0,0 +1,159 @@
+package com.android.systemui.statusbar
+
+import android.view.View
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+
+class FakeStatusBarStateController : SysuiStatusBarStateController {
+ @JvmField var state = StatusBarState.SHADE
+
+ @JvmField var upcomingState = StatusBarState.SHADE
+
+ @JvmField var lastState = StatusBarState.SHADE
+
+ @JvmField var dozing = false
+
+ @JvmField var expanded = false
+
+ @JvmField var pulsing = false
+
+ @JvmField var dreaming = false
+
+ @JvmField var dozeAmount = 0.0f
+
+ @JvmField var interpolatedDozeAmount = 0.0f
+
+ @JvmField var dozeAmountTarget = 0.0f
+
+ @JvmField var leaveOpen = false
+
+ @JvmField var keyguardRequested = false
+
+ var lastSetDozeAmountView: View? = null
+ private set
+
+ var lastSetDozeAmountAnimated = false
+ private set
+
+ var lastSystemBarAppearance = 0
+ private set
+
+ var lastSystemBarBehavior = 0
+ private set
+
+ var lastSystemBarRequestedVisibleTypes = 0
+ private set
+
+ var lastSystemBarPackageName: String? = null
+ private set
+
+ private val _callbacks = mutableSetOf<StatusBarStateController.StateListener>()
+
+ @JvmField val callbacks: Set<StatusBarStateController.StateListener> = _callbacks
+
+ private var fullscreen = false
+
+ override fun start() {}
+
+ override fun getState() = state
+
+ override fun setState(newState: Int, force: Boolean): Boolean {
+ val oldState = this.state
+ newState != oldState || force || return false
+
+ callbacks.forEach { it.onStatePreChange(oldState, newState) }
+ this.lastState = oldState
+ this.state = newState
+ setUpcomingState(newState)
+ callbacks.forEach { it.onStateChanged(newState) }
+ callbacks.forEach { it.onStatePostChange() }
+ return true
+ }
+
+ override fun getCurrentOrUpcomingState() = upcomingState
+
+ override fun setUpcomingState(upcomingState: Int) {
+ upcomingState != this.upcomingState || return
+ this.upcomingState = upcomingState
+ callbacks.forEach { it.onUpcomingStateChanged(upcomingState) }
+ }
+
+ override fun isDozing() = dozing
+
+ override fun setIsDozing(dozing: Boolean): Boolean {
+ dozing != this.dozing || return false
+ this.dozing = dozing
+ callbacks.forEach { it.onDozingChanged(dozing) }
+ return true
+ }
+
+ override fun isExpanded() = expanded
+
+ fun fakeShadeExpansionFullyChanged(expanded: Boolean) {
+ expanded != this.expanded || return
+ this.expanded = expanded
+ callbacks.forEach { it.onExpandedChanged(expanded) }
+ }
+
+ override fun isPulsing() = pulsing
+
+ override fun setPulsing(pulsing: Boolean) {
+ pulsing != this.pulsing || return
+ this.pulsing = pulsing
+ callbacks.forEach { it.onPulsingChanged(pulsing) }
+ }
+
+ override fun isDreaming() = dreaming
+
+ override fun setIsDreaming(drreaming: Boolean): Boolean {
+ dreaming != this.dreaming || return false
+ this.dreaming = dreaming
+ callbacks.forEach { it.onDreamingChanged(dreaming) }
+ return true
+ }
+
+ override fun getDozeAmount() = dozeAmount
+
+ override fun setAndInstrumentDozeAmount(view: View?, dozeAmount: Float, animated: Boolean) {
+ dozeAmountTarget = dozeAmount
+ lastSetDozeAmountView = view
+ lastSetDozeAmountAnimated = animated
+ if (!animated) {
+ this.dozeAmount = dozeAmount
+ }
+ }
+
+ override fun leaveOpenOnKeyguardHide() = leaveOpen
+
+ override fun setLeaveOpenOnKeyguardHide(leaveOpen: Boolean) {
+ this.leaveOpen = leaveOpen
+ }
+
+ override fun getInterpolatedDozeAmount() = interpolatedDozeAmount
+
+ fun fakeInterpolatedDozeAmountChanged(interpolatedDozeAmount: Float) {
+ this.interpolatedDozeAmount = interpolatedDozeAmount
+ callbacks.forEach { it.onDozeAmountChanged(dozeAmount, interpolatedDozeAmount) }
+ }
+
+ override fun goingToFullShade() = state == StatusBarState.SHADE && leaveOpen
+
+ override fun fromShadeLocked() = lastState == StatusBarState.SHADE_LOCKED
+
+ override fun isKeyguardRequested(): Boolean = keyguardRequested
+
+ override fun setKeyguardRequested(keyguardRequested: Boolean) {
+ this.keyguardRequested = keyguardRequested
+ }
+
+ override fun addCallback(listener: StatusBarStateController.StateListener?) {
+ _callbacks.add(listener!!)
+ }
+
+ override fun addCallback(listener: StatusBarStateController.StateListener?, rank: Int) {
+ throw RuntimeException("addCallback with rank unsupported")
+ }
+
+ override fun removeCallback(listener: StatusBarStateController.StateListener?) {
+ _callbacks.remove(listener!!)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
index eaa109d..209cac6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
@@ -25,6 +25,7 @@
public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCallback>
implements BatteryController {
+ private boolean mIsAodPowerSave = false;
private boolean mWirelessCharging;
public FakeBatteryController(LeakCheck test) {
@@ -63,7 +64,7 @@
@Override
public boolean isAodPowerSave() {
- return false;
+ return mIsAodPowerSave;
}
@Override
@@ -71,6 +72,10 @@
return mWirelessCharging;
}
+ public void setIsAodPowerSave(boolean isAodPowerSave) {
+ mIsAodPowerSave = isAodPowerSave;
+ }
+
public void setWirelessCharging(boolean wirelessCharging) {
mWirelessCharging = wirelessCharging;
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 961e9d3..3985a0e 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -155,6 +155,7 @@
"service-permission.stubs.system_server",
"service-rkp.stubs.system_server",
"service-sdksandbox.stubs.system_server",
+ "device_policy_aconfig_flags_lib",
],
plugins: ["ImmutabilityAnnotationProcessor"],
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 210c18d..e88d0c6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15934,7 +15934,7 @@
try {
sdkSandboxInfo =
sandboxManagerLocal.getSdkSandboxApplicationInfoForInstrumentation(
- sdkSandboxClientAppInfo, isSdkInSandbox);
+ sdkSandboxClientAppInfo, userId, isSdkInSandbox);
} catch (NameNotFoundException e) {
reportStartInstrumentationFailureLocked(
watcher, className, "Can't find SdkSandbox package");
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 516293b..052b0c2 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2680,8 +2680,17 @@
.filterAppAccess(packageName, callingUid, userId);
}
+ /** @deprecated Use {@link #noteProxyOperationWithState} instead. */
@Override
public SyncNotedAppOp noteProxyOperation(int code,
+ AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp,
+ String message, boolean shouldCollectMessage, boolean skipProxyOperation) {
+ return mCheckOpsDelegateDispatcher.noteProxyOperation(code, attributionSource,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation);
+ }
+
+ @Override
+ public SyncNotedAppOp noteProxyOperationWithState(int code,
AttributionSourceState attributionSourceState, boolean shouldCollectAsyncNotedOp,
String message, boolean shouldCollectMessage, boolean skipProxyOperation) {
AttributionSource attributionSource = new AttributionSource(attributionSourceState);
@@ -3212,8 +3221,21 @@
attributionChainId);
}
+ /** @deprecated Use {@link #startProxyOperationWithState} instead. */
@Override
public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code,
+ @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
+ boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
+ boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
+ @AttributionFlags int proxiedAttributionFlags, int attributionChainId) {
+ return mCheckOpsDelegateDispatcher.startProxyOperation(clientId, code, attributionSource,
+ startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags,
+ attributionChainId);
+ }
+
+ @Override
+ public SyncNotedAppOp startProxyOperationWithState(@NonNull IBinder clientId, int code,
@NonNull AttributionSourceState attributionSourceState, boolean startIfModeDefault,
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
@@ -3513,8 +3535,16 @@
finishOperationUnchecked(clientId, code, uid, resolvedPackageName, attributionTag);
}
+ /** @deprecated Use {@link #finishProxyOperationWithState} instead. */
@Override
public void finishProxyOperation(@NonNull IBinder clientId, int code,
+ @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
+ mCheckOpsDelegateDispatcher.finishProxyOperation(clientId, code, attributionSource,
+ skipProxyOperation);
+ }
+
+ @Override
+ public void finishProxyOperationWithState(@NonNull IBinder clientId, int code,
@NonNull AttributionSourceState attributionSourceState, boolean skipProxyOperation) {
AttributionSource attributionSource = new AttributionSource(attributionSourceState);
mCheckOpsDelegateDispatcher.finishProxyOperation(clientId, code, attributionSource,
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index c29d9bd..f085647 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -108,7 +108,7 @@
final boolean credentialRequested = Utils.isCredentialRequested(promptInfo);
final boolean credentialAvailable = trustManager.isDeviceSecure(userId,
- context.getAssociatedDisplayId());
+ context.getDeviceId());
// Assuming that biometric authenticators are listed in priority-order, the rest of this
// function will attempt to find the first authenticator that's as strong or stronger than
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 76dde54..e3c0cf7 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -646,7 +646,7 @@
intendingUid,
intendingUserId,
intendingDeviceId)
- || isDeviceLocked(intendingUserId)) {
+ || isDeviceLocked(intendingUserId, deviceId)) {
return null;
}
synchronized (mLock) {
@@ -686,7 +686,7 @@
intendingUserId,
intendingDeviceId,
false)
- || isDeviceLocked(intendingUserId)) {
+ || isDeviceLocked(intendingUserId, deviceId)) {
return null;
}
synchronized (mLock) {
@@ -710,7 +710,7 @@
intendingUserId,
intendingDeviceId,
false)
- || isDeviceLocked(intendingUserId)) {
+ || isDeviceLocked(intendingUserId, deviceId)) {
return false;
}
synchronized (mLock) {
@@ -785,7 +785,7 @@
intendingUserId,
intendingDeviceId,
false)
- || isDeviceLocked(intendingUserId)) {
+ || isDeviceLocked(intendingUserId, deviceId)) {
return false;
}
synchronized (mLock) {
@@ -814,7 +814,7 @@
intendingUserId,
intendingDeviceId,
false)
- || isDeviceLocked(intendingUserId)) {
+ || isDeviceLocked(intendingUserId, deviceId)) {
return null;
}
synchronized (mLock) {
@@ -1150,12 +1150,12 @@
&& text.equals(clipboard.primaryClip.getItemAt(0).getText());
}
- private boolean isDeviceLocked(@UserIdInt int userId) {
+ private boolean isDeviceLocked(@UserIdInt int userId, int deviceId) {
final long token = Binder.clearCallingIdentity();
try {
final KeyguardManager keyguardManager = getContext().getSystemService(
KeyguardManager.class);
- return keyguardManager != null && keyguardManager.isDeviceLocked(userId);
+ return keyguardManager != null && keyguardManager.isDeviceLocked(userId, deviceId);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 67a1ccd..78077a8 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -40,6 +40,7 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.media.flags.Flags;
import java.util.List;
import java.util.Objects;
@@ -358,21 +359,8 @@
RoutingSessionInfo newSessionInfo = builder.setProviderId(mUniqueId).build();
- if (mPendingSessionCreationRequest != null) {
- SessionCreationRequest sessionCreationRequest;
- synchronized (mRequestLock) {
- sessionCreationRequest = mPendingSessionCreationRequest;
- mPendingSessionCreationRequest = null;
- }
- if (sessionCreationRequest != null) {
- if (TextUtils.equals(mSelectedRouteId, sessionCreationRequest.mRouteId)) {
- mCallback.onSessionCreated(this,
- sessionCreationRequest.mRequestId, newSessionInfo);
- } else {
- mCallback.onRequestFailed(this, sessionCreationRequest.mRequestId,
- MediaRoute2ProviderService.REASON_UNKNOWN_ERROR);
- }
- }
+ synchronized (mRequestLock) {
+ reportPendingSessionRequestResultLockedIfNeeded(newSessionInfo);
}
if (Objects.equals(oldSessionInfo, newSessionInfo)) {
@@ -395,6 +383,59 @@
}
}
+ @GuardedBy("mRequestLock")
+ private void reportPendingSessionRequestResultLockedIfNeeded(
+ RoutingSessionInfo newSessionInfo) {
+ if (mPendingSessionCreationRequest == null) {
+ // No pending request, nothing to report.
+ return;
+ }
+
+ long pendingRequestId = mPendingSessionCreationRequest.mRequestId;
+ if (TextUtils.equals(mSelectedRouteId, mPendingSessionCreationRequest.mRouteId)) {
+ if (DEBUG) {
+ Slog.w(
+ TAG,
+ "Session creation success to route "
+ + mPendingSessionCreationRequest.mRouteId);
+ }
+ mPendingSessionCreationRequest = null;
+ mCallback.onSessionCreated(this, pendingRequestId, newSessionInfo);
+ } else {
+ boolean isRequestedRouteConnectedBtRoute = isRequestedRouteConnectedBtRoute();
+ if (!Flags.enableWaitingStateForSystemSessionCreationRequest()
+ || !isRequestedRouteConnectedBtRoute) {
+ if (DEBUG) {
+ Slog.w(
+ TAG,
+ "Session creation failed to route "
+ + mPendingSessionCreationRequest.mRouteId);
+ }
+ mPendingSessionCreationRequest = null;
+ mCallback.onRequestFailed(
+ this, pendingRequestId, MediaRoute2ProviderService.REASON_UNKNOWN_ERROR);
+ } else if (DEBUG) {
+ Slog.w(
+ TAG,
+ "Session creation waiting state to route "
+ + mPendingSessionCreationRequest.mRouteId);
+ }
+ }
+ }
+
+ @GuardedBy("mRequestLock")
+ private boolean isRequestedRouteConnectedBtRoute() {
+ // Using AllRoutes instead of TransferableRoutes as BT Stack sends an intermediate update
+ // where two BT routes are active so the transferable routes list is empty.
+ // See b/307723189 for context
+ for (MediaRoute2Info btRoute : mBluetoothRouteController.getAllBluetoothRoutes()) {
+ if (TextUtils.equals(btRoute.getId(), mPendingSessionCreationRequest.mRouteId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void publishProviderState() {
updateProviderState();
notifyProviderState();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 58927d1..893ed61 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -470,6 +470,11 @@
}
@VisibleForTesting
+ void notifyPermissionRequestCancelled(int hostUid) {
+ mMediaProjectionMetricsLogger.logProjectionPermissionRequestCancelled(hostUid);
+ }
+
+ @VisibleForTesting
void notifyAppSelectorDisplayed(int hostUid) {
mMediaProjectionMetricsLogger.logAppSelectorDisplayed(hostUid);
}
@@ -852,19 +857,6 @@
@Override // Binder call
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public void notifyPermissionRequestStateChange(int hostUid, int state,
- int sessionCreationSource) {
- notifyPermissionRequestStateChange_enforcePermission();
- final long token = Binder.clearCallingIdentity();
- try {
- mMediaProjectionMetricsLogger.notifyProjectionStateChange(hostUid, state, sessionCreationSource);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override // Binder call
- @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public void notifyPermissionRequestInitiated(int hostUid, int sessionCreationSource) {
notifyPermissionRequestInitiated_enforcePermission();
final long token = Binder.clearCallingIdentity();
@@ -890,6 +882,18 @@
@Override // Binder call
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
+ public void notifyPermissionRequestCancelled(int hostUid) {
+ notifyPermissionRequestCancelled_enforcePermission();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ MediaProjectionManagerService.this.notifyPermissionRequestCancelled(hostUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public void notifyAppSelectorDisplayed(int hostUid) {
notifyAppSelectorDisplayed_enforcePermission();
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
index 55a30bf..d7fefeb 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
@@ -118,6 +118,23 @@
}
/**
+ * Logs that requesting permission for media projection was cancelled by the user.
+ *
+ * @param hostUid UID of the package that initiates MediaProjection.
+ */
+ public void logProjectionPermissionRequestCancelled(int hostUid) {
+ write(
+ mSessionIdGenerator.getCurrentSessionId(),
+ FrameworkStatsLog
+ .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED,
+ hostUid,
+ TARGET_UID_UNKNOWN,
+ TIME_SINCE_LAST_ACTIVE_UNKNOWN,
+ FrameworkStatsLog
+ .MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ }
+
+ /**
* Logs that the app selector dialog is shown for the user.
*
* @param hostUid UID of the package that initiates MediaProjection.
@@ -174,23 +191,6 @@
}
}
- public void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) {
- write(hostUid, state, sessionCreationSource);
- }
-
- private void write(int hostUid, int state, int sessionCreationSource) {
- mFrameworkStatsLogWrapper.write(
- /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
- /* session_id */ 123,
- /* state */ state,
- /* previous_state */ FrameworkStatsLog
- .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
- /* host_uid */ hostUid,
- /* target_uid */ -1,
- /* time_since_last_active */ 0,
- /* creation_source */ sessionCreationSource);
- }
-
private void write(
int sessionId,
int state,
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 1134714..e57ea0f 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -16,6 +16,8 @@
package com.android.server.os;
+import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
+
import android.Manifest;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -52,8 +54,10 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.HashSet;
import java.util.Objects;
import java.util.OptionalInt;
+import java.util.Set;
/**
* Implementation of the service that provides a privileged API to capture and consume bugreports.
@@ -101,10 +105,12 @@
private final ArrayMap<Pair<Integer, String>, ArraySet<String>> mBugreportFiles =
new ArrayMap<>();
+ @GuardedBy("mLock")
+ private final Set<String> mBugreportFilesToPersist = new HashSet<>();
+
/**
* Checks that a given file was generated on behalf of the given caller. If the file was
- * generated on behalf of the caller, it is removed from the bugreport mapping so that it
- * may not be retrieved again. If the file was not generated on behalf of the caller, an
+ * not generated on behalf of the caller, an
* {@link IllegalArgumentException} is thrown.
*
* @param callingInfo a (uid, package name) pair identifying the caller
@@ -114,35 +120,76 @@
* @throws IllegalArgumentException if {@code bugreportFile} is not associated with
* {@code callingInfo}.
*/
+ @RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS,
+ conditional = true)
void ensureCallerPreviouslyGeneratedFile(
- Pair<Integer, String> callingInfo, String bugreportFile) {
+ Context context, Pair<Integer, String> callingInfo, int userId,
+ String bugreportFile) {
synchronized (mLock) {
- ArraySet<String> bugreportFilesForCaller = mBugreportFiles.get(callingInfo);
- if (bugreportFilesForCaller != null
- && bugreportFilesForCaller.contains(bugreportFile)) {
- bugreportFilesForCaller.remove(bugreportFile);
- if (bugreportFilesForCaller.isEmpty()) {
- mBugreportFiles.remove(callingInfo);
+ if (onboardingBugreportV2Enabled()) {
+ final int uidForUser = Binder.withCleanCallingIdentity(() -> {
+ try {
+ return context.getPackageManager()
+ .getPackageUidAsUser(callingInfo.second, userId);
+ } catch (PackageManager.NameNotFoundException exception) {
+ throwInvalidBugreportFileForCallerException(
+ bugreportFile, callingInfo.second);
+ return -1;
+ }
+ });
+ if (uidForUser != callingInfo.first && context.checkCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ callingInfo.second + " does not hold the "
+ + "INTERACT_ACROSS_USERS permission to access "
+ + "cross-user bugreports.");
+ }
+ ArraySet<String> bugreportFilesForUid = mBugreportFiles.get(
+ new Pair<>(uidForUser, callingInfo.second));
+ if (bugreportFilesForUid == null
+ || !bugreportFilesForUid.contains(bugreportFile)) {
+ throwInvalidBugreportFileForCallerException(
+ bugreportFile, callingInfo.second);
}
} else {
- throw new IllegalArgumentException(
- "File " + bugreportFile + " was not generated"
- + " on behalf of calling package " + callingInfo.second);
+ ArraySet<String> bugreportFilesForCaller = mBugreportFiles.get(callingInfo);
+ if (bugreportFilesForCaller != null
+ && bugreportFilesForCaller.contains(bugreportFile)) {
+ bugreportFilesForCaller.remove(bugreportFile);
+ if (bugreportFilesForCaller.isEmpty()) {
+ mBugreportFiles.remove(callingInfo);
+ }
+ } else {
+ throwInvalidBugreportFileForCallerException(
+ bugreportFile, callingInfo.second);
+
+ }
}
}
}
+ private static void throwInvalidBugreportFileForCallerException(
+ String bugreportFile, String packageName) {
+ throw new IllegalArgumentException("File " + bugreportFile + " was not generated on"
+ + " behalf of calling package " + packageName);
+ }
+
/**
* Associates a bugreport file with a caller, which is identified as a
* (uid, package name) pair.
*/
- void addBugreportFileForCaller(Pair<Integer, String> caller, String bugreportFile) {
+ void addBugreportFileForCaller(
+ Pair<Integer, String> caller, String bugreportFile, boolean keepOnRetrieval) {
synchronized (mLock) {
if (!mBugreportFiles.containsKey(caller)) {
mBugreportFiles.put(caller, new ArraySet<>());
}
ArraySet<String> bugreportFilesForCaller = mBugreportFiles.get(caller);
bugreportFilesForCaller.add(bugreportFile);
+ if ((onboardingBugreportV2Enabled()) && keepOnRetrieval) {
+ mBugreportFilesToPersist.add(bugreportFile);
+ }
}
}
}
@@ -246,16 +293,17 @@
}
@Override
- @RequiresPermission(Manifest.permission.DUMP)
- public void retrieveBugreport(int callingUidUnused, String callingPackage,
- FileDescriptor bugreportFd, String bugreportFile, IDumpstateListener listener) {
+ @RequiresPermission(value = Manifest.permission.DUMP, conditional = true)
+ public void retrieveBugreport(int callingUidUnused, String callingPackage, int userId,
+ FileDescriptor bugreportFd, String bugreportFile,
+ boolean keepBugreportOnRetrievalUnused, IDumpstateListener listener) {
int callingUid = Binder.getCallingUid();
enforcePermission(callingPackage, callingUid, false);
Slogf.i(TAG, "Retrieving bugreport for %s / %d", callingPackage, callingUid);
try {
mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
- new Pair<>(callingUid, callingPackage), bugreportFile);
+ mContext, new Pair<>(callingUid, callingPackage), userId, bugreportFile);
} catch (IllegalArgumentException e) {
Slog.e(TAG, e.getMessage());
reportError(listener, IDumpstateListener.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
@@ -281,10 +329,17 @@
// Wrap the listener so we can intercept binder events directly.
DumpstateListener myListener = new DumpstateListener(listener, ds,
new Pair<>(callingUid, callingPackage), /* reportFinishedFile= */ true);
+
+ boolean keepBugreportOnRetrieval = false;
+ if (onboardingBugreportV2Enabled()) {
+ keepBugreportOnRetrieval = mBugreportFileManager.mBugreportFilesToPersist.contains(
+ bugreportFile);
+ }
+
setCurrentDumpstateListenerLocked(myListener);
try {
- ds.retrieveBugreport(callingUid, callingPackage, bugreportFd,
- bugreportFile, myListener);
+ ds.retrieveBugreport(callingUid, callingPackage, userId, bugreportFd,
+ bugreportFile, keepBugreportOnRetrieval, myListener);
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException in retrieveBugreport", e);
}
@@ -317,7 +372,8 @@
private void validateBugreportFlags(int flags) {
flags = clearBugreportFlag(flags,
BugreportParams.BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA
- | BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT);
+ | BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT
+ | BugreportParams.BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL);
if (flags != 0) {
Slog.w(TAG, "Unknown bugreport flags: " + flags);
throw new IllegalArgumentException("Unknown bugreport flags: " + flags);
@@ -482,6 +538,9 @@
boolean reportFinishedFile =
(bugreportFlags & BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT) != 0;
+ boolean keepBugreportOnRetrieval =
+ (bugreportFlags & BugreportParams.BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL) != 0;
+
IDumpstate ds = startAndGetDumpstateBinderServiceLocked();
if (ds == null) {
Slog.w(TAG, "Unable to get bugreport service");
@@ -490,7 +549,8 @@
}
DumpstateListener myListener = new DumpstateListener(listener, ds,
- new Pair<>(callingUid, callingPackage), reportFinishedFile);
+ new Pair<>(callingUid, callingPackage), reportFinishedFile,
+ keepBugreportOnRetrieval);
setCurrentDumpstateListenerLocked(myListener);
try {
ds.startBugreport(callingUid, callingPackage, bugreportFd, screenshotFd, bugreportMode,
@@ -646,9 +706,16 @@
private final boolean mReportFinishedFile;
private int mProgress; // used for debugging purposes only
private boolean mDone;
+ private boolean mKeepBugreportOnRetrieval;
DumpstateListener(IDumpstateListener listener, IDumpstate ds,
Pair<Integer, String> caller, boolean reportFinishedFile) {
+ this(listener, ds, caller, reportFinishedFile, /* keepBugreportOnRetrieval= */ false);
+ }
+
+ DumpstateListener(IDumpstateListener listener, IDumpstate ds,
+ Pair<Integer, String> caller, boolean reportFinishedFile,
+ boolean keepBugreportOnRetrieval) {
if (DEBUG) {
Slogf.d(TAG, "Starting DumpstateListener(id=%d) for caller %s", mId, caller);
}
@@ -656,6 +723,7 @@
mDs = ds;
mCaller = caller;
mReportFinishedFile = reportFinishedFile;
+ mKeepBugreportOnRetrieval = keepBugreportOnRetrieval;
try {
mDs.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -690,7 +758,8 @@
reportFinishedLocked("File: " + bugreportFile);
}
if (mReportFinishedFile) {
- mBugreportFileManager.addBugreportFileForCaller(mCaller, bugreportFile);
+ mBugreportFileManager.addBugreportFileForCaller(
+ mCaller, bugreportFile, mKeepBugreportOnRetrieval);
} else if (DEBUG) {
Slog.d(TAG, "Not reporting finished file");
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 7c32cde..2951ef6 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -2374,12 +2374,6 @@
permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
mPm.mPermissionManager.onPackageInstalled(pkg, installRequest.getPreviousAppId(),
permissionParamsBuilder.build(), userId);
- // Apply restricted settings on potentially dangerous packages.
- if (installRequest.getPackageSource() == PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
- || installRequest.getPackageSource()
- == PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE) {
- enableRestrictedSettings(pkgName, pkg.getUid());
- }
}
installRequest.setName(pkgName);
installRequest.setAppId(pkg.getUid());
@@ -2394,16 +2388,13 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- private void enableRestrictedSettings(String pkgName, int appId) {
+ private void enableRestrictedSettings(String pkgName, int appId, int userId) {
final AppOpsManager appOpsManager = mPm.mContext.getSystemService(AppOpsManager.class);
- final int[] allUsersList = mPm.mUserManager.getUserIds();
- for (int userId : allUsersList) {
- final int uid = UserHandle.getUid(userId, appId);
- appOpsManager.setMode(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
- uid,
- pkgName,
- AppOpsManager.MODE_ERRORED);
- }
+ final int uid = UserHandle.getUid(userId, appId);
+ appOpsManager.setMode(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
+ uid,
+ pkgName,
+ AppOpsManager.MODE_ERRORED);
}
/**
@@ -2820,13 +2811,10 @@
mPm.mRequiredInstallerPackage,
/* packageSender= */ mPm, launchedForRestore, killApp, update, archived);
-
// Work that needs to happen on first install within each user
- if (firstUserIds.length > 0) {
- for (int userId : firstUserIds) {
- mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
- userId);
- }
+ for (int userId : firstUserIds) {
+ mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
+ userId);
}
if (request.isAllNewUsers() && !update) {
@@ -2835,6 +2823,16 @@
mPm.notifyPackageChanged(packageName, request.getAppId());
}
+ for (int userId : firstUserIds) {
+ // Apply restricted settings on potentially dangerous packages. Needs to happen
+ // after appOpsManager is notified of the new package
+ if (request.getPackageSource() == PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
+ || request.getPackageSource()
+ == PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE) {
+ enableRestrictedSettings(packageName, request.getAppId(), userId);
+ }
+ }
+
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c260be9..8b82a1c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -506,6 +506,9 @@
if (!canAccessProfile(userId, "cannot get shouldHideFromSuggestions")) {
return false;
}
+ if (Flags.archiving() && packageName != null && isPackageArchived(packageName, user)) {
+ return true;
+ }
if (mPackageManagerInternal.filterAppAccess(
packageName, Binder.getCallingUid(), userId)) {
return false;
@@ -537,7 +540,7 @@
== 0) {
return launcherActivities;
}
- if (launcherActivities == null || launcherActivities.getList().isEmpty()) {
+ if (launcherActivities == null) {
// Cannot access profile, so we don't even return any hidden apps.
return null;
}
@@ -758,6 +761,10 @@
}
}
+ private boolean isPackageArchived(@NonNull String packageName, UserHandle user) {
+ return !getApplicationInfoForArchivedApp(packageName, user).isEmpty();
+ }
+
@NonNull
private List<LauncherActivityInfoInternal> generateLauncherActivitiesForArchivedApp(
@Nullable String packageName, UserHandle user) {
@@ -969,11 +976,17 @@
final int callingUid = injectBinderCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- final PackageInfo info = mPackageManagerInternal.getPackageInfo(packageName,
+ long callingFlag =
PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- callingUid, user.getIdentifier());
- return info != null && info.applicationInfo.enabled;
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ if (Flags.archiving()) {
+ callingFlag |= PackageManager.MATCH_ARCHIVED_PACKAGES;
+ }
+ final PackageInfo info =
+ mPackageManagerInternal.getPackageInfo(
+ packageName, callingFlag, callingUid, user.getIdentifier());
+ return info != null
+ && (info.applicationInfo.enabled || info.applicationInfo.isArchived);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1439,7 +1452,18 @@
if (!canAccessProfile(user.getIdentifier(), "Cannot check component")) {
return false;
}
-
+ if (Flags.archiving() && component != null && component.getPackageName() != null) {
+ List<LauncherActivityInfoInternal> archiveActivities =
+ generateLauncherActivitiesForArchivedApp(component.getPackageName(), user);
+ if (!archiveActivities.isEmpty()) {
+ for (int i = 0; i < archiveActivities.size(); i++) {
+ if (archiveActivities.get(i).getComponentName().equals(component)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
final int callingUid = injectBinderCallingUid();
final int state = mPackageManagerInternal.getComponentEnabledSetting(component,
callingUid, user.getIdentifier());
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 6a2ddc8..ea082cf 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -159,6 +159,9 @@
if (pkgSetting.getPkg().isCoreApp()) {
throw new IllegalStateException("Found a core app that's not important");
}
+ // Use REASON_FIRST_BOOT to query "pm.dexopt.first-boot" for the compiler filter, but
+ // the reason itself won't make it into the actual compiler reason because it will be
+ // overridden in otapreopt.cpp.
mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.getPkg(), pkgSetting,
PackageManagerService.REASON_FIRST_BOOT));
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index b9b5908..305e353 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -44,6 +44,7 @@
import android.content.IntentSender.SendIntentException;
import android.content.pm.ApplicationInfo;
import android.content.pm.ArchivedPackageParcel;
+import android.content.pm.Flags;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageInstallerSession;
@@ -745,6 +746,22 @@
params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
}
+ if (Flags.rollbackLifetime()) {
+ if (params.rollbackLifetimeMillis > 0) {
+ if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
+ throw new IllegalArgumentException(
+ "Can't set rollbackLifetimeMillis when rollback is not enabled");
+ }
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Setting rollback lifetime requires the MANAGE_ROLLBACKS permission");
+ }
+ } else if (params.rollbackLifetimeMillis < 0) {
+ throw new IllegalArgumentException("rollbackLifetimeMillis can't be negative.");
+ }
+ }
+
boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
if (isApex) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES)
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5dc7dab..1be28ca 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1282,6 +1282,7 @@
info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
info.autoRevokePermissionsMode = params.autoRevokePermissionsMode;
info.installFlags = params.installFlags;
+ info.rollbackLifetimeMillis = params.rollbackLifetimeMillis;
info.isMultiPackage = params.isMultiPackage;
info.isStaged = params.isStaged;
info.rollbackDataPolicy = params.rollbackDataPolicy;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 978d8e4..3430bb4d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2138,6 +2138,19 @@
}
@Override
+ public boolean isForegroundUserAdmin() {
+ // No permission requirements for this API.
+ synchronized (mUsersLock) {
+ final int currentUserId = getCurrentUserId();
+ if (currentUserId != UserHandle.USER_NULL) {
+ final UserInfo userInfo = getUserInfoLU(currentUserId);
+ return userInfo != null && userInfo.isAdmin();
+ }
+ }
+ return false;
+ }
+
+ @Override
public @NonNull String getUserName() {
final int callingUid = Binder.getCallingUid();
if (!hasQueryOrCreateUsersPermission()
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 85d93f4..a5b90f1 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -174,6 +174,11 @@
@Nullable private final String mInstallerPackageName;
/**
+ * Time after which rollback expires.
+ */
+ private long mRollbackLifetimeMillis = 0;
+
+ /**
* Session ids for all packages in the install. For multi-package sessions, this is the list
* of child session ids. For normal sessions, this list is a single element with the normal
* session id.
@@ -286,6 +291,24 @@
}
/**
+ * Sets rollback lifetime in milliseconds, for purposes of expiring rollback data.
+ */
+ @WorkerThread
+ void setRollbackLifetimeMillis(long lifetimeMillis) {
+ assertInWorkerThread();
+ mRollbackLifetimeMillis = lifetimeMillis;
+ }
+
+ /**
+ * Returns rollback lifetime in milliseconds, for purposes of expiring rollback data.
+ */
+ @WorkerThread
+ long getRollbackLifetimeMillis() {
+ assertInWorkerThread();
+ return mRollbackLifetimeMillis;
+ }
+
+ /**
* Returns the session ID associated with this rollback, or {@code -1} if unknown.
*/
@AnyThread
@@ -930,6 +953,7 @@
ipw.println("-state: " + getStateAsString());
ipw.println("-stateDescription: " + mStateDescription);
ipw.println("-timestamp: " + getTimestamp());
+ ipw.println("-rollbackLifetimeMillis: " + getRollbackLifetimeMillis());
ipw.println("-isStaged: " + isStaged());
ipw.println("-originalSessionId: " + getOriginalSessionId());
ipw.println("-packages:");
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 720c773..8d93408 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -28,6 +28,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
+import android.content.pm.Flags;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
@@ -702,6 +703,15 @@
// Schedules future expiration as appropriate.
@WorkerThread
private void runExpiration() {
+ if (Flags.rollbackLifetime()) {
+ runExpirationCustomRollbackLifetime();
+ } else {
+ runExpirationDefaultRollbackLifetime();
+ }
+ }
+
+ @WorkerThread
+ private void runExpirationDefaultRollbackLifetime() {
getHandler().removeCallbacks(mRunExpiration);
assertInWorkerThread();
Instant now = Instant.now();
@@ -729,6 +739,44 @@
}
}
+ @WorkerThread
+ private void runExpirationCustomRollbackLifetime() {
+ getHandler().removeCallbacks(mRunExpiration);
+ assertInWorkerThread();
+ Instant now = Instant.now();
+ long minDelay = 0;
+ Iterator<Rollback> iter = mRollbacks.iterator();
+ while (iter.hasNext()) {
+ Rollback rollback = iter.next();
+ if (!rollback.isAvailable() && !rollback.isCommitted()) {
+ continue;
+ }
+ long rollbackLifetimeMillis = rollback.getRollbackLifetimeMillis();
+ if (rollbackLifetimeMillis <= 0) {
+ rollbackLifetimeMillis = mRollbackLifetimeDurationInMillis;
+ }
+
+ Instant rollbackExpiryTimestamp = rollback.getTimestamp()
+ .plusMillis(rollbackLifetimeMillis);
+ if (!now.isBefore(rollbackExpiryTimestamp)) {
+ Slog.i(TAG, "runExpiration id=" + rollback.info.getRollbackId());
+ iter.remove();
+ deleteRollback(rollback, "Expired by timeout");
+ continue;
+ }
+
+ long delay = now.until(
+ rollbackExpiryTimestamp, ChronoUnit.MILLIS);
+ if (minDelay == 0 || delay < minDelay) {
+ minDelay = delay;
+ }
+ }
+
+ if (minDelay != 0) {
+ getHandler().postDelayed(mRunExpiration, minDelay);
+ }
+ }
+
@AnyThread
private Handler getHandler() {
return mHandler;
@@ -1277,6 +1325,7 @@
}
final Rollback rollback;
+
if (parentSession.isStaged()) {
rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
installerPackageName, packageSessionIds, getExtensionVersions());
@@ -1285,6 +1334,11 @@
installerPackageName, packageSessionIds, getExtensionVersions());
}
+ if (Flags.rollbackLifetime()) {
+ rollback.setRollbackLifetimeMillis(parentSession.rollbackLifetimeMillis);
+ }
+
+
mRollbacks.add(rollback);
return rollback;
}
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 8068c6f..0af137f 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -19,6 +19,7 @@
import static com.android.server.rollback.Rollback.rollbackStateFromString;
import android.annotation.NonNull;
+import android.content.pm.Flags;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
@@ -312,6 +313,9 @@
JSONObject dataJson = new JSONObject();
dataJson.put("info", rollbackInfoToJson(rollback.info));
dataJson.put("timestamp", rollback.getTimestamp().toString());
+ if (Flags.rollbackLifetime()) {
+ dataJson.put("rollbackLifetimeMillis", rollback.getRollbackLifetimeMillis());
+ }
dataJson.put("originalSessionId", rollback.getOriginalSessionId());
dataJson.put("state", rollback.getStateAsString());
dataJson.put("stateDescription", rollback.getStateDescription());
@@ -375,7 +379,7 @@
@VisibleForTesting
static Rollback rollbackFromJson(JSONObject dataJson, File backupDir)
throws JSONException, ParseException {
- return new Rollback(
+ Rollback rollback = new Rollback(
rollbackInfoFromJson(dataJson.getJSONObject("info")),
backupDir,
Instant.parse(dataJson.getString("timestamp")),
@@ -388,6 +392,10 @@
dataJson.optInt("userId", UserHandle.SYSTEM.getIdentifier()),
dataJson.optString("installerPackageName", ""),
extensionVersionsFromJson(dataJson.optJSONArray("extensionVersions")));
+ if (Flags.rollbackLifetime()) {
+ rollback.setRollbackLifetimeMillis(dataJson.optLong("rollbackLifetimeMillis"));
+ }
+ return rollback;
}
private static JSONObject toJson(VersionedPackage pkg) throws JSONException {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 635e11b..f82f08b 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -70,7 +70,6 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.Xml;
-import android.view.Display;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
@@ -79,7 +78,6 @@
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
-import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
@@ -1523,57 +1521,13 @@
mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
}
- /**
- * @param uid: uid of the calling app (obtained via getCallingUid())
- * @param displayId: the id of a Display
- * @return Returns true if both of the following conditions hold -
- * 1) the uid belongs to an app instead of a system core component; and
- * 2) either the uid is running on a virtual device or the displayId
- * is owned by a virtual device
- */
- private boolean isAppOrDisplayOnAnyVirtualDevice(int uid, int displayId) {
- if (UserHandle.isCore(uid)) {
- return false;
- }
-
- if (mVirtualDeviceManager == null) {
- mVirtualDeviceManager = LocalServices.getService(
- VirtualDeviceManagerInternal.class);
- if (mVirtualDeviceManager == null) {
- // VirtualDeviceManager service may not have been published
- return false;
- }
- }
-
- switch (displayId) {
- case Display.INVALID_DISPLAY:
- // There is no Display object associated with the Context of the calling app.
- if (mVirtualDeviceManager.isAppRunningOnAnyVirtualDevice(uid)) {
- return true;
- }
- break;
- case Display.DEFAULT_DISPLAY:
- // The DEFAULT_DISPLAY is by definition not virtual.
- break;
- default:
- // Other display IDs can belong to logical displays created for other purposes.
- if (mVirtualDeviceManager.isDisplayOwnedByAnyVirtualDevice(displayId)) {
- return true;
- }
- break;
- }
- return false;
- }
-
@Override
- public boolean isDeviceLocked(int userId, int displayId) throws RemoteException {
- int uid = getCallingUid();
- if (isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
- // Virtual displays are considered insecure because they may be used for streaming
- // to other devices.
+ public boolean isDeviceLocked(int userId, int deviceId) throws RemoteException {
+ if (deviceId != Context.DEVICE_ID_DEFAULT) {
+ // Virtual devices are considered insecure.
return false;
}
- userId = ActivityManager.handleIncomingUser(getCallingPid(), uid, userId,
+ userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
false /* allowAll */, true /* requireFull */, "isDeviceLocked", null);
final long token = Binder.clearCallingIdentity();
@@ -1588,15 +1542,12 @@
}
@Override
- public boolean isDeviceSecure(int userId, int displayId) throws RemoteException {
- int uid = getCallingUid();
- if (isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
- // Virtual displays are considered insecure because they may be used for streaming
- // to other devices.
+ public boolean isDeviceSecure(int userId, int deviceId) throws RemoteException {
+ if (deviceId != Context.DEVICE_ID_DEFAULT) {
+ // Virtual devices are considered insecure.
return false;
}
-
- userId = ActivityManager.handleIncomingUser(getCallingPid(), uid, userId,
+ userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e7893da..f314900 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4716,6 +4716,17 @@
scheduleAnimation();
mWmService.mH.post(() -> InputMethodManagerInternal.get().onImeParentChanged());
+ } else if (mImeControlTarget != null && mImeControlTarget == mImeLayeringTarget) {
+ // Even if the IME surface parent is not changed, the layer target belonging to the
+ // parent may have changes. Then attempt to reassign if the IME control target is
+ // possible to be the relative layer.
+ final SurfaceControl lastRelativeLayer = mImeWindowsContainer.getLastRelativeLayer();
+ if (lastRelativeLayer != mImeLayeringTarget.mSurfaceControl) {
+ assignRelativeLayerForIme(getSyncTransaction(), false /* forceUpdate */);
+ if (lastRelativeLayer != mImeWindowsContainer.getLastRelativeLayer()) {
+ scheduleAnimation();
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d2f6d16..6cad16c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -486,8 +486,6 @@
private boolean mForceShowForAllUsers;
- private boolean mForceTranslucent = false;
-
// The display category name for this task.
String mRequiredDisplayCategory;
@@ -3643,7 +3641,7 @@
*/
TaskFragmentParentInfo getTaskFragmentParentInfo() {
return new TaskFragmentParentInfo(getConfiguration(), getDisplayId(),
- shouldBeVisible(null /* starting */));
+ shouldBeVisible(null /* starting */), hasNonFinishingDirectActivity());
}
@Override
@@ -4502,10 +4500,6 @@
return true;
}
- void setForceTranslucent(boolean set) {
- mForceTranslucent = set;
- }
-
@Override
public boolean isAlwaysOnTop() {
return !isForceHidden() && super.isAlwaysOnTop();
@@ -4523,11 +4517,6 @@
}
@Override
- protected boolean isForceTranslucent() {
- return mForceTranslucent;
- }
-
- @Override
long getProtoFieldId() {
return TASK;
}
@@ -6062,6 +6051,11 @@
// Non-root task position changed.
mRootWindowContainer.invalidateTaskLayers();
}
+
+ if (child.asActivityRecord() != null) {
+ // Send for TaskFragmentParentInfo#hasDirectActivity change.
+ sendTaskFragmentParentInfoChangedIfNeeded();
+ }
}
void reparent(TaskDisplayArea newParent, boolean onTop) {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 82d3424..00f2b89 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -374,6 +374,8 @@
@interface FlagForceHidden {}
protected int mForceHiddenFlags = 0;
+ private boolean mForceTranslucent = false;
+
final Point mLastSurfaceSize = new Point();
private final Rect mTmpBounds = new Rect();
@@ -843,8 +845,12 @@
return true;
}
- protected boolean isForceTranslucent() {
- return false;
+ boolean isForceTranslucent() {
+ return mForceTranslucent;
+ }
+
+ void setForceTranslucent(boolean set) {
+ mForceTranslucent = set;
}
boolean isLeafTaskFragment() {
@@ -1049,6 +1055,10 @@
return getActivity(ActivityRecord::canBeTopRunning);
}
+ /**
+ * Reports non-finishing activity count including this TaskFragment's child embedded
+ * TaskFragments' children activities.
+ */
int getNonFinishingActivityCount() {
final int[] runningActivityCount = new int[1];
forAllActivities(a -> {
@@ -1059,6 +1069,20 @@
return runningActivityCount[0];
}
+ /**
+ * Returns {@code true} if there's any non-finishing direct children activity, which is not
+ * embedded in TaskFragments
+ */
+ boolean hasNonFinishingDirectActivity() {
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityRecord activity = getChildAt(i).asActivityRecord();
+ if (activity != null && !activity.finishing) {
+ return true;
+ }
+ }
+ return false;
+ }
+
boolean isTopActivityFocusable() {
final ActivityRecord r = topRunningActivity();
return r != null ? r.isFocusable()
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 4a0f44b..8f884d2f 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2706,6 +2706,10 @@
return mLastLayer;
}
+ SurfaceControl getLastRelativeLayer() {
+ return mLastRelativeToLayer;
+ }
+
protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
if (mSurfaceFreezer.hasLeash()) {
// When the freezer has created animation leash parent for the window, set the layer
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index eb60aab..a8b9417 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -37,6 +37,7 @@
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_UNKNOWN;
import static android.window.WindowContainerTransaction.Change.CHANGE_FOCUSABLE;
+import static android.window.WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT;
import static android.window.WindowContainerTransaction.Change.CHANGE_HIDDEN;
import static android.window.WindowContainerTransaction.Change.CHANGE_RELATIVE_BOUNDS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER;
@@ -768,8 +769,7 @@
}
}
- if ((c.getChangeMask()
- & WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT) != 0) {
+ if ((c.getChangeMask() & CHANGE_FORCE_TRANSLUCENT) != 0) {
tr.setForceTranslucent(c.getForceTranslucent());
effects = TRANSACT_EFFECTS_LIFECYCLE;
}
@@ -877,6 +877,11 @@
effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
}
+ if ((c.getChangeMask() & CHANGE_FORCE_TRANSLUCENT) != 0) {
+ taskFragment.setForceTranslucent(c.getForceTranslucent());
+ effects = TRANSACT_EFFECTS_LIFECYCLE;
+ }
+
effects |= applyChanges(taskFragment, c);
if (taskFragment.shouldStartChangeTransition(mTmpBounds0, mTmpBounds1)) {
@@ -2022,9 +2027,11 @@
if (mTaskFragmentOrganizerController.isSystemOrganizer(organizer.asBinder())) {
// System organizer is allowed to update the hidden and focusable state.
- // We unset the CHANGE_HIDDEN and CHANGE_FOCUSABLE bits because they are checked here.
+ // We unset the CHANGE_HIDDEN, CHANGE_FOCUSABLE, and CHANGE_FORCE_TRANSLUCENT bits
+ // because they are checked here.
changeMaskToBeChecked &= ~CHANGE_HIDDEN;
changeMaskToBeChecked &= ~CHANGE_FOCUSABLE;
+ changeMaskToBeChecked &= ~CHANGE_FORCE_TRANSLUCENT;
}
// setRelativeBounds is allowed.
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 4e6dd06..ece3dfe 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -674,6 +674,17 @@
}
@Test
+ public void notifyPermissionRequestCancelled_forwardsToLogger() {
+ int hostUid = 123;
+ mService =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+
+ mService.notifyPermissionRequestCancelled(hostUid);
+
+ verify(mMediaProjectionMetricsLogger).logProjectionPermissionRequestCancelled(hostUid);
+ }
+
+ @Test
public void notifyAppSelectorDisplayed_forwardsToLogger() {
int hostUid = 456;
mService =
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
index 410604f..ad1cd6e 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED;
@@ -452,6 +453,63 @@
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
}
+ @Test
+ public void logProjectionPermissionRequestCancelled_logsStateChangedAtomId() {
+ mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+ verifyStateChangedAtomIdLogged();
+ }
+
+ @Test
+ public void logProjectionPermissionRequestCancelled_logsExistingSessionId() {
+ int existingSessionId = 456;
+ when(mSessionIdGenerator.getCurrentSessionId()).thenReturn(existingSessionId);
+
+ mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+ verifySessionIdLogged(existingSessionId);
+ }
+
+ @Test
+ public void logProjectionPermissionRequestCancelled_logsStateCancelled() {
+ mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+ verifyStateLogged(MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED);
+ }
+
+ @Test
+ public void logProjectionPermissionRequestCancelled_logsPreviousState() {
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ verifyPreviousStateLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN);
+
+ mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+ verifyPreviousStateLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
+ }
+
+ @Test
+ public void logProjectionPermissionRequestCancelled_logsHostUid() {
+ mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+ verifyHostUidLogged(TEST_HOST_UID);
+ }
+
+ @Test
+ public void logProjectionPermissionRequestCancelled_logsUnknownTargetUid() {
+ mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+ verifyTargetUidLogged(-2);
+ }
+
+ @Test
+ public void logProjectionPermissionRequestCancelled_logsUnknownCreationSource() {
+ mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+ verifyCreationSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ }
+
private void verifyStateChangedAtomIdLogged() {
verify(mFrameworkStatsLogWrapper)
.write(
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index fc27edc..a4d50f0 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -94,27 +94,31 @@
public void testBugreportFileManagerFileExists() {
Pair<Integer, String> callingInfo = new Pair<>(mCallingUid, mCallingPackage);
mBugreportFileManager.addBugreportFileForCaller(
- callingInfo, mBugreportFile);
+ callingInfo, mBugreportFile, /* keepOnRetrieval= */ false);
assertThrows(IllegalArgumentException.class, () ->
mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
- callingInfo, "unknown-file.zip"));
+ mContext, callingInfo, Process.myUserHandle().getIdentifier(),
+ "unknown-file.zip"));
// No exception should be thrown.
- mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(callingInfo, mBugreportFile);
+ mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
+ mContext, callingInfo, mContext.getUserId(), mBugreportFile);
}
@Test
public void testBugreportFileManagerMultipleFiles() {
Pair<Integer, String> callingInfo = new Pair<>(mCallingUid, mCallingPackage);
mBugreportFileManager.addBugreportFileForCaller(
- callingInfo, mBugreportFile);
+ callingInfo, mBugreportFile, /* keepOnRetrieval= */ false);
mBugreportFileManager.addBugreportFileForCaller(
- callingInfo, mBugreportFile2);
+ callingInfo, mBugreportFile2, /* keepOnRetrieval= */ false);
// No exception should be thrown.
- mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(callingInfo, mBugreportFile);
- mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(callingInfo, mBugreportFile2);
+ mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
+ mContext, callingInfo, mContext.getUserId(), mBugreportFile);
+ mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
+ mContext, callingInfo, mContext.getUserId(), mBugreportFile2);
}
@Test
@@ -122,7 +126,8 @@
Pair<Integer, String> callingInfo = new Pair<>(mCallingUid, mCallingPackage);
assertThrows(IllegalArgumentException.class,
() -> mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
- callingInfo, "test-file.zip"));
+ mContext, callingInfo, Process.myUserHandle().getIdentifier(),
+ "test-file.zip"));
}
@Test
@@ -130,7 +135,8 @@
CountDownLatch latch = new CountDownLatch(1);
Listener listener = new Listener(latch);
mService.retrieveBugreport(Binder.getCallingUid(), mContext.getPackageName(),
- new FileDescriptor(), mBugreportFile, listener);
+ mContext.getUserId(), new FileDescriptor(), mBugreportFile,
+ /* keepOnRetrieval= */ false, listener);
assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(listener.getErrorCode()).isEqualTo(
BugreportCallback.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 6235b3b..c57b051 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -1742,6 +1742,7 @@
private void testApplyTransaction_reorder_failsIfNotSystemOrganizer_common(
@TaskFragmentOperation.OperationType int opType) {
final Task task = createTask(mDisplayContent);
+ doNothing().when(task).sendTaskFragmentParentInfoChangedIfNeeded();
// Create a non-embedded Activity at the bottom.
final ActivityRecord bottomActivity = new ActivityBuilder(mAtm)
.setTask(task)
@@ -1934,7 +1935,7 @@
/** Setups the mock Task as the parent of the given TaskFragment. */
private static void setupMockParent(TaskFragment taskFragment, Task mockParent) {
doReturn(mockParent).when(taskFragment).getTask();
- doReturn(new TaskFragmentParentInfo(new Configuration(), DEFAULT_DISPLAY, true))
+ doReturn(new TaskFragmentParentInfo(new Configuration(), DEFAULT_DISPLAY, true, true))
.when(mockParent).getTaskFragmentParentInfo();
// Task needs to be visible
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 0c58069..435a835 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -1568,6 +1568,7 @@
final TaskFragment fragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
final ActivityRecord embeddedActivity = fragment.getTopMostActivity();
+ doNothing().when(task).sendTaskFragmentParentInfoChangedIfNeeded();
task.moveActivityToFront(activity);
assertEquals("Activity must be moved to front", activity, task.getTopMostActivity());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index cd3fef6..699580a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -101,6 +101,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.function.BiConsumer;
/**
* Test class for {@link ITaskOrganizer} and {@link android.window.ITaskOrganizerController}.
@@ -583,7 +584,7 @@
}
@Test
- public void testTaskFragmentHiddenAndFocusableChanges() {
+ public void testTaskFragmentHiddenFocusableTranslucentChanges() {
removeGlobalMinSizeRestriction();
final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).build();
@@ -605,10 +606,12 @@
assertTrue(taskFragment.shouldBeVisible(null));
assertTrue(taskFragment.isFocusable());
assertTrue(taskFragment.isTopActivityFocusable());
+ assertFalse(taskFragment.isForceTranslucent());
// Apply transaction to the TaskFragment hidden and not focusable.
t.setHidden(taskFragment.mRemoteToken.toWindowContainerToken(), true);
t.setFocusable(taskFragment.mRemoteToken.toWindowContainerToken(), false);
+ t.setForceTranslucent(taskFragment.mRemoteToken.toWindowContainerToken(), true);
mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked(
t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE,
false /* shouldApplyIndependently */);
@@ -617,10 +620,12 @@
assertFalse(taskFragment.shouldBeVisible(null));
assertFalse(taskFragment.isFocusable());
assertFalse(taskFragment.isTopActivityFocusable());
+ assertTrue(taskFragment.isForceTranslucent());
// Apply transaction to the TaskFragment not hidden and focusable.
t.setHidden(taskFragment.mRemoteToken.toWindowContainerToken(), false);
t.setFocusable(taskFragment.mRemoteToken.toWindowContainerToken(), true);
+ t.setForceTranslucent(taskFragment.mRemoteToken.toWindowContainerToken(), false);
mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked(
t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE,
false /* shouldApplyIndependently */);
@@ -629,10 +634,32 @@
assertTrue(taskFragment.shouldBeVisible(null));
assertTrue(taskFragment.isFocusable());
assertTrue(taskFragment.isTopActivityFocusable());
+ assertFalse(taskFragment.isForceTranslucent());
}
@Test
- public void testTaskFragmentHiddenAndFocusableChanges_throwsWhenNotSystemOrganizer() {
+ public void testTaskFragmentChangeHidden_throwsWhenNotSystemOrganizer() {
+ // Non-system organizers are not allow to update the hidden state.
+ testTaskFragmentChangesWithoutSystemOrganizerThrowException(
+ (t, windowContainerToken) -> t.setHidden(windowContainerToken, true));
+ }
+
+ @Test
+ public void testTaskFragmentChangeFocusable_throwsWhenNotSystemOrganizer() {
+ // Non-system organizers are not allow to update the focusable state.
+ testTaskFragmentChangesWithoutSystemOrganizerThrowException(
+ (t, windowContainerToken) -> t.setFocusable(windowContainerToken, false));
+ }
+
+ @Test
+ public void testTaskFragmentChangeTranslucent_throwsWhenNotSystemOrganizer() {
+ // Non-system organizers are not allow to update the translucent state.
+ testTaskFragmentChangesWithoutSystemOrganizerThrowException(
+ (t, windowContainerToken) -> t.setForceTranslucent(windowContainerToken, true));
+ }
+
+ private void testTaskFragmentChangesWithoutSystemOrganizerThrowException(
+ BiConsumer<WindowContainerTransaction, WindowContainerToken> addOp) {
removeGlobalMinSizeRestriction();
final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).build();
@@ -641,21 +668,15 @@
final TaskFragmentOrganizer organizer =
createTaskFragmentOrganizer(t, false /* isSystemOrganizer */);
- final IBinder token = new Binder();
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(rootTask)
- .setFragmentToken(token)
+ .setFragmentToken(new Binder())
.setOrganizer(organizer)
.createActivityCount(1)
.build();
- assertTrue(rootTask.shouldBeVisible(null));
- assertTrue(taskFragment.shouldBeVisible(null));
+ addOp.accept(t, taskFragment.mRemoteToken.toWindowContainerToken());
- t.setHidden(taskFragment.mRemoteToken.toWindowContainerToken(), true);
- t.setFocusable(taskFragment.mRemoteToken.toWindowContainerToken(), false);
-
- // Non-system organizers are not allow to update the hidden and focusable states.
assertThrows(SecurityException.class, () ->
mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked(
t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 3ec6f42..973ab84 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -448,7 +448,6 @@
mDisplayContent.updateImeParent();
// Ime should on top of the popup IME layering target window.
- mDisplayContent.assignChildLayers(mTransaction);
assertWindowHigher(mImeWindow, popupImeTargetWin);
}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index a1a39ff..359ef83 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -125,6 +125,17 @@
TUNNEL_CONNECTION_PARAMS);
}
+ private static VcnGatewayConnectionConfig.Builder newBuilderMinimal() {
+ final VcnGatewayConnectionConfig.Builder builder =
+ new VcnGatewayConnectionConfig.Builder(
+ "newBuilderMinimal", TUNNEL_CONNECTION_PARAMS);
+ for (int caps : EXPOSED_CAPS) {
+ builder.addExposedCapability(caps);
+ }
+
+ return builder;
+ }
+
private static VcnGatewayConnectionConfig buildTestConfigWithExposedCapsAndOptions(
VcnGatewayConnectionConfig.Builder builder,
Set<Integer> gatewayOptions,
@@ -273,6 +284,7 @@
assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
assertEquals(MAX_MTU, config.getMaxMtu());
+ assertTrue(config.isSafeModeEnabled());
assertFalse(
config.hasGatewayOption(
@@ -290,6 +302,13 @@
}
@Test
+ public void testBuilderAndGettersSafeModeDisabled() {
+ final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build();
+
+ assertFalse(config.isSafeModeEnabled());
+ }
+
+ @Test
public void testPersistableBundle() {
final VcnGatewayConnectionConfig config = buildTestConfig();
@@ -305,6 +324,13 @@
}
@Test
+ public void testPersistableBundleSafeModeDisabled() {
+ final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build();
+
+ assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
+ }
+
+ @Test
public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() {
PersistableBundle configBundle = buildTestConfig().toPersistableBundle();
configBundle.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, null);
@@ -411,4 +437,18 @@
assertEquals(config, configEqual);
assertNotEquals(config, configNotEqual);
}
+
+ @Test
+ public void testSafeModeEnableDisableEquality() throws Exception {
+ final VcnGatewayConnectionConfig config = newBuilderMinimal().build();
+ final VcnGatewayConnectionConfig configEqual = newBuilderMinimal().build();
+
+ assertEquals(config.isSafeModeEnabled(), configEqual.isSafeModeEnabled());
+
+ final VcnGatewayConnectionConfig configNotEqual =
+ newBuilderMinimal().enableSafeMode(false).build();
+
+ assertEquals(config, configEqual);
+ assertNotEquals(config, configNotEqual);
+ }
}