Merge "Added more metrics for Autofill:" into oc-mr1-dev am: d4f72ac3c4
am: b093daa296
Change-Id: Iae09ba2c6a082b87b74bd05320222955bde30dda
This commit is contained in:
@@ -44,7 +44,7 @@ import android.view.View;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -1245,10 +1245,10 @@ public final class AutofillManager {
|
||||
}
|
||||
}
|
||||
|
||||
final 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);
|
||||
final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_DATASET_APPLIED)
|
||||
.setPackageName(mContext.getPackageName())
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied);
|
||||
mMetricsLogger.write(log);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4451,6 +4451,82 @@ message MetricsEvent {
|
||||
// OS: O MR
|
||||
FIELD_SELECTION_SMART_RANGE = 1123;
|
||||
|
||||
// The value of an autofillable and savable view was reset
|
||||
// Package: Package of app that was autofilled
|
||||
// OS: O MR
|
||||
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
|
||||
// Tag FIELD_AUTOFILL_PREVIOUS_LENGTH: the previous length of the value
|
||||
AUTOFILL_VALUE_RESET = 1124;
|
||||
|
||||
// Tag of AUTOFILL_VALUE_RESET
|
||||
// OS: O MR
|
||||
FIELD_AUTOFILL_PREVIOUS_LENGTH = 1125;
|
||||
|
||||
// An autofill dataset authentification succeeded
|
||||
// Package: Package of app that was autofilled
|
||||
// OS: O MR
|
||||
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
|
||||
AUTOFILL_DATASET_AUTHENTICATED = 1126;
|
||||
|
||||
// An autofill service provided an invalid dataset authentification
|
||||
// Package: Package of app that was autofilled
|
||||
// OS: O MR
|
||||
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
|
||||
AUTOFILL_INVALID_DATASET_AUTHENTICATION = 1127;
|
||||
|
||||
// An autofill service provided an invalid authentification extra
|
||||
// Package: Package of app that was autofilled
|
||||
// OS: O MR
|
||||
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
|
||||
AUTOFILL_INVALID_AUTHENTICATION = 1128;
|
||||
|
||||
// An autofill service used a custom description (using RemoteViews) in the Save affordance
|
||||
// Package: Package of app that is autofilled
|
||||
// OS: O MR
|
||||
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
|
||||
// Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
|
||||
AUTOFILL_SAVE_CUSTOM_DESCRIPTION = 1129;
|
||||
|
||||
// FIELD - Type of save object passed by the service when the Save UI is shown
|
||||
// OS: O MR
|
||||
FIELD_AUTOFILL_SAVE_TYPE = 1130;
|
||||
|
||||
// An autofill service used a custom subtitle (String) in the Save affordance
|
||||
// Package: Package of app that is autofilled
|
||||
// OS: O MR
|
||||
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
|
||||
// Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
|
||||
AUTOFILL_SAVE_CUSTOM_SUBTITLE = 1131;
|
||||
|
||||
// User tapped a link in the custom description of the Save affordance provided by an autofill service
|
||||
// Package: Package of app that is autofilled
|
||||
// OS: O MR
|
||||
// Type TYPE_UNKNOWN: The link was not properly set by the service
|
||||
// Type TYPE_OPEN: The link launched an activity
|
||||
// Type TYPE_FAILURE: The link could not launc an activity
|
||||
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
|
||||
// Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
|
||||
AUTOFILL_SAVE_LINK_TAPPED = 1132;
|
||||
|
||||
// Result of the validation on save when an autofill service provided a validator
|
||||
// Package: Package of app that is autofilled
|
||||
// OS: O MR
|
||||
// Type TYPE_FAILURE: The validation could not be performed due to an error
|
||||
// Type TYPE_SUCCESS: The validation passed
|
||||
// Type TYPE_DISMISS: The validation failed
|
||||
// Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
|
||||
// Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
|
||||
AUTOFILL_SAVE_VALIDATION = 1133;
|
||||
|
||||
// Result of an operation in the autofill save affordance after the user tapped a link in the custom description
|
||||
// provided by the autofill service
|
||||
// Package: Package of app that is autofilled
|
||||
// OS: O MR
|
||||
// Type TYPE_OPEN: The save affordance was restored
|
||||
// Type TYPE_DISMISS: The save affordcance was destroyed
|
||||
// Type TYPE_FAILURE: An invalid opperation was reported by the app's AutofillManager
|
||||
AUTOFILL_PENDING_SAVE_UI_OPERATION = 1134;
|
||||
|
||||
// ---- End O-MR1 Constants, all O-MR1 constants go above this line ----
|
||||
|
||||
// OPEN: Settings > Network & Internet > Mobile network
|
||||
|
||||
@@ -650,7 +650,7 @@ public final class AutofillManagerService extends SystemService {
|
||||
synchronized (mLock) {
|
||||
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
|
||||
if (service == null) return false;
|
||||
return Objects.equals(packageName, service.getPackageName());
|
||||
return Objects.equals(packageName, service.getServicePackageName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,8 +146,9 @@ final class AutofillManagerServiceImpl {
|
||||
updateLocked(disabled);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
CharSequence getServiceName() {
|
||||
final String packageName = getPackageName();
|
||||
final String packageName = getServicePackageName();
|
||||
if (packageName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -162,7 +163,8 @@ final class AutofillManagerServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
String getPackageName() {
|
||||
@Nullable
|
||||
String getServicePackageName() {
|
||||
final ComponentName serviceComponent = getServiceComponentName();
|
||||
if (serviceComponent != null) {
|
||||
return serviceComponent.getPackageName();
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.autofill;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.metrics.LogMaker;
|
||||
import android.os.Bundle;
|
||||
import android.service.autofill.Dataset;
|
||||
import android.util.ArrayMap;
|
||||
@@ -25,6 +26,8 @@ import android.util.ArraySet;
|
||||
import android.view.autofill.AutofillId;
|
||||
import android.view.autofill.AutofillValue;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
@@ -99,4 +102,14 @@ public final class Helper {
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static LogMaker newLogMaker(int category, String packageName,
|
||||
String servicePackageName) {
|
||||
final LogMaker log = new LogMaker(category).setPackageName(packageName);
|
||||
if (servicePackageName != null) {
|
||||
log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
|
||||
}
|
||||
return log;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
mPackageName = packageName;
|
||||
mClient = IAutoFillManagerClient.Stub.asInterface(client);
|
||||
|
||||
mMetricsLogger.action(MetricsEvent.AUTOFILL_SESSION_STARTED, mPackageName);
|
||||
writeLog(MetricsEvent.AUTOFILL_SESSION_STARTED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -477,13 +477,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
processResponseLocked(response, requestFlags);
|
||||
}
|
||||
|
||||
final LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST))
|
||||
final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
|
||||
.setType(MetricsEvent.TYPE_SUCCESS)
|
||||
.setPackageName(mPackageName)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
|
||||
response.getDatasets() == null ? 0 : response.getDatasets().size())
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE,
|
||||
servicePackageName);
|
||||
response.getDatasets() == null ? 0 : response.getDatasets().size());
|
||||
mMetricsLogger.write(log);
|
||||
}
|
||||
|
||||
@@ -499,10 +496,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
}
|
||||
mService.resetLastResponse();
|
||||
}
|
||||
LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST))
|
||||
.setType(MetricsEvent.TYPE_FAILURE)
|
||||
.setPackageName(mPackageName)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
|
||||
LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
|
||||
.setType(MetricsEvent.TYPE_FAILURE);
|
||||
mMetricsLogger.write(log);
|
||||
|
||||
getUiForShowing().showError(message, this);
|
||||
@@ -521,11 +516,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogMaker log = (new LogMaker(
|
||||
MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST))
|
||||
.setType(MetricsEvent.TYPE_SUCCESS)
|
||||
.setPackageName(mPackageName)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
|
||||
LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
|
||||
.setType(MetricsEvent.TYPE_SUCCESS);
|
||||
mMetricsLogger.write(log);
|
||||
|
||||
// Nothing left to do...
|
||||
@@ -545,11 +537,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogMaker log = (new LogMaker(
|
||||
MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST))
|
||||
.setType(MetricsEvent.TYPE_FAILURE)
|
||||
.setPackageName(mPackageName)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
|
||||
LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
|
||||
.setType(MetricsEvent.TYPE_FAILURE);
|
||||
mMetricsLogger.write(log);
|
||||
|
||||
getUiForShowing().showError(message, this);
|
||||
@@ -746,21 +735,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
|
||||
if (sDebug) Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result);
|
||||
if (result instanceof FillResponse) {
|
||||
final FillResponse response = (FillResponse) result;
|
||||
mMetricsLogger.action(MetricsEvent.AUTOFILL_AUTHENTICATED, mPackageName);
|
||||
replaceResponseLocked(authenticatedResponse, response);
|
||||
writeLog(MetricsEvent.AUTOFILL_AUTHENTICATED);
|
||||
replaceResponseLocked(authenticatedResponse, (FillResponse) result);
|
||||
} else if (result instanceof Dataset) {
|
||||
// TODO: add proper metric
|
||||
if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
|
||||
writeLog(MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
|
||||
final Dataset dataset = (Dataset) result;
|
||||
authenticatedResponse.getDatasets().set(datasetIdx, dataset);
|
||||
autoFill(requestId, datasetIdx, dataset, false);
|
||||
} else {
|
||||
writeLog(MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
|
||||
}
|
||||
} else {
|
||||
if (result != null) {
|
||||
Slog.w(TAG, "service returned invalid auth type: " + result);
|
||||
}
|
||||
// TODO: add proper metric (on else)
|
||||
writeLog(MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
|
||||
processNullResponseLocked(0);
|
||||
}
|
||||
}
|
||||
@@ -774,6 +764,44 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
mHasCallback = hasIt;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private FillResponse getLastResponseLocked(@Nullable String logPrefix) {
|
||||
if (mContexts == null) {
|
||||
if (sDebug && logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts");
|
||||
return null;
|
||||
}
|
||||
if (mResponses == null) {
|
||||
// Happens when the activity / session was finished before the service replied, or
|
||||
// when the service cannot autofill it (and returned a null response).
|
||||
if (sVerbose && logPrefix != null) {
|
||||
Slog.v(TAG, logPrefix + ": no responses on session");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final int lastResponseIdx = getLastResponseIndexLocked();
|
||||
if (lastResponseIdx < 0) {
|
||||
if (logPrefix != null) {
|
||||
Slog.w(TAG, logPrefix + ": did not get last response. mResponses=" + mResponses
|
||||
+ ", mViewStates=" + mViewStates);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final FillResponse response = mResponses.valueAt(lastResponseIdx);
|
||||
if (sVerbose && logPrefix != null) {
|
||||
Slog.v(TAG, logPrefix + ": mResponses=" + mResponses + ", mContexts=" + mContexts
|
||||
+ ", mViewStates=" + mViewStates);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SaveInfo getSaveInfoLocked() {
|
||||
final FillResponse response = getLastResponseLocked(null);
|
||||
return response == null ? null : response.getSaveInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the save UI, when session can be saved.
|
||||
*
|
||||
@@ -785,32 +813,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
+ id + " destroyed");
|
||||
return false;
|
||||
}
|
||||
if (mContexts == null) {
|
||||
Slog.d(TAG, "showSaveLocked(): no contexts");
|
||||
return true;
|
||||
}
|
||||
if (mResponses == null) {
|
||||
// Happens when the activity / session was finished before the service replied, or
|
||||
// when the service cannot autofill it (and returned a null response).
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "showSaveLocked(): no responses on session");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
final int lastResponseIdx = getLastResponseIndexLocked();
|
||||
if (lastResponseIdx < 0) {
|
||||
Slog.w(TAG, "showSaveLocked(): did not get last response. mResponses=" + mResponses
|
||||
+ ", mViewStates=" + mViewStates);
|
||||
return true;
|
||||
}
|
||||
|
||||
final FillResponse response = mResponses.valueAt(lastResponseIdx);
|
||||
final SaveInfo saveInfo = response.getSaveInfo();
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "showSaveLocked(): mResponses=" + mResponses + ", mContexts=" + mContexts
|
||||
+ ", mViewStates=" + mViewStates);
|
||||
}
|
||||
final FillResponse response = getLastResponseLocked("showSaveLocked()");
|
||||
final SaveInfo saveInfo = response == null ? null : response.getSaveInfo();
|
||||
|
||||
/*
|
||||
* The Save dialog is only shown if all conditions below are met:
|
||||
@@ -922,15 +926,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
|
||||
final InternalValidator validator = saveInfo.getValidator();
|
||||
if (validator != null) {
|
||||
final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_SAVE_VALIDATION);
|
||||
boolean isValid;
|
||||
try {
|
||||
isValid = validator.isValid(valueFinder);
|
||||
log.setType(isValid
|
||||
? MetricsEvent.TYPE_SUCCESS
|
||||
: MetricsEvent.TYPE_DISMISS);
|
||||
} catch (Exception e) {
|
||||
Slog.e(TAG, "Not showing save UI because of exception during validation "
|
||||
+ e.getClass());
|
||||
Slog.e(TAG, "Not showing save UI because validation failed:", e);
|
||||
log.setType(MetricsEvent.TYPE_FAILURE);
|
||||
mMetricsLogger.write(log);
|
||||
return true;
|
||||
}
|
||||
|
||||
mMetricsLogger.write(log);
|
||||
if (!isValid) {
|
||||
Slog.i(TAG, "not showing save UI because fields failed validation");
|
||||
return true;
|
||||
@@ -978,7 +988,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
final IAutoFillManagerClient client = getClient();
|
||||
mPendingSaveUi = new PendingUi(mActivityToken, id, client);
|
||||
getUiForShowing().showSaveUi(mService.getServiceLabel(), mService.getServiceIcon(),
|
||||
saveInfo, valueFinder, mPackageName, this, mPendingSaveUi);
|
||||
mService.getServicePackageName(), saveInfo, valueFinder, mPackageName, this,
|
||||
mPendingSaveUi);
|
||||
if (client != null) {
|
||||
try {
|
||||
client.setSaveUiState(id, true);
|
||||
@@ -1244,6 +1255,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
break;
|
||||
case ACTION_VALUE_CHANGED:
|
||||
if (value != null && !value.equals(viewState.getCurrentValue())) {
|
||||
if (value.isEmpty()
|
||||
&& viewState.getCurrentValue() != null
|
||||
&& viewState.getCurrentValue().isText()
|
||||
&& viewState.getCurrentValue().getTextValue() != null
|
||||
&& getSaveInfoLocked() != null) {
|
||||
final int length = viewState.getCurrentValue().getTextValue().length();
|
||||
if (sDebug) {
|
||||
Slog.d(TAG, "updateLocked(" + id + "): resetting value that was "
|
||||
+ length + " chars long");
|
||||
}
|
||||
final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_VALUE_RESET)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_PREVIOUS_LENGTH, length);
|
||||
mMetricsLogger.write(log);
|
||||
}
|
||||
|
||||
// Always update the internal state.
|
||||
viewState.setCurrentValue(value);
|
||||
|
||||
@@ -1319,7 +1345,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
filterText = value.getTextValue().toString();
|
||||
}
|
||||
|
||||
getUiForShowing().showFillUi(filledId, response, filterText, mPackageName, this);
|
||||
getUiForShowing().showFillUi(filledId, response, filterText,
|
||||
mService.getServicePackageName(), mPackageName, this);
|
||||
}
|
||||
|
||||
boolean isDestroyed() {
|
||||
@@ -1735,7 +1762,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
mUi.destroyAll(mPendingSaveUi, this);
|
||||
mUi.clearCallback(this);
|
||||
mDestroyed = true;
|
||||
mMetricsLogger.action(MetricsEvent.AUTOFILL_SESSION_FINISHED, mPackageName);
|
||||
writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED);
|
||||
return mRemoteFillService;
|
||||
}
|
||||
|
||||
@@ -1820,4 +1847,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
}
|
||||
return lastResponseIdx;
|
||||
}
|
||||
|
||||
private LogMaker newLogMaker(int category) {
|
||||
return newLogMaker(category, mService.getServicePackageName());
|
||||
}
|
||||
|
||||
private LogMaker newLogMaker(int category, String servicePackageName) {
|
||||
return Helper.newLogMaker(category, mPackageName, servicePackageName);
|
||||
}
|
||||
|
||||
private void writeLog(int category) {
|
||||
mMetricsLogger.write(newLogMaker(category));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,9 @@ import android.view.autofill.IAutofillWindowPresenter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.server.UiThread;
|
||||
import com.android.server.autofill.Helper;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@@ -158,21 +159,22 @@ public final class AutoFillUI {
|
||||
* @param focusedId the currently focused field
|
||||
* @param response the current fill response
|
||||
* @param filterText text of the view to be filled
|
||||
* @param servicePackageName package name of the autofill service filling the activity
|
||||
* @param packageName package name of the activity that is filled
|
||||
* @param callback Identifier for the caller
|
||||
*/
|
||||
public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
|
||||
@Nullable String filterText, @NonNull String packageName,
|
||||
@NonNull AutoFillUiCallback callback) {
|
||||
@Nullable String filterText, @Nullable String servicePackageName,
|
||||
@NonNull String packageName, @NonNull AutoFillUiCallback callback) {
|
||||
if (sDebug) {
|
||||
final int size = filterText == null ? 0 : filterText.length();
|
||||
Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars");
|
||||
}
|
||||
final LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI))
|
||||
.setPackageName(packageName)
|
||||
.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN,
|
||||
final LogMaker log =
|
||||
Helper.newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, packageName, servicePackageName)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN,
|
||||
filterText == null ? 0 : filterText.length())
|
||||
.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
|
||||
response.getDatasets() == null ? 0 : response.getDatasets().size());
|
||||
|
||||
mHandler.post(() -> {
|
||||
@@ -184,7 +186,7 @@ public final class AutoFillUI {
|
||||
filterText, mOverlayControl, new FillUi.Callback() {
|
||||
@Override
|
||||
public void onResponsePicked(FillResponse response) {
|
||||
log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL);
|
||||
log.setType(MetricsEvent.TYPE_DETAIL);
|
||||
hideFillUiUiThread(callback);
|
||||
if (mCallback != null) {
|
||||
mCallback.authenticate(response.getRequestId(),
|
||||
@@ -195,7 +197,7 @@ public final class AutoFillUI {
|
||||
|
||||
@Override
|
||||
public void onDatasetPicked(Dataset dataset) {
|
||||
log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
|
||||
log.setType(MetricsEvent.TYPE_ACTION);
|
||||
hideFillUiUiThread(callback);
|
||||
if (mCallback != null) {
|
||||
final int datasetIndex = response.getDatasets().indexOf(dataset);
|
||||
@@ -205,14 +207,14 @@ public final class AutoFillUI {
|
||||
|
||||
@Override
|
||||
public void onCanceled() {
|
||||
log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
|
||||
log.setType(MetricsEvent.TYPE_DISMISS);
|
||||
hideFillUiUiThread(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
|
||||
log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
|
||||
if (log.getType() == MetricsEvent.TYPE_UNKNOWN) {
|
||||
log.setType(MetricsEvent.TYPE_CLOSE);
|
||||
}
|
||||
mMetricsLogger.write(log);
|
||||
}
|
||||
@@ -246,27 +248,29 @@ public final class AutoFillUI {
|
||||
* Shows the UI asking the user to save for autofill.
|
||||
*/
|
||||
public void showSaveUi(@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
|
||||
@NonNull SaveInfo info,@NonNull ValueFinder valueFinder, @NonNull String packageName,
|
||||
@Nullable String servicePackageName, @NonNull SaveInfo info,
|
||||
@NonNull ValueFinder valueFinder, @NonNull String packageName,
|
||||
@NonNull AutoFillUiCallback callback, @NonNull PendingUi pendingSaveUi) {
|
||||
if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info);
|
||||
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);
|
||||
final LogMaker log =
|
||||
Helper.newLogMaker(MetricsEvent.AUTOFILL_SAVE_UI, packageName, servicePackageName)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
|
||||
|
||||
mHandler.post(() -> {
|
||||
if (callback != mCallback) {
|
||||
return;
|
||||
}
|
||||
hideAllUiThread(callback);
|
||||
mSaveUi = new SaveUi(mContext, pendingSaveUi, serviceLabel, serviceIcon, info,
|
||||
valueFinder, mOverlayControl, new SaveUi.OnSaveListener() {
|
||||
mSaveUi = new SaveUi(mContext, pendingSaveUi, serviceLabel, serviceIcon,
|
||||
servicePackageName, packageName, info, valueFinder, mOverlayControl,
|
||||
new SaveUi.OnSaveListener() {
|
||||
@Override
|
||||
public void onSave() {
|
||||
log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
|
||||
log.setType(MetricsEvent.TYPE_ACTION);
|
||||
hideSaveUiUiThread(mCallback);
|
||||
if (mCallback != null) {
|
||||
mCallback.save();
|
||||
@@ -276,7 +280,7 @@ public final class AutoFillUI {
|
||||
|
||||
@Override
|
||||
public void onCancel(IntentSender listener) {
|
||||
log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
|
||||
log.setType(MetricsEvent.TYPE_DISMISS);
|
||||
hideSaveUiUiThread(mCallback);
|
||||
if (listener != null) {
|
||||
try {
|
||||
@@ -294,8 +298,8 @@ public final class AutoFillUI {
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
|
||||
log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
|
||||
if (log.getType() == MetricsEvent.TYPE_UNKNOWN) {
|
||||
log.setType(MetricsEvent.TYPE_CLOSE);
|
||||
|
||||
if (mCallback != null) {
|
||||
mCallback.cancelSave();
|
||||
|
||||
@@ -20,6 +20,7 @@ import static com.android.server.autofill.Helper.sDebug;
|
||||
import static com.android.server.autofill.Helper.sVerbose;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Dialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
@@ -30,6 +31,7 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.metrics.LogMaker;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
@@ -53,6 +55,8 @@ import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.server.UiThread;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -111,6 +115,7 @@ final class SaveUi {
|
||||
}
|
||||
|
||||
private final Handler mHandler = UiThread.getHandler();
|
||||
private final MetricsLogger mMetricsLogger = new MetricsLogger();
|
||||
|
||||
private final @NonNull Dialog mDialog;
|
||||
|
||||
@@ -121,16 +126,21 @@ final class SaveUi {
|
||||
private final CharSequence mTitle;
|
||||
private final CharSequence mSubTitle;
|
||||
private final PendingUi mPendingUi;
|
||||
private final String mServicePackageName;
|
||||
private final String mPackageName;
|
||||
|
||||
private boolean mDestroyed;
|
||||
|
||||
SaveUi(@NonNull Context context, @NonNull PendingUi pendingUi,
|
||||
@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
|
||||
@Nullable String servicePackageName, @NonNull String packageName,
|
||||
@NonNull SaveInfo info, @NonNull ValueFinder valueFinder,
|
||||
@NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener) {
|
||||
mPendingUi= pendingUi;
|
||||
mListener = new OneTimeListener(listener);
|
||||
mOverlayControl = overlayControl;
|
||||
mServicePackageName = servicePackageName;
|
||||
mPackageName = packageName;
|
||||
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
final View view = inflater.inflate(R.layout.autofill_save, null);
|
||||
@@ -181,6 +191,8 @@ final class SaveUi {
|
||||
ScrollView subtitleContainer = null;
|
||||
final CustomDescription customDescription = info.getCustomDescription();
|
||||
if (customDescription != null) {
|
||||
writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION, type);
|
||||
|
||||
mSubTitle = null;
|
||||
if (sDebug) Slog.d(TAG, "Using custom description");
|
||||
|
||||
@@ -190,40 +202,35 @@ final class SaveUi {
|
||||
@Override
|
||||
public boolean onClickHandler(View view, PendingIntent pendingIntent,
|
||||
Intent intent) {
|
||||
final LogMaker log =
|
||||
newLogMaker(MetricsEvent.AUTOFILL_SAVE_LINK_TAPPED, type);
|
||||
// We need to hide the Save UI before launching the pending intent, and
|
||||
// restore back it once the activity is finished, and that's achieved by
|
||||
// adding a custom extra in the activity intent.
|
||||
if (pendingIntent != null) {
|
||||
if (intent == null) {
|
||||
Slog.w(TAG,
|
||||
"remote view on custom description does not have intent");
|
||||
return false;
|
||||
}
|
||||
if (!pendingIntent.isActivity()) {
|
||||
Slog.w(TAG, "ignoring custom description pending intent that's not "
|
||||
+ "for an activity: " + pendingIntent);
|
||||
return false;
|
||||
}
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG,
|
||||
"Intercepting custom description intent: " + intent);
|
||||
}
|
||||
final IBinder token = mPendingUi.getToken();
|
||||
intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
|
||||
try {
|
||||
pendingUi.client.startIntentSender(pendingIntent.getIntentSender(),
|
||||
intent);
|
||||
mPendingUi.setState(PendingUi.STATE_PENDING);
|
||||
if (sDebug) {
|
||||
Slog.d(TAG, "hiding UI until restored with token " + token);
|
||||
}
|
||||
hide();
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "error triggering pending intent: " + intent);
|
||||
return false;
|
||||
}
|
||||
final boolean isValid = isValidLink(pendingIntent, intent);
|
||||
if (!isValid) {
|
||||
log.setType(MetricsEvent.TYPE_UNKNOWN);
|
||||
mMetricsLogger.write(log);
|
||||
return false;
|
||||
}
|
||||
if (sVerbose) Slog.v(TAG, "Intercepting custom description intent");
|
||||
final IBinder token = mPendingUi.getToken();
|
||||
intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
|
||||
try {
|
||||
pendingUi.client.startIntentSender(pendingIntent.getIntentSender(),
|
||||
intent);
|
||||
mPendingUi.setState(PendingUi.STATE_PENDING);
|
||||
if (sDebug) Slog.d(TAG, "hiding UI until restored with token " + token);
|
||||
hide();
|
||||
log.setType(MetricsEvent.TYPE_OPEN);
|
||||
mMetricsLogger.write(log);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "error triggering pending intent: " + intent);
|
||||
log.setType(MetricsEvent.TYPE_FAILURE);
|
||||
mMetricsLogger.write(log);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -241,6 +248,7 @@ final class SaveUi {
|
||||
} else {
|
||||
mSubTitle = info.getDescription();
|
||||
if (mSubTitle != null) {
|
||||
writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_SUBTITLE, type);
|
||||
subtitleContainer = view.findViewById(R.id.autofill_save_custom_subtitle);
|
||||
final TextView subtitleView = new TextView(context);
|
||||
subtitleView.setText(mSubTitle);
|
||||
@@ -313,6 +321,37 @@ final class SaveUi {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValidLink(PendingIntent pendingIntent, Intent intent) {
|
||||
if (pendingIntent == null) {
|
||||
Slog.w(TAG, "isValidLink(): custom description without pending intent");
|
||||
return false;
|
||||
}
|
||||
if (!pendingIntent.isActivity()) {
|
||||
Slog.w(TAG, "isValidLink(): pending intent not for activity");
|
||||
return false;
|
||||
}
|
||||
if (intent == null) {
|
||||
Slog.w(TAG, "isValidLink(): no intent");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private LogMaker newLogMaker(int category, int saveType) {
|
||||
return newLogMaker(category)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SAVE_TYPE, saveType);
|
||||
}
|
||||
|
||||
private LogMaker newLogMaker(int category) {
|
||||
return new LogMaker(category)
|
||||
.setPackageName(mPackageName)
|
||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, mServicePackageName);
|
||||
}
|
||||
|
||||
private void writeLog(int category, int saveType) {
|
||||
mMetricsLogger.write(newLogMaker(category, saveType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the pending UI, if any.
|
||||
*
|
||||
@@ -326,17 +365,25 @@ final class SaveUi {
|
||||
+ mPendingUi.getToken());
|
||||
return;
|
||||
}
|
||||
switch (operation) {
|
||||
case AutofillManager.PENDING_UI_OPERATION_RESTORE:
|
||||
if (sDebug) Slog.d(TAG, "Restoring save dialog for " + token);
|
||||
show();
|
||||
break;
|
||||
case AutofillManager.PENDING_UI_OPERATION_CANCEL:
|
||||
if (sDebug) Slog.d(TAG, "Cancelling pending save dialog for " + token);
|
||||
hide();
|
||||
break;
|
||||
default:
|
||||
Slog.w(TAG, "restore(): invalid operation " + operation);
|
||||
final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_PENDING_SAVE_UI_OPERATION);
|
||||
try {
|
||||
switch (operation) {
|
||||
case AutofillManager.PENDING_UI_OPERATION_RESTORE:
|
||||
if (sDebug) Slog.d(TAG, "Restoring save dialog for " + token);
|
||||
log.setType(MetricsEvent.TYPE_OPEN);
|
||||
show();
|
||||
break;
|
||||
case AutofillManager.PENDING_UI_OPERATION_CANCEL:
|
||||
log.setType(MetricsEvent.TYPE_DISMISS);
|
||||
if (sDebug) Slog.d(TAG, "Cancelling pending save dialog for " + token);
|
||||
hide();
|
||||
break;
|
||||
default:
|
||||
log.setType(MetricsEvent.TYPE_FAILURE);
|
||||
Slog.w(TAG, "restore(): invalid operation " + operation);
|
||||
}
|
||||
} finally {
|
||||
mMetricsLogger.write(log);
|
||||
}
|
||||
mPendingUi.setState(PendingUi.STATE_FINISHED);
|
||||
}
|
||||
@@ -385,6 +432,8 @@ final class SaveUi {
|
||||
pw.print(prefix); pw.print("title: "); pw.println(mTitle);
|
||||
pw.print(prefix); pw.print("subtitle: "); pw.println(mSubTitle);
|
||||
pw.print(prefix); pw.print("pendingUi: "); pw.println(mPendingUi);
|
||||
pw.print(prefix); pw.print("service: "); pw.println(mServicePackageName);
|
||||
pw.print(prefix); pw.print("app: "); pw.println(mPackageName);
|
||||
|
||||
final View view = mDialog.getWindow().getDecorView();
|
||||
final int[] loc = view.getLocationOnScreen();
|
||||
|
||||
Reference in New Issue
Block a user