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);
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);
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);
package android.app;
+import android.metrics.LogMaker;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
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;
/*package*/ Configuration mCurrentConfig;
private SearchManager mSearchManager;
private MenuInflater mMenuInflater;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
static final class NonConfigurationInstances {
Object activity;
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);
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 */
* </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;
}
/**
*
* @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;
}
/**
/** @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;
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);
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();
}
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);
}
@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
}
@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
}
@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
}
@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
}
@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
}
@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
// 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.
// 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.
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;
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;
@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);
}
}
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;
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;
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;
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;
}
}
- 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;
}
}
final Session newSession = createSessionByTokenLocked(activityToken,
- windowToken, appCallbackToken, hasCallback, flags);
+ windowToken, appCallbackToken, hasCallback, flags, packageName);
newSession.updateLocked(autofillId, bounds, value, FLAG_START_SESSION);
}
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);
/*
* - 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();
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) {
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<>();
* 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 {
} 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;
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();
}
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) {
if (atLeastOneChanged) {
getUiForShowing().showSaveUi(
mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()),
- saveInfo);
+ saveInfo, mPackageName);
return;
}
}
filterText = value.getTextValue().toString();
}
- getUiForShowing().showFillUi(filledId, response, bounds, filterText);
+ getUiForShowing().showFillUi(filledId, response, bounds, filterText, mPackageName);
}
private void notifyChangeToClient(AutofillId id, int event) {
+ "):" + 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");
private void destroyLocked() {
mRemoteFillService.destroy();
mUi.setCallback(null, null);
+
+ mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_FINISHED,
+ mPackageName);
}
private void removeSelf() {
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();
}
FillResponse response) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestSuccess(response);
+ mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName());
}
});
}
CharSequence message) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestFailure(message);
+ mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
}
});
}
private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onSaveRequestSuccess();
+ mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName());
}
});
}
CharSequence message) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onSaveRequestFailure(message);
+ mCallbacks.onSaveRequestFailure(message, mComponentName.getPackageName());
}
});
}
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;
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;
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);
* @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;
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());
@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);
/**
* 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;
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 {
mCallback.cancelSave();
}
}
+
+ @Override
+ public void onDestroy() {
+ if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
+ log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+ }
+ mMetricsLogger.write(log);
+ }
}, mSaveTimeoutMs);
});
}
void onResponsePicked(@NonNull FillResponse response);
void onDatasetPicked(@NonNull Dataset dataset);
void onCanceled();
+ void onDestroy();
}
private final Rect mAnchorBounds = new Rect();
public void destroy() {
throwIfDestroyed();
+ mCallback.onDestroy();
mWindow.hide();
mDestroyed = true;
}
public interface OnSaveListener {
void onSave();
void onCancel(IntentSender listener);
+ void onDestroy();
}
private final Handler mHandler = UiThread.getHandler();
void destroy() {
throwIfDestroyed();
+ mListener.onDestroy();
mHandler.removeCallbacksAndMessages(mListener);
mDialog.dismiss();
mDestroyed = true;