Initial commit of Content Suggestions (overview long press) Manager.

Test: compile
Bug: 120865921
Change-Id: I9f8310112bedc883406f0f50a99041f542036fd9
diff --git a/Android.bp b/Android.bp
index 687d2d7..4c7db0d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -104,6 +104,9 @@
         "core/java/android/app/backup/IRestoreObserver.aidl",
         "core/java/android/app/backup/IRestoreSession.aidl",
         "core/java/android/app/backup/ISelectBackupTransportCallback.aidl",
+        "core/java/android/app/contentsuggestions/IClassificationsCallback.aidl",
+        "core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl",
+        "core/java/android/app/contentsuggestions/ISelectionsCallback.aidl",
         "core/java/android/app/prediction/IPredictionCallback.aidl",
         "core/java/android/app/prediction/IPredictionManager.aidl",
         "core/java/android/app/role/IOnRoleHoldersChangedListener.aidl",
@@ -285,6 +288,7 @@
         "core/java/android/service/carrier/ICarrierService.aidl",
         "core/java/android/service/carrier/ICarrierMessagingCallback.aidl",
         "core/java/android/service/carrier/ICarrierMessagingService.aidl",
+        "core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl",
         "core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl",
         "core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl",
         "core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl",
diff --git a/api/system-current.txt b/api/system-current.txt
index 667a356..d92a7ed 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -92,6 +92,7 @@
     field public static final java.lang.String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE";
     field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
     field public static final java.lang.String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
+    field public static final java.lang.String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
     field public static final java.lang.String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
     field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
     field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
@@ -849,6 +850,73 @@
 
 }
 
+package android.app.contentsuggestions {
+
+  public final class ClassificationsRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public java.util.List<android.app.contentsuggestions.ContentSelection> getSelections();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ClassificationsRequest> CREATOR;
+  }
+
+  public static final class ClassificationsRequest.Builder {
+    ctor public ClassificationsRequest.Builder(java.util.List<android.app.contentsuggestions.ContentSelection>);
+    method public android.app.contentsuggestions.ClassificationsRequest build();
+    method public android.app.contentsuggestions.ClassificationsRequest.Builder setExtras(android.os.Bundle);
+  }
+
+  public final class ContentClassification implements android.os.Parcelable {
+    ctor public ContentClassification(java.lang.String, android.os.Bundle);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentClassification> CREATOR;
+  }
+
+  public final class ContentSelection implements android.os.Parcelable {
+    ctor public ContentSelection(java.lang.String, android.os.Bundle);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentSelection> CREATOR;
+  }
+
+  public final class ContentSuggestionsManager {
+    method public void classifyContentSelections(android.app.contentsuggestions.ClassificationsRequest, java.util.concurrent.Executor, android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
+    method public void notifyInteraction(java.lang.String, android.os.Bundle);
+    method public void provideContextImage(int, android.os.Bundle);
+    method public void suggestContentSelections(android.app.contentsuggestions.SelectionsRequest, java.util.concurrent.Executor, android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
+  }
+
+  public static abstract interface ContentSuggestionsManager.ClassificationsCallback {
+    method public abstract void onContentClassificationsAvailable(int, java.util.List<android.app.contentsuggestions.ContentClassification>);
+  }
+
+  public static abstract interface ContentSuggestionsManager.SelectionsCallback {
+    method public abstract void onContentSelectionsAvailable(int, java.util.List<android.app.contentsuggestions.ContentSelection>);
+  }
+
+  public final class SelectionsRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public android.graphics.Point getInterestPoint();
+    method public int getTaskId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.SelectionsRequest> CREATOR;
+  }
+
+  public static final class SelectionsRequest.Builder {
+    ctor public SelectionsRequest.Builder(int);
+    method public android.app.contentsuggestions.SelectionsRequest build();
+    method public android.app.contentsuggestions.SelectionsRequest.Builder setExtras(android.os.Bundle);
+    method public android.app.contentsuggestions.SelectionsRequest.Builder setInterestPoint(android.graphics.Point);
+  }
+
+}
+
 package android.app.job {
 
   public abstract class JobScheduler {
@@ -1126,6 +1194,7 @@
     method public void startActivityAsUser(android.content.Intent, android.os.UserHandle);
     field public static final java.lang.String APP_PREDICTION_SERVICE = "app_prediction";
     field public static final java.lang.String BACKUP_SERVICE = "backup";
+    field public static final java.lang.String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub";
     field public static final java.lang.String EUICC_CARD_SERVICE = "euicc_card";
     field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
@@ -5374,6 +5443,19 @@
 
 }
 
+package android.service.contentsuggestions {
+
+  public abstract class ContentSuggestionsService extends android.app.Service {
+    ctor public ContentSuggestionsService();
+    method public abstract void classifyContentSelections(android.app.contentsuggestions.ClassificationsRequest, android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
+    method public abstract void notifyInteraction(java.lang.String, android.os.Bundle);
+    method public abstract void processContextImage(int, android.graphics.Bitmap, android.os.Bundle);
+    method public abstract void suggestContentSelections(android.app.contentsuggestions.SelectionsRequest, android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.contentsuggestions.ContentSuggestionsService";
+  }
+
+}
+
 package android.service.euicc {
 
   public final class DownloadSubscriptionResult implements android.os.Parcelable {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6710233d..4001261 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -21,6 +21,8 @@
 import android.app.ContextImpl.ServiceInitializationState;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.IDevicePolicyManager;
+import android.app.contentsuggestions.ContentSuggestionsManager;
+import android.app.contentsuggestions.IContentSuggestionsManager;
 import android.app.job.IJobScheduler;
 import android.app.job.JobScheduler;
 import android.app.prediction.AppPredictionManager;
@@ -1105,6 +1107,20 @@
             }
         });
 
+        registerService(Context.CONTENT_SUGGESTIONS_SERVICE,
+                ContentSuggestionsManager.class,
+                new CachedServiceFetcher<ContentSuggestionsManager>() {
+                    @Override
+                    public ContentSuggestionsManager createService(ContextImpl ctx) {
+                        // No throw as this is an optional service
+                        IBinder b = ServiceManager.getService(
+                                Context.CONTENT_SUGGESTIONS_SERVICE);
+                        IContentSuggestionsManager service =
+                                IContentSuggestionsManager.Stub.asInterface(b);
+                        return new ContentSuggestionsManager(service);
+                    }
+                });
+
         registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
             @Override
             public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl b/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl
new file mode 100644
index 0000000..a66413b
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.app.contentsuggestions;
+
+parcelable ClassificationsRequest;
diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.java b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
new file mode 100644
index 0000000..3f71518
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ClassificationsRequest implements Parcelable {
+    @NonNull
+    private final List<ContentSelection> mSelections;
+    @Nullable
+    private final Bundle mExtras;
+
+    private ClassificationsRequest(@NonNull List<ContentSelection> selections,
+            @Nullable Bundle extras) {
+        mSelections = selections;
+        mExtras = extras;
+    }
+
+    /**
+     * Return request selections.
+     */
+    public List<ContentSelection> getSelections() {
+        return mSelections;
+    }
+
+    /**
+     * Return the request extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedList(mSelections);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<ClassificationsRequest> CREATOR =
+            new Creator<ClassificationsRequest>() {
+        @Override
+        public ClassificationsRequest createFromParcel(Parcel source) {
+            return new ClassificationsRequest(
+                    source.createTypedArrayList(ContentSelection.CREATOR),
+                    source.readBundle());
+        }
+
+        @Override
+        public ClassificationsRequest[] newArray(int size) {
+            return new ClassificationsRequest[size];
+        }
+    };
+
+    /**
+     * A builder for classifications request events.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final List<ContentSelection> mSelections;
+        private Bundle mExtras;
+
+        public Builder(@NonNull List<ContentSelection> selections) {
+            mSelections = selections;
+        }
+
+        /**
+         * Sets the request extras.
+         */
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Builds a new request instance.
+         */
+        public ClassificationsRequest build() {
+            return new ClassificationsRequest(mSelections, mExtras);
+        }
+    }
+}
diff --git a/core/java/android/app/contentsuggestions/ContentClassification.aidl b/core/java/android/app/contentsuggestions/ContentClassification.aidl
new file mode 100644
index 0000000..f67b2c8
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentClassification.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.app.contentsuggestions;
+
+parcelable ContentClassification;
diff --git a/core/java/android/app/contentsuggestions/ContentClassification.java b/core/java/android/app/contentsuggestions/ContentClassification.java
new file mode 100644
index 0000000..f18520f
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentClassification.java
@@ -0,0 +1,79 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ContentClassification implements Parcelable {
+    @NonNull
+    private final String mClassificationId;
+    @NonNull
+    private final Bundle mExtras;
+
+    public ContentClassification(@NonNull String classificationId, @NonNull Bundle extras) {
+        mClassificationId = classificationId;
+        mExtras = extras;
+    }
+
+    /**
+     * Return the classification id.
+     */
+    public String getId() {
+        return mClassificationId;
+    }
+
+    /**
+     * Return the classification extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mClassificationId);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<ContentClassification> CREATOR =
+            new Creator<ContentClassification>() {
+        @Override
+        public ContentClassification createFromParcel(Parcel source) {
+            return new ContentClassification(
+                    source.readString(),
+                    source.readBundle());
+        }
+
+        @Override
+        public ContentClassification[] newArray(int size) {
+            return new ContentClassification[size];
+        }
+    };
+}
diff --git a/core/java/android/app/contentsuggestions/ContentSelection.aidl b/core/java/android/app/contentsuggestions/ContentSelection.aidl
new file mode 100644
index 0000000..e626d69
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSelection.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.app.contentsuggestions;
+
+parcelable ContentSelection;
diff --git a/core/java/android/app/contentsuggestions/ContentSelection.java b/core/java/android/app/contentsuggestions/ContentSelection.java
new file mode 100644
index 0000000..a8917f7
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSelection.java
@@ -0,0 +1,79 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ContentSelection implements Parcelable {
+    @NonNull
+    private final String mSelectionId;
+    @NonNull
+    private final Bundle mExtras;
+
+    public ContentSelection(@NonNull String selectionId, @NonNull Bundle extras) {
+        mSelectionId = selectionId;
+        mExtras = extras;
+    }
+
+    /**
+     * Return the selection id.
+     */
+    public String getId() {
+        return mSelectionId;
+    }
+
+    /**
+     * Return the selection extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mSelectionId);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<ContentSelection> CREATOR =
+            new Creator<ContentSelection>() {
+        @Override
+        public ContentSelection createFromParcel(Parcel source) {
+            return new ContentSelection(
+                    source.readString(),
+                    source.readBundle());
+        }
+
+        @Override
+        public ContentSelection[] newArray(int size) {
+            return new ContentSelection[size];
+        }
+    };
+}
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
new file mode 100644
index 0000000..b4d8977
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -0,0 +1,230 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * When provided with content from an app, can suggest selections and classifications of that
+ * content.
+ *
+ * <p>The content is mainly a snapshot of a running task, the selections will be text and image
+ * selections with that image content. These mSelections can then be classified to find actions and
+ * entities on those selections.
+ *
+ * <p>Only accessible to blessed components such as Overview.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ContentSuggestionsManager {
+    private static final String TAG = ContentSuggestionsManager.class.getSimpleName();
+
+    @Nullable
+    private final IContentSuggestionsManager mService;
+
+    /** @hide */
+    public ContentSuggestionsManager(@Nullable IContentSuggestionsManager service) {
+        mService = service;
+    }
+
+    /**
+     * Hints to the system that a new context image for the provided task should be sent to the
+     * system content suggestions service.
+     *
+     * @param taskId of the task to snapshot.
+     * @param imageContextRequestExtras sent with with request to provide implementation specific
+     *                                  extra information.
+     */
+    public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+        if (mService == null) {
+            Log.e(TAG, "provideContextImage called, but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.provideContextImage(taskId, imageContextRequestExtras);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Suggest content selections, based on the provided task id and optional
+     * location on screen provided in the request. Called after provideContextImage().
+     * The result can be passed to
+     * {@link #classifyContentSelections(ClassificationsRequest, Executor, ClassificationsCallback)}
+     *  to classify actions and entities on these selections.
+     *
+     * @param request containing the task and point location.
+     * @param callbackExecutor to execute the provided callback on.
+     * @param callback to receive the selections.
+     */
+    public void suggestContentSelections(
+            @NonNull SelectionsRequest request,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull SelectionsCallback callback) {
+        if (mService == null) {
+            Log.e(TAG,
+                    "suggestContentSelections called, but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.suggestContentSelections(
+                    request, new SelectionsCallbackWrapper(callback, callbackExecutor));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Classify actions and entities in content selections, as returned from
+     * suggestContentSelections. Note these selections may be modified by the
+     * caller before being passed here.
+     *
+     * @param request containing the selections to classify.
+     * @param callbackExecutor to execute the provided callback on.
+     * @param callback to receive the classifications.
+     */
+    public void classifyContentSelections(
+            @NonNull ClassificationsRequest request,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull ClassificationsCallback callback) {
+        if (mService == null) {
+            Log.e(TAG, "classifyContentSelections called, "
+                    + "but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.classifyContentSelections(
+                    request, new ClassificationsCallbackWrapper(callback, callbackExecutor));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Report telemetry for interaction with suggestions / classifications.
+     *
+     * @param requestId the id for the associated interaction
+     * @param interaction to report back to the system content suggestions service.
+     */
+    public void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction) {
+        if (mService == null) {
+            Log.e(TAG, "notifyInteraction called, but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.notifyInteraction(requestId, interaction);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Callback to receive content selections from
+     *  {@link #suggestContentSelections(SelectionsRequest, Executor, SelectionsCallback)}.
+     */
+    public interface SelectionsCallback {
+        /**
+         * Async callback called when the content suggestions service has selections available.
+         * These can be modified and sent back to the manager for classification. The contents of
+         * the selection is implementation dependent.
+         *
+         * @param statusCode as defined by the implementation of content suggestions service.
+         * @param selections not {@code null}, but can be size {@code 0}.
+         */
+        void onContentSelectionsAvailable(
+                int statusCode, @NonNull List<ContentSelection> selections);
+    }
+
+    /**
+     * Callback to receive classifications from
+     * {@link #classifyContentSelections(ClassificationsRequest, Executor, ClassificationsCallback)}
+     */
+    public interface ClassificationsCallback {
+        /**
+         * Async callback called when the content suggestions service has classified selections. The
+         * contents of the classification is implementation dependent.
+         *
+         * @param statusCode as defined by the implementation of content suggestions service.
+         * @param classifications not {@code null}, but can be size {@code 0}.
+         */
+        void onContentClassificationsAvailable(int statusCode,
+                @NonNull List<ContentClassification> classifications);
+    }
+
+    private static class SelectionsCallbackWrapper extends ISelectionsCallback.Stub {
+        private final SelectionsCallback mCallback;
+        private final Executor mExecutor;
+
+        SelectionsCallbackWrapper(
+                @NonNull SelectionsCallback callback, @NonNull Executor executor) {
+            mCallback = callback;
+            mExecutor = executor;
+        }
+
+        @Override
+        public void onContentSelectionsAvailable(
+                int statusCode, List<ContentSelection> selections) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mCallback.onContentSelectionsAvailable(statusCode, selections));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    private static final class ClassificationsCallbackWrapper extends
+            IClassificationsCallback.Stub {
+        private final ClassificationsCallback mCallback;
+        private final Executor mExecutor;
+
+        ClassificationsCallbackWrapper(@NonNull ClassificationsCallback callback,
+                @NonNull Executor executor) {
+            mCallback = callback;
+            mExecutor = executor;
+        }
+
+        @Override
+        public void onContentClassificationsAvailable(
+                int statusCode, List<ContentClassification> classifications) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mCallback.onContentClassificationsAvailable(statusCode, classifications));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl b/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl
new file mode 100644
index 0000000..69f5d55
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl
@@ -0,0 +1,25 @@
+/**
+ * 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.app.contentsuggestions;
+
+import android.app.contentsuggestions.ContentClassification;
+
+/** @hide */
+oneway interface IClassificationsCallback {
+    void onContentClassificationsAvailable(
+            int statusCode, in List<ContentClassification> classifications);
+}
diff --git a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
new file mode 100644
index 0000000..24f5ad8
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.os.Bundle;
+
+/** @hide */
+oneway interface IContentSuggestionsManager {
+    void provideContextImage(
+            int taskId,
+            in Bundle imageContextRequestExtras);
+    void suggestContentSelections(
+            in SelectionsRequest request,
+            in ISelectionsCallback callback);
+    void classifyContentSelections(
+            in ClassificationsRequest request,
+            in IClassificationsCallback callback);
+    void notifyInteraction(in String requestId, in Bundle interaction);
+}
diff --git a/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl b/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl
new file mode 100644
index 0000000..1952583
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl
@@ -0,0 +1,25 @@
+/**
+ * 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.app.contentsuggestions;
+
+import android.app.contentsuggestions.ContentSelection;
+import android.os.Bundle;
+
+/** @hide */
+oneway interface ISelectionsCallback {
+    void onContentSelectionsAvailable(int statusCode, in List<ContentSelection> selections);
+}
diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.aidl b/core/java/android/app/contentsuggestions/SelectionsRequest.aidl
new file mode 100644
index 0000000..f5ce7c3
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.app.contentsuggestions;
+
+parcelable SelectionsRequest;
diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.java b/core/java/android/app/contentsuggestions/SelectionsRequest.java
new file mode 100644
index 0000000..16f3e6b
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class SelectionsRequest implements Parcelable {
+    private final int mTaskId;
+    @Nullable
+    private final Point mInterestPoint;
+    @Nullable
+    private final Bundle mExtras;
+
+    private SelectionsRequest(int taskId, @Nullable Point interestPoint, @Nullable Bundle extras) {
+        mTaskId = taskId;
+        mInterestPoint = interestPoint;
+        mExtras = extras;
+    }
+
+    /**
+     * Return the request task id.
+     */
+    public int getTaskId() {
+        return mTaskId;
+    }
+
+    /**
+     * Return the request point of interest.
+     */
+    public Point getInterestPoint() {
+        return mInterestPoint;
+    }
+
+    /**
+     * Return the request extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mTaskId);
+        dest.writeTypedObject(mInterestPoint, flags);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<SelectionsRequest> CREATOR =
+            new Creator<SelectionsRequest>() {
+        @Override
+        public SelectionsRequest createFromParcel(Parcel source) {
+            return new SelectionsRequest(
+                    source.readInt(), source.readTypedObject(Point.CREATOR), source.readBundle());
+        }
+
+        @Override
+        public SelectionsRequest[] newArray(int size) {
+            return new SelectionsRequest[size];
+        }
+    };
+
+    /**
+     * A builder for selections requests events.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final int mTaskId;
+        private Point mInterestPoint;
+        private Bundle mExtras;
+
+        public Builder(int taskId) {
+            mTaskId = taskId;
+        }
+
+        /**
+         * Sets the request extras.
+         */
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Sets the request interest point.
+         */
+        public Builder setInterestPoint(@NonNull Point interestPoint) {
+            mInterestPoint = interestPoint;
+            return this;
+        }
+
+        /**
+         * Builds a new request instance.
+         */
+        public SelectionsRequest build() {
+            return new SelectionsRequest(mTaskId, mInterestPoint, mExtras);
+        }
+    }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 1626d30..fb28307 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3975,6 +3975,15 @@
     public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
 
     /**
+     * Used for getting content selections and classifications for task snapshots.
+     *
+     * @hide
+     * @see #getSystemService(String)
+     */
+    @SystemApi
+    public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
+
+    /**
      * Official published name of the app prediction service.
      *
      * @hide
diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
new file mode 100644
index 0000000..0da8039
--- /dev/null
+++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
@@ -0,0 +1,154 @@
+/*
+ * 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.contentsuggestions;
+
+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.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.ContentSuggestionsManager;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+/**
+ * @hide
+ */
+@SystemApi
+public abstract class ContentSuggestionsService extends Service {
+
+    private static final String TAG = ContentSuggestionsService.class.getSimpleName();
+
+    private Handler mHandler;
+
+    /**
+     * The action for the intent used to define the content suggestions service.
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.service.contentsuggestions.ContentSuggestionsService";
+
+    private final IContentSuggestionsService mInterface = new IContentSuggestionsService.Stub() {
+        @Override
+        public void provideContextImage(int taskId, GraphicBuffer contextImage,
+                Bundle imageContextRequestExtras) {
+            mHandler.sendMessage(
+                    obtainMessage(ContentSuggestionsService::processContextImage,
+                            ContentSuggestionsService.this, taskId,
+                            Bitmap.createHardwareBitmap(contextImage),
+                            imageContextRequestExtras));
+        }
+
+        @Override
+        public void suggestContentSelections(SelectionsRequest request,
+                ISelectionsCallback callback) {
+            mHandler.sendMessage(obtainMessage(ContentSuggestionsService::suggestContentSelections,
+                    ContentSuggestionsService.this, request, wrapSelectionsCallback(callback)));
+
+        }
+
+        @Override
+        public void classifyContentSelections(ClassificationsRequest request,
+                IClassificationsCallback callback) {
+            mHandler.sendMessage(obtainMessage(ContentSuggestionsService::classifyContentSelections,
+                    ContentSuggestionsService.this, request, wrapClassificationCallback(callback)));
+        }
+
+        @Override
+        public void notifyInteraction(String requestId, Bundle interaction) {
+            mHandler.sendMessage(
+                    obtainMessage(ContentSuggestionsService::notifyInteraction,
+                            ContentSuggestionsService.this, requestId, interaction));
+        }
+    };
+
+    @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;
+    }
+
+    /**
+     * Called by the system to provide the snapshot for the task associated with the given
+     * {@param taskId}.
+     */
+    public abstract void processContextImage(
+            int taskId, @Nullable Bitmap contextImage, @NonNull Bundle extras);
+
+    /**
+     * Called by a client app to make a request for content selections.
+     */
+    public abstract void suggestContentSelections(@NonNull SelectionsRequest request,
+            @NonNull ContentSuggestionsManager.SelectionsCallback callback);
+
+    /**
+     * Called by a client app to classify the provided content selections.
+     */
+    public abstract void classifyContentSelections(@NonNull ClassificationsRequest request,
+            @NonNull ContentSuggestionsManager.ClassificationsCallback callback);
+
+    /**
+     * Called by a client app to report an interaction.
+     */
+    public abstract void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction);
+
+    private ContentSuggestionsManager.SelectionsCallback wrapSelectionsCallback(
+            ISelectionsCallback callback) {
+        return (statusCode, selections) -> {
+            try {
+                callback.onContentSelectionsAvailable(statusCode, selections);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending result: " + e);
+            }
+        };
+    }
+
+    private ContentSuggestionsManager.ClassificationsCallback wrapClassificationCallback(
+            IClassificationsCallback callback) {
+        return ((statusCode, classifications) -> {
+            try {
+                callback.onContentClassificationsAvailable(statusCode, classifications);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending result: " + e);
+            }
+        });
+    }
+}
diff --git a/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl b/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl
new file mode 100644
index 0000000..1926478
--- /dev/null
+++ b/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.contentsuggestions;
+
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+
+/**
+ * Interface from the system to an implementation of a content suggestions service.
+ *
+ * @hide
+ */
+oneway interface IContentSuggestionsService {
+    void provideContextImage(
+            int taskId,
+            in GraphicBuffer contextImage,
+            in Bundle imageContextRequestExtras);
+    void suggestContentSelections(
+            in SelectionsRequest request,
+            in ISelectionsCallback callback);
+    void classifyContentSelections(
+            in ClassificationsRequest request,
+            in IClassificationsCallback callback);
+    void notifyInteraction(in String requestId, in Bundle interaction);
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3fa7cfb..e73267b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4254,6 +4254,11 @@
     <permission android:name="android.permission.MANAGE_CONTENT_CAPTURE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to manage the content suggestions service.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS"
+         android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to manage the app predictions service.
          @hide  <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.MANAGE_APP_PREDICTIONS"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 22bff7d..928d73c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3425,6 +3425,17 @@
     -->
     <string name="config_defaultAppPredictionService" translatable="false"></string>
 
+    <!-- The package name for the system's content suggestions service.
+         Provides suggestions for text and image selection regions in snapshots of apps and should
+         be able to classify the type of entities in those selections.
+
+         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 suggestions wil be
+         disabled.
+         Example: "com.android.contentsuggestions/.ContentSuggestionsService"
+    -->
+    <string name="config_defaultContentSuggestionsService" 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 d9dbb10..4089109 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3276,6 +3276,7 @@
   <java-symbol type="string" name="config_defaultContentCaptureService" />
   <java-symbol type="string" name="config_defaultAugmentedAutofillService" />
   <java-symbol type="string" name="config_defaultAppPredictionService" />
+  <java-symbol type="string" name="config_defaultContentSuggestionsService" />
 
   <java-symbol type="string" name="notification_channel_foreground_service" />
   <java-symbol type="string" name="foreground_service_app_in_background" />
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 562d44d..fa2289d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -134,6 +134,7 @@
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
     <uses-permission android:name="android.permission.MANAGE_AUTO_FILL" />
     <uses-permission android:name="android.permission.MANAGE_CONTENT_CAPTURE" />
+    <uses-permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" />
     <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
     <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
diff --git a/services/Android.bp b/services/Android.bp
index 8e96ccc..567efac 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -23,6 +23,7 @@
         "services.backup",
         "services.companion",
         "services.contentcapture",
+        "services.contentsuggestions",
         "services.coverage",
         "services.devicepolicy",
         "services.midi",
diff --git a/services/contentsuggestions/Android.bp b/services/contentsuggestions/Android.bp
new file mode 100644
index 0000000..fc09d2e
--- /dev/null
+++ b/services/contentsuggestions/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+    name: "services.contentsuggestions",
+    srcs: ["java/**/*.java"],
+    libs: ["services.core"],
+}
\ No newline at end of file
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
new file mode 100644
index 0000000..58dbea4
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -0,0 +1,205 @@
+/*
+ * 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 com.android.server.contentsuggestions;
+
+import static android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.IContentSuggestionsManager;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.io.FileDescriptor;
+
+/**
+ * The system service for providing recents / overview with content suggestion selections and
+ * classifications.
+ *
+ * <p>Calls are received here from
+ * {@link android.app.contentsuggestions.ContentSuggestionsManager} then delegated to
+ * a per user version of the service. From there they are routed to the remote actual implementation
+ * that provides the suggestion selections and classifications.
+ */
+public class ContentSuggestionsManagerService extends
+        AbstractMasterSystemService<
+                        ContentSuggestionsManagerService, ContentSuggestionsPerUserService> {
+
+    private static final String TAG = ContentSuggestionsManagerService.class.getSimpleName();
+    private static final boolean VERBOSE = false; // TODO: make dynamic
+
+    private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+
+    private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+    public ContentSuggestionsManagerService(Context context) {
+        super(context, new FrameworkResourcesServiceNameResolver(context,
+                com.android.internal.R.string.config_defaultContentSuggestionsService), null);
+        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+    }
+
+    @Override
+    protected ContentSuggestionsPerUserService newServiceLocked(int resolvedUserId,
+            boolean disabled) {
+        return new ContentSuggestionsPerUserService(this, mLock, resolvedUserId);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(
+                Context.CONTENT_SUGGESTIONS_SERVICE, new ContentSuggestionsManagerStub());
+    }
+
+    @Override
+    protected void enforceCallingPermissionForManagement() {
+        getContext().enforceCallingPermission(MANAGE_CONTENT_SUGGESTIONS, TAG);
+    }
+
+    @Override
+    protected int getMaximumTemporaryServiceDurationMs() {
+        return MAX_TEMP_SERVICE_DURATION_MS;
+    }
+
+    private boolean isCallerRecents(int userId) {
+        if (mServiceNameResolver.isTemporary(userId)) {
+            // If a temporary service is set then skip the recents check
+            return true;
+        }
+        return mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid());
+    }
+
+    private void enforceCallerIsRecents(int userId, String func) {
+        if (isCallerRecents(userId)) {
+            return;
+        }
+
+        String msg = "Permission Denial: " + func + " from pid="
+                + Binder.getCallingPid()
+                + ", uid=" + Binder.getCallingUid()
+                + " expected caller is recents";
+        Slog.w(TAG, msg);
+        throw new SecurityException(msg);
+    }
+
+    private class ContentSuggestionsManagerStub extends IContentSuggestionsManager.Stub {
+        @Override
+        public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+            if (imageContextRequestExtras == null) {
+                throw new IllegalArgumentException("Expected non-null imageContextRequestExtras");
+            }
+
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "provideContextImage");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.provideContextImageLocked(taskId, imageContextRequestExtras);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "provideContextImageLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void suggestContentSelections(
+                @NonNull SelectionsRequest selectionsRequest,
+                @NonNull ISelectionsCallback selectionsCallback) {
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "suggestContentSelections");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.suggestContentSelectionsLocked(selectionsRequest, selectionsCallback);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "suggestContentSelectionsLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void classifyContentSelections(
+                @NonNull ClassificationsRequest classificationsRequest,
+                @NonNull IClassificationsCallback callback) {
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "classifyContentSelections");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.classifyContentSelectionsLocked(classificationsRequest, callback);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "classifyContentSelectionsLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void notifyInteraction(@NonNull String requestId, @NonNull Bundle bundle) {
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "notifyInteraction");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.notifyInteractionLocked(requestId, bundle);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "reportInteractionLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+                @Nullable FileDescriptor err,
+                @NonNull String[] args, @Nullable ShellCallback callback,
+                @NonNull ResultReceiver resultReceiver) throws RemoteException {
+            // Ensure that the caller is the shell process
+            final int callingUid = Binder.getCallingUid();
+            if (callingUid != android.os.Process.SHELL_UID
+                    && callingUid != android.os.Process.ROOT_UID) {
+                Slog.e(TAG, "Expected shell caller");
+                return;
+            }
+            new ContentSuggestionsManagerServiceShellCommand(ContentSuggestionsManagerService.this)
+                    .exec(this, in, out, err, args, callback, resultReceiver);
+        }
+    }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java
new file mode 100644
index 0000000..e34f1ea
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java
@@ -0,0 +1,84 @@
+/*
+ * 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 com.android.server.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * The shell command implementation for the ContentSuggestionsManagerService.
+ */
+public class ContentSuggestionsManagerServiceShellCommand extends ShellCommand {
+
+    private static final String TAG =
+            ContentSuggestionsManagerServiceShellCommand.class.getSimpleName();
+
+    private final ContentSuggestionsManagerService mService;
+
+    public ContentSuggestionsManagerServiceShellCommand(
+            @NonNull ContentSuggestionsManagerService service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        switch (cmd) {
+            case "set": {
+                final String what = getNextArgRequired();
+                switch (what) {
+                    case "temporary-service": {
+                        final int userId = Integer.parseInt(getNextArgRequired());
+                        String serviceName = getNextArg();
+                        if (serviceName == null) {
+                            mService.resetTemporaryService(userId);
+                            return 0;
+                        }
+                        final int duration = Integer.parseInt(getNextArgRequired());
+                        mService.setTemporaryService(userId, serviceName, duration);
+                        pw.println("ContentSuggestionsService temporarily set to " + serviceName
+                                + " for " + duration + "ms");
+                        break;
+                    }
+                }
+            }
+            break;
+            default:
+                return handleDefaultCommands(cmd);
+        }
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        try (PrintWriter pw = getOutPrintWriter()) {
+            pw.println("ContentSuggestionsManagerService commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+            pw.println("    Temporarily (for DURATION ms) changes the service implemtation.");
+            pw.println("    To reset, call with just the USER_ID argument.");
+            pw.println("");
+        }
+    }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
new file mode 100644
index 0000000..385bc6c
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
@@ -0,0 +1,162 @@
+/*
+ * 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 com.android.server.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractPerUserSystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+/**
+ * Per user delegate of {@link ContentSuggestionsManagerService}.
+ *
+ * <p>Main job is to forward calls to the remote implementation that can provide suggestion
+ * selections and classifications.
+ */
+public final class ContentSuggestionsPerUserService extends
+        AbstractPerUserSystemService<
+                        ContentSuggestionsPerUserService, ContentSuggestionsManagerService> {
+    private static final String TAG = ContentSuggestionsPerUserService.class.getSimpleName();
+
+    @Nullable
+    @GuardedBy("mLock")
+    private RemoteContentSuggestionsService mRemoteService;
+
+    @NonNull
+    private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+    ContentSuggestionsPerUserService(
+            ContentSuggestionsManagerService master, Object lock, int userId) {
+        super(master, lock, userId);
+        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+            throws PackageManager.NameNotFoundException {
+        ServiceInfo si;
+        try {
+            si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+                    PackageManager.GET_META_DATA, mUserId);
+        } catch (RemoteException e) {
+            throw new PackageManager.NameNotFoundException(
+                    "Could not get service for " + serviceComponent);
+        }
+        return si;
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected boolean updateLocked(boolean disabled) {
+        final boolean enabledChanged = super.updateLocked(disabled);
+        if (enabledChanged) {
+            if (!isEnabledLocked()) {
+                // Clear the remote service for the next call
+                mRemoteService = null;
+            }
+        }
+        return enabledChanged;
+    }
+
+    @GuardedBy("mLock")
+    void provideContextImageLocked(int taskId, @NonNull Bundle imageContextRequestExtras) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            ActivityManager.TaskSnapshot snapshot =
+                    mActivityTaskManagerInternal.getTaskSnapshot(taskId, false);
+            GraphicBuffer snapshotBuffer = null;
+            if (snapshot != null) {
+                snapshotBuffer = snapshot.getSnapshot();
+            }
+
+            service.provideContextImage(taskId, snapshotBuffer, imageContextRequestExtras);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void suggestContentSelectionsLocked(
+            @NonNull SelectionsRequest selectionsRequest,
+            @NonNull ISelectionsCallback selectionsCallback) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.suggestContentSelections(selectionsRequest, selectionsCallback);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void classifyContentSelectionsLocked(
+            @NonNull ClassificationsRequest classificationsRequest,
+            @NonNull IClassificationsCallback callback) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.classifyContentSelections(classificationsRequest, callback);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void notifyInteractionLocked(@NonNull String requestId, @NonNull Bundle bundle) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.notifyInteraction(requestId, bundle);
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private RemoteContentSuggestionsService getRemoteServiceLocked() {
+        if (mRemoteService == null) {
+            final String serviceName = getComponentNameLocked();
+            if (serviceName == null) {
+                if (mMaster.verbose) {
+                    Slog.v(TAG, "getRemoteServiceLocked(): not set");
+                }
+                return null;
+            }
+            ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+
+            mRemoteService = new RemoteContentSuggestionsService(getContext(),
+                    serviceComponent, mUserId,
+                    new RemoteContentSuggestionsService.Callbacks() {
+                        @Override
+                        public void onServiceDied(
+                                @NonNull RemoteContentSuggestionsService service) {
+                            // TODO(b/120865921): properly implement
+                            Slog.w(TAG, "remote content suggestions service died");
+                        }
+                    }, mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+        }
+
+        return mRemoteService;
+    }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java
new file mode 100644
index 0000000..bf48d76
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java
@@ -0,0 +1,97 @@
+/*
+ * 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 com.android.server.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.service.contentsuggestions.ContentSuggestionsService;
+import android.service.contentsuggestions.IContentSuggestionsService;
+import android.text.format.DateUtils;
+
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+
+/**
+ * Delegates calls from {@link ContentSuggestionsPerUserService} to the remote actual implementation
+ * of the suggestion selection and classification service.
+ */
+public class RemoteContentSuggestionsService extends
+        AbstractMultiplePendingRequestsRemoteService<RemoteContentSuggestionsService,
+                                IContentSuggestionsService> {
+
+    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+
+    RemoteContentSuggestionsService(Context context, ComponentName serviceName,
+            int userId, Callbacks callbacks,
+            boolean bindInstantServiceAllowed, boolean verbose) {
+        super(context, ContentSuggestionsService.SERVICE_INTERFACE, serviceName, userId, callbacks,
+                bindInstantServiceAllowed, verbose, /* initialCapacity= */ 1);
+    }
+
+    @Override
+    protected IContentSuggestionsService getServiceInterface(IBinder service) {
+        return IContentSuggestionsService.Stub.asInterface(service);
+    }
+
+    @Override
+    protected long getTimeoutIdleBindMillis() {
+        return PERMANENT_BOUND_TIMEOUT_MS;
+    }
+
+    @Override
+    protected long getRemoteRequestMillis() {
+        return TIMEOUT_REMOTE_REQUEST_MILLIS;
+    }
+
+    void provideContextImage(int taskId, @Nullable GraphicBuffer contextImage,
+            @NonNull Bundle imageContextRequestExtras) {
+        scheduleAsyncRequest((s) -> s.provideContextImage(taskId, contextImage,
+                imageContextRequestExtras));
+    }
+
+    void suggestContentSelections(
+            @NonNull SelectionsRequest selectionsRequest,
+            @NonNull ISelectionsCallback selectionsCallback) {
+        scheduleAsyncRequest(
+                (s) -> s.suggestContentSelections(selectionsRequest, selectionsCallback));
+    }
+
+    void classifyContentSelections(
+            @NonNull ClassificationsRequest classificationsRequest,
+            @NonNull IClassificationsCallback callback) {
+        scheduleAsyncRequest((s) -> s.classifyContentSelections(classificationsRequest, callback));
+    }
+
+    void notifyInteraction(@NonNull String requestId, @NonNull Bundle bundle) {
+        scheduleAsyncRequest((s) -> s.notifyInteraction(requestId, bundle));
+    }
+
+    interface Callbacks
+            extends VultureCallback<RemoteContentSuggestionsService> {
+        // NOTE: so far we don't need to notify the callback implementation
+        // (ContentSuggestionsManager) of the request results (success, timeouts, etc..), so this
+        // callback interface is empty.
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0f286ce..d8644df 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.AppProtoEnums;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
@@ -479,4 +480,10 @@
     public abstract void setProfilerInfo(ProfilerInfo profilerInfo);
 
     public abstract ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry();
+
+    /**
+     * Gets bitmap snapshot of the provided task id.
+     */
+    public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId,
+            boolean reducedResolution);
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 42121ca..28515ff 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -7012,5 +7012,12 @@
                 return mStackSupervisor.getActivityMetricsLogger().getLaunchObserverRegistry();
             }
         }
+
+        @Override
+        public ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution) {
+            synchronized (mGlobalLock) {
+                return ActivityTaskManagerService.this.getTaskSnapshot(taskId, reducedResolution);
+            }
+        }
     }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ced4261..1fef5b0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -262,6 +262,8 @@
             "com.android.server.adb.AdbService$Lifecycle";
     private static final String APP_PREDICTION_MANAGER_SERVICE_CLASS =
             "com.android.server.appprediction.AppPredictionManagerService";
+    private static final String CONTENT_SUGGESTIONS_SERVICE_CLASS =
+            "com.android.server.contentsuggestions.ContentSuggestionsManagerService";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -1160,6 +1162,11 @@
             mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
             traceEnd();
 
+            // Content suggestions manager service
+            traceBeginAndSlog("StartContentSuggestionsService");
+            mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS);
+            traceEnd();
+
             // NOTE: ClipboardService indirectly depends on IntelligenceService
             traceBeginAndSlog("StartClipboardService");
             mSystemServiceManager.startService(ClipboardService.class);