Yet another (major) refactoring on Content Capture and Augmented Autofill.
Bunch of changes:
- Split public SmartSuggestionsService info ContentCaptureService and
AugmentedAutofillService
- Renamed 'intelligence' packages to either 'contentcapture' or
'autofil.augmented'
- Renamed internal packages and classes.
- Changed permissions, resource names, etc...
- Moved Augmented Autofill logic from IntelligeceManagerService (R.I.P.) to
Autofill.
- Optimized IPCs by passing a String instead of the InteractionSessionId
(that also solves the view -> service dependency).
Test: atest CtsContentCaptureServiceTestCases \
CtsAutoFillServiceTestCases \
FrameworksCoreTests:SettingsBackupTest
Test: manual verification with Augmented Autofill Service
Bug: 119638877
Bug: 117944706
Change-Id: I787fc2a0dbd9ad53e4d5edb0d2a9242346e4652d
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f3f065a..cfda803 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -121,8 +121,8 @@
import android.view.autofill.AutofillManager.AutofillClient;
import android.view.autofill.AutofillPopupWindow;
import android.view.autofill.IAutofillWindowPresenter;
-import android.view.intelligence.ContentCaptureEvent;
-import android.view.intelligence.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ContentCaptureManager;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.Toolbar;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 0404e80..43e1836 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -165,9 +165,9 @@
import android.view.accessibility.CaptioningManager;
import android.view.autofill.AutofillManager;
import android.view.autofill.IAutoFillManager;
+import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.IContentCaptureManager;
import android.view.inputmethod.InputMethodManager;
-import android.view.intelligence.ContentCaptureManager;
-import android.view.intelligence.IIntelligenceManager;
import android.view.textclassifier.TextClassificationManager;
import android.view.textservice.TextServicesManager;
@@ -1070,7 +1070,7 @@
if (outerContext.isContentCaptureSupported()) {
IBinder b = ServiceManager
.getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
- IIntelligenceManager service = IIntelligenceManager.Stub.asInterface(b);
+ IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(b);
return new ContentCaptureManager(outerContext, service);
}
return null;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index e2c7b85..d7d3cb5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3939,13 +3939,12 @@
public static final String AUTOFILL_MANAGER_SERVICE = "autofill";
/**
- * Official published name of the smart suggestions service.
+ * Official published name of the content capture service.
*
* @hide
* @see #getSystemService(String)
*/
- // TODO(b/111276913): rename string (will require SELinux change first)
- public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "intelligence";
+ public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
/**
* Use with {@link #getSystemService(String)} to access the
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index abfcfaa..86f81d8 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -948,7 +948,7 @@
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
*/
- public static final String DISALLOW_INTELLIGENCE_CAPTURE = "no_intelligence_capture";
+ public static final String DISALLOW_CONTENT_CAPTURE = "no_content_capture";
/**
* Specifies if user switching is blocked on the current user.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c3217a2..64aa088 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12840,7 +12840,7 @@
/**
* Property used by {@code com.android.server.SystemServer} on start to decide whether
- * the Smart Suggestions service should be created or not
+ * the Content Capture service should be created or not
*
* <p>By default it should *NOT* be set (in which case the decision is based on whether
* the OEM provides an implementation for the service), but it can be overridden to:
@@ -12852,8 +12852,8 @@
*
* @hide
*/
- public static final String SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED =
- "smart_suggestions_service_explicitly_enabled";
+ public static final String CONTENT_CAPTURE_SERVICE_EXPLICITLY_ENABLED =
+ "content_capture_service_explicitly_enabled";
/**
* Settings to backup. This is here so that it's in the same place as the settings
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 573d577..f39ef9a 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -618,7 +618,7 @@
if (SERVICE_INTERFACE.equals(intent.getAction())) {
return mInterface.asBinder();
}
- Log.w(TAG, "Tried to bind to wrong intent: " + intent);
+ Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
return null;
}
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
new file mode 100644
index 0000000..68a86f3
--- /dev/null
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.autofill.augmented;
+
+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;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
+import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.view.autofill.IAugmentedAutofillManagerClient;
+
+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;
+
+/**
+ * A service used to augment the Autofill subsystem by potentially providing autofill data when the
+ * "standard" workflow failed (for example, because the standard AutofillService didn't have data).
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class AugmentedAutofillService extends Service {
+
+ private static final String TAG = AugmentedAutofillService.class.getSimpleName();
+
+ // TODO(b/111330312): STOPSHIP use dynamic value, or change to false
+ static final boolean DEBUG = true;
+ static final boolean VERBOSE = false;
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ * To be supported, the service must also require the
+ * {@link android.Manifest.permission#BIND_AUGMENTED_AUTOFILL_SERVICE} permission so
+ * that other applications can not abuse it.
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.service.autofill.augmented.AugmentedAutofillService";
+
+ private Handler mHandler;
+
+ private SparseArray<AutofillProxy> mAutofillProxies;
+
+ private final IAugmentedAutofillService mInterface = new IAugmentedAutofillService.Stub() {
+
+ @Override
+ public void onFillRequest(int sessionId, IBinder client, int taskId,
+ ComponentName componentName, AutofillId focusedId, AutofillValue focusedValue,
+ long requestTime, IFillCallback callback) {
+ mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnFillRequest,
+ AugmentedAutofillService.this, sessionId, client, taskId, componentName,
+ focusedId, focusedValue, requestTime, callback));
+ }
+
+ @Override
+ public void onDestroyFillWindowRequest(int sessionId) {
+ mHandler.sendMessage(
+ obtainMessage(AugmentedAutofillService::handleOnDestroyFillWindowRequest,
+ AugmentedAutofillService.this, sessionId));
+ }
+ };
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(Looper.getMainLooper(), null, true);
+ }
+
+ /** @hide */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mInterface.asBinder();
+ }
+ Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
+ return null;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnUnbind,
+ AugmentedAutofillService.this));
+ return false;
+ }
+
+ // TODO(b/111330312): add methods to disable autofill per app / activity?
+
+ /**
+ * Asks the service to handle an "augmented" autofill request.
+ *
+ * <p>This method is called when the "stantard" autofill service cannot handle a request, which
+ * typically occurs when:
+ * <ul>
+ * <li>Service does not recognize what should be autofilled.
+ * <li>Service does not have data to fill the request.
+ * <li>Service blacklisted that app (or activity) for autofill.
+ * <li>App disabled itself for autofill.
+ * </ul>
+ *
+ * <p>Differently from the standard autofill workflow, on augmented autofill the service is
+ * responsible to generate the autofill UI and request the Android system to autofill the
+ * activity when the user taps an action in that UI (through the
+ * {@link FillController#autofill(List)} method).
+ *
+ * <p>The service <b>MUST</b> call {@link
+ * FillCallback#onSuccess(android.service.autofill.augmented.FillResponse)} as soon as possible,
+ * passing {@code null} when it cannot fulfill the request.
+ * @param request the request to handle.
+ * @param cancellationSignal signal for observing cancellation requests. The system will use
+ * this to notify you that the fill result is no longer needed and you should stop
+ * handling this fill request in order to save resources.
+ * @param controller object used to interact with the autofill system.
+ * @param callback object used to notify the result of the request. Service <b>must</b> call
+ * {@link FillCallback#onSuccess(android.service.autofill.augmented.FillResponse)}.
+ */
+ public void onFillRequest(@NonNull FillRequest request,
+ @NonNull CancellationSignal cancellationSignal, @NonNull FillController controller,
+ @NonNull FillCallback callback) {
+ }
+
+ private void handleOnFillRequest(int sessionId, @NonNull IBinder client, int taskId,
+ @NonNull ComponentName componentName, @NonNull AutofillId focusedId,
+ @Nullable AutofillValue focusedValue, long requestTime,
+ @NonNull IFillCallback callback) {
+ if (mAutofillProxies == null) {
+ mAutofillProxies = new SparseArray<>();
+ }
+ AutofillProxy proxy = mAutofillProxies.get(sessionId);
+ if (proxy == null) {
+ proxy = new AutofillProxy(sessionId, client, taskId, componentName, focusedId,
+ focusedValue, requestTime, callback);
+ mAutofillProxies.put(sessionId, proxy);
+ } else {
+ // TODO(b/111330312): figure out if it's ok to reuse the proxy; add logging
+ if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
+ }
+ // TODO(b/111330312): set cancellation signal
+ final CancellationSignal cancellationSignal = null;
+ onFillRequest(new FillRequest(proxy), cancellationSignal, new FillController(proxy),
+ new FillCallback(proxy));
+ }
+
+ private void handleOnDestroyFillWindowRequest(@NonNull int sessionId) {
+ AutofillProxy proxy = null;
+ if (mAutofillProxies != null) {
+ proxy = mAutofillProxies.get(sessionId);
+ }
+ if (proxy == null) {
+ // TODO(b/111330312): this might be fine, in which case we should logv it
+ Log.w(TAG, "No proxy for session " + sessionId);
+ return;
+ }
+ proxy.destroy();
+ mAutofillProxies.remove(sessionId);
+ }
+
+ private void handleOnUnbind() {
+ if (mAutofillProxies == null) {
+ if (DEBUG) Log.d(TAG, "onUnbind(): no proxy to destroy");
+ return;
+ }
+ final int size = mAutofillProxies.size();
+ if (DEBUG) Log.d(TAG, "onUnbind(): destroying " + size + " proxies");
+ for (int i = 0; i < size; i++) {
+ final AutofillProxy proxy = mAutofillProxies.valueAt(i);
+ try {
+ proxy.destroy();
+ } catch (Exception e) {
+ Log.w(TAG, "error destroying " + proxy);
+ }
+ }
+ mAutofillProxies = null;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mAutofillProxies != null) {
+ final int size = mAutofillProxies.size();
+ pw.print("Number proxies: "); pw.println(size);
+ for (int i = 0; i < size; i++) {
+ final int sessionId = mAutofillProxies.keyAt(i);
+ final AutofillProxy proxy = mAutofillProxies.valueAt(i);
+ pw.print(i); pw.print(") SessionId="); pw.print(sessionId); pw.println(":");
+ proxy.dump(" ", pw);
+ }
+ }
+ }
+
+ /** @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 mSessionId;
+ private final IFillCallback mCallback;
+ public final int taskId;
+ public final ComponentName componentName;
+ 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;
+
+ @GuardedBy("mLock")
+ private FillWindow mFillWindow;
+
+ private AutofillProxy(int sessionId, @NonNull IBinder client, int taskId,
+ @NonNull ComponentName componentName, @NonNull AutofillId focusedId,
+ @Nullable AutofillValue focusedValue, long requestTime,
+ @NonNull IFillCallback callback) {
+ mSessionId = sessionId;
+ mClient = IAugmentedAutofillManagerClient.Stub.asInterface(client);
+ mCallback = callback;
+ this.taskId = taskId;
+ this.componentName = componentName;
+ this.focusedId = focusedId;
+ this.focusedValue = focusedValue;
+ this.mRequestTime = requestTime;
+ // TODO(b/111330312): linkToDeath
+ }
+
+ @NonNull
+ public SystemPopupPresentationParams getSmartSuggestionParams() {
+ synchronized (mLock) {
+ if (mSmartSuggestion != null) {
+ return mSmartSuggestion;
+ }
+ Rect rect;
+ try {
+ rect = mClient.getViewCoordinates(focusedId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not get coordinates for " + focusedId);
+ return null;
+ }
+ if (rect == null) {
+ if (DEBUG) Log.d(TAG, "getViewCoordinates(" + focusedId + ") returned null");
+ return null;
+ }
+ mSmartSuggestion = new SystemPopupPresentationParams(this, rect);
+ return mSmartSuggestion;
+ }
+ }
+
+ public void autofill(@NonNull List<Pair<AutofillId, AutofillValue>> pairs)
+ throws RemoteException {
+ final int size = pairs.size();
+ final List<AutofillId> ids = new ArrayList<>(size);
+ final List<AutofillValue> values = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final Pair<AutofillId, AutofillValue> pair = pairs.get(i);
+ ids.add(pair.first);
+ values.add(pair.second);
+ }
+ mClient.autofill(mSessionId, ids, values);
+ }
+
+ public void setFillWindow(@NonNull FillWindow fillWindow) {
+ synchronized (mLock) {
+ mFillWindow = fillWindow;
+ }
+ }
+
+ public FillWindow getFillWindow() {
+ synchronized (mLock) {
+ return mFillWindow;
+ }
+ }
+
+ // Used (mostly) 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));
+ }
+ }
+ try {
+ mCallback.onSuccess();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error reporting success: " + e);
+ }
+ 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("sessionId: "); pw.println(mSessionId);
+ pw.print(prefix); pw.print("taskId: "); pw.println(taskId);
+ pw.print(prefix); pw.print("component: ");
+ pw.println(componentName.flattenToShortString());
+ 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) {
+ pw.print(prefix); pw.println("window:");
+ mFillWindow.dump(prefix2, pw);
+ }
+ if (mSmartSuggestion != null) {
+ 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() {
+ synchronized (mLock) {
+ if (mFillWindow != null) {
+ if (DEBUG) Log.d(TAG, "destroying window");
+ mFillWindow.destroy();
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/intelligence/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
similarity index 92%
rename from core/java/android/service/intelligence/FillCallback.java
rename to core/java/android/service/autofill/augmented/FillCallback.java
index ddf37f7..0546465 100644
--- a/core/java/android/service/intelligence/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.autofill.augmented;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
+import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
/**
* Callback used to indicate at {@link FillRequest} has been fulfilled.
diff --git a/core/java/android/service/intelligence/FillController.java b/core/java/android/service/autofill/augmented/FillController.java
similarity index 90%
rename from core/java/android/service/intelligence/FillController.java
rename to core/java/android/service/autofill/augmented/FillController.java
index 4a9c85d..e65cf47 100644
--- a/core/java/android/service/intelligence/FillController.java
+++ b/core/java/android/service/autofill/augmented/FillController.java
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.autofill.augmented;
-import static android.service.intelligence.SmartSuggestionsService.DEBUG;
+import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.RemoteException;
-import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
+import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
import android.util.Log;
import android.util.Pair;
import android.view.autofill.AutofillId;
diff --git a/core/java/android/service/intelligence/FillRequest.java b/core/java/android/service/autofill/augmented/FillRequest.java
similarity index 71%
rename from core/java/android/service/intelligence/FillRequest.java
rename to core/java/android/service/autofill/augmented/FillRequest.java
index 53e99a5..fd75b15 100644
--- a/core/java/android/service/intelligence/FillRequest.java
+++ b/core/java/android/service/autofill/augmented/FillRequest.java
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.autofill.augmented;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
+import android.content.ComponentName;
+import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
@@ -27,6 +28,7 @@
* @hide
*/
@SystemApi
+// TODO(b/111330312): pass a requestId and/or sessionId
public final class FillRequest {
final AutofillProxy mProxy;
@@ -37,11 +39,18 @@
}
/**
- * Gets the session associated with this request.
+ * Gets the task of the activity associated with this request.
+ */
+ public int getTaskId() {
+ return mProxy.taskId;
+ }
+
+ /**
+ * Gets the name of the activity associated with this request.
*/
@NonNull
- public InteractionSessionId getSessionId() {
- return mProxy.sessionId;
+ public ComponentName getActivityComponent() {
+ return mProxy.componentName;
}
/**
@@ -56,7 +65,7 @@
* Gets the current value of the field that triggered the request.
*/
@NonNull
- public AutofillValue getFocusedAutofillValue() {
+ public AutofillValue getFocusedValue() {
return mProxy.focusedValue;
}
@@ -72,6 +81,7 @@
@Override
public String toString() {
- return "FillRequest[id=" + mProxy.focusedId + "]";
+ return "FillRequest[act=" + getActivityComponent().flattenToShortString()
+ + ", id=" + mProxy.focusedId + "]";
}
}
diff --git a/core/java/android/service/intelligence/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java
similarity index 97%
rename from core/java/android/service/intelligence/FillResponse.java
rename to core/java/android/service/autofill/augmented/FillResponse.java
index 860c027..7064b6f 100644
--- a/core/java/android/service/intelligence/FillResponse.java
+++ b/core/java/android/service/autofill/augmented/FillResponse.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.autofill.augmented;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -50,7 +50,7 @@
* @hide
*/
@SystemApi
- public static class Builder {
+ public static final class Builder {
private FillWindow mFillWindow;
diff --git a/core/java/android/service/intelligence/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
similarity index 94%
rename from core/java/android/service/intelligence/FillWindow.java
rename to core/java/android/service/autofill/augmented/FillWindow.java
index 39d7e08..9e3aba4 100644
--- a/core/java/android/service/intelligence/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.autofill.augmented;
-import static android.service.intelligence.SmartSuggestionsService.DEBUG;
+import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG;
import android.annotation.LongDef;
import android.annotation.NonNull;
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.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
+import android.service.autofill.augmented.PresentationParams.Area;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
@@ -60,7 +60,7 @@
* @hide
*/
@SystemApi
-public final class FillWindow {
+public final class FillWindow implements AutoCloseable {
private static final String TAG = "FillWindow";
/** Indicates the data being shown is a physical address */
@@ -238,4 +238,10 @@
}
}
}
+
+ /** @hide */
+ @Override
+ public void close() throws Exception {
+ destroy();
+ }
}
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
new file mode 100644
index 0000000..b3ac2da
--- /dev/null
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill.augmented;
+
+import android.content.ComponentName;
+import android.os.IBinder;
+
+import android.service.autofill.augmented.IFillCallback;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+
+import java.util.List;
+
+/**
+ * Interface from the system to an Augmented Autofill service.
+ *
+ * @hide
+ */
+oneway interface IAugmentedAutofillService {
+
+ void onFillRequest(int sessionId, in IBinder autofillManagerClient, int taskId,
+ in ComponentName activityComponent, in AutofillId focusedId,
+ in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
+
+ void onDestroyFillWindowRequest(int sessionId);
+}
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
new file mode 100644
index 0000000..dac7590
--- /dev/null
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill.augmented;
+
+import android.os.ICancellationSignal;
+
+/**
+ * Interface to receive the result of an autofill request.
+ *
+ * @hide
+ */
+interface IFillCallback {
+ // TODO(b/111330312): add cancellation (after we have CTS tests, so we can test it)
+// void onCancellable(in ICancellationSignal cancellation);
+ // TODO(b/111330312): might need to pass the response (once IME implements Smart Suggestions)
+ void onSuccess();
+}
diff --git a/core/java/android/service/intelligence/PresentationParams.java b/core/java/android/service/autofill/augmented/PresentationParams.java
similarity index 95%
rename from core/java/android/service/intelligence/PresentationParams.java
rename to core/java/android/service/autofill/augmented/PresentationParams.java
index 9530309..0124ecc 100644
--- a/core/java/android/service/intelligence/PresentationParams.java
+++ b/core/java/android/service/autofill/augmented/PresentationParams.java
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.autofill.augmented;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.graphics.Rect;
-import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
+import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
import android.util.DebugUtils;
import android.view.View;
@@ -174,11 +174,12 @@
*
* @param bounds boundaries relative to this Area.
*
- * @throws {@link IllegalArgumentException} if the {@code bounds} is not fully-contained
- * inside this full Area.
- *
* @return new subarea, or {@code null} if the Smart Suggestion host does not support such
* subaarea.
+ *
+ * @throws IllegalArgumentException if the {@code bounds} is not fully-contained inside this
+ * full Area.
+ *
*/
@Nullable
public Area getSubArea(@NonNull Rect bounds) {
diff --git a/core/java/android/service/intelligence/ContentCaptureEventsRequest.aidl b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.aidl
similarity index 94%
rename from core/java/android/service/intelligence/ContentCaptureEventsRequest.aidl
rename to core/java/android/service/contentcapture/ContentCaptureEventsRequest.aidl
index 23d607d..c032cfd 100644
--- a/core/java/android/service/intelligence/ContentCaptureEventsRequest.aidl
+++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.contentcapture;
parcelable ContentCaptureEventsRequest;
diff --git a/core/java/android/service/intelligence/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
similarity index 95%
rename from core/java/android/service/intelligence/ContentCaptureEventsRequest.java
rename to core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
index bc5b92b..df58f52 100644
--- a/core/java/android/service/intelligence/ContentCaptureEventsRequest.java
+++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.contentcapture;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.view.intelligence.ContentCaptureEvent;
+import android.view.contentcapture.ContentCaptureEvent;
import java.util.List;
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
new file mode 100644
index 0000000..3dfeede
--- /dev/null
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.contentcapture;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.contentcapture.ContentCaptureEvent;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A service used to capture the content of the screen to provide contextual data in other areas of
+ * the system such as Autofill.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class ContentCaptureService extends Service {
+
+ private static final String TAG = ContentCaptureService.class.getSimpleName();
+
+ // TODO(b/111330312): STOPSHIP use dynamic value, or change to false
+ static final boolean DEBUG = true;
+ static final boolean VERBOSE = false;
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ *
+ * <p>To be supported, the service must also require the
+ * {@link android.Manifest.permission#BIND_CONTENT_CAPTURE_SERVICE} permission so
+ * that other applications can not abuse it.
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.service.contentcapture.ContentCaptureService";
+
+ private Handler mHandler;
+
+ private final IContentCaptureService mInterface = new IContentCaptureService.Stub() {
+
+ @Override
+ public void onSessionLifecycle(InteractionContext context, String sessionId)
+ throws RemoteException {
+ if (context != null) {
+ mHandler.sendMessage(
+ obtainMessage(ContentCaptureService::handleOnCreateInteractionSession,
+ ContentCaptureService.this, context, sessionId));
+ } else {
+ mHandler.sendMessage(
+ obtainMessage(ContentCaptureService::handleOnDestroyInteractionSession,
+ ContentCaptureService.this, sessionId));
+ }
+ }
+
+ @Override
+ public void onContentCaptureEventsRequest(String sessionId,
+ ContentCaptureEventsRequest request) {
+ mHandler.sendMessage(
+ obtainMessage(ContentCaptureService::handleOnContentCaptureEventsRequest,
+ ContentCaptureService.this, sessionId, request));
+
+ }
+
+ @Override
+ public void onActivitySnapshot(String sessionId, SnapshotData snapshotData) {
+ mHandler.sendMessage(
+ obtainMessage(ContentCaptureService::handleOnActivitySnapshot,
+ ContentCaptureService.this, sessionId, snapshotData));
+ }
+ };
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(Looper.getMainLooper(), null, true);
+ }
+
+ /** @hide */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mInterface.asBinder();
+ }
+ Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
+ return null;
+ }
+
+ /**
+ * Explicitly limits content capture to the given packages and activities.
+ *
+ * <p>When the whitelist is set, it overrides the values passed to
+ * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}
+ * and {@link #setPackageContentCaptureEnabled(String, boolean)}.
+ *
+ * <p>To reset the whitelist, call it passing {@code null} to both arguments.
+ *
+ * <p>Useful when the service wants to restrict content capture to a category of apps, like
+ * chat apps. For example, if the service wants to support view captures on all activities of
+ * app {@code ChatApp1} and just activities {@code act1} and {@code act2} of {@code ChatApp2},
+ * it would call: {@code setContentCaptureWhitelist(Arrays.asList("ChatApp1"),
+ * Arrays.asList(new ComponentName("ChatApp2", "act1"),
+ * new ComponentName("ChatApp2", "act2")));}
+ */
+ public final void setContentCaptureWhitelist(@Nullable List<String> packages,
+ @Nullable List<ComponentName> activities) {
+ //TODO(b/111276913): implement
+ }
+
+ /**
+ * Defines whether content capture should be enabled for activities with such
+ * {@link android.content.ComponentName}.
+ *
+ * <p>Useful to blacklist a particular activity.
+ */
+ public final void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
+ boolean enabled) {
+ //TODO(b/111276913): implement
+ }
+
+ /**
+ * Defines whether content capture should be enabled for activities of the app with such
+ * {@code packageName}.
+ *
+ * <p>Useful to blacklist any activity from a particular app.
+ */
+ public final void setPackageContentCaptureEnabled(@NonNull String packageName,
+ boolean enabled) {
+ //TODO(b/111276913): implement
+ }
+
+ /**
+ * Gets the activities where content capture was disabled by
+ * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}.
+ */
+ @NonNull
+ public final Set<ComponentName> getContentCaptureDisabledActivities() {
+ //TODO(b/111276913): implement
+ return null;
+ }
+
+ /**
+ * Gets the apps where content capture was disabled by
+ * {@link #setPackageContentCaptureEnabled(String, boolean)}.
+ */
+ @NonNull
+ public final Set<String> getContentCaptureDisabledPackages() {
+ //TODO(b/111276913): implement
+ return null;
+ }
+
+ /**
+ * Creates a new interaction session.
+ *
+ * @param context interaction context
+ * @param sessionId the session's Id
+ */
+ public void onCreateInteractionSession(@NonNull InteractionContext context,
+ @NonNull InteractionSessionId sessionId) {
+ if (VERBOSE) {
+ Log.v(TAG, "onCreateInteractionSession(id=" + sessionId + ", ctx=" + context + ")");
+ }
+ }
+
+ /**
+ * Notifies the service of {@link ContentCaptureEvent events} associated with a content capture
+ * session.
+ *
+ * @param sessionId the session's Id
+ * @param request the events
+ */
+ public abstract void onContentCaptureEventsRequest(@NonNull InteractionSessionId sessionId,
+ @NonNull ContentCaptureEventsRequest request);
+
+ /**
+ * Notifies the service of {@link SnapshotData snapshot data} associated with a session.
+ *
+ * @param sessionId the session's Id
+ * @param snapshotData the data
+ */
+ public void onActivitySnapshot(@NonNull InteractionSessionId sessionId,
+ @NonNull SnapshotData snapshotData) {}
+
+ /**
+ * Destroys the interaction session.
+ *
+ * @param sessionId the id of the session to destroy
+ */
+ public void onDestroyInteractionSession(@NonNull InteractionSessionId sessionId) {
+ if (VERBOSE) {
+ Log.v(TAG, "onDestroyInteractionSession(id=" + sessionId + ")");
+ }
+ }
+
+ //TODO(b/111276913): consider caching the InteractionSessionId for the lifetime of the session,
+ // so we don't need to create a temporary InteractionSessionId for each event.
+
+ private void handleOnCreateInteractionSession(@NonNull InteractionContext context,
+ @NonNull String sessionId) {
+ onCreateInteractionSession(context, new InteractionSessionId(sessionId));
+ }
+
+ private void handleOnContentCaptureEventsRequest(@NonNull String sessionId,
+ @NonNull ContentCaptureEventsRequest request) {
+ onContentCaptureEventsRequest(new InteractionSessionId(sessionId), request);
+ }
+
+ private void handleOnActivitySnapshot(@NonNull String sessionId,
+ @NonNull SnapshotData snapshotData) {
+ onActivitySnapshot(new InteractionSessionId(sessionId), snapshotData);
+ }
+
+ private void handleOnDestroyInteractionSession(@NonNull String sessionId) {
+ onDestroyInteractionSession(new InteractionSessionId(sessionId));
+ }
+}
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
new file mode 100644
index 0000000..29e9abb
--- /dev/null
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.contentcapture;
+
+import android.service.contentcapture.ContentCaptureEventsRequest;
+import android.service.contentcapture.InteractionContext;
+import android.service.contentcapture.SnapshotData;
+
+import java.util.List;
+
+/**
+ * Interface from the system to a Content Capture service.
+ *
+ * @hide
+ */
+oneway interface IContentCaptureService {
+
+ // Called when session is created (context not null) or destroyed (context null)
+ void onSessionLifecycle(in InteractionContext context, String sessionId);
+
+ void onContentCaptureEventsRequest(String sessionId, in ContentCaptureEventsRequest request);
+
+ void onActivitySnapshot(String sessionId, in SnapshotData snapshotData);
+}
diff --git a/core/java/android/service/intelligence/InteractionContext.aidl b/core/java/android/service/contentcapture/InteractionContext.aidl
similarity index 93%
rename from core/java/android/service/intelligence/InteractionContext.aidl
rename to core/java/android/service/contentcapture/InteractionContext.aidl
index 4ce6aa4..982e095 100644
--- a/core/java/android/service/intelligence/InteractionContext.aidl
+++ b/core/java/android/service/contentcapture/InteractionContext.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.contentcapture;
parcelable InteractionContext;
diff --git a/core/java/android/service/intelligence/InteractionContext.java b/core/java/android/service/contentcapture/InteractionContext.java
similarity index 96%
rename from core/java/android/service/intelligence/InteractionContext.java
rename to core/java/android/service/contentcapture/InteractionContext.java
index 7f4283d..f1281ff 100644
--- a/core/java/android/service/intelligence/InteractionContext.java
+++ b/core/java/android/service/contentcapture/InteractionContext.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.contentcapture;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -37,7 +37,7 @@
/**
* Flag used to indicate that the app explicitly disabled content capture for the activity
* (using
- * {@link android.view.intelligence.ContentCaptureManager#setContentCaptureEnabled()}),
+ * {@link android.view.contentcapture.ContentCaptureManager#setContentCaptureEnabled(boolean)}),
* in which case the service will just receive activity-level events.
*/
public static final int FLAG_DISABLED_BY_APP = 0x1;
diff --git a/core/java/android/service/intelligence/InteractionSessionId.java b/core/java/android/service/contentcapture/InteractionSessionId.java
similarity index 90%
rename from core/java/android/service/intelligence/InteractionSessionId.java
rename to core/java/android/service/contentcapture/InteractionSessionId.java
index 667193b..8411947 100644
--- a/core/java/android/service/intelligence/InteractionSessionId.java
+++ b/core/java/android/service/contentcapture/InteractionSessionId.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.contentcapture;
import android.annotation.NonNull;
import android.annotation.SystemApi;
@@ -22,10 +22,12 @@
import android.os.Parcelable;
import java.io.PrintWriter;
-import java.util.UUID;
-// TODO(b/111276913): add javadocs / implement equals/hashcode/string
-/** @hide */
+/**
+ * Identifier for a Content Capture session.
+ *
+ * @hide
+ */
@SystemApi
public final class InteractionSessionId implements Parcelable {
@@ -34,15 +36,6 @@
/**
* Creates a new instance.
*
- * @hide
- */
- public InteractionSessionId() {
- this(UUID.randomUUID().toString());
- }
-
- /**
- * Creates a new instance.
- *
* @param value The internal value.
*
* @hide
diff --git a/core/java/android/service/intelligence/SnapshotData.aidl b/core/java/android/service/contentcapture/SnapshotData.aidl
similarity index 93%
rename from core/java/android/service/intelligence/SnapshotData.aidl
rename to core/java/android/service/contentcapture/SnapshotData.aidl
index 31d1339..a00e852 100644
--- a/core/java/android/service/intelligence/SnapshotData.aidl
+++ b/core/java/android/service/contentcapture/SnapshotData.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.contentcapture;
parcelable SnapshotData;
diff --git a/core/java/android/service/intelligence/SnapshotData.java b/core/java/android/service/contentcapture/SnapshotData.java
similarity index 98%
rename from core/java/android/service/intelligence/SnapshotData.java
rename to core/java/android/service/contentcapture/SnapshotData.java
index b9310ea..bc2116a 100644
--- a/core/java/android/service/intelligence/SnapshotData.java
+++ b/core/java/android/service/contentcapture/SnapshotData.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.service.intelligence;
+package android.service.contentcapture;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/service/intelligence/IIntelligenceService.aidl b/core/java/android/service/intelligence/IIntelligenceService.aidl
deleted file mode 100644
index 2b924fb..0000000
--- a/core/java/android/service/intelligence/IIntelligenceService.aidl
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.intelligence;
-
-import android.os.IBinder;
-import android.service.intelligence.ContentCaptureEventsRequest;
-import android.service.intelligence.InteractionSessionId;
-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;
-
-/**
- * Interface from the system to an intelligence service.
- *
- * @hide
- */
- // TODO(b/111276913): rename / update javadoc (once the final name is defined)
-oneway interface IIntelligenceService {
-
- // Called when session is created (context not null) or destroyed (context null)
- void onSessionLifecycle(in InteractionContext context, in InteractionSessionId sessionId);
-
- void onContentCaptureEventsRequest(in InteractionSessionId sessionId,
- in ContentCaptureEventsRequest request);
-
- void onActivitySnapshot(in InteractionSessionId sessionId,
- in SnapshotData snapshotData);
-
- void onAutofillRequest(in InteractionSessionId sessionId, in IBinder autofillManagerClient,
- int autofilSessionId, in AutofillId focusedId,
- in AutofillValue focusedValue, long requestTime);
-
- void onDestroyAutofillWindowsRequest(in InteractionSessionId sessionId);
-}
diff --git a/core/java/android/service/intelligence/InteractionSessionId.aidl b/core/java/android/service/intelligence/InteractionSessionId.aidl
deleted file mode 100644
index a5392b6..0000000
--- a/core/java/android/service/intelligence/InteractionSessionId.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.intelligence;
-
-parcelable InteractionSessionId;
diff --git a/core/java/android/service/intelligence/SmartSuggestionsService.java b/core/java/android/service/intelligence/SmartSuggestionsService.java
deleted file mode 100644
index b684b02..0000000
--- a/core/java/android/service/intelligence/SmartSuggestionsService.java
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.os.CancellationSignal;
-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;
-import android.view.intelligence.ContentCaptureEvent;
-
-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;
-
-/**
- * A service used to capture the content of the screen to provide contextual data in other areas of
- * the system such as Autofill.
- *
- * @hide
- */
-@SystemApi
-public abstract class SmartSuggestionsService extends Service {
-
- private static final String TAG = "SmartSuggestionsService";
-
- // TODO(b/111330312): STOPSHIP use dynamic value, or change to false
- static final boolean DEBUG = true;
- static final boolean VERBOSE = false;
-
- /**
- * The {@link Intent} that must be declared as handled by the service.
- * To be supported, the service must also require the
- * {@link android.Manifest.permission#BIND_SMART_SUGGESTIONS_SERVICE} permission so
- * that other applications can not abuse it.
- */
- public static final String SERVICE_INTERFACE =
- "android.service.intelligence.SmartSuggestionsService";
-
- private Handler mHandler;
-
- private ArrayMap<InteractionSessionId, AutofillProxy> mAutofillProxies;
-
- private final IIntelligenceService mInterface = new IIntelligenceService.Stub() {
-
- @Override
- public void onSessionLifecycle(InteractionContext context, InteractionSessionId sessionId)
- throws RemoteException {
- if (context != null) {
- mHandler.sendMessage(
- obtainMessage(SmartSuggestionsService::onCreateInteractionSession,
- SmartSuggestionsService.this, context, sessionId));
- } else {
- mHandler.sendMessage(
- obtainMessage(SmartSuggestionsService::onDestroyInteractionSession,
- SmartSuggestionsService.this, sessionId));
- }
- }
-
- @Override
- public void onContentCaptureEventsRequest(InteractionSessionId sessionId,
- ContentCaptureEventsRequest request) {
- mHandler.sendMessage(
- obtainMessage(SmartSuggestionsService::onContentCaptureEventsRequest,
- SmartSuggestionsService.this, sessionId, request));
-
- }
-
- @Override
- public void onActivitySnapshot(InteractionSessionId sessionId,
- SnapshotData snapshotData) {
- mHandler.sendMessage(
- obtainMessage(SmartSuggestionsService::onActivitySnapshot,
- SmartSuggestionsService.this, sessionId, snapshotData));
- }
-
- @Override
- public void onAutofillRequest(InteractionSessionId sessionId, IBinder client,
- int autofilSessionId, AutofillId focusedId, AutofillValue focusedValue,
- long requestTime) {
- mHandler.sendMessage(obtainMessage(SmartSuggestionsService::handleOnAutofillRequest,
- SmartSuggestionsService.this, sessionId, client, autofilSessionId, focusedId,
- focusedValue, requestTime));
- }
-
- @Override
- public void onDestroyAutofillWindowsRequest(InteractionSessionId sessionId) {
- mHandler.sendMessage(
- obtainMessage(SmartSuggestionsService::handleOnDestroyAutofillWindowsRequest,
- SmartSuggestionsService.this, sessionId));
- }
- };
-
- @CallSuper
- @Override
- public void onCreate() {
- super.onCreate();
- mHandler = new Handler(Looper.getMainLooper(), null, true);
- }
-
- /** @hide */
- @Override
- public final IBinder onBind(Intent intent) {
- if (SERVICE_INTERFACE.equals(intent.getAction())) {
- return mInterface.asBinder();
- }
- Log.w(TAG, "Tried to bind to wrong intent: " + intent);
- return null;
- }
-
- /**
- * Explicitly limits content capture to the given packages and activities.
- *
- * <p>When the whitelist is set, it overrides the values passed to
- * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}
- * and {@link #setPackageContentCaptureEnabled(String, boolean)}.
- *
- * <p>To reset the whitelist, call it passing {@code null} to both arguments.
- *
- * <p>Useful when the service wants to restrict content capture to a category of apps, like
- * chat apps. For example, if the service wants to support view captures on all activities of
- * app {@code ChatApp1} and just activities {@code act1} and {@code act2} of {@code ChatApp2},
- * it would call: {@code setContentCaptureWhitelist(Arrays.asList("ChatApp1"),
- * Arrays.asList(new ComponentName("ChatApp2", "act1"),
- * new ComponentName("ChatApp2", "act2")));}
- */
- public final void setContentCaptureWhitelist(@Nullable List<String> packages,
- @Nullable List<ComponentName> activities) {
- //TODO(b/111276913): implement
- }
-
- /**
- * Defines whether content capture should be enabled for activities with such
- * {@link android.content.ComponentName}.
- *
- * <p>Useful to blacklist a particular activity.
- */
- public final void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
- boolean enabled) {
- //TODO(b/111276913): implement
- }
-
- /**
- * Defines whether content capture should be enabled for activities of the app with such
- * {@code packageName}.
- *
- * <p>Useful to blacklist any activity from a particular app.
- */
- public final void setPackageContentCaptureEnabled(@NonNull String packageName,
- boolean enabled) {
- //TODO(b/111276913): implement
- }
-
- /**
- * Gets the activities where content capture was disabled by
- * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}.
- */
- @NonNull
- public final Set<ComponentName> getContentCaptureDisabledActivities() {
- //TODO(b/111276913): implement
- return null;
- }
-
- /**
- * Gets the apps where content capture was disabled by
- * {@link #setPackageContentCaptureEnabled(String, boolean)}.
- */
- @NonNull
- public final Set<String> getContentCaptureDisabledPackages() {
- //TODO(b/111276913): implement
- return null;
- }
-
- /**
- * Creates a new interaction session.
- *
- * @param context interaction context
- * @param sessionId the session's Id
- */
- public void onCreateInteractionSession(@NonNull InteractionContext context,
- @NonNull InteractionSessionId sessionId) {
- if (VERBOSE) {
- Log.v(TAG, "onCreateInteractionSession(id=" + sessionId + ", ctx=" + context + ")");
- }
- }
-
- /**
- * Notifies the service of {@link ContentCaptureEvent events} associated with a content capture
- * session.
- *
- * @param sessionId the session's Id
- * @param request the events
- */
- // TODO(b/111276913): rename to onContentCaptureEvents or something like that; also, pass a
- // Request object so it can be extended
- public abstract void onContentCaptureEventsRequest(@NonNull InteractionSessionId sessionId,
- @NonNull ContentCaptureEventsRequest request);
-
- private void handleOnAutofillRequest(@NonNull InteractionSessionId sessionId,
- @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, focusedValue,
- requestTime);
- mAutofillProxies.put(sessionId, proxy);
- } else {
- // TODO(b/111330312): figure out if it's ok to reuse the proxy; add logging
- if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
- }
- // TODO(b/111330312): set cancellation signal
- final CancellationSignal cancellationSignal = null;
- onFillRequest(sessionId, new FillRequest(proxy), cancellationSignal,
- new FillController(proxy), new FillCallback(proxy));
- }
-
- /**
- * Asks the service to handle an "augmented" autofill request.
- *
- * <p>This method is called when the "stantard" autofill service cannot handle a request, which
- * typically occurs when:
- * <ul>
- * <li>Service does not recognize what should be autofilled.
- * <li>Service does not have data to fill the request.
- * <li>Service blacklisted that app (or activity) for autofill.
- * <li>App disabled itself for autofill.
- * </ul>
- *
- * <p>Differently from the standard autofill workflow, on augmented autofill the service is
- * responsible to generate the autofill UI and request the Android system to autofill the
- * activity when the user taps an action in that UI (through the
- * {@link FillController#autofill(List)} method).
- *
- * <p>The service <b>MUST</b> call {@link
- * FillCallback#onSuccess(android.service.intelligence.FillResponse)} as soon as possible,
- * passing {@code null} when it cannot fulfill the request.
- *
- * @param sessionId the session's id
- * @param request the request to handle.
- * @param cancellationSignal signal for observing cancellation requests. The system will use
- * this to notify you that the fill result is no longer needed and you should stop
- * handling this fill request in order to save resources.
- * @param controller object used to interact with the autofill system.
- * @param callback object used to notify the result of the request. Service <b>must</b> call
- * {@link FillCallback#onSuccess(android.service.intelligence.FillResponse)}.
- */
- public void onFillRequest(@NonNull InteractionSessionId sessionId, @NonNull FillRequest request,
- @NonNull CancellationSignal cancellationSignal, @NonNull FillController controller,
- @NonNull FillCallback callback) {
- }
-
- private void handleOnDestroyAutofillWindowsRequest(@NonNull InteractionSessionId sessionId) {
- AutofillProxy proxy = null;
- if (mAutofillProxies != null) {
- proxy = mAutofillProxies.get(sessionId);
- }
- if (proxy == null) {
- // TODO(b/111330312): this might be fine, in which case we should logv it
- Log.w(TAG, "No proxy for session " + sessionId);
- return;
- }
- proxy.destroy();
- mAutofillProxies.remove(sessionId);
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mAutofillProxies != null) {
- final int size = mAutofillProxies.size();
- pw.print("Number proxies: "); pw.println(size);
- for (int i = 0; i < size; i++) {
- final InteractionSessionId sessionId = mAutofillProxies.keyAt(i);
- final AutofillProxy proxy = mAutofillProxies.valueAt(i);
- pw.print(i); pw.print(") SessionId="); pw.print(sessionId); pw.println(":");
- proxy.dump(" ", pw);
- }
- }
- }
-
- /**
- * Notifies the service of {@link SnapshotData snapshot data} associated with a session.
- *
- * @param sessionId the session's Id
- * @param snapshotData the data
- */
- public void onActivitySnapshot(@NonNull InteractionSessionId sessionId,
- @NonNull SnapshotData snapshotData) {}
-
- /**
- * Destroys the interaction session.
- *
- * @param sessionId the id of the session to destroy
- */
- public void onDestroyInteractionSession(@NonNull InteractionSessionId sessionId) {
- if (VERBOSE) {
- Log.v(TAG, "onDestroyInteractionSession(id=" + sessionId + ")");
- }
- }
-
- /** @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;
-
- @GuardedBy("mLock")
- private FillWindow mFillWindow;
-
- private AutofillProxy(@NonNull InteractionSessionId sessionId, @NonNull IBinder client,
- 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
- }
-
- @NonNull
- public SystemPopupPresentationParams getSmartSuggestionParams() {
- synchronized (mLock) {
- if (mSmartSuggestion != null) {
- return mSmartSuggestion;
- }
- Rect rect;
- try {
- rect = mClient.getViewCoordinates(focusedId);
- } catch (RemoteException e) {
- Log.w(TAG, "Could not get coordinates for " + focusedId);
- return null;
- }
- if (rect == null) {
- if (DEBUG) Log.d(TAG, "getViewCoordinates(" + focusedId + ") returned null");
- return null;
- }
- mSmartSuggestion = new SystemPopupPresentationParams(this, rect);
- return mSmartSuggestion;
- }
- }
-
- public void autofill(@NonNull List<Pair<AutofillId, AutofillValue>> pairs)
- throws RemoteException {
- final int size = pairs.size();
- final List<AutofillId> ids = new ArrayList<>(size);
- final List<AutofillValue> values = new ArrayList<>(size);
- for (int i = 0; i < size; i++) {
- final Pair<AutofillId, AutofillValue> pair = pairs.get(i);
- ids.add(pair.first);
- values.add(pair.second);
- }
- mClient.autofill(mAutofillSessionId, ids, values);
- }
-
- public void setFillWindow(@NonNull FillWindow fillWindow) {
- synchronized (mLock) {
- mFillWindow = fillWindow;
- }
- }
-
- public FillWindow getFillWindow() {
- synchronized (mLock) {
- return mFillWindow;
- }
- }
-
- // 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) {
- pw.print(prefix); pw.println("window:");
- mFillWindow.dump(prefix2, pw);
- }
- if (mSmartSuggestion != null) {
- 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() {
- synchronized (mLock) {
- if (mFillWindow != null) {
- if (DEBUG) Log.d(TAG, "destroying window");
- mFillWindow.destroy();
- }
- }
- }
- }
-}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bd2aa64..4297efb7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -109,13 +109,13 @@
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
+import android.view.contentcapture.ContentCaptureManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.view.inspector.InspectableProperty;
import android.view.inspector.InspectableProperty.EnumMap;
import android.view.inspector.InspectableProperty.FlagMap;
-import android.view.intelligence.ContentCaptureManager;
import android.widget.Checkable;
import android.widget.FrameLayout;
import android.widget.ScrollBarDrawable;
diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.aidl b/core/java/android/view/contentcapture/ContentCaptureEvent.aidl
similarity index 94%
rename from core/java/android/view/intelligence/ContentCaptureEvent.aidl
rename to core/java/android/view/contentcapture/ContentCaptureEvent.aidl
index c66a6cb..abaf9ed 100644
--- a/core/java/android/view/intelligence/ContentCaptureEvent.aidl
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.view.intelligence;
+package android.view.contentcapture;
parcelable ContentCaptureEvent;
diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
similarity index 91%
rename from core/java/android/view/intelligence/ContentCaptureEvent.java
rename to core/java/android/view/contentcapture/ContentCaptureEvent.java
index f636281..66fa530 100644
--- a/core/java/android/view/intelligence/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.view.intelligence;
+package android.view.contentcapture;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -42,22 +42,38 @@
/**
* Called when the activity is started.
+ *
+ * @deprecated - TODO(b/111276913): we should abstract the Activity lifecycle concepts into
+ * something related to a session and/or domain.
*/
+ @Deprecated
public static final int TYPE_ACTIVITY_STARTED = 1;
/**
* Called when the activity is resumed.
+ *
+ * @deprecated - TODO(b/111276913): we should abstract the Activity lifecycle concepts into
+ * something related to a session and/or domain.
*/
+ @Deprecated
public static final int TYPE_ACTIVITY_RESUMED = 2;
/**
* Called when the activity is paused.
+ *
+ * @deprecated - TODO(b/111276913): we should abstract the Activity lifecycle concepts into
+ * something related to a session and/or domain.
*/
+ @Deprecated
public static final int TYPE_ACTIVITY_PAUSED = 3;
/**
* Called when the activity is stopped.
+ *
+ * @deprecated - TODO(b/111276913): we should abstract the Activity lifecycle concepts into
+ * something related to a session and/or domain.
*/
+ @Deprecated
public static final int TYPE_ACTIVITY_STOPPED = 4;
/**
@@ -163,7 +179,7 @@
* Gets optional flags associated with the event.
*
* @return either {@code 0} or
- * {@link android.view.intelligence.ContentCaptureManager#FLAG_USER_INPUT}.
+ * {@link android.view.contentcapture.ContentCaptureManager#FLAG_USER_INPUT}.
*/
public int getFlags() {
return mFlags;
diff --git a/core/java/android/view/intelligence/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
similarity index 95%
rename from core/java/android/view/intelligence/ContentCaptureManager.java
rename to core/java/android/view/contentcapture/ContentCaptureManager.java
index 45518d5..48831da 100644
--- a/core/java/android/view/intelligence/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.view.intelligence;
+package android.view.contentcapture;
-import static android.view.intelligence.ContentCaptureEvent.TYPE_VIEW_APPEARED;
-import static android.view.intelligence.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
-import static android.view.intelligence.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -31,18 +31,18 @@
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
-import android.service.intelligence.InteractionSessionId;
import android.util.Log;
import android.view.View;
import android.view.ViewStructure;
import android.view.autofill.AutofillId;
-import android.view.intelligence.ContentCaptureEvent.EventType;
+import android.view.contentcapture.ContentCaptureEvent.EventType;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.Preconditions;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
/*
@@ -58,7 +58,7 @@
@SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE)
public final class ContentCaptureManager {
- private static final String TAG = "ContentCaptureManager";
+ private static final String TAG = ContentCaptureManager.class.getSimpleName();
// TODO(b/111276913): define a way to dynamically set them(for example, using settings?)
private static final boolean VERBOSE = false;
@@ -113,10 +113,10 @@
private final Context mContext;
@Nullable
- private final IIntelligenceManager mService;
+ private final IContentCaptureManager mService;
@Nullable
- private InteractionSessionId mId;
+ private String mId;
private int mState = STATE_UNKNOWN;
@@ -137,7 +137,8 @@
private final Handler mHandler;
/** @hide */
- public ContentCaptureManager(@NonNull Context context, @Nullable IIntelligenceManager service) {
+ public ContentCaptureManager(@NonNull Context context,
+ @Nullable IContentCaptureManager service) {
mContext = Preconditions.checkNotNull(context, "context cannot be null");
if (VERBOSE) {
Log.v(TAG, "Constructor for " + context.getPackageName());
@@ -165,7 +166,7 @@
return;
}
mState = STATE_WAITING_FOR_SERVER;
- mId = new InteractionSessionId();
+ mId = UUID.randomUUID().toString();
mApplicationToken = token;
mComponentName = componentName;
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
new file mode 100644
index 0000000..8704dad
--- /dev/null
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.contentcapture;
+
+import android.content.ComponentName;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.os.IBinder;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.List;
+
+/**
+ * {@hide}
+ */
+oneway interface IContentCaptureManager {
+ void startSession(int userId, IBinder activityToken, in ComponentName componentName,
+ String sessionId, int flags, in IResultReceiver result);
+ void finishSession(int userId, String sessionId, in List<ContentCaptureEvent> events);
+ void sendEvents(int userId, in String sessionId, in List<ContentCaptureEvent> events);
+}
diff --git a/core/java/android/view/intelligence/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
similarity index 99%
rename from core/java/android/view/intelligence/ViewNode.java
rename to core/java/android/view/contentcapture/ViewNode.java
index ea57461..86b89adb 100644
--- a/core/java/android/view/intelligence/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.view.intelligence;
+package android.view.contentcapture;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/view/intelligence/IIntelligenceManager.aidl b/core/java/android/view/intelligence/IIntelligenceManager.aidl
deleted file mode 100644
index 882fb26..0000000
--- a/core/java/android/view/intelligence/IIntelligenceManager.aidl
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.intelligence;
-
-import android.content.ComponentName;
-import android.os.IBinder;
-import android.service.intelligence.InteractionSessionId;
-import android.view.intelligence.ContentCaptureEvent;
-
-import com.android.internal.os.IResultReceiver;
-
-import java.util.List;
-
-/**
- * {@hide}
- */
-// TODO(b/111276913): rename once the final name is defined
-oneway interface IIntelligenceManager {
- /**
- * Starts a session, sending the "remote" sessionId to the receiver.
- */
- void startSession(int userId, IBinder activityToken, in ComponentName componentName,
- in InteractionSessionId sessionId, int flags, in IResultReceiver result);
-
- /**
- * Finishes a session.
- */
- void finishSession(int userId, in InteractionSessionId sessionId,
- in List<ContentCaptureEvent> events);
-
- /**
- * Sends a batch of events
- */
- void sendEvents(int userId, in InteractionSessionId sessionId,
- in List<ContentCaptureEvent> events);
-}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 90cf871..2a42232 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -157,6 +157,7 @@
import android.view.animation.AnimationUtils;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
+import android.view.contentcapture.ContentCaptureManager;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -166,7 +167,6 @@
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
-import android.view.intelligence.ContentCaptureManager;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 4c1fc5c..9620e4b 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -222,6 +222,13 @@
}
optional Connectivity connectivity = 32;
+ message ContentCapture {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto service_explicitly_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional ContentCapture content_capture = 145;
+
optional SettingProto contact_metadata_sync_enabled = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto contacts_database_wal_enabled = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
@@ -761,13 +768,6 @@
}
optional SmartSelection smart_selection = 108;
- message SmartSuggestions {
- option (android.msg_privacy).dest = DEST_EXPLICIT;
-
- optional SettingProto service_explicitly_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
- }
- optional SmartSuggestions smart_suggestions = 145;
-
message Sms {
option (android.msg_privacy).dest = DEST_EXPLICIT;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3018614..594ae6b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3047,12 +3047,20 @@
<permission android:name="android.permission.BIND_TEXTCLASSIFIER_SERVICE"
android:protectionLevel="signature" />
- <!-- Must be required by a android.service.intelligence.SmartSuggestionsService,
+ <!-- Must be required by a android.service.contentcapture.ContentCaptureService,
to ensure that only the system can bind to it.
@SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
<p>Protection level: signature
-->
- <permission android:name="android.permission.BIND_SMART_SUGGESTIONS_SERVICE"
+ <permission android:name="android.permission.BIND_CONTENT_CAPTURE_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a android.service.autofill.augmented.AugmentedAutofillService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE"
android:protectionLevel="signature" />
<!-- Must be required by hotword enrollment application,
@@ -4177,9 +4185,9 @@
<permission android:name="android.permission.MANAGE_AUTO_FILL"
android:protectionLevel="signature" />
- <!-- @SystemApi Allows an application to manage the smart suggestions service.
+ <!-- @SystemApi Allows an application to manage the content capture service.
@hide <p>Not for use by third-party applications.</p> -->
- <permission android:name="android.permission.MANAGE_SMART_SUGGESTIONS"
+ <permission android:name="android.permission.MANAGE_CONTENT_CAPTURE"
android:protectionLevel="signature" />
<!-- Allows an app to set the theme overlay in /vendor/overlay
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 499278c..62ec5c4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3350,13 +3350,21 @@
-->
<string name="config_defaultTextClassifierPackage" translatable="false"></string>
- <!-- The package name for the system's smart suggestion service.
+ <!-- The package name for the system's content capture service.
This service must be trusted, as it can be activated without explicit consent of the user.
- If no service with the specified name exists on the device, content capture and
- smart suggestions will be disabled.
- Example: "com.android.intelligence/.SmartSuggestionsService"
+ If no service with the specified name exists on the device, content capture will be
+ disabled.
+ Example: "com.android.contentcapture/.ContentcaptureService"
-->
- <string name="config_defaultSmartSuggestionsService" translatable="false"></string>
+ <string name="config_defaultContentCaptureService" translatable="false"></string>
+
+ <!-- The package name for the system's augmented autofill service.
+ This service must be trusted, as it can be activated without explicit consent of the user.
+ If no service with the specified name exists on the device, augmented autofill wil be
+ disabled.
+ Example: "com.android.augmentedautofill/.AugmentedAutofillService"
+ -->
+ <string name="config_defaultAugmentedAutofillService" translatable="false"></string>
<!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
<bool name="config_useDefaultFocusHighlight">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6854a84e..82a679e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3265,7 +3265,8 @@
<java-symbol type="string" name="notification_channel_do_not_disturb" />
<java-symbol type="string" name="config_defaultAutofillService" />
<java-symbol type="string" name="config_defaultTextClassifierPackage" />
- <java-symbol type="string" name="config_defaultSmartSuggestionsService" />
+ <java-symbol type="string" name="config_defaultContentCaptureService" />
+ <java-symbol type="string" name="config_defaultAugmentedAutofillService" />
<java-symbol type="string" name="notification_channel_foreground_service" />
<java-symbol type="string" name="foreground_service_app_in_background" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ed9c3d5..f1ed1c2 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -183,6 +183,7 @@
Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE,
Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
Settings.Global.CONTACT_METADATA_SYNC_ENABLED,
+ Settings.Global.CONTENT_CAPTURE_SERVICE_EXPLICITLY_ENABLED,
Settings.Global.CONVERSATION_ACTIONS_UPDATE_CONTENT_URL,
Settings.Global.CONVERSATION_ACTIONS_UPDATE_METADATA_URL,
Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
@@ -415,7 +416,6 @@
Settings.Global.SHOW_TEMPERATURE_WARNING,
Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
- Settings.Global.SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED,
Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED,
Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,