Merge "Few improvements on Augmented Autofill."

This commit is contained in:
TreeHugger Robot
2018-12-05 23:19:06 +00:00
committed by Android (Google) Code Review
12 changed files with 183 additions and 26 deletions

View File

@@ -15,8 +15,10 @@
*/
package android.service.intelligence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
/**
* Callback used to indicate at {@link FillRequest} has been fulfilled.
@@ -25,8 +27,11 @@ import android.annotation.SystemApi;
*/
@SystemApi
public final class FillCallback {
private final AutofillProxy mProxy;
FillCallback() {}
FillCallback(@NonNull AutofillProxy proxy) {
mProxy = proxy;
}
/**
* Sets the response associated with the request.
@@ -35,6 +40,7 @@ public final class FillCallback {
* could not provide autofill for the request.
*/
public void onSuccess(@Nullable FillResponse response) {
mProxy.report(AutofillProxy.REPORT_EVENT_ON_SUCCESS);
final FillWindow fillWindow = response.getFillWindow();
if (fillWindow != null) {
fillWindow.show();

View File

@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
/**
* Represents a request to augment-fill an activity.
@@ -51,6 +52,14 @@ public final class FillRequest {
return mProxy.focusedId;
}
/**
* Gets the current value of the field that triggered the request.
*/
@NonNull
public AutofillValue getFocusedAutofillValue() {
return mProxy.focusedValue;
}
/**
* Gets the Smart Suggestions object used to embed the autofill UI.
*

View File

@@ -23,6 +23,7 @@ import android.annotation.SystemApi;
import android.app.Dialog;
import android.graphics.Rect;
import android.service.intelligence.PresentationParams.Area;
import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
@@ -33,6 +34,8 @@ import android.view.WindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -73,6 +76,7 @@ public final class FillWindow {
@interface Flags{}
private final Object mLock = new Object();
private final CloseGuard mCloseGuard = CloseGuard.get();
@GuardedBy("mLock")
private Dialog mDialog;
@@ -80,6 +84,8 @@ public final class FillWindow {
@GuardedBy("mLock")
private boolean mDestroyed;
private AutofillProxy mProxy;
/**
* Updates the content of the window.
*
@@ -123,6 +129,8 @@ public final class FillWindow {
synchronized (mLock) {
checkNotDestroyedLocked();
mProxy = area.proxy;
// TODO(b/111330312): once we have the SurfaceControl approach, we should update the
// window instead of destroying. In fact, it might be better to allocate a full window
// initially, which is transparent (and let touches get through) everywhere but in the
@@ -133,6 +141,7 @@ public final class FillWindow {
// etc.
mDialog = new Dialog(rootView.getContext());
mCloseGuard.open("destroy");
final Window window = mDialog.getWindow();
window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
@@ -156,7 +165,7 @@ public final class FillWindow {
Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView);
}
area.proxy.setFillWindow(this);
mProxy.setFillWindow(this);
return true;
}
}
@@ -173,6 +182,9 @@ public final class FillWindow {
}
mDialog.show();
if (mProxy != null) {
mProxy.report(AutofillProxy.REPORT_EVENT_UI_SHOWN);
}
}
}
@@ -182,15 +194,29 @@ public final class FillWindow {
* <p>Once destroyed, this window cannot be used anymore
*/
public void destroy() {
if (DEBUG) Log.d(TAG, "destroy(): mDestroyed = " + mDestroyed);
if (DEBUG) Log.d(TAG, "destroy(): mDestroyed=" + mDestroyed + " mDialog=" + mDialog);
synchronized (this) {
if (mDestroyed) return;
if (mDestroyed || mDialog == null) return;
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
mDialog.dismiss();
mDialog = null;
if (mProxy != null) {
mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
}
mCloseGuard.close();
}
}
@Override
protected void finalize() throws Throwable {
try {
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
}
destroy();
} finally {
super.finalize();
}
}

View File

@@ -23,6 +23,7 @@ import android.service.intelligence.InteractionContext;
import android.service.intelligence.SnapshotData;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.intelligence.ContentCaptureEvent;
import java.util.List;
@@ -45,7 +46,8 @@ oneway interface IIntelligenceService {
in SnapshotData snapshotData);
void onAutofillRequest(in InteractionSessionId sessionId, in IBinder autofillManagerClient,
int autofilSessionId, in AutofillId focusedId);
int autofilSessionId, in AutofillId focusedId,
in AutofillValue focusedValue, long requestTime);
void onDestroyAutofillWindowsRequest(in InteractionSessionId sessionId);
}

View File

