summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Felipe Leme <felipeal@google.com> 2019-02-27 17:01:51 -0800
committer Felipe Leme <felipeal@google.com> 2019-03-07 13:06:21 -0800
commit141864d61086c94fa3c04edac2c60858845c8af2 (patch)
treecb2c8c43cf0f85b0adaacb3b43b0ebf59d37cbfc
parentb14ac6e9af3faa80b0c7cd48e36bda2767e5ed17 (diff)
New API: ContentCaptureService.onActivityEvent()
This API is needed for high-level events that happened on activities that are not whitelisted for Content Capture. Test: atest CtsContentCaptureServiceTestCases:android.contentcaptureservice.cts.LoginActivityTest#testSimpleLifecycle_defaultSession Test: atest CtsContentCaptureServiceTestCases # sanity check Test: m update-api Bug: 126262658 Change-Id: Id2d4ccfb04d56eba561200d6875374a932c526ae
-rw-r--r--api/system-current.txt11
-rw-r--r--api/test-current.txt11
-rw-r--r--core/java/android/service/contentcapture/ActivityEvent.aidl19
-rw-r--r--core/java/android/service/contentcapture/ActivityEvent.java131
-rw-r--r--core/java/android/service/contentcapture/ContentCaptureService.java27
-rw-r--r--core/java/android/service/contentcapture/IContentCaptureService.aidl3
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java14
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java15
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java20
-rw-r--r--services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java8
-rw-r--r--services/java/com/android/server/SystemServer.java8
12 files changed, 273 insertions, 2 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index ced52599948f..ff3ce9a75e2f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6436,9 +6436,20 @@ package android.service.carrier {
package android.service.contentcapture {
+ public final class ActivityEvent implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.content.ComponentName getComponentName();
+ method public int getEventType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR;
+ field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2
+ field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1
+ }
+
public abstract class ContentCaptureService extends android.app.Service {
ctor public ContentCaptureService();
method public final void disableContentCaptureServices();
+ method public void onActivityEvent(@NonNull android.service.contentcapture.ActivityEvent);
method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
method public void onConnected();
method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent);
diff --git a/api/test-current.txt b/api/test-current.txt
index 3b0295488ded..8b04dd000554 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2297,9 +2297,20 @@ package android.service.autofill.augmented {
package android.service.contentcapture {
+ public final class ActivityEvent implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.content.ComponentName getComponentName();
+ method public int getEventType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR;
+ field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2
+ field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1
+ }
+
public abstract class ContentCaptureService extends android.app.Service {
ctor public ContentCaptureService();
method public final void disableContentCaptureServices();
+ method public void onActivityEvent(@NonNull android.service.contentcapture.ActivityEvent);
method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
method public void onConnected();
method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent);
diff --git a/core/java/android/service/contentcapture/ActivityEvent.aidl b/core/java/android/service/contentcapture/ActivityEvent.aidl
new file mode 100644
index 000000000000..558cac4d29e8
--- /dev/null
+++ b/core/java/android/service/contentcapture/ActivityEvent.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2019, 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;
+
+parcelable ActivityEvent;
diff --git a/core/java/android/service/contentcapture/ActivityEvent.java b/core/java/android/service/contentcapture/ActivityEvent.java
new file mode 100644
index 000000000000..7ac380d97d9d
--- /dev/null
+++ b/core/java/android/service/contentcapture/ActivityEvent.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 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.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.app.usage.UsageEvents.Event;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Represents an activity-level event that is not associated with a session.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class ActivityEvent implements Parcelable {
+
+ /**
+ * The activity resumed.
+ */
+ public static final int TYPE_ACTIVITY_RESUMED = Event.ACTIVITY_RESUMED;
+
+ /**
+ * The activity paused.
+ */
+ public static final int TYPE_ACTIVITY_PAUSED = Event.ACTIVITY_PAUSED;
+
+ /** @hide */
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_ACTIVITY_RESUMED,
+ TYPE_ACTIVITY_PAUSED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ActivityEventType{}
+
+ private final @NonNull ComponentName mComponentName;
+ private final @ActivityEventType int mType;
+
+ /** @hide */
+ public ActivityEvent(@NonNull ComponentName componentName, @ActivityEventType int type) {
+ mComponentName = componentName;
+ mType = type;
+ }
+
+ /**
+ * Gests the {@link ComponentName} of the activity associated with the event.
+ */
+ @NonNull
+ public ComponentName getComponentName() {
+ return mComponentName;
+ }
+
+ /**
+ * Gets the event type.
+ *
+ * @return either {@link #TYPE_ACTIVITY_RESUMED} or {@value #TYPE_ACTIVITY_PAUSED}.
+ */
+ @ActivityEventType
+ public int getEventType() {
+ return mType;
+ }
+
+ /** @hide */
+ public static String getTypeAsString(@ActivityEventType int type) {
+ switch (type) {
+ case TYPE_ACTIVITY_RESUMED:
+ return "ACTIVITY_RESUMED";
+ case TYPE_ACTIVITY_PAUSED:
+ return "ACTIVITY_PAUSED";
+ default:
+ return "UKNOWN_TYPE: " + type;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("ActivityEvent[").append(mComponentName.toShortString())
+ .append("]:").append(getTypeAsString(mType)).toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeParcelable(mComponentName, flags);
+ parcel.writeInt(mType);
+ }
+
+ public static final @android.annotation.NonNull Creator<ActivityEvent> CREATOR =
+ new Creator<ActivityEvent>() {
+
+ @Override
+ @NonNull
+ public ActivityEvent createFromParcel(@NonNull Parcel parcel) {
+ final ComponentName componentName = parcel.readParcelable(null);
+ final int eventType = parcel.readInt();
+ return new ActivityEvent(componentName, eventType);
+ }
+
+ @Override
+ @NonNull
+ public ActivityEvent[] newArray(int size) {
+ return new ActivityEvent[size];
+ }
+ };
+}
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 9c4669f8dcd3..ce3210f89f00 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -127,6 +127,13 @@ public abstract class ContentCaptureService extends Service {
obtainMessage(ContentCaptureService::handleOnUserDataRemovalRequest,
ContentCaptureService.this, request));
}
+
+ @Override
+ public void onActivityEvent(ActivityEvent event) {
+ mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnActivityEvent,
+ ContentCaptureService.this, event));
+
+ }
};
/**
@@ -261,7 +268,21 @@ public abstract class ContentCaptureService extends Service {
* @param snapshotData the data
*/
public void onActivitySnapshot(@NonNull ContentCaptureSessionId sessionId,
- @NonNull SnapshotData snapshotData) {}
+ @NonNull SnapshotData snapshotData) {
+ if (sVerbose) Log.v(TAG, "onActivitySnapshot(id=" + sessionId + ")");
+ }
+
+ /**
+ * Notifies the service of an activity-level event that is not associated with a session.
+ *
+ * <p>This method can be used to track some high-level events for all activities, even those
+ * that are not whitelisted for Content Capture.
+ *
+ * @param event high-level activity event
+ */
+ public void onActivityEvent(@NonNull ActivityEvent event) {
+ if (sVerbose) Log.v(TAG, "onActivityEvent(): " + event);
+ }
/**
* Destroys the content capture session.
@@ -397,6 +418,10 @@ public abstract class ContentCaptureService extends Service {
onUserDataRemovalRequest(request);
}
+ private void handleOnActivityEvent(@NonNull ActivityEvent event) {
+ onActivityEvent(event);
+ }
+
/**
* Checks if the given {@code uid} owns the session associated with the event.
*/
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index eb650324a942..f32432f099c0 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -16,7 +16,9 @@
package android.service.contentcapture;
+import android.content.ComponentName;
import android.os.IBinder;
+import android.service.contentcapture.ActivityEvent;
import android.service.contentcapture.SnapshotData;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.UserDataRemovalRequest;
@@ -38,4 +40,5 @@ oneway interface IContentCaptureService {
void onSessionFinished(String sessionId);
void onActivitySnapshot(String sessionId, in SnapshotData snapshotData);
void onUserDataRemovalRequest(in UserDataRemovalRequest request);
+ void onActivityEvent(in ActivityEvent event);
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 9f7a940c1d16..7112beb686b2 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -43,6 +43,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.service.contentcapture.ActivityEvent.ActivityEventType;
import android.util.LocalLog;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -632,7 +633,7 @@ public final class ContentCaptureManagerService extends
}
@Override
- public ContentCaptureOptions getOptionsForPackage(int userId, String packageName) {
+ public ContentCaptureOptions getOptionsForPackage(int userId, @NonNull String packageName) {
synchronized (mLock) {
final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
if (service != null) {
@@ -641,5 +642,16 @@ public final class ContentCaptureManagerService extends
}
return null;
}
+
+ @Override
+ public void notifyActivityEvent(int userId, @NonNull ComponentName activityComponent,
+ @ActivityEventType int eventType) {
+ synchronized (mLock) {
+ final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ service.onActivityEventLocked(activityComponent, eventType);
+ }
+ }
+ }
}
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 9df09b97da40..516f7f59e593 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -47,6 +47,8 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.contentcapture.ActivityEvent;
+import android.service.contentcapture.ActivityEvent.ActivityEventType;
import android.service.contentcapture.ContentCaptureService;
import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.SnapshotData;
@@ -432,6 +434,19 @@ final class ContentCapturePerUserService
return options;
}
+ @GuardedBy("mLock")
+ void onActivityEventLocked(@NonNull ComponentName componentName, @ActivityEventType int type) {
+ if (mRemoteService == null) {
+ if (mMaster.debug) Slog.d(mTag, "onActivityEvent(): no remote service");
+ return;
+ }
+ final ActivityEvent event = new ActivityEvent(componentName, type);
+
+ if (mMaster.verbose) Slog.v(mTag, "onActivityEvent(): " + event);
+
+ mRemoteService.onActivityLifecycleEvent(event);
+ }
+
@Override
protected void dumpLocked(String prefix, PrintWriter pw) {
super.dumpLocked(prefix, pw);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index dc07c0ab0c76..f7ac7b8c61b2 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.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.os.IBinder;
+import android.service.contentcapture.ActivityEvent;
import android.service.contentcapture.IContentCaptureService;
import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.SnapshotData;
@@ -111,6 +112,13 @@ final class RemoteContentCaptureService
scheduleAsyncRequest((s) -> s.onUserDataRemovalRequest(request));
}
+ /**
+ * Called by {@link ContentCaptureServerSession} to notify a high-level activity event.
+ */
+ public void onActivityLifecycleEvent(@NonNull ActivityEvent event) {
+ scheduleAsyncRequest((s) -> s.onActivityEvent(event));
+ }
+
public interface ContentCaptureServiceCallbacks
extends VultureCallback<RemoteContentCaptureService> {
// NOTE: so far we don't need to notify the callback implementation
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 73884a000f44..f98327b3c1c1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -185,6 +185,7 @@ import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
import android.app.backup.IBackupManager;
import android.app.usage.UsageEvents;
+import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.AutofillOptions;
@@ -1489,6 +1490,11 @@ public class ActivityManagerService extends IActivityManager.Stub
private ParcelFileDescriptor[] mLifeMonitorFds;
+ /**
+ * Used to notify activity lifecycle events.
+ */
+ @Nullable ContentCaptureManagerInternal mContentCaptureService;
+
final class UiHandler extends Handler {
public UiHandler() {
super(com.android.server.UiThread.get().getLooper(), null, true);
@@ -1983,6 +1989,16 @@ public class ActivityManagerService extends IActivityManager.Stub
mActivityTaskManager.setUsageStatsManager(usageStatsManager);
}
+ /**
+ * Sets the internal content capture manager service.
+ *
+ * <p>It's called when {@code SystemServer} starts, so we don't really need to acquire the lock.
+ */
+ public void setContentCaptureManager(
+ @Nullable ContentCaptureManagerInternal contentCaptureManager) {
+ mContentCaptureService = contentCaptureManager;
+ }
+
public void startObservingNativeCrashes() {
final NativeCrashListener ncl = new NativeCrashListener(this);
ncl.start();
@@ -2915,6 +2931,10 @@ public class ActivityManagerService extends IActivityManager.Stub
taskRoot);
}
}
+ if (mContentCaptureService != null
+ && (event == Event.ACTIVITY_PAUSED || event == Event.ACTIVITY_RESUMED)) {
+ mContentCaptureService.notifyActivityEvent(userId, activity, event);
+ }
}
/**
diff --git a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
index d04f92039f4c..fa7d3fca75b5 100644
--- a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
+++ b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
@@ -18,9 +18,11 @@ package com.android.server.contentcapture;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.os.Bundle;
import android.os.IBinder;
+import android.service.contentcapture.ActivityEvent.ActivityEventType;
/**
* ContentCapture Manager local system service interface.
@@ -51,4 +53,10 @@ public abstract class ContentCaptureManagerInternal {
@Nullable
public abstract ContentCaptureOptions getOptionsForPackage(@UserIdInt int userId,
@NonNull String packageName);
+
+ /**
+ * Notifies the intelligence service of a high-level activity event for the given user.
+ */
+ public abstract void notifyActivityEvent(@UserIdInt int userId,
+ @NonNull ComponentName activityComponent, @ActivityEventType int eventType);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index eba0081291ca..e73383013367 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -87,6 +87,7 @@ import com.android.server.broadcastradio.BroadcastRadioService;
import com.android.server.camera.CameraServiceProxy;
import com.android.server.clipboard.ClipboardService;
import com.android.server.connectivity.IpConnectivityMetrics;
+import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.coverage.CoverageService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
@@ -2250,6 +2251,13 @@ public final class SystemServer {
traceBeginAndSlog("StartContentCaptureService");
mSystemServiceManager.startService(CONTENT_CAPTURE_MANAGER_SERVICE_CLASS);
+
+ ContentCaptureManagerInternal ccmi =
+ LocalServices.getService(ContentCaptureManagerInternal.class);
+ if (ccmi != null && mActivityManagerService != null) {
+ mActivityManagerService.setContentCaptureManager(ccmi);
+ }
+
traceEnd();
}