Merge "Use IoThread instead of BackgroundThread for HistoricalRegistry." into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 6975b55..eac416a 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -1243,6 +1243,13 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+java_aconfig_library {
+ name: "android.crashrecovery.flags-aconfig-java-host",
+ aconfig_declarations: "android.crashrecovery.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ host_supported: true,
+}
+
// Backup
java_aconfig_library {
name: "backup_flags_lib",
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index f21e11a..c7b0be7 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -244,6 +244,10 @@
* {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}. You will generally handle
* this in {@link DeviceAdminReceiver#onProfileProvisioningComplete}.
*
+ * <p>The intent for this action may include the following extras:
+ * <ul>
+ * <li>{@link DevicePolicyManager#EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}
+ *
* @see DevicePolicyManager#ACTION_PROVISIONING_SUCCESSFUL
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -801,6 +805,9 @@
* {@link DevicePolicyManager#ACTION_PROVISIONING_SUCCESSFUL} will also be sent to the same
* application.
*
+ * <p>The {@code Intent} may include any of the extras specified for
+ * {@link #ACTION_PROFILE_PROVISIONING_COMPLETE}.
+ *
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
*/
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ba91be9..9058713 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -192,32 +192,134 @@
import java.util.concurrent.Executor;
import java.util.function.Consumer;
-// TODO(b/172376923) - add CarDevicePolicyManager examples below (or remove reference to it).
/**
- * Public interface for managing policies enforced on a device. Most clients of this class must be
- * registered with the system as a <a href="{@docRoot}guide/topics/admin/device-admin.html">device
- * administrator</a>. Additionally, a device administrator may be registered as either a profile or
- * device owner. A given method is accessible to all device administrators unless the documentation
- * for that method specifies that it is restricted to either device or profile owners. Any
- * application calling an api may only pass as an argument a device administrator component it
- * owns. Otherwise, a {@link SecurityException} will be thrown.
+ * Manages device policy and restrictions applied to the user of the device or
+ * apps running on the device.
*
- * <p><b>Note: </b>on
- * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}, some methods can
- * throw an {@link UnsafeStateException} exception (for example, if the vehicle is moving), so
- * callers running on automotive builds should always check for that exception, otherwise they
- * might crash.
+ * <p>This class contains three types of methods:
+ * <ol><li>Those aimed at <a href="#managingapps">managing apps</a>
+ * <li>Those aimed at the <a href="#roleholder">Device Policy Management Role Holder</a>
+ * <li>Those aimed at <a href="#querying">apps which wish to respect device policy</a>
+ * </ol>
*
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>
- * For more information about managing policies for device administration, read the <a href=
- * "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a> developer
- * guide. </div>
+ * <p>The intended caller for each API is indicated in its Javadoc.
+ *
+ * <p id="managingapps"><b>Managing Apps</b>
+ * <p>Apps can be made capable of setting device policy ("Managing Apps") either by
+ * being set as a <a href="#deviceadmin">Device Administrator</a>, being set as a
+ * <a href="#devicepolicycontroller">Device Policy Controller</a>, or by holding the
+ * appropriate <a href="#permissions">Permissions</a>.
+ *
+ * <p id="deviceadmin">A <b>Device Administrator</b> is an app which is able to enforce device
+ * policies that it has declared in its device admin XML file. An app can prompt the user to give it
+ * device administator privileges using the {@link #ACTION_ADD_DEVICE_ADMIN} action.
+ *
+ * <p>For more information about Device Administration, read the
+ * <a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>
+ * developer guide.
+ *
+ * <p id="devicepolicycontroller">Through <a href="#managed_provisioning">Managed Provisioning</a>,
+ * Device Administrator apps can also be recognised as <b>
+ Device Policy Controllers</b>. Device Policy Controllers can be one of
+ * two types:
+ * <ul>
+ * <li>A <i id="deviceowner">Device Owner</i>, which only ever exists on the
+ * {@link UserManager#isSystemUser System User} or {@link UserManager#isMainUser Main User}, is
+ * the most powerful type of Device Policy Controller and can affect policy across the device.
+ * <li>A <i id="profileowner">Profile Owner<i>, which can exist on any user, can
+ * affect policy on the user it is on, and when it is running on
+ * {@link UserManager#isProfile a profile} has
+ * <a href="#profile-on-parent">limited</a> ability to affect policy on its
+ * {@link UserManager#getProfileParent parent}.
+ * </ul>
+ *
+ * <p>Additional capabilities can be provided to Device Policy Controllers in
+ * the following circumstances:
+ * <ul>
+ * <li>A Profile Owner on an <a href="#organization-owned">organization owned</a> device has access
+ * to additional abilities, both <a href="#profile-on-parent-organization-owned">affecting policy on the profile's</a>
+ * {@link UserManager#getProfileParent parent} and also the profile itself.
+ * <li>A Profile Owner running on the {@link UserManager#isSystemUser System User} has access to
+ * additional capabilities which affect the {@link UserManager#isSystemUser System User} and
+ * also the whole device.
+ * <li>A Profile Owner running on an <a href="#affiliated">affiliated</a> user has
+ * capabilities similar to that of a <a href="#deviceowner">Device Owner</a>
+ * </ul>
+ *
+ * <p>For more information, see <a href="{@docRoot}work/dpc/build-dpc">Building a Device Policy
+ * Controller</a>.
+ *
+ * <p><a href="#permissions">Permissions</a> are generally only given to apps
+ * fulfilling particular key roles on the device (such as managing {@link DeviceLockManager
+device locks}).
+ *
+ * <p id="roleholder"><b>Device Policy Management Role Holder</b>
+ * <p>One app on the device fulfills the {@link RoleManager#ROLE_DEVICE_POLICY_MANAGEMENT Device
+Policy Management Role} and is trusted with managing the overall state of
+ * Device Policy. This has access to much more powerful methods than
+ * <a href="#managingapps">managing apps</a>.
+ *
+ * <p id="querying"><b>Querying Device Policy</b>
+ * <p>In most cases, regular apps do not need to concern themselves with device
+ * policy, and restrictions will be enforced automatically. There are some cases
+ * where an app may wish to query device policy to provide a better user
+ * experience. Only a small number of policies allow apps to query them directly.
+ * These APIs will typically have no special required permissions.
+ *
+ * <p id="managedprovisioning"><b>Managed Provisioning</b>
+ * <p>Managed Provisioning is the process of recognising an app as a
+ * <a href="#deviceowner">Device Owner</a> or <a href="#profileowner">Profile Owner</a>. It
+ * involves presenting education and consent screens to the user to ensure they
+ * are aware of the capabilities this grants the <a href="#devicepolicycontroller">Device Policy
+ * Controller</a>
+ *
+ * <p>For more information on provisioning, see <a href="{@docRoot}work/dpc/build-dpc">Building a
+ * Device Policy Controller</a>.
+ *
+ * <p id="managed_profile">A <b>Managed Profile</b> enables data separation. For example to use
+ * a device both for personal and corporate usage. The managed profile and its
+ * {@link UserManager#getProfileParent parent} share a launcher.
+ *
+ * <p id="affiliated"><b>Affiliation</b>
+ * <p>Using the {@link #setAffiliationIds} method, a
+ * <a href="#deviceowner">Device Owner</a> can set a list of affiliation ids for the
+ * {@link UserManager#isSystemUser System User}. Any <a href="#profileowner">Profile Owner</a> on
+ * the same device can also call {@link #setAffiliationIds} to set affiliation ids
+ * for the {@link UserManager user} it is on. When there is the same ID
+ * present in both lists, the user is said to be "affiliated" and we can refer to
+ * the <a href="#profileowner">Profile Owner</a> as a "profile owner on an affiliated
+ * user" or an "affiliated profile owner".
+ *
+ * Becoming affiliated grants the <a href="#profileowner">Profile Owner</a> capabilities similar to
+ * that of the <a href="#deviceowner">Device Owner</a>. It also allows use of the
+ * {@link #bindDeviceAdminServiceAsUser} APIs for direct communication between the
+ * <a href="#deviceowner">Device Owner</a> and
+ * affiliated <a href="#profileowner">Profile Owners</a>.
+ *
+ * <p id="organization-owned"><b>Organization Owned</b></p>
+ * An organization owned device is one which is not owned by the person making use of the device and
+ * is instead owned by an organization such as their employer or education provider. These devices
+ * are recognised as being organization owned either by the presence of a
+ * <a href="#deviceowner">device owner</a> or of a
+ * {@link #isOrganizationOwnedDeviceWithManagedProfile profile which has a profile owner is marked
+ * as organization owned}.
+ *
+ * <p id="profile-on-parent-organization-owned">Profile owners running on an
+ * <a href="organization-owned">organization owned</a> device can exercise additional capabilities
+ * using the {@link #getParentProfileInstance(ComponentName)} API which apply to the parent user.
+ * Each API will indicate if it is usable in this way.
+ *
+ * <p id="automotive"><b>Android Automotive</b>
+ * <p>On {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE
+ * "Android Automotive builds"}, some methods can throw
+ * {@link UnsafeStateException "an exception"} if an action is unsafe (for example, if the vehicle
+ * is moving). Callers running on
+ * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE
+ * "Android Automotive builds"} should always check for this exception.
*/
+
@SystemService(Context.DEVICE_POLICY_SERVICE)
@RequiresFeature(PackageManager.FEATURE_DEVICE_ADMIN)
-@SuppressLint("UseIcu")
public class DevicePolicyManager {
/** @hide */
@@ -257,7 +359,7 @@
* Fetch the current value of mService. This is used in the binder cache lambda
* expressions.
*/
- private final IDevicePolicyManager getService() {
+ private IDevicePolicyManager getService() {
return mService;
}
@@ -265,7 +367,7 @@
* Fetch the current value of mParentInstance. This is used in the binder cache
* lambda expressions.
*/
- private final boolean isParentInstance() {
+ private boolean isParentInstance() {
return mParentInstance;
}
@@ -273,7 +375,7 @@
* Fetch the current value of mContext. This is used in the binder cache lambda
* expressions.
*/
- private final Context getContext() {
+ private Context getContext() {
return mContext;
}
@@ -284,39 +386,80 @@
}
/**
- * Activity action: Starts the provisioning flow which sets up a managed profile.
- *
- * <p>A managed profile allows data separation for example for the usage of a
- * device as a personal and corporate device. The user which provisioning is started from and
- * the managed profile share a launcher.
- *
- * <p>This intent will typically be sent by a mobile device management application (MDM).
- * Provisioning adds a managed profile and sets the MDM as the profile owner who has full
- * control over the profile.
+ * Activity action: Starts the provisioning flow which sets up a
+ * <a href="#managed-profile">managed profile</a>.
*
* <p>It is possible to check if provisioning is allowed or not by querying the method
* {@link #isProvisioningAllowed(String)}.
*
- * <p>In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this intent must contain the
- * extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
- * As of {@link android.os.Build.VERSION_CODES#M}, it should contain the extra
- * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, although specifying only
- * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported.
+ * <p>The intent may contain the following extras:
*
- * <p>The intent may also contain the following extras:
- * <ul>
- * <li>{@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}, optional </li>
- * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional, supported from
- * {@link android.os.Build.VERSION_CODES#N}</li>
- * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_SKIP_USER_CONSENT}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}, optional</li>
- * </ul>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th>Extra</th>
+ * <th></th>
+ * <th>Supported Versions</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}</td>
+ * <td colspan="2"></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}</td>
+ * <td></td>
+ * <td>{@link android.os.Build.VERSION_CODES#N}+</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</td>
+ * <td colspan="2"></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_LOGO_URI}</td>
+ * <td colspan="2"></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_SKIP_USER_CONSENT}</td>
+ * <td colspan="2"><b>Can only be used by an existing device owner trying to create a
+ * managed profile</b></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION}</td>
+ * <td colspan="2"></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_DISCLAIMERS}</td>
+ * <td colspan="2"></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</td>
+ * <td>
+ * <b>Required if {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} is not
+ * specified. Must match the package name of the calling application.</b>
+ * </td>
+ * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}+</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</td>
+ * <td>
+ * <b>Required if {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is not
+ * specified. Package name must match the package name of the calling
+ * application.</b>
+ * </td>
+ * <td>{@link android.os.Build.VERSION_CODES#M}+</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXTRA_PROVISIONING_ALLOW_OFFLINE}</td>
+ * <td colspan="2">On {@link android.os.Build.VERSION_CODES#TIRAMISU}+, when set to
+ * true this will <b>force</b> offline provisioning instead of allowing it</td>
+ * </tr>
+ * </tbody>
+ * </table>
*
- * <p>When managed provisioning has completed, broadcasts are sent to the application specified
- * in the provisioning intent. The
+ * <p>When <a href="#managedprovisioning">managed provisioning</a> has completed, broadcasts
+ * are sent to the application specified in the provisioning intent. The
* {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} broadcast is sent in the
* managed profile and the {@link #ACTION_MANAGED_PROFILE_PROVISIONED} broadcast is sent in
* the primary profile.
@@ -325,25 +468,25 @@
* completed, along with the above broadcast, activity intent
* {@link #ACTION_PROVISIONING_SUCCESSFUL} will also be sent to the profile owner.
*
- * <p>If provisioning fails, the managedProfile is removed so the device returns to its
+ * <p>If provisioning fails, the managed profile is removed so the device returns to its
* previous state.
*
* <p>If launched with {@link android.app.Activity#startActivityForResult(Intent, int)} a
- * result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part of
+ * result code of {@link android.app.Activity#RESULT_OK} indicates that the synchronous part of
* the provisioning flow was successful, although this doesn't guarantee the full flow will
- * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} implies
- * that the user backed-out of provisioning, or some precondition for provisioning wasn't met.
+ * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} indicates
+ * that the user backed-out of provisioning or some precondition for provisioning wasn't met.
*
- * <p>If a device policy management role holder (DPMRH) updater is present on the device, an
- * internet connection attempt must be made prior to launching this intent. If internet
- * connection could not be established, provisioning will fail unless {@link
+ * <p>If a <a href="#roleholder">device policy management role holder</a> updater is present on
+ * the device, an internet connection attempt must be made prior to launching this intent. If
+ * an internet connection can not be established, provisioning will fail unless {@link
* #EXTRA_PROVISIONING_ALLOW_OFFLINE} is explicitly set to {@code true}, in which case
- * provisioning will continue without using the DPMRH. If an internet connection has been
- * established, the DPMRH updater will be launched, which will update the DPMRH if it's not
- * present on the device, or if it's present and not valid.
- *
- * <p>If a DPMRH is present on the device and valid, the provisioning flow will be deferred to
- * it.
+ * provisioning will continue without using the
+ * <a href="#roleholder">device policy management role holder</a>. If an internet connection
+ * has been established, the <a href="#roleholder">device policy management role holder</a>
+ * updater will be launched, which may update the
+ * <a href="#roleholder">device policy management role holder</a> before continuing
+ * provisioning.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_PROVISION_MANAGED_PROFILE
@@ -822,31 +965,25 @@
"android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
/**
- * A boolean extra indicating whether offline provisioning is allowed.
- *
- * <p>For the online provisioning flow, there will be an attempt to download and install
- * the latest version of the device policy management role holder. The platform will then
- * delegate provisioning to the device policy management role holder via role holder-specific
- * provisioning actions.
- *
- * <p>For the offline provisioning flow, the provisioning flow will always be handled by
- * the platform.
- *
- * <p>If this extra is set to {@code false}, the provisioning flow will enforce that an
- * internet connection is established, which will start the online provisioning flow. If an
- * internet connection cannot be established, provisioning will fail.
- *
- * <p>If this extra is set to {@code true}, the provisioning flow will still try to connect to
- * the internet, but if it fails it will start the offline provisioning flow.
- *
- * <p>For T if this extra is set to {@code true}, the provisioning flow will be forced through
- * the platform and there will be no attempt to download and install the device policy
- * management role holder.
+ * A boolean extra indicating whether offline provisioning should be used.
*
* <p>The default value is {@code false}.
*
- * <p>This extra is respected when provided via the provisioning intent actions such as {@link
- * #ACTION_PROVISION_MANAGED_PROFILE}.
+ * <p>Usually during the <a href="#managedprovisioning">provisioning flow</a>, there will be
+ * an attempt to download and install the latest version of the <a href="#roleholder">device
+ * policy management role holder</a>. The platform will then
+ * delegate provisioning to the <a href="#roleholder">device
+ * * policy management role holder</a>.
+ *
+ * <p>When this extra is set to {@code true}, the
+ * <a href="#managedprovisioning">provisioning flow</a> will always be handled by the platform
+ * and the <a href="#roleholder">device policy management role holder</a>'s part skipped.
+ *
+ * <p>On Android versions prior to {@link Build.VERSION_CODES#TIRAMISU}, when this extra is
+ * {@code false}, the <a href="#managedprovisioning">provisioning flow</a> will enforce that an
+ * internet connection is established, or otherwise fail. When this extra is {@code true}, a
+ * connection will still be attempted but when it cannot be established provisioning will
+ * continue offline.
*/
public static final String EXTRA_PROVISIONING_ALLOW_OFFLINE =
"android.app.extra.PROVISIONING_ALLOW_OFFLINE";
@@ -1057,64 +1194,40 @@
public static final long DEFAULT_STRONG_AUTH_TIMEOUT_MS = 72 * 60 * 60 * 1000; // 72h
/**
- * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
- * allows a mobile device management application or NFC programmer application which starts
- * managed provisioning to pass data to the management application instance after provisioning.
+ * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that is
+ * passed directly to the <a href="#devicepolicycontroller">Device Policy Controller</a>
+ * after <a href="#managed-provisioning">provisioning</a>.
+ *
* <p>
- * If used with {@link #ACTION_PROVISION_MANAGED_PROFILE} it can be used by the application that
- * sends the intent to pass data to itself on the newly created profile.
- * If used with {@link #ACTION_PROVISION_MANAGED_DEVICE} it allows passing data to the same
- * instance of the app on the primary user.
* Starting from {@link android.os.Build.VERSION_CODES#M}, if used with
* {@link #MIME_TYPE_PROVISIONING_NFC} as part of NFC managed device provisioning, the NFC
* message should contain a stringified {@link java.util.Properties} instance, whose string
* properties will be converted into a {@link android.os.PersistableBundle} and passed to the
* management application after provisioning.
- *
- * <p>Admin apps will receive this extra in their {@link #ACTION_GET_PROVISIONING_MODE} and
- * {@link #ACTION_ADMIN_POLICY_COMPLIANCE} intent handlers. Additionally, {@link
- * #ACTION_GET_PROVISIONING_MODE} may also return this extra which will then be sent over to
- * {@link #ACTION_ADMIN_POLICY_COMPLIANCE}, alongside the original values that were passed to
- * {@link #ACTION_GET_PROVISIONING_MODE}.
- *
- * <p>
- * In both cases the application receives the data in
- * {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with the action
- * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. The bundle is not changed
- * during the managed provisioning.
*/
public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE =
"android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
/**
- * A String extra holding the package name of the mobile device management application that
- * will be set as the profile owner or device owner.
+ * A String extra holding the package name of the application that
+ * will be set as <a href="#devicepolicycontroller">Device Policy Controller</a>.
*
- * <p>If an application starts provisioning directly via an intent with action
- * {@link #ACTION_PROVISION_MANAGED_PROFILE} this package has to match the package name of the
- * application that started provisioning. The package will be set as profile owner in that case.
+ * <p>When this extra is set, the application must have exactly one
+ * {@link DeviceAdminReceiver device admin receiver}. This receiver will be set as the
+ * <a href="#devicepolicycontroller">Device Policy Controller</a>.
*
- * <p>This package is set as device owner when device owner provisioning is started by an NFC
- * message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
- *
- * <p> When this extra is set, the application must have exactly one device admin receiver.
- * This receiver will be set as the profile or device owner and active admin.
- *
- * @see DeviceAdminReceiver
- * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still
- * supported, but only if there is only one device admin receiver in the package that requires
- * the permission {@link android.Manifest.permission#BIND_DEVICE_ADMIN}.
+ * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}.
*/
@Deprecated
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
/**
- * A ComponentName extra indicating the device admin receiver of the mobile device management
- * application that will be set as the profile owner or device owner and active admin.
+ * A ComponentName extra indicating the {@link DeviceAdminReceiver device admin receiver} of
+ * the application that will be set as the <a href="#devicepolicycontroller">
+ * Device Policy Controller</a>.
*
* <p>If an application starts provisioning directly via an intent with action
- * {@link #ACTION_PROVISION_MANAGED_PROFILE} or
* {@link #ACTION_PROVISION_MANAGED_DEVICE} the package name of this
* component has to match the package name of the application that started provisioning.
*
@@ -1123,35 +1236,28 @@
* message containing an NFC record with MIME type
* {@link #MIME_TYPE_PROVISIONING_NFC}. For the NFC record, the component name must be
* flattened to a string, via {@link ComponentName#flattenToShortString()}.
- *
- * @see DeviceAdminReceiver
*/
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
/**
* An {@link android.accounts.Account} extra holding the account to migrate during managed
- * profile provisioning. If the account supplied is present in the primary user, it will be
- * copied, along with its credentials to the managed profile and removed from the primary user.
+ * profile provisioning.
*
- * Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}, with managed account provisioning, or
- * return as an extra to the intent result from the {@link #ACTION_GET_PROVISIONING_MODE}
- * activity.
+ * <p>If the account supplied is present in the user, it will be copied, along with its
+ * credentials to the managed profile and removed from the user.
*/
-
public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE
= "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
/**
- * Boolean extra to indicate that the migrated account should be kept. This is used in
- * conjunction with {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}. If it's set to {@code true},
- * the account will not be removed from the primary user after it is migrated to the newly
- * created user or profile.
+ * Boolean extra to indicate that the
+ * {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE migrated account} should be kept.
*
- * <p> Defaults to {@code false}
+ * <p>If it's set to {@code true}, the account will not be removed from the user after it is
+ * migrated to the newly created user or profile.
*
- * <p> Use with {@link #ACTION_PROVISION_MANAGED_PROFILE} or set as an extra to the
- * intent result of the {@link #ACTION_GET_PROVISIONING_MODE} activity.
+ * <p>Defaults to {@code false}
*
* @see #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE
*/
@@ -1590,17 +1696,14 @@
"android.app.action.PROVISIONING_SUCCESSFUL";
/**
- * A boolean extra indicating whether device encryption can be skipped as part of device owner
- * or managed profile provisioning.
+ * A boolean extra indicating whether device encryption can be skipped as part of
+ * <a href="#managed-provisioning>provisioning</a>.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} or an intent with action
* {@link #ACTION_PROVISION_MANAGED_DEVICE} that starts device owner provisioning.
*
* <p>From {@link android.os.Build.VERSION_CODES#N} onwards, this is also supported for an
* intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}.
- *
- * <p>This extra can also be returned by the admin app when performing the admin-integrated
- * provisioning flow as a result of the {@link #ACTION_GET_PROVISIONING_MODE} activity.
*/
public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =
"android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
@@ -1608,23 +1711,22 @@
/**
* A {@link Uri} extra pointing to a logo image. This image will be shown during the
* provisioning. If this extra is not passed, a default image will be shown.
- * <h5>The following URI schemes are accepted:</h5>
+ *
+ * <p><b>The following URI schemes are accepted:</b>
* <ul>
* <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
* <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
* </ul>
*
- * <p> It is the responsibility of the caller to provide an image with a reasonable
+ * <p>It is the responsibility of the caller to provide an image with a reasonable
* pixel density for the device.
*
- * <p> If a content: URI is passed, the intent should have the flag
+ * <p>If a content: URI is passed, the intent should also have the flag
* {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and the uri should be added to the
- * {@link android.content.ClipData} of the intent too.
+ * {@link android.content.ClipData} of the intent.
*
- * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE} or
- * {@link #ACTION_PROVISION_MANAGED_DEVICE}
- *
- * @deprecated Logo customization is no longer supported in the provisioning flow.
+ * @deprecated Logo customization is no longer supported in the
+ * <a href="#managedprovisioning">provisioning flow</a>.
*/
@Deprecated
public static final String EXTRA_PROVISIONING_LOGO_URI =
@@ -1632,7 +1734,8 @@
/**
* A {@link Bundle}[] extra consisting of list of disclaimer headers and disclaimer contents.
- * Each {@link Bundle} must have both {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER}
+ *
+ * <p>Each {@link Bundle} must have both {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER}
* as disclaimer header, and {@link #EXTRA_PROVISIONING_DISCLAIMER_CONTENT} as disclaimer
* content.
*
@@ -1653,20 +1756,21 @@
/**
* A String extra of localized disclaimer header.
*
- * <p> The extra is typically the company name of mobile device management application (MDM)
+ * <p>The extra is typically the company name of mobile device management application (MDM)
* or the organization name.
*
- * <p> Use in Bundle {@link #EXTRA_PROVISIONING_DISCLAIMERS}
+ * <p>{@link ApplicationInfo#FLAG_SYSTEM System apps} can also insert a disclaimer by declaring
+ * an application-level meta-data in {@code AndroidManifest.xml}.
*
- * <p> System app, i.e. application with {@link ApplicationInfo#FLAG_SYSTEM}, can also insert a
- * disclaimer by declaring an application-level meta-data in {@code AndroidManifest.xml}.
- * Must use it with {@link #EXTRA_PROVISIONING_DISCLAIMER_CONTENT}. Here is the example:
- *
+ * <p>For example:
* <pre>
* <meta-data
* android:name="android.app.extra.PROVISIONING_DISCLAIMER_HEADER"
* android:resource="@string/disclaimer_header"
* /></pre>
+ *
+ * <p>This must be accompanied with another extra using the key
+ * {@link #EXTRA_PROVISIONING_DISCLAIMER_CONTENT}.
*/
public static final String EXTRA_PROVISIONING_DISCLAIMER_HEADER =
"android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
@@ -1680,35 +1784,35 @@
* <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
* </ul>
*
- * <p> Styled text is supported in the disclaimer content. The content is parsed by
- * {@link android.text.Html#fromHtml(String)} and displayed in a
- * {@link android.widget.TextView}.
+ * <p>Styled text is supported. This is parsed by {@link android.text.Html#fromHtml(String)}
+ * and displayed in a {@link android.widget.TextView}.
*
- * <p> If a <code>content:</code> URI is passed, URI is passed, the intent should have the flag
- * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and the uri should be added to the
- * {@link android.content.ClipData} of the intent too.
+ * <p>If a <code>content:</code> URI is passed, the intent should also have the
+ * flag {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and the uri should be added to the
+ * {@link android.content.ClipData} of the intent.
*
- * <p> Use in Bundle {@link #EXTRA_PROVISIONING_DISCLAIMERS}
- *
- * <p> System app, i.e. application with {@link ApplicationInfo#FLAG_SYSTEM}, can also insert a
+ * <p>{@link ApplicationInfo#FLAG_SYSTEM System apps} can also insert a
* disclaimer by declaring an application-level meta-data in {@code AndroidManifest.xml}.
- * Must use it with {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER}. Here is the example:
+ *
+ * <p>For example:
*
* <pre>
* <meta-data
* android:name="android.app.extra.PROVISIONING_DISCLAIMER_CONTENT"
* android:resource="@string/disclaimer_content"
* /></pre>
+ *
+ * <p>This must be accompanied with another extra using the key
+ * {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER}.
*/
public static final String EXTRA_PROVISIONING_DISCLAIMER_CONTENT =
"android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
/**
- * A boolean extra indicating if the user consent steps from the provisioning flow should be
- * skipped. If unspecified, defaults to {@code false}.
+ * A boolean extra indicating if the user consent steps from the
+ * <a href="#managed-provisioning">provisioning flow</a> should be skipped.
*
- * It can only be used by an existing device owner trying to create a managed profile via
- * {@link #ACTION_PROVISION_MANAGED_PROFILE}. Otherwise it is ignored.
+ * <p>If unspecified, defaults to {@code false}.
*
* @deprecated this extra is no longer relevant as device owners cannot create managed profiles
*/
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 17d1404..7dc151d 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -288,7 +288,7 @@
if (bitmap == null) {
throw new IllegalArgumentException("bitmap must not be null");
}
- validateHotSpot(bitmap, hotSpotX, hotSpotY);
+ validateHotSpot(bitmap, hotSpotX, hotSpotY, false /* isScaled */);
PointerIcon icon = new PointerIcon(TYPE_CUSTOM);
icon.mBitmap = bitmap;
@@ -521,7 +521,9 @@
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable);
- validateHotSpot(bitmap, hotSpotX, hotSpotY);
+ // The bitmap and hotspot are loaded from the context, which means it is implicitly scaled
+ // to the current display density, so treat this as a scaled icon when verifying hotspot.
+ validateHotSpot(bitmap, hotSpotX, hotSpotY, true /* isScaled */);
// Set the properties now that we have successfully loaded the icon.
mBitmap = bitmap;
mHotSpotX = hotSpotX;
@@ -535,11 +537,16 @@
+ ", hotspotX=" + mHotSpotX + ", hotspotY=" + mHotSpotY + "}";
}
- private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) {
- if (hotSpotX < 0 || hotSpotX >= bitmap.getWidth()) {
+ private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY,
+ boolean isScaled) {
+ // Be more lenient when checking the hotspot for scaled icons to account for the restriction
+ // that bitmaps must have an integer size.
+ if (hotSpotX < 0 || (isScaled ? (int) hotSpotX > bitmap.getWidth()
+ : hotSpotX >= bitmap.getWidth())) {
throw new IllegalArgumentException("x hotspot lies outside of the bitmap area");
}
- if (hotSpotY < 0 || hotSpotY >= bitmap.getHeight()) {
+ if (hotSpotY < 0 || (isScaled ? (int) hotSpotY > bitmap.getHeight()
+ : hotSpotY >= bitmap.getHeight())) {
throw new IllegalArgumentException("y hotspot lies outside of the bitmap area");
}
}
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index e531bcb..06ae11fee 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -135,7 +135,7 @@
DialogStatus.SHOWN,
})
/** Denotes the user shortcut type. */
- @interface DialogStatus {
+ public @interface DialogStatus {
int NOT_SHOWN = 0;
int SHOWN = 1;
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2115f64..a622d36 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -7015,4 +7015,9 @@
<!-- Frame rate compatibility value for Wallpaper
FRAME_RATE_COMPATIBILITY_MIN (102) is used by default for lower power consumption -->
<integer name="config_wallpaperFrameRateCompatibility">102</integer>
+
+ <!-- Min time in milliseconds to complete an emergency gesture for it count.
+ If the gesture is completed faster than this, we assume it's not performed by human and the
+ event gets ignored. -->
+ <integer name="config_defaultMinEmergencyGestureTapDurationMillis">200</integer>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9e09540..eccd7bf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5401,4 +5401,6 @@
<!-- Frame rate compatibility value for Wallpaper -->
<java-symbol type="integer" name="config_wallpaperFrameRateCompatibility" />
+
+ <java-symbol type="integer" name="config_defaultMinEmergencyGestureTapDurationMillis" />
</resources>
diff --git a/packages/CredentialManager/wear/res/drawable/passkey_icon.xml b/packages/CredentialManager/wear/res/drawable/passkey_icon.xml
deleted file mode 100644
index be366bf..0000000
--- a/packages/CredentialManager/wear/res/drawable/passkey_icon.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:pathData="M23,10.5H17V13.5H23V10.5Z"
- android:fillColor="#188038"/>
- <path
- android:pathData="M6.5,17.5C3.5,17.5 1,15 1,12C1,9 3.5,6.5 6.5,6.5C9.5,6.5 12,9 12,12C12,15 9.5,17.5 6.5,17.5ZM6.5,9.5C5.1,9.5 4,10.6 4,12C4,13.4 5.1,14.5 6.5,14.5C7.9,14.5 9,13.4 9,12C9,10.6 7.9,9.5 6.5,9.5Z"
- android:fillColor="#4285F4"/>
- <path
- android:pathData="M21,13.5H19H17V16.5H19V15.5C19,14.9 19.4,14.5 20,14.5C20.6,14.5 21,14.9 21,15.5V16.5H23V13.5H21Z"
- android:fillColor="#34A853"/>
- <path
- android:pathData="M11.8,10.5H8.5C8.8,10.9 9,11.4 9,12C9,12.6 8.8,13.1 8.5,13.5H11.8C11.9,13 12,12.5 12,12C12,11.5 11.9,11 11.8,10.5Z"
- android:fillColor="#EA4335"/>
- <path
- android:pathData="M17,10.5H11.8C11.9,11 12,11.5 12,12C12,12.5 11.9,13 11.8,13.5H17V10.5Z"
- android:fillColor="#FBBC04"/>
-</vector>
diff --git a/packages/CredentialManager/wear/res/values-watch/donottranslate.xml b/packages/CredentialManager/wear/res/values-watch/donottranslate.xml
new file mode 100644
index 0000000..c3ab3cb
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-watch/donottranslate.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- font-family-device-default is expected to be preloaded in the font_customization.xml(/vendor/<OEM>/products/<PRODUCT>/fonts/fonts_customization.xml)-->
+ <!-- Falls back to system default when font-family-device-default doesn't exist -->
+ <string name="wear_material_compose_display_1_font_family">font-family-device-default</string>
+ <string name="wear_material_compose_display_2_font_family">font-family-device-default</string>
+ <string name="wear_material_compose_display_3_font_family">font-family-device-default</string>
+ <string name="wear_material_compose_title_1_font_family">font-family-medium-device-default</string>
+ <string name="wear_material_compose_title_2_font_family">font-family-medium-device-default</string>
+ <string name="wear_material_compose_title_3_font_family">font-family-device-default</string>
+ <string name="wear_material_compose_body_1_font_family">font-family-text-device-default</string>
+ <string name="wear_material_compose_body_2_font_family">font-family-text-device-default</string>
+ <string name="wear_material_compose_button_font_family">font-family-text-medium-device-default</string>
+ <string name="wear_material_compose_caption_1_font_family">font-family-text-medium-device-default</string>
+ <string name="wear_material_compose_caption_2_font_family">font-family-text-medium-device-default</string>
+ <string name="wear_material_compose_caption_3_font_family">font-family-text-medium-device-default</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values/colors.xml b/packages/CredentialManager/wear/res/values/colors.xml
deleted file mode 100644
index bf10bb3..0000000
--- a/packages/CredentialManager/wear/res/values/colors.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2024 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources>
- <color name="wear_material_almond">#FFFCF7EB</color>
- <color name="wear_material_almond_dark">#FF262523</color>
-</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/wear/res/values/overlayable.xml b/packages/CredentialManager/wear/res/values/overlayable.xml
new file mode 100644
index 0000000..5b9d372
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values/overlayable.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <overlayable name="CredentialSelectorStyles">
+ <policy type="product|system|vendor|odm|oem">
+ <!--START WEAR SPECIFIC FONT STRINGS -->
+ <item type="string" name="wear_material_compose_display_1_font_family" />
+ <item type="string" name="wear_material_compose_display_2_font_family" />
+ <item type="string" name="wear_material_compose_display_3_font_family" />
+ <item type="string" name="wear_material_compose_title_1_font_family" />
+ <item type="string" name="wear_material_compose_title_2_font_family" />
+ <item type="string" name="wear_material_compose_title_3_font_family" />
+ <item type="string" name="wear_material_compose_body_1_font_family" />
+ <item type="string" name="wear_material_compose_body_2_font_family" />
+ <item type="string" name="wear_material_compose_button_font_family" />
+ <item type="string" name="wear_material_compose_caption_1_font_family" />
+ <item type="string" name="wear_material_compose_caption_2_font_family" />
+ <item type="string" name="wear_material_compose_caption_3_font_family" />
+ <!--END WEAR SPECIFIC FONT STRINGS -->
+
+ </policy>
+
+ </overlayable>
+
+</resources>
diff --git a/packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorUiStateGetMapperTest.kt b/packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorUiStateGetMapperTest.kt
index 3422d3d..6c14563 100644
--- a/packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorUiStateGetMapperTest.kt
+++ b/packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorUiStateGetMapperTest.kt
@@ -65,29 +65,29 @@
isLastUnlocked = true
)
- val passkeyCredentialEntryInfo =
+ private val passkeyCredentialEntryInfo =
createCredentialEntryInfo(credentialType = CredentialType.PASSKEY, userName = "userName")
- val unknownCredentialEntryInfo =
+ private val unknownCredentialEntryInfo =
createCredentialEntryInfo(credentialType = CredentialType.UNKNOWN, userName = "userName2")
- val passwordCredentialEntryInfo =
+ private val passwordCredentialEntryInfo =
createCredentialEntryInfo(credentialType = CredentialType.PASSWORD, userName = "userName")
- val recentlyUsedPasskeyCredential =
+ private val recentlyUsedPasskeyCredential =
createCredentialEntryInfo(credentialType =
CredentialType.PASSKEY, lastUsedTimeMillis = 2L, userName = "userName")
- val recentlyUsedPasswordCredential =
+ private val recentlyUsedPasswordCredential =
createCredentialEntryInfo(credentialType =
CredentialType.PASSWORD, lastUsedTimeMillis = 2L, userName = "userName")
- val credentialList1 = listOf(
+ private val credentialList1 = listOf(
passkeyCredentialEntryInfo,
passwordCredentialEntryInfo
)
- val credentialList2 = listOf(
+ private val credentialList2 = listOf(
passkeyCredentialEntryInfo,
passwordCredentialEntryInfo,
recentlyUsedPasskeyCredential,
@@ -118,11 +118,12 @@
unknownCredentialEntryInfo)))).toGet(isPrimary = true)
assertThat(getCredentialUiState).isEqualTo(
- CredentialSelectorUiState.Get.SingleEntryPerAccount(
+ CredentialSelectorUiState.Get.MultipleEntryPrimaryScreen(
sortedEntries = listOf(
passkeyCredentialEntryInfo, // userName
unknownCredentialEntryInfo // userName2
),
+ icon = mDrawable,
authenticationEntryList = listOf(authenticationEntryInfo)
)) // prefer passkey from account 1, then unknown from account 2
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 0fe35e6..652e62c 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -21,7 +21,7 @@
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
-import androidx.wear.compose.material.MaterialTheme
+import com.android.credentialmanager.ui.theme.WearCredentialSelectorTheme
import com.android.credentialmanager.ui.WearApp
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import dagger.hilt.android.AndroidEntryPoint
@@ -36,7 +36,7 @@
super.onCreate(savedInstanceState)
setTheme(android.R.style.Theme_DeviceDefault)
setContent {
- MaterialTheme {
+ WearCredentialSelectorTheme {
WearApp(
flowEngine = viewModel,
onCloseApp = { finish() },
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index b7fa33e..3608568 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -86,7 +86,7 @@
when (uiState.value) {
is Get.MultipleEntry -> isPrimaryScreen.value = true
is Create, Close, is Cancel, Idle -> shouldClose.value = true
- is Get.SingleEntry, is Get.SingleEntryPerAccount -> cancel()
+ is Get.SingleEntry, is Get.MultipleEntryPrimaryScreen -> cancel()
}
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt
index c05fc93..b2f55c1 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt
@@ -17,6 +17,7 @@
package com.android.credentialmanager
import android.content.Intent
+import android.graphics.drawable.Drawable
import androidx.activity.result.IntentSenderRequest
import androidx.compose.runtime.Composable
import com.android.credentialmanager.model.EntryInfo
@@ -71,14 +72,14 @@
/** Getting credential UI state when there is only one credential available. */
data class SingleEntry(val entry: CredentialEntryInfo) : Get()
/**
- * Getting credential UI state when there is only one account while with multiple
- * credentials, with different types(eg, passkey vs password) or providers.
+ * Getting credential UI state on primary screen when there is are multiple accounts.
*/
- data class SingleEntryPerAccount(
+ data class MultipleEntryPrimaryScreen(
+ val icon: Drawable?,
val sortedEntries: List<CredentialEntryInfo>,
val authenticationEntryList: List<AuthenticationEntryInfo>,
) : Get()
- /** Getting credential UI state when there are multiple accounts available. */
+ /** Getting credential UI state on secondary screen when there are multiple accounts available. */
data class MultipleEntry(
val accounts: List<PerUserNameEntries>,
val actionEntryList: List<ActionEntryInfo>,
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
index 018db68..d67c8c2 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
@@ -29,7 +29,7 @@
import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState
import com.android.credentialmanager.CredentialSelectorUiState
-import com.android.credentialmanager.CredentialSelectorUiState.Get.SingleEntryPerAccount
+import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntryPrimaryScreen
import com.android.credentialmanager.CredentialSelectorUiState.Get.SingleEntry
import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntry
import com.android.credentialmanager.FlowEngine
@@ -95,7 +95,7 @@
scrollable(Screen.MultipleCredentialsScreenFold.route) {
MultiCredentialsFoldScreen(
- credentialSelectorUiState = (remember { uiState } as SingleEntryPerAccount),
+ credentialSelectorUiState = (remember { uiState } as MultipleEntryPrimaryScreen),
columnState = it.columnState,
flowEngine = flowEngine,
)
@@ -169,7 +169,7 @@
}
}
- is SingleEntryPerAccount -> {
+ is MultipleEntryPrimaryScreen -> {
navController.navigateToMultipleCredentialsFoldScreen()
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt
index 18c9f31..c641d7f 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt
@@ -32,7 +32,6 @@
import androidx.wear.compose.material.ChipColors
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.style.TextAlign
import androidx.wear.compose.material.ChipDefaults
import com.android.credentialmanager.R
@@ -80,8 +79,7 @@
icon: Drawable? = null,
isAuthenticationEntryLocked: Boolean = false,
modifier: Modifier = Modifier,
- colors: ChipColors =
- ChipDefaults.chipColors(backgroundColor = colorResource(R.color.wear_material_almond)),
+ colors: ChipColors = ChipDefaults.primaryChipColors(),
) {
val labelParam: (@Composable RowScope.() -> Unit) =
{
@@ -168,11 +166,9 @@
WearButtonText(
text = stringResource(R.string.dialog_continue_button),
textAlign = TextAlign.Center,
- color = colorResource(R.color.wear_material_almond_dark),
)
},
- colors =
- ChipDefaults.chipColors(backgroundColor = colorResource(R.color.wear_material_almond)),
+ colors = ChipDefaults.primaryChipColors(),
)
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt
index e7a854f..22f6bf0 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt
@@ -26,7 +26,6 @@
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
-import com.android.compose.theme.LocalAndroidColorScheme
import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme
@Composable
@@ -34,7 +33,7 @@
Text(
modifier = modifier.wrapContentSize(),
text = text,
- color = LocalAndroidColorScheme.current.onSurface,
+ color = WearMaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
style = WearMaterialTheme.typography.title3,
)
@@ -45,7 +44,7 @@
Text(
modifier = modifier.wrapContentSize(),
text = text,
- color = LocalAndroidColorScheme.current.onSurface,
+ color = WearMaterialTheme.colors.onSurfaceVariant,
textAlign = TextAlign.Center,
overflow = TextOverflow.Ellipsis,
maxLines = 2,
@@ -56,28 +55,30 @@
@Composable
fun WearUsernameText(
text: String,
+ textAlign: TextAlign = TextAlign.Center,
modifier: Modifier = Modifier,
onTextLayout: (TextLayoutResult) -> Unit = {},
) {
Text(
modifier = modifier.padding(start = 8.dp, end = 8.dp).wrapContentSize(),
text = text,
- color = LocalAndroidColorScheme.current.onSurfaceVariant,
+ color = WearMaterialTheme.colors.onSurfaceVariant,
style = WearMaterialTheme.typography.caption1,
overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Center,
+ textAlign = textAlign,
maxLines = 2,
onTextLayout = onTextLayout,
)
}
+// used for primary label in button
@Composable
fun WearButtonText(
text: String,
textAlign: TextAlign,
maxLines: Int = 1,
modifier: Modifier = Modifier,
- color: Color = LocalAndroidColorScheme.current.onSurface,
+ color: Color = WearMaterialTheme.colors.onSurface,
onTextLayout: (TextLayoutResult) -> Unit = {},
) {
Text(
@@ -101,8 +102,8 @@
Text(
modifier = modifier.wrapContentSize(),
text = text,
- color = LocalAndroidColorScheme.current.onSurfaceVariant,
- style = WearMaterialTheme.typography.button,
+ color = WearMaterialTheme.colors.onSurfaceVariant,
+ style = WearMaterialTheme.typography.caption1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
maxLines = 1,
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
index 7a936b6..0417533 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
@@ -16,6 +16,7 @@
package com.android.credentialmanager.ui.mappers
+import android.graphics.drawable.Drawable
import com.android.credentialmanager.model.Request
import com.android.credentialmanager.CredentialSelectorUiState
import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntry.PerUserNameEntries
@@ -35,10 +36,19 @@
entry = accounts[0].value.minWith(comparator)
)
} else {
- CredentialSelectorUiState.Get.SingleEntryPerAccount(
- sortedEntries = accounts.map {
- it.value.minWith(comparator)
- }.sortedWith(comparator),
+ val sortedEntries = accounts.map {
+ it.value.minWith(comparator)
+ }.sortedWith(comparator)
+
+ var icon: Drawable? = null
+ // provide icon if all entries have the same provider
+ if (sortedEntries.all {it.providerId == sortedEntries[0].providerId}) {
+ icon = providerInfos[0].icon
+ }
+
+ CredentialSelectorUiState.Get.MultipleEntryPrimaryScreen(
+ sortedEntries = sortedEntries,
+ icon = icon,
authenticationEntryList = providerInfos.flatMap { it.authenticationEntryList }
)
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt
index acf4eca..23163d5 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt
@@ -48,7 +48,7 @@
@OptIn(ExperimentalHorologistApi::class)
@Composable
fun MultiCredentialsFoldScreen(
- credentialSelectorUiState: CredentialSelectorUiState.Get.SingleEntryPerAccount,
+ credentialSelectorUiState: CredentialSelectorUiState.Get.MultipleEntryPrimaryScreen,
columnState: ScalingLazyColumnState,
flowEngine: FlowEngine,
) {
@@ -68,7 +68,7 @@
}
SignInHeader(
- icon = null,
+ icon = credentialSelectorUiState.icon,
title = title,
)
}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialSelectorTheme.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialSelectorTheme.kt
new file mode 100644
index 0000000..ee0ba7b
--- /dev/null
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialSelectorTheme.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.credentialmanager.ui.theme
+
+import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.StringRes
+import androidx.wear.compose.material.Colors
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.font.DeviceFontFamilyName
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.wear.compose.material.Typography
+import androidx.wear.compose.material.MaterialTheme
+import com.android.credentialmanager.R
+import androidx.compose.ui.graphics.Color
+
+/** The Material 3 Theme Wrapper for Supporting RRO. */
+@Composable
+fun WearCredentialSelectorTheme(content: @Composable () -> Unit) {
+ val context = LocalContext.current
+ val colors =
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ overlayColors(context)
+ .copy(error = MaterialTheme.colors.error, onError = MaterialTheme.colors.onError)
+ } else {
+ MaterialTheme.colors
+ }
+ MaterialTheme(colors = colors, typography = deviceDefaultTypography(context), content = content)
+}
+
+/**
+ * Creates a dynamic color maps that can be overlaid. 100 - Lightest shade; 0 - Darkest Shade; In
+ * wear we only support dark theme for the time being. Thus the fill colors and variants are dark
+ * and anything on top is light. We will use this custom redirection until wear compose material
+ * supports color scheming.
+ *
+ * The mapping is best case match on wear material color tokens from
+ * /android/clockwork/common/wearable/wearmaterial/color/res/values/color-tokens.xml
+ *
+ * @param context The context required to get system resource data.
+ */
+@RequiresApi(Build.VERSION_CODES.S)
+internal fun overlayColors(context: Context): Colors {
+ val tonalPalette = dynamicTonalPalette(context)
+ return Colors(
+ background = Color.Black,
+ onBackground = Color.White,
+ primary = tonalPalette.primary90,
+ primaryVariant = tonalPalette.primary80,
+ onPrimary = tonalPalette.primary10,
+ secondary = tonalPalette.tertiary90,
+ secondaryVariant = tonalPalette.tertiary60,
+ onSecondary = tonalPalette.tertiary10,
+ surface = tonalPalette.neutral20,
+ onSurface = tonalPalette.neutral95,
+ onSurfaceVariant = tonalPalette.neutralVariant80,
+ )
+}
+
+private fun fontFamily(context: Context, @StringRes id: Int): FontFamily {
+ val typefaceName = context.resources.getString(id)
+ val font = Font(familyName = DeviceFontFamilyName(typefaceName))
+ return FontFamily(font)
+}
+
+/*
+ Only customizes font family. The material 3 roles to 2.5 are mapped to the best case matching of
+ google3/java/com/google/android/wearable/libraries/compose/theme/GoogleMaterialTheme.kt
+*/
+internal fun deviceDefaultTypography(context: Context): Typography {
+ val defaultTypography = Typography()
+ return Typography(
+ display1 =
+ defaultTypography.display1.copy(
+ fontFamily =
+ fontFamily(context, R.string.wear_material_compose_display_1_font_family)
+ ),
+ display2 =
+ defaultTypography.display2.copy(
+ fontFamily =
+ fontFamily(context, R.string.wear_material_compose_display_2_font_family)
+ ),
+ display3 =
+ defaultTypography.display1.copy(
+ fontFamily =
+ fontFamily(context, R.string.wear_material_compose_display_3_font_family)
+ ),
+ title1 =
+ defaultTypography.title1.copy(
+ fontFamily = fontFamily(context, R.string.wear_material_compose_title_1_font_family)
+ ),
+ title2 =
+ defaultTypography.title2.copy(
+ fontFamily = fontFamily(context, R.string.wear_material_compose_title_2_font_family)
+ ),
+ title3 =
+ defaultTypography.title3.copy(
+ fontFamily = fontFamily(context, R.string.wear_material_compose_title_3_font_family)
+ ),
+ body1 =
+ defaultTypography.body1.copy(
+ fontFamily = fontFamily(context, R.string.wear_material_compose_body_1_font_family)
+ ),
+ body2 =
+ defaultTypography.body2.copy(
+ fontFamily = fontFamily(context, R.string.wear_material_compose_body_2_font_family)
+ ),
+ button =
+ defaultTypography.button.copy(
+ fontFamily = fontFamily(context, R.string.wear_material_compose_button_font_family)
+ ),
+ caption1 =
+ defaultTypography.caption1.copy(
+ fontFamily =
+ fontFamily(context, R.string.wear_material_compose_caption_1_font_family)
+ ),
+ caption2 =
+ defaultTypography.caption2.copy(
+ fontFamily =
+ fontFamily(context, R.string.wear_material_compose_caption_2_font_family)
+ ),
+ caption3 =
+ defaultTypography.caption3.copy(
+ fontFamily =
+ fontFamily(context, R.string.wear_material_compose_caption_3_font_family)
+ ),
+ )
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialTonalPalette.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialTonalPalette.kt
new file mode 100644
index 0000000..1d6ed33
--- /dev/null
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialTonalPalette.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.credentialmanager.ui.theme
+
+import android.R
+import android.content.Context
+import android.os.Build
+import androidx.annotation.ColorRes
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+
+import androidx.compose.ui.graphics.Color
+
+/**
+ * Tonal Palette structure in Material.
+ *
+ * A tonal palette is comprised of 5 tonal ranges. Each tonal range includes the 13 stops, or tonal
+ * swatches.
+ *
+ * Tonal range names are:
+ * - Neutral (N)
+ * - Neutral variant (NV)
+ * - Primary (P)
+ * - Secondary (S)
+ * - Tertiary (T)
+ */
+internal class WearCredentialSelectorTonalPalette(
+ // The neutral tonal range.
+ val neutral100: Color,
+ val neutral99: Color,
+ val neutral95: Color,
+ val neutral90: Color,
+ val neutral80: Color,
+ val neutral70: Color,
+ val neutral60: Color,
+ val neutral50: Color,
+ val neutral40: Color,
+ val neutral30: Color,
+ val neutral20: Color,
+ val neutral10: Color,
+ val neutral0: Color,
+
+ // The neutral variant tonal range, sometimes called "neutral 2"
+ val neutralVariant100: Color,
+ val neutralVariant99: Color,
+ val neutralVariant95: Color,
+ val neutralVariant90: Color,
+ val neutralVariant80: Color,
+ val neutralVariant70: Color,
+ val neutralVariant60: Color,
+ val neutralVariant50: Color,
+ val neutralVariant40: Color,
+ val neutralVariant30: Color,
+ val neutralVariant20: Color,
+ val neutralVariant10: Color,
+ val neutralVariant0: Color,
+
+ // The primary tonal range, also known as accent 1
+ val primary100: Color,
+ val primary99: Color,
+ val primary95: Color,
+ val primary90: Color,
+ val primary80: Color,
+ val primary70: Color,
+ val primary60: Color,
+ val primary50: Color,
+ val primary40: Color,
+ val primary30: Color,
+ val primary20: Color,
+ val primary10: Color,
+ val primary0: Color,
+
+ // The Secondary tonal range, also know as accent 2
+ val secondary100: Color,
+ val secondary99: Color,
+ val secondary95: Color,
+ val secondary90: Color,
+ val secondary80: Color,
+ val secondary70: Color,
+ val secondary60: Color,
+ val secondary50: Color,
+ val secondary40: Color,
+ val secondary30: Color,
+ val secondary20: Color,
+ val secondary10: Color,
+ val secondary0: Color,
+
+ // The tertiary tonal range, also known as accent 3
+ val tertiary100: Color,
+ val tertiary99: Color,
+ val tertiary95: Color,
+ val tertiary90: Color,
+ val tertiary80: Color,
+ val tertiary70: Color,
+ val tertiary60: Color,
+ val tertiary50: Color,
+ val tertiary40: Color,
+ val tertiary30: Color,
+ val tertiary20: Color,
+ val tertiary10: Color,
+ val tertiary0: Color,
+)
+/** Dynamic colors for wear compose material to support resource overlay. */
+@RequiresApi(Build.VERSION_CODES.S)
+// TODO: once we have proper support for this on Wear 6+, we will do something similar to
+// https://source.corp.google.com/h/android/platform/superproject/+/androidx-main:frameworks/support/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DynamicTonalPalette.android.kt;l=307-362?q=dynamicTonalPalette&sq=repo:android%2Fplatform%2Fsuperproject%20b:androidx-main
+// Tracking Bug: b/270720571
+internal fun dynamicTonalPalette(context: Context) =
+ WearCredentialSelectorTonalPalette(
+ // The neutral tonal range from the generated dynamic color palette.
+ neutral100 = ColorResourceHelper.getColor(context, R.color.system_neutral1_0),
+ neutral99 = ColorResourceHelper.getColor(context, R.color.system_neutral1_10),
+ neutral95 = ColorResourceHelper.getColor(context, R.color.system_neutral1_50),
+ neutral90 = ColorResourceHelper.getColor(context, R.color.system_neutral1_100),
+ neutral80 = ColorResourceHelper.getColor(context, R.color.system_neutral1_200),
+ neutral70 = ColorResourceHelper.getColor(context, R.color.system_neutral1_300),
+ neutral60 = ColorResourceHelper.getColor(context, R.color.system_neutral1_400),
+ neutral50 = ColorResourceHelper.getColor(context, R.color.system_neutral1_500),
+ neutral40 = ColorResourceHelper.getColor(context, R.color.system_neutral1_600),
+ neutral30 = ColorResourceHelper.getColor(context, R.color.system_neutral1_700),
+ neutral20 = ColorResourceHelper.getColor(context, R.color.system_neutral1_800),
+ neutral10 = ColorResourceHelper.getColor(context, R.color.system_neutral1_900),
+ neutral0 = ColorResourceHelper.getColor(context, R.color.system_neutral1_1000),
+
+ // The neutral variant tonal range, sometimes called "neutral 2", from the
+ // generated dynamic color palette.
+ neutralVariant100 = ColorResourceHelper.getColor(context, R.color.system_neutral2_0),
+ neutralVariant99 = ColorResourceHelper.getColor(context, R.color.system_neutral2_10),
+ neutralVariant95 = ColorResourceHelper.getColor(context, R.color.system_neutral2_50),
+ neutralVariant90 = ColorResourceHelper.getColor(context, R.color.system_neutral2_100),
+ neutralVariant80 = ColorResourceHelper.getColor(context, R.color.system_neutral2_200),
+ neutralVariant70 = ColorResourceHelper.getColor(context, R.color.system_neutral2_300),
+ neutralVariant60 = ColorResourceHelper.getColor(context, R.color.system_neutral2_400),
+ neutralVariant50 = ColorResourceHelper.getColor(context, R.color.system_neutral2_500),
+ neutralVariant40 = ColorResourceHelper.getColor(context, R.color.system_neutral2_600),
+ neutralVariant30 = ColorResourceHelper.getColor(context, R.color.system_neutral2_700),
+ neutralVariant20 = ColorResourceHelper.getColor(context, R.color.system_neutral2_800),
+ neutralVariant10 = ColorResourceHelper.getColor(context, R.color.system_neutral2_900),
+ neutralVariant0 = ColorResourceHelper.getColor(context, R.color.system_neutral2_1000),
+
+ // The primary tonal range from the generated dynamic color palette.
+ primary100 = ColorResourceHelper.getColor(context, R.color.system_accent1_0),
+ primary99 = ColorResourceHelper.getColor(context, R.color.system_accent1_10),
+ primary95 = ColorResourceHelper.getColor(context, R.color.system_accent1_50),
+ primary90 = ColorResourceHelper.getColor(context, R.color.system_accent1_100),
+ primary80 = ColorResourceHelper.getColor(context, R.color.system_accent1_200),
+ primary70 = ColorResourceHelper.getColor(context, R.color.system_accent1_300),
+ primary60 = ColorResourceHelper.getColor(context, R.color.system_accent1_400),
+ primary50 = ColorResourceHelper.getColor(context, R.color.system_accent1_500),
+ primary40 = ColorResourceHelper.getColor(context, R.color.system_accent1_600),
+ primary30 = ColorResourceHelper.getColor(context, R.color.system_accent1_700),
+ primary20 = ColorResourceHelper.getColor(context, R.color.system_accent1_800),
+ primary10 = ColorResourceHelper.getColor(context, R.color.system_accent1_900),
+ primary0 = ColorResourceHelper.getColor(context, R.color.system_accent1_1000),
+
+ // The secondary tonal range from the generated dynamic color palette.
+ secondary100 = ColorResourceHelper.getColor(context, R.color.system_accent2_0),
+ secondary99 = ColorResourceHelper.getColor(context, R.color.system_accent2_10),
+ secondary95 = ColorResourceHelper.getColor(context, R.color.system_accent2_50),
+ secondary90 = ColorResourceHelper.getColor(context, R.color.system_accent2_100),
+ secondary80 = ColorResourceHelper.getColor(context, R.color.system_accent2_200),
+ secondary70 = ColorResourceHelper.getColor(context, R.color.system_accent2_300),
+ secondary60 = ColorResourceHelper.getColor(context, R.color.system_accent2_400),
+ secondary50 = ColorResourceHelper.getColor(context, R.color.system_accent2_500),
+ secondary40 = ColorResourceHelper.getColor(context, R.color.system_accent2_600),
+ secondary30 = ColorResourceHelper.getColor(context, R.color.system_accent2_700),
+ secondary20 = ColorResourceHelper.getColor(context, R.color.system_accent2_800),
+ secondary10 = ColorResourceHelper.getColor(context, R.color.system_accent2_900),
+ secondary0 = ColorResourceHelper.getColor(context, R.color.system_accent2_1000),
+
+ // The tertiary tonal range from the generated dynamic color palette.
+ tertiary100 = ColorResourceHelper.getColor(context, R.color.system_accent3_0),
+ tertiary99 = ColorResourceHelper.getColor(context, R.color.system_accent3_10),
+ tertiary95 = ColorResourceHelper.getColor(context, R.color.system_accent3_50),
+ tertiary90 = ColorResourceHelper.getColor(context, R.color.system_accent3_100),
+ tertiary80 = ColorResourceHelper.getColor(context, R.color.system_accent3_200),
+ tertiary70 = ColorResourceHelper.getColor(context, R.color.system_accent3_300),
+ tertiary60 = ColorResourceHelper.getColor(context, R.color.system_accent3_400),
+ tertiary50 = ColorResourceHelper.getColor(context, R.color.system_accent3_500),
+ tertiary40 = ColorResourceHelper.getColor(context, R.color.system_accent3_600),
+ tertiary30 = ColorResourceHelper.getColor(context, R.color.system_accent3_700),
+ tertiary20 = ColorResourceHelper.getColor(context, R.color.system_accent3_800),
+ tertiary10 = ColorResourceHelper.getColor(context, R.color.system_accent3_900),
+ tertiary0 = ColorResourceHelper.getColor(context, R.color.system_accent3_1000),
+ )
+
+private object ColorResourceHelper {
+ @DoNotInline
+ fun getColor(context: Context, @ColorRes id: Int): Color {
+ return Color(context.resources.getColor(id, context.theme))
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index 8137e40..14ebc39 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -32,6 +32,16 @@
}
flag {
+ name: "floating_menu_narrow_target_content_observer"
+ namespace: "accessibility"
+ description: "stops the FAB from monitoring enabled services to trigger target content changes."
+ bug: "331740049"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "floating_menu_overlaps_nav_bars_flag"
namespace: "accessibility"
description: "Adjusts bounds to allow the floating menu to render on top of navigation bars."
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index b105a4e..ef5e292 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -477,10 +477,13 @@
}
flag {
- name: "screenshot_private_profile"
+ name: "screenshot_private_profile_behavior_fix"
namespace: "systemui"
description: "Private profile support for screenshots"
bug: "327613051"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensor.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensor.kt
index a2b1198..f07dce5 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensor.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics.shared.model
+import android.graphics.Rect
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
/** Fingerprint sensor property. Represents [FingerprintSensorPropertiesInternal]. */
@@ -23,12 +24,23 @@
val sensorId: Int,
val sensorStrength: SensorStrength,
val maxEnrollmentsPerUser: Int,
- val sensorType: FingerprintSensorType
+ val sensorType: FingerprintSensorType,
+ val sensorBounds: Rect,
+ val sensorRadius: Int,
)
/** Convert [FingerprintSensorPropertiesInternal] to corresponding [FingerprintSensor] */
fun FingerprintSensorPropertiesInternal.toFingerprintSensor(): FingerprintSensor {
val sensorStrength: SensorStrength = this.sensorStrength.toSensorStrength()
val sensorType: FingerprintSensorType = this.sensorType.toSensorType()
- return FingerprintSensor(this.sensorId, sensorStrength, this.maxEnrollmentsPerUser, sensorType)
+ val sensorBounds: Rect = this.location.rect
+ val sensorRadius = this.location.sensorRadius
+ return FingerprintSensor(
+ this.sensorId,
+ sensorStrength,
+ this.maxEnrollmentsPerUser,
+ sensorType,
+ sensorBounds,
+ sensorRadius,
+ )
}
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
index 476daac..0f3d285 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
@@ -33,3 +33,10 @@
SensorProperties.STRENGTH_STRONG -> SensorStrength.STRONG
else -> throw IllegalArgumentException("Invalid SensorStrength value: $this")
}
+/** Convert [SensorStrength] to corresponding [Int] */
+fun SensorStrength.toInt(): Int =
+ when (this) {
+ SensorStrength.CONVENIENCE -> SensorProperties.STRENGTH_CONVENIENCE
+ SensorStrength.WEAK -> SensorProperties.STRENGTH_WEAK
+ SensorStrength.STRONG -> SensorProperties.STRENGTH_STRONG
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
index 1018f70..eb840f1 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
@@ -244,11 +244,13 @@
mSecureSettings.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
/* notifyForDescendants */ false, mMenuTargetFeaturesContentObserver,
UserHandle.USER_CURRENT);
- mSecureSettings.registerContentObserverForUser(
- mSecureSettings.getUriFor(ENABLED_ACCESSIBILITY_SERVICES),
- /* notifyForDescendants */ false,
- mMenuTargetFeaturesContentObserver,
- UserHandle.USER_CURRENT);
+ if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) {
+ mSecureSettings.registerContentObserverForUser(
+ mSecureSettings.getUriFor(ENABLED_ACCESSIBILITY_SERVICES),
+ /* notifyForDescendants */ false,
+ mMenuTargetFeaturesContentObserver,
+ UserHandle.USER_CURRENT);
+ }
mSecureSettings.registerContentObserverForUser(
mSecureSettings.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),
/* notifyForDescendants */ false, mMenuSizeContentObserver,
@@ -263,8 +265,10 @@
UserHandle.USER_CURRENT);
mContext.registerComponentCallbacks(mComponentCallbacks);
- mAccessibilityManager.addAccessibilityServicesStateChangeListener(
- mA11yServicesStateChangeListener);
+ if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) {
+ mAccessibilityManager.addAccessibilityServicesStateChangeListener(
+ mA11yServicesStateChangeListener);
+ }
}
void unregisterObserversAndCallbacks() {
@@ -273,8 +277,10 @@
mContext.getContentResolver().unregisterContentObserver(mMenuFadeOutContentObserver);
mContext.unregisterComponentCallbacks(mComponentCallbacks);
- mAccessibilityManager.removeAccessibilityServicesStateChangeListener(
- mA11yServicesStateChangeListener);
+ if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) {
+ mAccessibilityManager.removeAccessibilityServicesStateChangeListener(
+ mA11yServicesStateChangeListener);
+ }
}
interface OnSettingsContentsChanged {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt
index a6b01e7..44f767a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt
@@ -19,7 +19,7 @@
import android.content.ComponentName
import android.content.Context
import android.os.Process
-import com.android.systemui.Flags.screenshotPrivateProfile
+import com.android.systemui.Flags.screenshotPrivateProfileBehaviorFix
import com.android.systemui.SystemUIService
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -72,7 +72,7 @@
displayContentRepoProvider: Provider<DisplayContentRepository>,
policyListProvider: Provider<List<CapturePolicy>>,
): ScreenshotRequestProcessor {
- return if (screenshotPrivateProfile()) {
+ return if (screenshotPrivateProfileBehaviorFix()) {
PolicyRequestProcessor(
background = background,
capture = imageCapture,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
index 5e7d8fb..91f3912 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
+import kotlin.test.Ignore
import kotlin.test.Test
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestCoroutineScheduler
@@ -55,6 +56,7 @@
private lateinit var actionExecutor: ActionExecutor
+ @Ignore // Fixed with newer mockito version (in main)
@Test
fun startSharedTransition_callsLaunchIntent() = runTest {
actionExecutor = createActionExecutor()
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index bfa1c7b..8ab2e0f 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -56,6 +56,13 @@
}
flag {
+ name: "enable_hardware_shortcut_disables_warning"
+ namespace: "accessibility"
+ description: "When the user purposely enables the hardware shortcut, preemptively disables the first-time warning message."
+ bug: "287065325"
+}
+
+flag {
name: "enable_magnification_joystick"
namespace: "accessibility"
description: "Whether to enable joystick controls for magnification"
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e64e500..ccf9a90 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -4273,6 +4273,13 @@
}
if (shortcutType == UserShortcutType.HARDWARE) {
skipVolumeShortcutDialogTimeoutRestriction(userId);
+ if (com.android.server.accessibility.Flags.enableHardwareShortcutDisablesWarning()) {
+ persistIntToSetting(
+ userId,
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN
+ );
+ }
} else if (shortcutType == UserShortcutType.SOFTWARE) {
// Update the A11y FAB size to large when the Magnification shortcut is
// enabled and the user hasn't changed the floating button size
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 1741593..ccc44a4 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static com.android.internal.R.integer.config_defaultMinEmergencyGestureTapDurationMillis;
+
import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
@@ -70,12 +72,6 @@
*/
@VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300;
- /**
- * Min time in milliseconds to complete the emergency gesture for it count. If the gesture is
- * completed faster than this, we assume it's not performed by human and the
- * event gets ignored.
- */
- @VisibleForTesting static final int EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS = 200;
/**
* Interval in milliseconds in which the power button must be depressed in succession to be
@@ -570,7 +566,8 @@
long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
- EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS);
+ mContext.getResources().getInteger(
+ config_defaultMinEmergencyGestureTapDurationMillis));
if (emergencyGestureSpentTime <= emergencyGestureTapDetectionMinTimeMs) {
Slog.i(TAG, "Emergency gesture detected but it's too fast. Gesture time: "
+ emergencyGestureSpentTime + " ms");
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index f7f76aa..57ea233 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -807,7 +807,7 @@
getDefaultSystemHandlerActivityPackage(pm,
SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
- NOTIFICATION_PERMISSIONS, PHONE_PERMISSIONS);
+ NOTIFICATION_PERMISSIONS, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS);
}
// Voice recognition
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index 4e059b4..fe883e4 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -17,7 +17,6 @@
package com.android.server;
import static com.android.server.GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
-import static com.android.server.GestureLauncherService.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -1449,7 +1448,7 @@
long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
- EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS);
+ 200);
assertTrue(intercepted);
if (tapIntervalMs * 4 > emergencyGestureTapDetectionMinTimeMs) {
assertTrue(outLaunched.value);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 1bf9a9d..5a17851 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -69,10 +69,9 @@
import android.os.IBinder;
import android.os.LocaleList;
import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
@@ -144,8 +143,7 @@
ApplicationProvider.getApplicationContext());
@Rule
- public final CheckFlagsRule mCheckFlagsRule =
- DeviceFlagsValueProvider.createCheckFlagsRule();
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final int ACTION_ID = 20;
private static final String LABEL = "label";
@@ -624,7 +622,7 @@
@SmallTest
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+ @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
public void testOnClientChange_magnificationTwoFingerTripleTapEnabled_requestConnection() {
when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false);
@@ -642,7 +640,7 @@
@SmallTest
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+ @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
public void testOnClientChange_magnificationTwoFingerTripleTapDisabled_requestDisconnection() {
when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false);
@@ -704,7 +702,7 @@
@SmallTest
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+ @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
public void onClientChange_magnificationTwoFingerTripleTapDisabled_removeMagnificationButton() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
@@ -720,7 +718,7 @@
@SmallTest
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+ @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
public void onClientChange_magnificationTwoFingerTripleTapEnabled_keepMagnificationButton() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
@@ -772,7 +770,7 @@
@SmallTest
@Test
- @RequiresFlagsDisabled(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
+ @DisableFlags(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
public void testPerformAccessibilityShortcut_hearingAids_startActivityWithExpectedComponent() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
@@ -790,7 +788,7 @@
@SmallTest
@Test
- @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
+ @EnableFlags(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
public void testPerformAccessibilityShortcut_hearingAids_sendExpectedBroadcast() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
@@ -949,7 +947,7 @@
}
@Test
- @RequiresFlagsEnabled(FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES)
+ @EnableFlags(FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES)
public void testIsAccessibilityServiceWarningRequired_notRequiredIfAllowlisted() {
mockManageAccessibilityGranted(mTestableContext);
final AccessibilityServiceInfo info_a = mockAccessibilityServiceInfo(
@@ -1008,6 +1006,33 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_HARDWARE_SHORTCUT_DISABLES_WARNING)
+ public void enableHardwareShortcutsForTargets_shortcutDialogSetting_isShown() {
+ Settings.Secure.putInt(
+ mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN
+ );
+
+ mockManageAccessibilityGranted(mTestableContext);
+ setupShortcutTargetServices();
+ String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.HARDWARE,
+ List.of(target),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(Settings.Secure.getInt(
+ mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN))
+ .isEqualTo(AccessibilityShortcutController.DialogStatus.SHOWN);
+ }
+
+ @Test
public void enableShortcutsForTargets_disableSoftwareShortcut_shortcutTurnedOff()
throws Exception {
String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
@@ -1341,7 +1366,7 @@
}
@Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_statusBarServiceNotGranted_throwsException() {
mTestableContext.getTestablePermissions().setPermission(
Manifest.permission.STATUS_BAR_SERVICE, PackageManager.PERMISSION_DENIED);
@@ -1355,7 +1380,7 @@
}
@Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_manageAccessibilityNotGranted_throwsException() {
mockStatusBarServiceGranted(mTestableContext);
mTestableContext.getTestablePermissions().setPermission(
@@ -1369,7 +1394,7 @@
}
@Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_qsTileChanges_updateA11yTilesInQsPanel() {
mockStatusBarServiceGranted(mTestableContext);
mockManageAccessibilityGranted(mTestableContext);
@@ -1389,7 +1414,7 @@
}
@Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_sameQsTiles_noUpdateToA11yTilesInQsPanel() {
notifyQuickSettingsTilesChanged_qsTileChanges_updateA11yTilesInQsPanel();
List<ComponentName> tiles =
@@ -1406,7 +1431,7 @@
}
@Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_serviceWarningRequired_qsShortcutRemainDisabled() {
mockStatusBarServiceGranted(mTestableContext);
mockManageAccessibilityGranted(mTestableContext);
@@ -1424,7 +1449,7 @@
}
@Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_serviceWarningNotRequired_qsShortcutEnabled() {
mockStatusBarServiceGranted(mTestableContext);
mockManageAccessibilityGranted(mTestableContext);
@@ -1446,7 +1471,7 @@
}
@Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_addFrameworkTile_qsShortcutEnabled() {
mockStatusBarServiceGranted(mTestableContext);
mockManageAccessibilityGranted(mTestableContext);
@@ -1469,7 +1494,7 @@
}
@Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_removeFrameworkTile_qsShortcutDisabled() {
notifyQuickSettingsTilesChanged_addFrameworkTile_qsShortcutEnabled();
Set<ComponentName> qsTiles = mA11yms.getCurrentUserState().getA11yQsTilesInQsPanel();
@@ -1487,7 +1512,7 @@
}
@Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void restoreAccessibilityQsTargets_a11yQsTargetsRestored() {
String daltonizerTile =
AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString();
@@ -1510,7 +1535,7 @@
}
@Test
- @RequiresFlagsDisabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void restoreAccessibilityQsTargets_a11yQsTargetsNotRestored() {
String daltonizerTile =
AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString();