From 43574b03e5604e346f088a1b0da2ab37fb115226 Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Wed, 12 Apr 2017 09:25:20 -0700 Subject: [PATCH] Add autofill feature API We now have a software feature for autofill which can be used by partners to disable it on low-end devices or form factors for which autofill doesn't make sense. bug:35956220 Test: manual (requires a custom build) Change-Id: I6c06462ed9ca3ae93331700dce38a8c08dfd0722 --- api/current.txt | 1 + api/system-current.txt | 1 + api/test-current.txt | 1 + .../android/app/SystemServiceRegistry.java | 9 ++- .../android/content/pm/PackageManager.java | 9 +++ .../service/autofill/FillResponse.java | 1 - .../view/autofill/AutofillManager.java | 59 ++++++++++++++++++- .../java/com/android/server/SystemServer.java | 8 ++- 8 files changed, 81 insertions(+), 8 deletions(-) diff --git a/api/current.txt b/api/current.txt index fada9aad6c052..3247e64be2a9d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10619,6 +10619,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency"; field public static final java.lang.String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output"; field public static final java.lang.String FEATURE_AUDIO_PRO = "android.hardware.audio.pro"; + field public static final java.lang.String FEATURE_AUTOFILL = "android.software.autofill"; field public static final java.lang.String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive"; field public static final java.lang.String FEATURE_BACKUP = "android.software.backup"; field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; diff --git a/api/system-current.txt b/api/system-current.txt index 23dc949a961d2..e066862101d6c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -11303,6 +11303,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency"; field public static final java.lang.String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output"; field public static final java.lang.String FEATURE_AUDIO_PRO = "android.hardware.audio.pro"; + field public static final java.lang.String FEATURE_AUTOFILL = "android.software.autofill"; field public static final java.lang.String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive"; field public static final java.lang.String FEATURE_BACKUP = "android.software.backup"; field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; diff --git a/api/test-current.txt b/api/test-current.txt index 5c8edac69edbb..e4c22654c07d4 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -10658,6 +10658,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency"; field public static final java.lang.String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output"; field public static final java.lang.String FEATURE_AUDIO_PRO = "android.hardware.audio.pro"; + field public static final java.lang.String FEATURE_AUTOFILL = "android.software.autofill"; field public static final java.lang.String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive"; field public static final java.lang.String FEATURE_BACKUP = "android.software.backup"; field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 4572578ea608e..19f7426863cb4 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -641,7 +641,8 @@ final class SystemServiceRegistry { new CachedServiceFetcher() { @Override public PrintManager createService(ContextImpl ctx) throws ServiceNotFoundException { - IBinder iBinder = ServiceManager.getServiceOrThrow(Context.PRINT_SERVICE); + // Get the services without throwing as this is an optional feature + IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE); IPrintManager service = IPrintManager.Stub.asInterface(iBinder); return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(), UserHandle.getAppId(Process.myUid())); @@ -652,8 +653,9 @@ final class SystemServiceRegistry { @Override public CompanionDeviceManager createService(ContextImpl ctx) throws ServiceNotFoundException { + // Get the services without throwing as this is an optional feature IBinder iBinder = - ServiceManager.getServiceOrThrow(Context.COMPANION_DEVICE_SERVICE); + ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE); ICompanionDeviceManager service = ICompanionDeviceManager.Stub.asInterface(iBinder); return new CompanionDeviceManager(service, ctx); @@ -833,7 +835,8 @@ final class SystemServiceRegistry { new CachedServiceFetcher() { @Override public AutofillManager createService(ContextImpl ctx) throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.AUTOFILL_MANAGER_SERVICE); + // Get the services without throwing as this is an optional feature + IBinder b = ServiceManager.getService(Context.AUTOFILL_MANAGER_SERVICE); IAutoFillManager service = IAutoFillManager.Stub.asInterface(b); return new AutofillManager(ctx.getOuterContext(), service); }}); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index fa3e4e98b5510..855411fc2a5e0 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2402,6 +2402,15 @@ public abstract class PackageManager { public static final String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance"; + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device supports autofill of user credentials, addresses, credit cards, etc + * via integration with {@link android.service.autofill.AutofillService autofill + * providers}. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_AUTOFILL = "android.software.autofill"; + /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: * The device implements headtracking suitable for a VR device. diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index 3117f9842b646..eab0d4c882d0e 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -309,7 +309,6 @@ public final class FillResponse implements Parcelable { return this; } - /** * Builds a new {@link FillResponse} instance. You must provide at least * one dataset or some savable ids or an authentication with a presentation diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index ba004b9672601..e85a658a63167 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -192,6 +192,9 @@ public final class AutofillManager { * {@hide} */ public void onCreate(Bundle savedInstanceState) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { mLastAutofilledData = savedInstanceState.getParcelable(LAST_AUTOFILLED_DATA_TAG); @@ -237,6 +240,9 @@ public final class AutofillManager { * {@hide} */ public void onAttachedToWindow(@NonNull IBinder windowToken) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { if (mSessionId == NO_SESSION) { return; @@ -258,6 +264,9 @@ public final class AutofillManager { * {@hide} */ public void onSaveInstanceState(Bundle outState) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { if (mSessionId != NO_SESSION) { outState.putInt(SESSION_ID_TAG, mSessionId); @@ -278,6 +287,9 @@ public final class AutofillManager { * @return whether autofill is enabled for the current user. */ public boolean isEnabled() { + if (!hasAutofillFeature()) { + return false; + } synchronized (mLock) { ensureServiceClientAddedIfNeededLocked(); return mEnabled; @@ -294,6 +306,9 @@ public final class AutofillManager { * @param view view requesting the new autofill context. */ public void requestAutofill(@NonNull View view) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { ensureServiceClientAddedIfNeededLocked(); @@ -320,6 +335,9 @@ public final class AutofillManager { * @param bounds child boundaries, relative to the top window. */ public void requestAutofill(@NonNull View view, int childId, @NonNull Rect bounds) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { ensureServiceClientAddedIfNeededLocked(); @@ -339,6 +357,9 @@ public final class AutofillManager { * @param view {@link View} that was entered. */ public void notifyViewEntered(@NonNull View view) { + if (!hasAutofillFeature()) { + return; + } AutofillCallback callback = null; synchronized (mLock) { ensureServiceClientAddedIfNeededLocked(); @@ -372,6 +393,9 @@ public final class AutofillManager { * @param view {@link View} that was exited. */ public void notifyViewExited(@NonNull View view) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { ensureServiceClientAddedIfNeededLocked(); @@ -392,6 +416,9 @@ public final class AutofillManager { * @param bounds child boundaries, relative to the top window. */ public void notifyViewEntered(@NonNull View view, int childId, @NonNull Rect bounds) { + if (!hasAutofillFeature()) { + return; + } AutofillCallback callback = null; synchronized (mLock) { ensureServiceClientAddedIfNeededLocked(); @@ -426,6 +453,9 @@ public final class AutofillManager { * @param childId id identifying the virtual child inside the view. */ public void notifyViewExited(@NonNull View view, int childId) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { ensureServiceClientAddedIfNeededLocked(); @@ -444,6 +474,9 @@ public final class AutofillManager { * @param view view whose value changed. */ public void notifyValueChanged(View view) { + if (!hasAutofillFeature()) { + return; + } AutofillId id = null; boolean valueWasRead = false; AutofillValue value = null; @@ -486,7 +519,6 @@ public final class AutofillManager { } } - /** * Called to indicate the value of an autofillable virtual {@link View} changed. * @@ -495,6 +527,9 @@ public final class AutofillManager { * @param value new value of the child. */ public void notifyValueChanged(View view, int childId, AutofillValue value) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { if (!mEnabled || mSessionId == NO_SESSION) { return; @@ -512,6 +547,9 @@ public final class AutofillManager { * call this method after the form is submitted and another page is rendered. */ public void commit() { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { if (!mEnabled && mSessionId == NO_SESSION) { return; @@ -528,6 +566,9 @@ public final class AutofillManager { * call this method if the user does not post the form but moves to another form in this page. */ public void cancel() { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { if (!mEnabled && mSessionId == NO_SESSION) { return; @@ -542,6 +583,9 @@ public final class AutofillManager { * will be disabled. */ public void disableOwnedAutofillServices() { + if (!hasAutofillFeature()) { + return; + } try { mService.disableOwnedAutofillServices(mContext.getUserId()); } catch (RemoteException e) { @@ -558,6 +602,9 @@ public final class AutofillManager { /** @hide */ public void onAuthenticationResult(Intent data) { + if (!hasAutofillFeature()) { + return; + } // TODO(b/33197203): the result code is being ignored, so this method is not reliably // handling the cases where it's not RESULT_OK: it works fine if the service does not // set the EXTRA_AUTHENTICATION_RESULT extra, but it could cause weird results if the @@ -672,6 +719,9 @@ public final class AutofillManager { * @param callback callback to receive events. */ public void registerCallback(@Nullable AutofillCallback callback) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { if (callback == null) return; @@ -694,6 +744,9 @@ public final class AutofillManager { * @param callback callback to stop receiving events. */ public void unregisterCallback(@Nullable AutofillCallback callback) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { if (callback == null || mCallback == null || callback != mCallback) return; @@ -871,6 +924,10 @@ public final class AutofillManager { return view; } + private boolean hasAutofillFeature() { + return mService != null; + } + /** * Callback for auto-fill related events. * diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index f74512a001229..3b5f9bd7bf370 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1540,9 +1540,11 @@ public final class SystemServer { mSystemServiceManager.startService(RetailDemoModeService.class); traceEnd(); - traceBeginAndSlog("StartAutoFillService"); - mSystemServiceManager.startService(AUTO_FILL_MANAGER_SERVICE_CLASS); - traceEnd(); + if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOFILL)) { + traceBeginAndSlog("StartAutoFillService"); + mSystemServiceManager.startService(AUTO_FILL_MANAGER_SERVICE_CLASS); + traceEnd(); + } // It is now time to start up the app processes...