TRON log important auto-fill events
Example log from
android.autofillservice.cts.LoginActivityTest#testAutoFill#testAutoFillOneDatasetAndSave
(translated from numbers of human readable string):
AUTOFILL_SESSION_STARTED
package=android.autofillservice.cts
AUTOFILL_REQUEST
type=TYPE_SUCCESS
package=android.autofillservice.cts
FIELD_AUTOFILL_SERVICE=android.autofillservice.cts
FIELD_AUTOFILL_NUM_DATASETS=1
AUTOFILL_FILL_UI
type=TYPE_ACTION
package=android.autofillservice.cts
FIELD_AUTOFILL_NUM_DATASETS=1
FIELD_AUTOFILL_FILTERTEXT_LEN=0
AUTOFILL_DATASET_APPLIED
package=android.autofillservice.cts
FIELD_AUTOFILL_NUM_VALUES=2
FIELD_AUTOFILL_NUM_VIEWS_FILLED=2
AUTOFILL_SAVE_UI
package=android.autofillservice.cts
FIELD_AUTOFILL_NUM_IDS=2
AUTOFILL_DATA_SAVE_REQUEST
type=TYPE_SUCCESS
package=android.autofillservice.cts
FIELD_AUTOFILL_SERVICE=android.autofillservice.cts
AUTOFILL_SESSION_FINISHED
package=android.autofillservice.cts
Test: Ran auto-fill tests and looked at event log.
Change-Id: I58aaa58e4435e7d04c8cd91878411943d3eb13de
diff --git a/api/current.txt b/api/current.txt
index 9557ee5..8cb1262 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -45076,8 +45076,8 @@
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 6d01c6b..8d9c0c0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -48539,8 +48539,8 @@
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 1d0a289..46f9085 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -45436,8 +45436,8 @@
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 78c29e8..e65c7c8 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.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 @@
/*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 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 @@
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 80f6c32..6cddbac 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7445,8 +7445,11 @@
* </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 @@
*
* @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 f036b9c..244aba7 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -83,7 +83,7 @@
/** @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 @@
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 @@
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 85b05e5..97210cc 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -32,7 +32,7 @@
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 020e80a..fae5742 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -514,14 +514,15 @@
}
@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 899a824..9dc61ab 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -584,14 +584,16 @@
}
@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 f63573f..7d04f35 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -775,14 +775,16 @@
}
@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 5e8279a..a7574c7 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -426,23 +426,24 @@
}
@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 c5c317d..26edc43 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10028,14 +10028,17 @@
}
@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 cfa78b5..1e97e3b 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -530,14 +530,16 @@
}
@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 f11f302..8a3b9af 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -56,6 +56,12 @@
// 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 @@
// 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 af1193d..c7ba1ff 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.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 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 @@
@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 3e5ad82..3158786 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.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.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.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 @@
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 @@
}
}
- 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 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 @@
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 @@
* - 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 @@
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 @@
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 @@
* 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 @@
} 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 @@
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 @@
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 @@
if (atLeastOneChanged) {
getUiForShowing().showSaveUi(
mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()),
- saveInfo);
+ saveInfo, mPackageName);
return;
}
}
@@ -1034,7 +1079,7 @@
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 @@
+ "):" + 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 @@
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 b1cc89b..c41ac05 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 @@
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 @@
FillResponse response) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestSuccess(response);
+ mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName());
}
});
}
@@ -271,7 +271,7 @@
CharSequence message) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestFailure(message);
+ mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
}
});
}
@@ -279,7 +279,7 @@
private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onSaveRequestSuccess();
+ mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName());
}
});
}
@@ -288,7 +288,7 @@
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 c7e59a3..56c78be 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.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.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 @@
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 @@
* @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 @@
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 @@
@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 @@
/**
* 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 @@
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 @@
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 a7d9fe9..fbf5d26 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 @@
void onResponsePicked(@NonNull FillResponse response);
void onDatasetPicked(@NonNull Dataset dataset);
void onCanceled();
+ void onDestroy();
}
private final Rect mAnchorBounds = new Rect();
@@ -201,6 +202,7 @@
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 3f409ad..644abe6 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 @@
public interface OnSaveListener {
void onSave();
void onCancel(IntentSender listener);
+ void onDestroy();
}
private final Handler mHandler = UiThread.getHandler();
@@ -122,6 +123,7 @@
void destroy() {
throwIfDestroyed();
+ mListener.onDestroy();
mHandler.removeCallbacksAndMessages(mListener);
mDialog.dismiss();
mDestroyed = true;