Merge "Added more metrics for Autofill:" into oc-mr1-dev am: d4f72ac3c4

am: b093daa296

Change-Id: Iae09ba2c6a082b87b74bd05320222955bde30dda
This commit is contained in:
Felipe Leme
2017-09-18 21:26:55 +00:00
committed by android-build-merger
8 changed files with 310 additions and 127 deletions

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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());
}
}

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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));
}
}

View File

@@ -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();

View File

@@ -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();