diff options
20 files changed, 281 insertions, 69 deletions
diff --git a/api/current.txt b/api/current.txt index 8d7dcccfe1c1..1bdb49f10e28 100644 --- a/api/current.txt +++ b/api/current.txt @@ -45087,8 +45087,8 @@ package android.view { method public void addTouchables(java.util.ArrayList<android.view.View>); method public android.view.ViewPropertyAnimator animate(); method public void announceForAccessibility(java.lang.CharSequence); - method public void autofill(android.view.autofill.AutofillValue); - method public void autofillVirtual(int, android.view.autofill.AutofillValue); + method public boolean autofill(android.view.autofill.AutofillValue); + method public boolean autofillVirtual(int, android.view.autofill.AutofillValue); method protected boolean awakenScrollBars(); method protected boolean awakenScrollBars(int); method protected boolean awakenScrollBars(int, boolean); diff --git a/api/system-current.txt b/api/system-current.txt index 53c9e91f85be..c5a4bbc77bca 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -48550,8 +48550,8 @@ package android.view { method public void addTouchables(java.util.ArrayList<android.view.View>); method public android.view.ViewPropertyAnimator animate(); method public void announceForAccessibility(java.lang.CharSequence); - method public void autofill(android.view.autofill.AutofillValue); - method public void autofillVirtual(int, android.view.autofill.AutofillValue); + method public boolean autofill(android.view.autofill.AutofillValue); + method public boolean autofillVirtual(int, android.view.autofill.AutofillValue); method protected boolean awakenScrollBars(); method protected boolean awakenScrollBars(int); method protected boolean awakenScrollBars(int, boolean); diff --git a/api/test-current.txt b/api/test-current.txt index bd0e4662fad1..133deb673575 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -45447,8 +45447,8 @@ package android.view { method public void addTouchables(java.util.ArrayList<android.view.View>); method public android.view.ViewPropertyAnimator animate(); method public void announceForAccessibility(java.lang.CharSequence); - method public void autofill(android.view.autofill.AutofillValue); - method public void autofillVirtual(int, android.view.autofill.AutofillValue); + method public boolean autofill(android.view.autofill.AutofillValue); + method public boolean autofillVirtual(int, android.view.autofill.AutofillValue); method protected boolean awakenScrollBars(); method protected boolean awakenScrollBars(int); method protected boolean awakenScrollBars(int, boolean); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 78c29e840b9a..e65c7c815960 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -16,6 +16,7 @@ package android.app; +import android.metrics.LogMaker; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; @@ -23,6 +24,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.ToolbarActionBar; import com.android.internal.app.WindowDecorActionBar; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; import com.android.internal.policy.PhoneWindow; import android.annotation.CallSuper; @@ -765,6 +768,7 @@ public class Activity extends ContextThemeWrapper /*package*/ Configuration mCurrentConfig; private SearchManager mSearchManager; private MenuInflater mMenuInflater; + private final MetricsLogger mMetricsLogger = new MetricsLogger(); static final class NonConfigurationInstances { Object activity; @@ -7188,6 +7192,8 @@ public class Activity extends ContextThemeWrapper public void autofill(List<AutofillId> ids, List<AutofillValue> values) { final View root = getWindow().getDecorView(); final int itemCount = ids.size(); + int numApplied = 0; + for (int i = 0; i < itemCount; i++) { final AutofillId id = ids.get(i); final AutofillValue value = values.get(i); @@ -7197,12 +7203,22 @@ public class Activity extends ContextThemeWrapper Log.w(TAG, "autofill(): no View with id " + viewId); continue; } + final boolean wasApplied; if (id.isVirtual()) { - view.autofillVirtual(id.getVirtualChildId(), value); + wasApplied = view.autofillVirtual(id.getVirtualChildId(), value); } else { - view.autofill(value); + wasApplied = view.autofill(value); + } + + if (wasApplied) { + numApplied++; } } + + LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED); + log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount); + log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied); + mMetricsLogger.write(log); } /** @hide */ diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 80f6c3249428..6cddbac736af 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -7445,8 +7445,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * </pre> * * @param value value to be autofilled. + * + * @return {@code true} if the view was successfully autofilled, {@code false} otherwise */ - public void autofill(@SuppressWarnings("unused") AutofillValue value) { + public boolean autofill(@SuppressWarnings("unused") AutofillValue value) { + return false; } /** @@ -7457,9 +7460,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param value value to be autofilled. * @param virtualId id identifying the virtual child inside the custom view. + * + * @return {@code true} if the view was successfully autofilled, {@code false} otherwise */ - public void autofillVirtual(@SuppressWarnings("unused") int virtualId, + public boolean autofillVirtual(@SuppressWarnings("unused") int virtualId, @SuppressWarnings("unused") AutofillValue value) { + return false; } /** diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index f036b9cddec4..244aba7e9034 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -83,7 +83,7 @@ public final class AutofillManager { /** @hide */ public static final int FLAG_VIEW_EXITED = 0x20000000; /** @hide */ public static final int FLAG_VALUE_CHANGED = 0x10000000; - private final Rect mTempRect = new Rect(); + @NonNull private final Rect mTempRect = new Rect(); private final IAutoFillManager mService; private IAutoFillManagerClient mServiceClient; @@ -371,8 +371,8 @@ public final class AutofillManager { return new AutofillId(parent.getAccessibilityViewId(), childId); } - private void startSession(AutofillId id, IBinder windowToken, Rect bounds, - AutofillValue value, int flags) { + private void startSession(@NonNull AutofillId id, @NonNull IBinder windowToken, + @NonNull Rect bounds, @NonNull AutofillValue value, int flags) { if (DEBUG) { Log.d(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value + ", flags=" + flags); @@ -381,8 +381,8 @@ public final class AutofillManager { try { mService.startSession(mContext.getActivityToken(), windowToken, mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(), - mCallback != null, flags); - final AutofillClient client = getClient(); + mCallback != null, flags, mContext.getOpPackageName()); + AutofillClient client = getClient(); if (client != null) { client.resetableStateAvailable(); } diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index 85b05e585318..97210cc919a5 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -32,7 +32,7 @@ interface IAutoFillManager { boolean addClient(in IAutoFillManagerClient client, int userId); oneway void startSession(in IBinder activityToken, IBinder windowToken, in IBinder appCallback, in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId, - boolean hasCallback, int flags); + boolean hasCallback, int flags, String packageName); oneway void updateSession(in IBinder activityToken, in AutofillId id, in Rect bounds, in AutofillValue value, int flags, int userId); oneway void finishSession(in IBinder activityToken, int userId); diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java index 020e80a29134..fae574289b88 100644 --- a/core/java/android/widget/AbsSpinner.java +++ b/core/java/android/widget/AbsSpinner.java @@ -514,14 +514,15 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; if (value.isList()) { setSelection(value.getListValue()); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + return true; } @Override diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java index 899a824489e3..9dc61ab56b34 100644 --- a/core/java/android/widget/CompoundButton.java +++ b/core/java/android/widget/CompoundButton.java @@ -584,14 +584,16 @@ public abstract class CompoundButton extends Button implements Checkable { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; if (value.isToggle()) { setChecked(value.getToggleValue()); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + + return true; } @Override diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index f63573f4f3fe..7d04f355f251 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -775,14 +775,16 @@ public class DatePicker extends FrameLayout { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; if (value.isDate()) { mDelegate.updateDate(value.getDateValue()); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + + return true; } @Override diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java index 5e8279a3e7c9..a7574c7a45ae 100644 --- a/core/java/android/widget/RadioGroup.java +++ b/core/java/android/widget/RadioGroup.java @@ -426,23 +426,24 @@ public class RadioGroup extends LinearLayout { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; int index; if (value.isList()) { index = value.getListValue(); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); - return; + return false; } final View child = getChildAt(index); if (child == null) { Log.w(VIEW_LOG_TAG, "RadioGroup.autoFill(): no child with index " + index); - return; + return false; } check(child.getId()); + return true; } @Override diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index c5c317d671ef..26edc436b2f8 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -10028,14 +10028,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override - public void autofill(AutofillValue value) { + public boolean autofill(AutofillValue value) { if (value.isText()) { if (isTextEditable()) { setText(value.getTextValue(), mBufferType, true, 0); + return true; } } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + + return false; } @Override diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index cfa78b53dd91..1e97e3ba5134 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -530,14 +530,16 @@ public class TimePicker extends FrameLayout { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; if (value.isDate()) { mDelegate.setDate(value.getDateValue()); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + + return true; } @Override diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index f11f302618ab..8a3b9af0ce08 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -56,6 +56,12 @@ message MetricsEvent { // Type for APP_TRANSITION event: The transition brought an already existing activity to the // front. TYPE_TRANSITION_HOT_LAUNCH = 9; + + // The action was successful + TYPE_SUCCESS = 10; + + // The action failed + TYPE_FAILURE = 11; } // Known visual elements: views or controls. @@ -3702,6 +3708,75 @@ message MetricsEvent { // OS: O APP_TRANSITION_IS_EPHEMERAL = 905; + // An autofill session was started + // Package: Package of app that is autofilled + AUTOFILL_SESSION_STARTED = 906; + + // An autofill request was processed by a service + // Type TYPE_SUCCESS: The request succeeded + // Type TYPE_FAILURE: The request failed + // Package: Package of app that is autofilled + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + // Tag FIELD_AUTOFILL_NUM_DATASET: The number of datasets returned (only in success case) + AUTOFILL_REQUEST = 907; + + // Tag of a field for a package of an autofill service + FIELD_AUTOFILL_SERVICE = 908; + + // Tag of a field for the number of datasets + FIELD_AUTOFILL_NUM_DATASETS = 909; + + // An autofill dataset selection UI was shown + // Type TYPE_DISMISS: UI was explicityly canceled by the user + // Type TYPE_CLOSE: UI was destroyed without influence of the user + // Type TYPE_ACTION: dataset was selected + // Type TYPE_DETAIL: authentication was selected + // Package: Package of app that was autofilled + // Tag FIELD_AUTOFILL_FILTERTEXT_LEN: The length of the filter text + // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown + AUTOFILL_FILL_UI = 910; + + // Tag of a field for the length of the filter text + FIELD_AUTOFILL_FILTERTEXT_LEN = 911; + + // An autofill authentification succeeded + // Package: Package of app that was autofilled + AUTOFILL_AUTHENTICATED = 912; + + // An activity was autofilled and all values could be applied + // Package: Package of app that is autofilled + // Tag FIELD_AUTOFILL_NUM_VALUES: Number of values that were suggested to be autofilled + // Tag FIELD_AUTOFILL_NUM_VIEWS_FILLED: Number of views that could be filled + AUTOFILL_DATASET_APPLIED = 913; + + // Tag of a field for the number values to be filled in + FIELD_AUTOFILL_NUM_VALUES = 914; + + // Tag of a field for the number of views that were filled + FIELD_AUTOFILL_NUM_VIEWS_FILLED = 915; + + // An autofill save UI was shown + // Type TYPE_DISMISS: UI was explicityly canceled by the user + // Type TYPE_CLOSE: UI was destroyed without influence of the user + // Type TYPE_ACTION: data was saved + // Package: Package of app that was autofilled + // Tag FIELD_AUTOFILL_NUM_ID: The number of ids that are saved + AUTOFILL_SAVE_UI = 916; + + // Tag of a field for the number of saveable ids + FIELD_AUTOFILL_NUM_IDS = 917; + + // ACTION: An autofill service was reqiested to save data + // Type TYPE_SUCCESS: The request succeeded + // Type TYPE_FAILURE: The request failed + // Package: Package of app that was autofilled + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + AUTOFILL_DATA_SAVE_REQUEST = 918; + + // An auto-fill session was finished + // Package: Package of app that was autofilled + AUTOFILL_SESSION_FINISHED = 919; + // ---- End O Constants, all O constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index af1193d7edea..c7ba1ff60a1e 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -28,6 +28,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.database.ContentObserver; import android.graphics.Rect; @@ -53,6 +54,7 @@ import android.view.autofill.IAutoFillManagerClient; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; import com.android.internal.os.IResultReceiver; +import com.android.internal.util.Preconditions; import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -316,13 +318,27 @@ public final class AutofillManagerService extends SystemService { @Override public void startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback, AutofillId autofillId, Rect bounds, AutofillValue value, int userId, - boolean hasCallback, int flags) { + boolean hasCallback, int flags, String packageName) { // TODO(b/33197203): make sure it's called by resumed / focused activity + activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); + appCallback = Preconditions.checkNotNull(appCallback, "appCallback"); + autofillId = Preconditions.checkNotNull(autofillId, "autoFillId"); + bounds = Preconditions.checkNotNull(bounds, "bounds"); + packageName = Preconditions.checkNotNull(packageName, "packageName"); + + Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId"); + + try { + mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalArgumentException(packageName + " is not a valid package", e); + } + synchronized (mLock) { final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); service.startSessionLocked(activityToken, windowToken, appCallback, - autofillId, bounds, value, hasCallback, flags); + autofillId, bounds, value, hasCallback, flags, packageName); } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 3e5ad82d0129..31587867000f 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -28,6 +28,7 @@ import static com.android.server.autofill.Helper.DEBUG; import static com.android.server.autofill.Helper.VERBOSE; import static com.android.server.autofill.Helper.findValue; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; @@ -43,6 +44,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.graphics.Rect; +import android.metrics.LogMaker; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -68,6 +70,8 @@ import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import android.view.autofill.IAutoFillManagerClient; import com.android.internal.annotations.GuardedBy; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; import com.android.internal.os.HandlerCaller; import com.android.internal.os.IResultReceiver; import com.android.server.autofill.ui.AutoFillUI; @@ -92,6 +96,7 @@ final class AutofillManagerServiceImpl { private final Context mContext; private final Object mLock; private final AutoFillUI mUi; + private final MetricsLogger mMetricsLogger = new MetricsLogger(); private RemoteCallbackList<IAutoFillManagerClient> mClients; private AutofillServiceInfo mInfo; @@ -284,9 +289,10 @@ final class AutofillManagerServiceImpl { } } - void startSessionLocked(IBinder activityToken, IBinder windowToken, IBinder appCallbackToken, - AutofillId autofillId, Rect bounds, AutofillValue value, boolean hasCallback, - int flags) { + void startSessionLocked(@NonNull IBinder activityToken, @Nullable IBinder windowToken, + @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect bounds, + @Nullable AutofillValue value, boolean hasCallback, int flags, + @NonNull String packageName) { if (!hasService()) { return; } @@ -305,7 +311,7 @@ final class AutofillManagerServiceImpl { } final Session newSession = createSessionByTokenLocked(activityToken, - windowToken, appCallbackToken, hasCallback, flags); + windowToken, appCallbackToken, hasCallback, flags, packageName); newSession.updateLocked(autofillId, bounds, value, FLAG_START_SESSION); } @@ -337,10 +343,11 @@ final class AutofillManagerServiceImpl { session.destroyLocked(); } - private Session createSessionByTokenLocked(IBinder activityToken, IBinder windowToken, - IBinder appCallbackToken, boolean hasCallback, int flags) { + private Session createSessionByTokenLocked(@NonNull IBinder activityToken, + @Nullable IBinder windowToken, @NonNull IBinder appCallbackToken, boolean hasCallback, + int flags, @NonNull String packageName) { final Session newSession = new Session(mContext, activityToken, - windowToken, appCallbackToken, hasCallback, flags); + windowToken, appCallbackToken, hasCallback, flags, packageName); mSessions.put(activityToken, newSession); /* @@ -351,7 +358,6 @@ final class AutofillManagerServiceImpl { * - display disclosure if needed */ try { - // TODO(b/33197203): add MetricsLogger call final Bundle receiverExtras = new Bundle(); receiverExtras.putBinder(EXTRA_ACTIVITY_TOKEN, activityToken); final long identity = Binder.clearCallingIdentity(); @@ -371,7 +377,6 @@ final class AutofillManagerServiceImpl { void updateSessionLocked(IBinder activityToken, AutofillId autofillId, Rect bounds, AutofillValue value, int flags) { - // TODO(b/33197203): add MetricsLogger call final Session session = mSessions.get(activityToken); if (session == null) { if (VERBOSE) { @@ -595,6 +600,9 @@ final class AutofillManagerServiceImpl { private final IBinder mActivityToken; private final IBinder mWindowToken; + /** Package name of the app that is auto-filled */ + @NonNull private final String mPackageName; + @GuardedBy("mLock") private final Map<AutofillId, ViewState> mViewStates = new ArrayMap<>(); @@ -634,15 +642,16 @@ final class AutofillManagerServiceImpl { * Flags used to start the session. */ private int mFlags; - - private Session(Context context, IBinder activityToken, IBinder windowToken, - IBinder client, boolean hasCallback, int flags) { + private Session(@NonNull Context context, @NonNull IBinder activityToken, + @Nullable IBinder windowToken, @NonNull IBinder client, boolean hasCallback, + int flags, @NonNull String packageName) { mRemoteFillService = new RemoteFillService(context, mInfo.getServiceInfo().getComponentName(), mUserId, this); mActivityToken = activityToken; mWindowToken = windowToken; mHasCallback = hasCallback; mFlags = flags; + mPackageName = packageName; mClient = IAutoFillManagerClient.Stub.asInterface(client); try { @@ -656,12 +665,14 @@ final class AutofillManagerServiceImpl { } catch (RemoteException e) { Slog.w(TAG, "linkToDeath() on mClient failed: " + e); } + + mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_STARTED, mPackageName); } // FillServiceCallbacks @Override - public void onFillRequestSuccess(FillResponse response) { - // TODO(b/33197203): add MetricsLogger call + public void onFillRequestSuccess(@Nullable FillResponse response, + @NonNull String servicePackageName) { if (response == null) { removeSelf(); return; @@ -669,28 +680,59 @@ final class AutofillManagerServiceImpl { synchronized (mLock) { processResponseLocked(response); } + + LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST)) + .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS) + .setPackageName(mPackageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, + response.getDatasets() == null ? 0 : response.getDatasets().size()) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE, + servicePackageName); + mMetricsLogger.write(log); } // FillServiceCallbacks @Override - public void onFillRequestFailure(CharSequence message) { - // TODO(b/33197203): add MetricsLogger call + public void onFillRequestFailure(@Nullable CharSequence message, + @NonNull String servicePackageName) { + LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST)) + .setType(MetricsProto.MetricsEvent.TYPE_FAILURE) + .setPackageName(mPackageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE, + servicePackageName); + mMetricsLogger.write(log); + getUiForShowing().showError(message); removeSelf(); } // FillServiceCallbacks @Override - public void onSaveRequestSuccess() { - // TODO(b/33197203): add MetricsLogger call + public void onSaveRequestSuccess(@NonNull String servicePackageName) { + LogMaker log = (new LogMaker( + MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST)) + .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS) + .setPackageName(mPackageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE, + servicePackageName); + mMetricsLogger.write(log); + // Nothing left to do... removeSelf(); } // FillServiceCallbacks @Override - public void onSaveRequestFailure(CharSequence message) { - // TODO(b/33197203): add MetricsLogger call + public void onSaveRequestFailure(@Nullable CharSequence message, + @NonNull String servicePackageName) { + LogMaker log = (new LogMaker( + MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST)) + .setType(MetricsProto.MetricsEvent.TYPE_FAILURE) + .setPackageName(mPackageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE, + servicePackageName); + mMetricsLogger.write(log); + getUiForShowing().showError(message); removeSelf(); } @@ -773,6 +815,9 @@ final class AutofillManagerServiceImpl { Parcelable result = data.getParcelable( AutofillManager.EXTRA_AUTHENTICATION_RESULT); if (result instanceof FillResponse) { + mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_AUTHENTICATED, + mPackageName); + mCurrentResponse = (FillResponse) result; processResponseLocked(mCurrentResponse); } else if (result instanceof Dataset) { @@ -894,7 +939,7 @@ final class AutofillManagerServiceImpl { if (atLeastOneChanged) { getUiForShowing().showSaveUi( mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()), - saveInfo); + saveInfo, mPackageName); return; } } @@ -1034,7 +1079,7 @@ final class AutofillManagerServiceImpl { filterText = value.getTextValue().toString(); } - getUiForShowing().showFillUi(filledId, response, bounds, filterText); + getUiForShowing().showFillUi(filledId, response, bounds, filterText, mPackageName); } private void notifyChangeToClient(AutofillId id, int event) { @@ -1052,8 +1097,6 @@ final class AutofillManagerServiceImpl { + "):" + response); } - // TODO(b/33197203): add MetricsLogger calls - if (mCurrentViewState == null) { // TODO(b/33197203): temporary sanity check; should never happen Slog.w(TAG, "processResponseLocked(): mCurrentResponse is null"); @@ -1188,6 +1231,9 @@ final class AutofillManagerServiceImpl { private void destroyLocked() { mRemoteFillService.destroy(); mUi.setCallback(null, null); + + mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_FINISHED, + mPackageName); } private void removeSelf() { diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index b1cc89b5de44..c41ac05ef6aa 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -87,10 +87,10 @@ final class RemoteFillService implements DeathRecipient { private PendingRequest mPendingRequest; public interface FillServiceCallbacks { - void onFillRequestSuccess(FillResponse response); - void onFillRequestFailure(CharSequence message); - void onSaveRequestSuccess(); - void onSaveRequestFailure(CharSequence message); + void onFillRequestSuccess(@Nullable FillResponse response, @NonNull String servicePackageName); + void onFillRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName); + void onSaveRequestSuccess(@NonNull String servicePackageName); + void onSaveRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName); void onServiceDied(RemoteFillService service); void onDisableSelf(); } @@ -262,7 +262,7 @@ final class RemoteFillService implements DeathRecipient { FillResponse response) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onFillRequestSuccess(response); + mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName()); } }); } @@ -271,7 +271,7 @@ final class RemoteFillService implements DeathRecipient { CharSequence message) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onFillRequestFailure(message); + mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName()); } }); } @@ -279,7 +279,7 @@ final class RemoteFillService implements DeathRecipient { private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onSaveRequestSuccess(); + mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName()); } }); } @@ -288,7 +288,7 @@ final class RemoteFillService implements DeathRecipient { CharSequence message) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onSaveRequestFailure(message); + mCallbacks.onSaveRequestFailure(message, mComponentName.getPackageName()); } }); } diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index c7e59a39aeef..56c78be20867 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.IntentSender; import android.graphics.Rect; +import android.metrics.LogMaker; import android.os.Handler; import android.os.IBinder; import android.service.autofill.Dataset; @@ -34,6 +35,8 @@ import android.util.Slog; import android.view.autofill.AutofillId; import android.widget.Toast; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; import com.android.server.UiThread; import java.io.PrintWriter; @@ -60,6 +63,7 @@ public final class AutoFillUI { private @Nullable IBinder mWindowToken; private int mSaveTimeoutMs = (int) (5 * DateUtils.SECOND_IN_MILLIS); + private final MetricsLogger mMetricsLogger = new MetricsLogger(); public interface AutoFillUiCallback { void authenticate(@NonNull IntentSender intent); @@ -152,9 +156,17 @@ public final class AutoFillUI { * @param response the current fill response * @param anchorBounds bounds of the focused view * @param filterText text of the view to be filled + * @param packageName package name of the activity that is filled */ public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response, - @NonNull Rect anchorBounds, @Nullable String filterText) { + @NonNull Rect anchorBounds, @Nullable String filterText, @NonNull String packageName) { + LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI)) + .setPackageName(packageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN, + filterText == null ? 0 : filterText.length()) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, + response.getDatasets() == null ? 0 : response.getDatasets().size()); + mHandler.post(() -> { if (!hasCallback()) { return; @@ -164,6 +176,7 @@ public final class AutoFillUI { mWindowToken, anchorBounds, filterText, new FillUi.Callback() { @Override public void onResponsePicked(FillResponse response) { + log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL); hideFillUiUiThread(); if (mCallback != null) { mCallback.authenticate(response.getAuthentication()); @@ -172,17 +185,25 @@ public final class AutoFillUI { @Override public void onDatasetPicked(Dataset dataset) { + log.setType(MetricsProto.MetricsEvent.TYPE_ACTION); hideFillUiUiThread(); if (mCallback != null) { mCallback.fill(dataset); } - // TODO(b/33197203): add MetricsLogger call } @Override public void onCanceled() { + log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS); hideFillUiUiThread(); - // TODO(b/33197203): add MetricsLogger call + } + + @Override + public void onDestroy() { + if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) { + log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE); + } + mMetricsLogger.write(log); } }); mCallback.onEvent(focusedId, EVENT_INPUT_SHOWN); @@ -192,7 +213,16 @@ public final class AutoFillUI { /** * Shows the UI asking the user to save for autofill. */ - public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info) { + public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info, + @NonNull String packageName) { + int numIds = 0; + numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length; + numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length; + + LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_SAVE_UI)) + .setPackageName(packageName).addTaggedData( + MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds); + mHandler.post(() -> { if (!hasCallback()) { return; @@ -202,16 +232,16 @@ public final class AutoFillUI { new SaveUi.OnSaveListener() { @Override public void onSave() { + log.setType(MetricsProto.MetricsEvent.TYPE_ACTION); hideSaveUiUiThread(); if (mCallback != null) { mCallback.save(); } - // TODO(b/33197203): add MetricsLogger call } @Override public void onCancel(IntentSender listener) { - // TODO(b/33197203): add MetricsLogger call + log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS); hideSaveUiUiThread(); if (listener != null) { try { @@ -225,6 +255,14 @@ public final class AutoFillUI { mCallback.cancelSave(); } } + + @Override + public void onDestroy() { + if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) { + log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE); + } + mMetricsLogger.write(log); + } }, mSaveTimeoutMs); }); } diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java index a7d9fe96d0da..fbf5d262feae 100644 --- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java @@ -50,6 +50,7 @@ final class FillUi { void onResponsePicked(@NonNull FillResponse response); void onDatasetPicked(@NonNull Dataset dataset); void onCanceled(); + void onDestroy(); } private final Rect mAnchorBounds = new Rect(); @@ -201,6 +202,7 @@ final class FillUi { public void destroy() { throwIfDestroyed(); + mCallback.onDestroy(); mWindow.hide(); mDestroyed = true; } diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index 3f409ade68ed..644abe60e314 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -40,6 +40,7 @@ final class SaveUi { public interface OnSaveListener { void onSave(); void onCancel(IntentSender listener); + void onDestroy(); } private final Handler mHandler = UiThread.getHandler(); @@ -122,6 +123,7 @@ final class SaveUi { void destroy() { throwIfDestroyed(); + mListener.onDestroy(); mHandler.removeCallbacksAndMessages(mListener); mDialog.dismiss(); mDestroyed = true; |