diff options
| author | 2018-12-21 09:29:27 -0800 | |
|---|---|---|
| committer | 2018-12-21 15:11:49 -0800 | |
| commit | bb98ed65218d7bf4c8622a48cedaefff2b90b2b8 (patch) | |
| tree | 0d6f0a983449a52d21e1a685429009e04c67deb1 | |
| parent | 50b33dce5986ff588bc064f9d2616746366b7cb5 (diff) | |
New APIs for ContentCaptureService: onConnected() and onDisconnected()
Bug: 117944706
Test: atest CtsContentCaptureServiceTestCases:android.contentcaptureservice.cts.BlankActivityTest#testDisconnected
Test: atest CtsContentCaptureServiceTestCases
Change-Id: Iba3c1ae774221946a550fad95539d3a9771ae3d7
6 files changed, 75 insertions, 3 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index d98139933588..414558b4997b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5156,10 +5156,12 @@ package android.service.contentcapture { method public final java.util.Set<android.content.ComponentName> getContentCaptureDisabledActivities(); method public final java.util.Set<java.lang.String> getContentCaptureDisabledPackages(); method public void onActivitySnapshot(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.SnapshotData); + method public void onConnected(); method public void onContentCaptureEvent(android.view.contentcapture.ContentCaptureSessionId, android.view.contentcapture.ContentCaptureEvent); method public deprecated void onContentCaptureEventsRequest(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.ContentCaptureEventsRequest); method public void onCreateContentCaptureSession(android.view.contentcapture.ContentCaptureContext, android.view.contentcapture.ContentCaptureSessionId); method public void onDestroyContentCaptureSession(android.view.contentcapture.ContentCaptureSessionId); + method public void onDisconnected(); method public final void setActivityContentCaptureEnabled(android.content.ComponentName, boolean); method public final void setContentCaptureWhitelist(java.util.List<java.lang.String>, java.util.List<android.content.ComponentName>); method public final void setPackageContentCaptureEnabled(java.lang.String, boolean); diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 64f235546201..c9d46dd701b5 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -31,6 +31,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.service.autofill.AutofillService; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; @@ -82,6 +83,12 @@ public abstract class ContentCaptureService extends Service { private final IContentCaptureService mServerInterface = new IContentCaptureService.Stub() { @Override + public void onConnectedStateChanged(boolean state) { + mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnConnectedStateChanged, + ContentCaptureService.this, state)); + } + + @Override public void onSessionStarted(ContentCaptureContext context, String sessionId, int uid, IResultReceiver clientReceiver) { mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnCreateSession, @@ -204,6 +211,15 @@ public abstract class ContentCaptureService extends Service { } /** + * Called when the Android system connects to service. + * + * <p>You should generally do initialization here rather than in {@link #onCreate}. + */ + public void onConnected() { + Slog.i(TAG, "bound to " + getClass().getName()); + } + + /** * Creates a new content capture session. * * @param context content capture context @@ -257,6 +273,15 @@ public abstract class ContentCaptureService extends Service { if (VERBOSE) Log.v(TAG, "onDestroyContentCaptureSession(id=" + sessionId + ")"); } + /** + * Called when the Android system disconnects from the service. + * + * <p> At this point this service may no longer be an active {@link AutofillService}. + */ + public void onDisconnected() { + Slog.i(TAG, "unbinding from " + getClass().getName()); + } + @Override @CallSuper protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -271,6 +296,14 @@ public abstract class ContentCaptureService extends Service { } } + private void handleOnConnectedStateChanged(boolean state) { + if (state) { + onConnected(); + } else { + onDisconnected(); + } + } + //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. diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl index 20e8e99d4ce1..1b4cccf630a0 100644 --- a/core/java/android/service/contentcapture/IContentCaptureService.aidl +++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl @@ -29,6 +29,7 @@ import java.util.List; * @hide */ oneway interface IContentCaptureService { + void onConnectedStateChanged(boolean state); void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid, in IResultReceiver clientReceiver); void onSessionFinished(String sessionId); diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java index 9471e69d21bd..c94c64a879b3 100644 --- a/core/java/com/android/internal/infra/AbstractRemoteService.java +++ b/core/java/com/android/internal/infra/AbstractRemoteService.java @@ -63,7 +63,8 @@ import java.lang.ref.WeakReference; //TODO(b/117779333): improve javadoc above instead of using Autofill as an example public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I>, I extends IInterface> implements DeathRecipient { - private static final int MSG_UNBIND = 1; + private static final int MSG_BIND = 1; + private static final int MSG_UNBIND = 2; protected static final long PERMANENT_BOUND_TIMEOUT_MS = 0; @@ -106,7 +107,7 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I void onServiceDied(T service); } - // NOTE: must be package-protected so this class is not extend outside + // NOTE: must be package-protected so this class is not extended outside AbstractRemoteService(@NonNull Context context, @NonNull String serviceInterface, @NonNull ComponentName componentName, int userId, @NonNull VultureCallback<S> callback, boolean bindInstantServiceAllowed, boolean verbose) { @@ -284,6 +285,25 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I mHandler.removeMessages(MSG_UNBIND); } + /** + * Schedules a request to bind to the remote service. + * + * <p>Typically used on constructor for implementations that need a permanent connection to + * the remote service. + */ + protected void scheduleBind() { + if (mHandler.hasMessages(MSG_BIND)) { + if (mVerbose) Slog.v(mTag, "scheduleBind(): already scheduled"); + return; + } + mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleEnsureBound, this) + .setWhat(MSG_BIND)); + } + + /** + * Schedules a request to automatically unbind from the service after the + * {@link #getTimeoutIdleBindMillis() idle timeout} expires. + */ protected void scheduleUnbind() { final long unbindDelay = getTimeoutIdleBindMillis(); diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index e5529aff7c62..34fe5d916356 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -77,7 +77,7 @@ final class RemoteFillService try { mService.onConnectedStateChanged(state); } catch (Exception e) { - Slog.w(mTag, "Exception calling onConnectedStateChanged(): " + e); + Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e); } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java index 56ae87f25eba..824162868e19 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java @@ -23,6 +23,7 @@ import android.os.IBinder; import android.service.contentcapture.IContentCaptureService; import android.service.contentcapture.SnapshotData; import android.text.format.DateUtils; +import android.util.Slog; import android.view.contentcapture.ContentCaptureContext; import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; @@ -40,6 +41,9 @@ final class RemoteContentCaptureService boolean verbose) { super(context, serviceInterface, componentName, userId, callbacks, bindInstantServiceAllowed, verbose, /* initialCapacity= */ 2); + + // Bind right away, which will trigger a onConnected() on service's + scheduleBind(); } @Override // from AbstractRemoteService @@ -59,6 +63,18 @@ final class RemoteContentCaptureService return TIMEOUT_REMOTE_REQUEST_MILLIS; } + @Override // from RemoteService + protected void handleOnConnectedStateChanged(boolean state) { + if (state && getTimeoutIdleBindMillis() != PERMANENT_BOUND_TIMEOUT_MS) { + scheduleUnbind(); + } + try { + mService.onConnectedStateChanged(state); + } catch (Exception e) { + Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e); + } + } + /** * Called by {@link ContentCaptureServerSession} to generate a call to the * {@link RemoteContentCaptureService} to indicate the session was created. |