Merge "Added a UserManager.DISALLOW_AUTOFILL restriction."
diff --git a/api/current.txt b/api/current.txt
index 42d45ff..e124d09 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31652,6 +31652,7 @@
field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
+ field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
diff --git a/api/system-current.txt b/api/system-current.txt
index 4a7ee51..9daf8f0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -34466,6 +34466,7 @@
field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
+ field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
diff --git a/api/test-current.txt b/api/test-current.txt
index 292b505..8b2ca05 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -31777,6 +31777,7 @@
field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
+ field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 827a77f..deb5b31 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1584,6 +1584,7 @@
System.err.println(" pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm default-state [--user USER_ID] PACKAGE_OR_COMPONENT");
+ System.err.println(" pm set-user-restriction [--user USER_ID] RESTRICTION VALUE");
System.err.println(" pm hide [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm grant [--user USER_ID] PACKAGE PERMISSION");
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f6712f8..42575b6 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -706,6 +706,20 @@
= "allow_parent_profile_app_linking";
/**
+ * Specifies if a user is not allowed to use Autofill Services.
+ *
+ * <p>Device owner and profile owner can set this restriction. When it is set by device owner,
+ * only the target user will be affected.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_AUTOFILL = "no_autofill";
+
+ /**
* Application restriction key that is used to indicate the pending arrival
* of real restrictions for the app.
*
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 709e5f9..6f17d0e 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -228,8 +228,11 @@
*/
//TODO(b/33197203): remove once clients are not using anymore
@Deprecated
- public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
- @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
+ public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
+ @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
+ // Should never be called because it was abstract before.
+ throw new UnsupportedOperationException("deprecated");
+ }
/**
* Called when user requests service to save the fields of an {@link Activity}.
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 47e7803..484b875 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -208,7 +208,7 @@
}
/**
- * Sets the value of a field, usin a custom presentation to visualize it.
+ * Sets the value of a field, using a custom presentation to visualize it.
*
* @param id id returned by {@link
* android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
@@ -257,8 +257,7 @@
throwIfDestroyed();
mDestroyed = true;
if (mFieldIds == null) {
- throw new IllegalArgumentException(
- "at least one value must be set");
+ throw new IllegalArgumentException("at least one value must be set");
}
return new Dataset(this);
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index c7ba1ff..a77e533 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -18,7 +18,10 @@
import static android.Manifest.permission.MANAGE_AUTO_FILL;
import static android.content.Context.AUTOFILL_MANAGER_SERVICE;
+
+import static com.android.server.autofill.Helper.DEBUG;
import static com.android.server.autofill.Helper.VERBOSE;
+import static com.android.server.autofill.Helper.bundleToString;
import android.Manifest;
import android.annotation.NonNull;
@@ -28,8 +31,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.net.Uri;
@@ -41,16 +44,19 @@
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.provider.Settings;
import android.util.LocalLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
-
import android.view.autofill.IAutoFillManager;
import android.view.autofill.IAutoFillManagerClient;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.IResultReceiver;
@@ -90,20 +96,20 @@
* It has to be mapped by user id because the same current user could have simultaneous sessions
* associated to different user profiles (for example, in a multi-window environment or when
* device has work profiles).
- * <p>
- * Entries on this cache are added on demand and removed when:
- * <ol>
- * <li>An autofill service app is removed.
- * <li>The {@link android.provider.Settings.Secure#AUTOFILL_SERVICE} for an user change.
- * </ol>
*/
- // TODO(b/33197203): Update the above comment
@GuardedBy("mLock")
private SparseArray<AutofillManagerServiceImpl> mServicesCache = new SparseArray<>();
+ /**
+ * Users disabled due to {@link UserManager} restrictions.
+ */
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray();
+
// TODO(b/33197203): set a different max (or disable it) on low-memory devices.
private final LocalLog mRequestsHistory = new LocalLog(20);
+ // TODO(b/33197203): is this still needed?
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -122,10 +128,38 @@
mContext = context;
mUi = new AutoFillUI(mContext);
- IntentFilter filter = new IntentFilter();
+ final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- mContext.registerReceiver(mBroadcastReceiver, filter, null,
- FgThread.getHandler());
+ mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
+
+ // Hookup with UserManager to disable service when necessary.
+ final UserManager um = context.getSystemService(UserManager.class);
+ final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+ final List<UserInfo> users = um.getUsers();
+ for (int i = 0; i < users.size(); i++) {
+ final int userId = users.get(i).id;
+ final boolean disabled = umi.getUserRestriction(userId, UserManager.DISALLOW_AUTOFILL);
+ if (disabled) {
+ mDisabledUsers.put(userId, disabled);
+ }
+ }
+ umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> {
+ final boolean disabledNow =
+ newRestrictions.getBoolean(UserManager.DISALLOW_AUTOFILL, false);
+ synchronized (mLock) {
+ final boolean disabledBefore = mDisabledUsers.get(userId);
+ if (disabledBefore == disabledNow) {
+ // Nothing changed, do nothing.
+ if (DEBUG) {
+ Slog.d(TAG, "Restriction not changed for user " + userId + ": "
+ + bundleToString(newRestrictions));
+ return;
+ }
+ }
+ mDisabledUsers.put(userId, disabledNow);
+ updateCachedServiceLocked(userId, disabledNow);
+ }
+ });
}
@Override
@@ -164,7 +198,7 @@
AutofillManagerServiceImpl service = mServicesCache.get(userId);
if (service == null) {
service = new AutofillManagerServiceImpl(mContext, mLock,
- mRequestsHistory, userId, mUi);
+ mRequestsHistory, userId, mUi, mDisabledUsers.get(userId));
mServicesCache.put(userId, service);
}
return service;
@@ -272,9 +306,16 @@
* Updates a cached service for a given user.
*/
private void updateCachedServiceLocked(int userId) {
+ updateCachedServiceLocked(userId, mDisabledUsers.get(userId));
+ }
+
+ /**
+ * Updates a cached service for a given user.
+ */
+ private void updateCachedServiceLocked(int userId, boolean disabled) {
AutofillManagerServiceImpl service = mServicesCache.get(userId);
if (service != null) {
- service.updateLocked();
+ service.updateLocked(disabled);
}
}
@@ -386,6 +427,7 @@
return;
}
synchronized (mLock) {
+ pw.print("Disabled users: "); pw.println(mDisabledUsers);
final int size = mServicesCache.size();
pw.print("Cached services: ");
if (size == 0) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index d13cf77..6fb9f7c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -53,6 +53,7 @@
import android.os.Parcelable;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
@@ -105,6 +106,10 @@
private AutofillServiceInfo mInfo;
private final LocalLog mRequestsHistory;
+ /**
+ * Whether service was disabled for user due to {@link UserManager} restrictions.
+ */
+ private boolean mDisabled;
private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
switch (msg.what) {
@@ -183,13 +188,13 @@
};
AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
- int userId, AutoFillUI ui) {
+ int userId, AutoFillUI ui, boolean disabled) {
mContext = context;
mLock = lock;
mRequestsHistory = requestsHistory;
mUserId = userId;
mUi = ui;
- updateLocked();
+ updateLocked(disabled);
}
CharSequence getServiceName() {
@@ -209,7 +214,9 @@
}
}
- void updateLocked() {
+ void updateLocked(boolean disabled) {
+ final boolean wasEnabled = isEnabled();
+ mDisabled = disabled;
ComponentName serviceComponent = null;
ServiceInfo serviceInfo = null;
final String componentName = Settings.Secure.getStringForUser(
@@ -225,15 +232,14 @@
}
}
try {
- final boolean hadService = hasService();
if (serviceInfo != null) {
mInfo = new AutofillServiceInfo(mContext.getPackageManager(),
serviceComponent, mUserId);
} else {
mInfo = null;
}
- if (hadService != hasService()) {
- if (!hasService()) {
+ if (wasEnabled != isEnabled()) {
+ if (!isEnabled()) {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
final Session session = mSessions.valueAt(i);
@@ -251,7 +257,7 @@
* Used by {@link AutofillManagerServiceShellCommand} to request save for the current top app.
*/
void requestSaveForUserLocked(IBinder activityToken) {
- if (!hasService()) {
+ if (!isEnabled()) {
return;
}
final Session session = mSessions.get(activityToken);
@@ -268,11 +274,11 @@
mClients = new RemoteCallbackList<>();
}
mClients.register(client);
- return hasService();
+ return isEnabled();
}
void setAuthenticationResultLocked(Bundle data, IBinder activityToken) {
- if (!hasService()) {
+ if (!isEnabled()) {
return;
}
final Session session = mSessions.get(activityToken);
@@ -282,7 +288,7 @@
}
void setHasCallback(IBinder activityToken, boolean hasIt) {
- if (!hasService()) {
+ if (!isEnabled()) {
return;
}
final Session session = mSessions.get(activityToken);
@@ -295,7 +301,7 @@
@NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect bounds,
@Nullable AutofillValue value, boolean hasCallback, int flags,
@NonNull String packageName) {
- if (!hasService()) {
+ if (!isEnabled()) {
return;
}
@@ -318,7 +324,7 @@
}
void finishSessionLocked(IBinder activityToken) {
- if (!hasService()) {
+ if (!isEnabled()) {
return;
}
@@ -338,7 +344,7 @@
}
void cancelSessionLocked(IBinder activityToken) {
- if (!hasService()) {
+ if (!isEnabled()) {
return;
}
@@ -423,8 +429,9 @@
pw.print(prefix); pw.print("Component:"); pw.println(mInfo != null
? mInfo.getServiceInfo().getComponentName() : null);
+ pw.print(prefix); pw.print("Disabled:"); pw.println(mDisabled);
- if (VERBOSE) {
+ if (VERBOSE && mInfo != null) {
// ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
pw.print(prefix); pw.println("ServiceInfo:");
mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), prefix + prefix);
@@ -467,9 +474,9 @@
}
try {
for (int i = 0; i < userClientCount; i++) {
- IAutoFillManagerClient client = clients.getBroadcastItem(i);
+ final IAutoFillManagerClient client = clients.getBroadcastItem(i);
try {
- client.setState(hasService());
+ client.setState(isEnabled());
} catch (RemoteException re) {
/* ignore */
}
@@ -479,8 +486,8 @@
}
}
- private boolean hasService() {
- return mInfo != null;
+ private boolean isEnabled() {
+ return mInfo != null && !mDisabled;
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 090cf91..353b4ac 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -31,24 +31,21 @@
static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
static final boolean VERBOSE = false;
- static final String REDACTED = "[REDACTED]";
static void append(StringBuilder builder, Bundle bundle) {
- if (bundle == null) {
- builder.append("N/A");
- } else if (!VERBOSE) {
- builder.append(REDACTED);
- } else {
- final Set<String> keySet = bundle.keySet();
- builder.append("[Bundle with ").append(keySet.size()).append(" extras:");
- for (String key : keySet) {
- final Object value = bundle.get(key);
- builder.append(' ').append(key).append('=');
- builder.append((value instanceof Object[])
- ? Arrays.toString((Objects[]) value) : value);
- }
- builder.append(']');
+ if (bundle == null || !DEBUG) {
+ builder.append("null");
+ return;
}
+ final Set<String> keySet = bundle.keySet();
+ builder.append("[Bundle with ").append(keySet.size()).append(" extras:");
+ for (String key : keySet) {
+ final Object value = bundle.get(key);
+ builder.append(' ').append(key).append('=');
+ builder.append((value instanceof Object[])
+ ? Arrays.toString((Objects[]) value) : value);
+ }
+ builder.append(']');
}
static String bundleToString(Bundle bundle) {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index cb2ed6e..84381fe 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -109,6 +109,7 @@
UserManager.DISALLOW_SET_WALLPAPER,
UserManager.DISALLOW_OEM_UNLOCK,
UserManager.DISALLOW_UNMUTE_DEVICE,
+ UserManager.DISALLOW_AUTOFILL,
});
/**