@@ -18,6 +18,7 @@ package android.service.intelligence;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -30,10 +31,13 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.intelligence.PresentationParams.SystemPopupPresentationParams;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.TimeUtils;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAugmentedAutofillManagerClient;
@@ -43,6 +47,8 @@ import com.android.internal.annotations.GuardedBy;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -110,9 +116,11 @@ public abstract class SmartSuggestionsService extends Service {
@Override
public void onAutofillRequest(InteractionSessionId sessionId, IBinder client,
int autofilSessionId, AutofillId focusedId) {
int autofilSessionId, AutofillId focusedId, AutofillValue focusedValue,
long requestTime) {
mHandler.sendMessage(obtainMessage(SmartSuggestionsService::handleOnAutofillRequest,
SmartSuggestionsService.this, sessionId, client, autofilSessionId, focusedId));
SmartSuggestionsService.this, sessionId, client, autofilSessionId, focusedId,
focusedValue, requestTime));
}
@Override
@@ -229,13 +237,15 @@ public abstract class SmartSuggestionsService extends Service {
@NonNull ContentCaptureEventsRequest request);
private void handleOnAutofillRequest(@NonNull InteractionSessionId sessionId,
@NonNull IBinder client, int autofillSessionId, @NonNull AutofillId focusedId) {
@NonNull IBinder client, int autofillSessionId, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue, long requestTime) {
if (mAutofillProxies == null) {
mAutofillProxies = new ArrayMap<>();
}
AutofillProxy proxy = mAutofillProxies.get(sessionId);
if (proxy == null) {
proxy = new AutofillProxy(sessionId, client, autofillSessionId, focusedId);
proxy = new AutofillProxy(sessionId, client, autofillSessionId, focusedId, focusedValue,
requestTime);
mAutofillProxies.put(sessionId, proxy);
} else {
// TODO(b/111330312): figure out if it's ok to reuse the proxy; add logging
@@ -244,7 +254,7 @@ public abstract class SmartSuggestionsService extends Service {
// TODO(b/111330312): set cancellation signal
final CancellationSignal cancellationSignal = null;
onFillRequest(sessionId, new FillRequest(proxy), cancellationSignal,
new FillController(proxy), new FillCallback());
new FillController(proxy), new FillCallback(proxy));
}
/**
@@ -332,11 +342,32 @@ public abstract class SmartSuggestionsService extends Service {
/** @hide */
static final class AutofillProxy {
static final int REPORT_EVENT_ON_SUCCESS = 1;
static final int REPORT_EVENT_UI_SHOWN = 2;
static final int REPORT_EVENT_UI_DESTROYED = 3;
@IntDef(prefix = { "REPORT_EVENT_" }, value = {
REPORT_EVENT_ON_SUCCESS,
REPORT_EVENT_UI_SHOWN,
REPORT_EVENT_UI_DESTROYED
})
@Retention(RetentionPolicy.SOURCE)
@interface ReportEvent{}
private final Object mLock = new Object();
private final IAugmentedAutofillManagerClient mClient;
private final int mAutofillSessionId;
public final InteractionSessionId sessionId;
public final AutofillId focusedId;
public final AutofillValue focusedValue;
// Objects used to log metrics
private final long mRequestTime;
private long mOnSuccessTime;
private long mUiFirstShownTime;
private long mUiFirstDestroyedTime;
@GuardedBy("mLock")
private SystemPopupPresentationParams mSmartSuggestion;
@@ -345,11 +376,14 @@ public abstract class SmartSuggestionsService extends Service {
private FillWindow mFillWindow;
private AutofillProxy(@NonNull InteractionSessionId sessionId, @NonNull IBinder client,
int autofillSessionId, @NonNull AutofillId focusedId) {
int autofillSessionId, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue, long requestTime) {
this.sessionId = sessionId;
mClient = IAugmentedAutofillManagerClient.Stub.asInterface(client);
mAutofillSessionId = autofillSessionId;
this.focusedId = focusedId;
this.focusedValue = focusedValue;
this.mRequestTime = requestTime;
// TODO(b/111330312): linkToDeath
}
@@ -400,9 +434,50 @@ public abstract class SmartSuggestionsService extends Service {
}
}
// Used for metrics.
public void report(@ReportEvent int event) {
switch (event) {
case REPORT_EVENT_ON_SUCCESS:
if (mOnSuccessTime == 0) {
mOnSuccessTime = SystemClock.elapsedRealtime();
if (DEBUG) {
Slog.d(TAG, "Service responsed in "
+ TimeUtils.formatDuration(mOnSuccessTime - mRequestTime));
}
}
break;
case REPORT_EVENT_UI_SHOWN:
if (mUiFirstShownTime == 0) {
mUiFirstShownTime = SystemClock.elapsedRealtime();
if (DEBUG) {
Slog.d(TAG, "UI shown in "
+ TimeUtils.formatDuration(mUiFirstShownTime - mRequestTime));
}
}
break;
case REPORT_EVENT_UI_DESTROYED:
if (mUiFirstDestroyedTime == 0) {
mUiFirstDestroyedTime = SystemClock.elapsedRealtime();
if (DEBUG) {
Slog.d(TAG, "UI destroyed in "
+ TimeUtils.formatDuration(
mUiFirstDestroyedTime - mRequestTime));
}
}
break;
default:
Slog.w(TAG, "invalid event reported: " + event);
}
// TODO(b/111330312): log metrics as well
}
public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
pw.print(prefix); pw.print("afSessionId: "); pw.println(mAutofillSessionId);
pw.print(prefix); pw.print("focusedId: "); pw.println(focusedId);
if (focusedValue != null) {
pw.print(prefix); pw.print("focusedValue: "); pw.println(focusedValue);
}
pw.print(prefix); pw.print("client: "); pw.println(mClient);
final String prefix2 = prefix + " ";
if (mFillWindow != null) {
@@ -413,6 +488,23 @@ public abstract class SmartSuggestionsService extends Service {
pw.print(prefix); pw.println("smartSuggestion:");
mSmartSuggestion.dump(prefix2, pw);
}
if (mOnSuccessTime > 0) {
final long responseTime = mOnSuccessTime - mRequestTime;
pw.print(prefix); pw.print("response time: ");
TimeUtils.formatDuration(responseTime, pw); pw.println();
}
if (mUiFirstShownTime > 0) {
final long uiRenderingTime = mUiFirstShownTime - mRequestTime;
pw.print(prefix); pw.print("UI rendering time: ");
TimeUtils.formatDuration(uiRenderingTime, pw); pw.println();
}
if (mUiFirstDestroyedTime > 0) {
final long uiTotalTime = mUiFirstDestroyedTime - mRequestTime;
pw.print(prefix); pw.print("UI life time: ");
TimeUtils.formatDuration(uiTotalTime, pw); pw.println();
}
}
private void destroy() {