Merge "Extend assist context to foreground services"
diff --git a/api/current.txt b/api/current.txt
index b8795f3..d79a8c0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4228,6 +4228,7 @@
     method public void onCreate();
     method public void onDestroy();
     method public void onLowMemory();
+    method public void onProvideAssistData(android.os.Bundle);
     method public void onRebind(android.content.Intent);
     method public deprecated void onStart(android.content.Intent, int);
     method public int onStartCommand(android.content.Intent, int, int);
@@ -6273,6 +6274,8 @@
     field public static final deprecated java.lang.String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
     field public static final java.lang.String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
     field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
+    field public static final java.lang.String EXTRA_ASSIST_SERVICES_CONTEXTS = "android.intent.extra.ASSIST_SERVICES_CONTEXTS";
+    field public static final java.lang.String EXTRA_ASSIST_SERVICES_PACKAGES = "android.intent.extra.ASSIST_SERVICES_PACKAGES";
     field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
     field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
     field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -7337,6 +7340,7 @@
     method public void dump(android.util.Printer, java.lang.String);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2
+    field public static final int FLAG_PROVIDE_ASSIST_DATA = 4; // 0x4
     field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
     field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
     field public int flags;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 404f6aa..cc964c2 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1921,20 +1921,21 @@
             return true;
         }
 
-        case GET_TOP_ACTIVITY_EXTRAS_TRANSACTION: {
+        case GET_ASSIST_CONTEXT_EXTRAS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int requestType = data.readInt();
-            Bundle res = getTopActivityExtras(requestType);
+            Bundle res = getAssistContextExtras(requestType);
             reply.writeNoException();
             reply.writeBundle(res);
             return true;
         }
 
-        case REPORT_TOP_ACTIVITY_EXTRAS_TRANSACTION: {
+        case REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
             Bundle extras = data.readBundle();
-            reportTopActivityExtras(token, extras);
+            int index = data.readInt();
+            reportAssistContextExtras(token, extras, index);
             reply.writeNoException();
             return true;
         }
@@ -4456,12 +4457,12 @@
         return res;
     }
 
-    public Bundle getTopActivityExtras(int requestType) throws RemoteException {
+    public Bundle getAssistContextExtras(int requestType) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(requestType);
-        mRemote.transact(GET_TOP_ACTIVITY_EXTRAS_TRANSACTION, data, reply, 0);
+        mRemote.transact(GET_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
         reply.readException();
         Bundle res = reply.readBundle();
         data.recycle();
@@ -4469,13 +4470,15 @@
         return res;
     }
 
-    public void reportTopActivityExtras(IBinder token, Bundle extras) throws RemoteException {
+    public void reportAssistContextExtras(IBinder token, Bundle extras, int index)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
         data.writeBundle(extras);
-        mRemote.transact(REPORT_TOP_ACTIVITY_EXTRAS_TRANSACTION, data, reply, 0);
+        data.writeInt(index);
+        mRemote.transact(REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5300eca..2a28b76 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -529,10 +529,11 @@
         CompatibilityInfo info;
     }
 
-    static final class RequestActivityExtras {
+    static final class RequestAssistContextExtras {
         IBinder activityToken;
         IBinder requestToken;
         int requestType;
+        int index;
     }
 
     private native void dumpGraphicsInfo(FileDescriptor fd);
@@ -1197,13 +1198,14 @@
         }
 
         @Override
-        public void requestActivityExtras(IBinder activityToken, IBinder requestToken,
-                int requestType) {
-            RequestActivityExtras cmd = new RequestActivityExtras();
+        public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
+                int requestType, int index) {
+            RequestAssistContextExtras cmd = new RequestAssistContextExtras();
             cmd.activityToken = activityToken;
             cmd.requestToken = requestToken;
             cmd.requestType = requestType;
-            queueOrSendMessage(H.REQUEST_ACTIVITY_EXTRAS, cmd);
+            cmd.index = index;
+            queueOrSendMessage(H.REQUEST_ASSIST_CONTEXT_EXTRAS, cmd);
         }
 
         private void printRow(PrintWriter pw, String format, Object...objs) {
@@ -1292,7 +1294,7 @@
         public static final int TRIM_MEMORY             = 140;
         public static final int DUMP_PROVIDER           = 141;
         public static final int UNSTABLE_PROVIDER_DIED  = 142;
-        public static final int REQUEST_ACTIVITY_EXTRAS = 143;
+        public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
         public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
@@ -1340,7 +1342,7 @@
                     case TRIM_MEMORY: return "TRIM_MEMORY";
                     case DUMP_PROVIDER: return "DUMP_PROVIDER";
                     case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
-                    case REQUEST_ACTIVITY_EXTRAS: return "REQUEST_ACTIVITY_EXTRAS";
+                    case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS";
                     case TRANSLUCENT_CONVERSION_COMPLETE: return "TRANSLUCENT_CONVERSION_COMPLETE";
                 }
             }
@@ -1553,8 +1555,8 @@
                 case UNSTABLE_PROVIDER_DIED:
                     handleUnstableProviderDied((IBinder)msg.obj, false);
                     break;
-                case REQUEST_ACTIVITY_EXTRAS:
-                    handleRequestActivityExtras((RequestActivityExtras)msg.obj);
+                case REQUEST_ASSIST_CONTEXT_EXTRAS:
+                    handleRequestAssistContextExtras((RequestAssistContextExtras)msg.obj);
                     break;
                 case TRANSLUCENT_CONVERSION_COMPLETE:
                     handleTranslucentConversionComplete((IBinder)msg.obj, msg.arg1 == 1);
@@ -2275,19 +2277,24 @@
         performNewIntents(data.token, data.intents);
     }
 
-    public void handleRequestActivityExtras(RequestActivityExtras cmd) {
+    public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
         Bundle data = new Bundle();
         ActivityClientRecord r = mActivities.get(cmd.activityToken);
         if (r != null) {
             r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
             r.activity.onProvideAssistData(data);
+        } else {
+            Service service = mServices.get(cmd.activityToken);
+            if (service != null) {
+                service.onProvideAssistData(data);
+            }
         }
         if (data.isEmpty()) {
             data = null;
         }
         IActivityManager mgr = ActivityManagerNative.getDefault();
         try {
-            mgr.reportTopActivityExtras(cmd.requestToken, data);
+            mgr.reportAssistContextExtras(cmd.requestToken, data, cmd.index);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 1465de2..c0080be 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -600,13 +600,14 @@
             return true;
         }
 
-        case REQUEST_ACTIVITY_EXTRAS_TRANSACTION:
+        case REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION:
         {
             data.enforceInterface(IApplicationThread.descriptor);
             IBinder activityToken = data.readStrongBinder();
             IBinder requestToken = data.readStrongBinder();
             int requestType = data.readInt();
-            requestActivityExtras(activityToken, requestToken, requestType);
+            int index = data.readInt();
+            requestAssistContextExtras(activityToken, requestToken, requestType, index);
             reply.writeNoException();
             return true;
         }
@@ -1241,14 +1242,16 @@
     }
 
     @Override
-    public void requestActivityExtras(IBinder activityToken, IBinder requestToken, int requestType)
-            throws RemoteException {
+    public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
+            int requestType, int index) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(activityToken);
         data.writeStrongBinder(requestToken);
         data.writeInt(requestType);
-        mRemote.transact(REQUEST_ACTIVITY_EXTRAS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+        data.writeInt(index);
+        mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, null,
+                IBinder.FLAG_ONEWAY);
         data.recycle();
     }
 
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3eda58c..3851eb3 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -386,9 +386,10 @@
 
     public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException;
 
-    public Bundle getTopActivityExtras(int requestType) throws RemoteException;
+    public Bundle getAssistContextExtras(int requestType) throws RemoteException;
 
-    public void reportTopActivityExtras(IBinder token, Bundle extras) throws RemoteException;
+    public void reportAssistContextExtras(IBinder token, Bundle extras, int index)
+            throws RemoteException;
 
     public void killUid(int uid, String reason) throws RemoteException;
 
@@ -662,8 +663,8 @@
     int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158;
     int CLEAR_PENDING_BACKUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+159;
     int GET_INTENT_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+160;
-    int GET_TOP_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+161;
-    int REPORT_TOP_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+162;
+    int GET_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+161;
+    int REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+162;
     int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163;
     int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164;
     int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 61c499a..01a0a91 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -133,8 +133,8 @@
     void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void unstableProviderDied(IBinder provider) throws RemoteException;
-    void requestActivityExtras(IBinder activityToken, IBinder requestToken, int requestType)
-            throws RemoteException;
+    void requestAssistContextExtras(IBinder activityToken, IBinder requestToken, int requestType,
+            int index) throws RemoteException;
     void scheduleTranslucentConversionComplete(IBinder token, boolean timeout)
             throws RemoteException;
     void setProcessState(int state) throws RemoteException;
@@ -187,7 +187,7 @@
     int DUMP_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+44;
     int DUMP_DB_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+45;
     int UNSTABLE_PROVIDER_DIED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+46;
-    int REQUEST_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+47;
+    int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+47;
     int SCHEDULE_TRANSLUCENT_CONVERSION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+48;
     int SET_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+49;
 }
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 7dfc589f..f9c245e 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -869,7 +869,7 @@
             intent.setComponent(comp);
             if (inclContext) {
                 IActivityManager am = ActivityManagerNative.getDefault();
-                Bundle extras = am.getTopActivityExtras(0);
+                Bundle extras = am.getAssistContextExtras(0);
                 if (extras != null) {
                     intent.replaceExtras(extras);
                 }
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 3967740..7f8ddfd 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.util.Log;
@@ -307,6 +308,18 @@
     }
 
     /**
+     * This is called on foreground services when the user is requesting an assist, to build a
+     * full {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
+     * running foreground services.  You can override this method to place into the bundle
+     * anything you would like to appear as an item in the
+     * {@link Intent#EXTRA_SERVICES_ASSIST_CONTEXT} part of the assist Intent.
+     * This method will not be called if this service is not in the foreground.
+     * The default implementation does nothing.
+     */
+    public void onProvideAssistData(Bundle data) {
+    }
+
+    /**
      * @deprecated Implement {@link #onStartCommand(Intent, int, int)} instead.
      */
     @Deprecated
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 205ca6b..ff350b9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1152,9 +1152,10 @@
     /**
      * Activity Action: Perform assist action.
      * <p>
-     * Input: {@link #EXTRA_ASSIST_PACKAGE} and {@link #EXTRA_ASSIST_CONTEXT} can provide
-     * additional optional contextual information about where the user was when they requested
-     * the assist.
+     * Input: {@link #EXTRA_ASSIST_PACKAGE}, {@link #EXTRA_ASSIST_CONTEXT},
+     * {@link #EXTRA_ASSIST_SERVICES_PACKAGES}, and {@link #EXTRA_ASSIST_SERVICES_CONTEXTS} can
+     * provide additional optional contextual information about where the user was when they
+     * requested the assist.
      * Output: nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -1163,9 +1164,10 @@
     /**
      * Activity Action: Perform voice assist action.
      * <p>
-     * Input: {@link #EXTRA_ASSIST_PACKAGE} and {@link #EXTRA_ASSIST_CONTEXT} can provide
-     * additional optional contextual information about where the user was when they requested
-     * the voice assist.
+     * Input: {@link #EXTRA_ASSIST_PACKAGE}, {@link #EXTRA_ASSIST_CONTEXT},
+     * {@link #EXTRA_ASSIST_SERVICES_PACKAGES}, and {@link #EXTRA_ASSIST_SERVICES_CONTEXTS} can
+     * provide additional optional contextual information about where the user was when they
+     * requested the voice assist.
      * Output: nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -1189,6 +1191,25 @@
             = "android.intent.extra.ASSIST_CONTEXT";
 
     /**
+     * An optional field on {@link #ACTION_ASSIST} and {@link #ACTION_VOICE_ASSIST}
+     * containing an the names of the application package of foreground services at the time
+     * of the assist request.  This is an array of {@link String}s, with one entry
+     * per service.
+     */
+    public static final String EXTRA_ASSIST_SERVICES_PACKAGES
+            = "android.intent.extra.ASSIST_SERVICES_PACKAGES";
+
+    /**
+     * An optional field on {@link #ACTION_ASSIST} and {@link #ACTION_VOICE_ASSIST}
+     * containing additional contextual information supplied by the current
+     * foreground services at the time of the assist request.  This is an array
+     * of {@link Bundle}s of additional data, with one {@link Bundle} per service.
+     */
+    public static final String EXTRA_ASSIST_SERVICES_CONTEXTS
+            = "android.intent.extra.ASSIST_SERVICES_CONTEXTS";
+
+
+    /**
      * Activity Action: List all available applications
      * <p>Input: Nothing.
      * <p>Output: nothing.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index aaa2640..b432164 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3005,6 +3005,11 @@
 
         s.info.flags = 0;
         if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestService_provideAssistData,
+                false)) {
+            s.info.flags |= ServiceInfo.FLAG_PROVIDE_ASSIST_DATA;
+        }
+        if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
                 false)) {
             s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 796c2a4..a57a853 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -49,6 +49,14 @@
     public static final int FLAG_ISOLATED_PROCESS = 0x0002;
 
     /**
+     * Bit in {@link #flags}: If set,
+     * {@link Service#onProvideAssistData(android.os.Bundle)} will be
+     * called on the service when it is running in the foreground. Set from
+     * the {@link android.R.attr#provideAssistData} attribute.
+     */
+    public static final int FLAG_PROVIDE_ASSIST_DATA = 0x0004;
+
+    /**
      * Bit in {@link #flags}: If set, a single instance of the service will
      * run for all users on the device.  Set from the
      * {@link android.R.attr#singleUser} attribute.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 728b1b0..60ed0e5 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1379,6 +1379,9 @@
              component specific values). -->
         <attr name="enabled" />
         <attr name="exported" />
+        <!-- If set to true, onProvideAssistData will be called on this service when this service
+             is running in the foreground. -->
+        <attr name="provideAssistData" format="boolean" />
         <!-- If set to true, this service with be automatically stopped
              when the user remove a task rooted in an activity owned by
              the application.  The default is false. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1b5ee68..138debf 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -831,8 +831,8 @@
     <string name="permlab_getTopActivityInfo">get current app info</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getTopActivityInfo">Allows the holder to retrieve private information
-        about the current application in the foreground of the screen.</string>
-    
+        about the current application and services in the foreground of the screen.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_runSetActivityWatcher">monitor and control all app launching</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2d2d468..3d8843e 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -184,6 +184,7 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -306,8 +307,13 @@
     // Maximum number of users we allow to be running at a time.
     static final int MAX_RUNNING_USERS = 3;
 
-    // How long to wait in getTopActivityExtras for the activity to respond with the result.
-    static final int PENDING_ACTIVITY_RESULT_TIMEOUT = 2*2000;
+    // How long to wait in getAssistContextExtras for the activity and foreground services
+    // to respond with the result.
+    static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
+
+    // Index for assist context bundle pertaining to the top activity. Non-negative indices
+    // correspond to assist context bundles from foreground services.
+    static final int TOP_ACTIVITY_ASSIST_EXTRAS_INDEX = -1;
 
     static final int MY_PID = Process.myPid();
 
@@ -383,25 +389,38 @@
      */
     private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
 
-    public class PendingActivityExtras extends Binder implements Runnable {
+    public class PendingAssistExtras extends Binder implements Runnable {
         public final ActivityRecord activity;
-        public boolean haveResult = false;
-        public Bundle result = null;
-        public PendingActivityExtras(ActivityRecord _activity) {
+        public final List<ServiceRecord> services;
+        public int numPending;
+        public int numRespondedServices = 0;
+        public Bundle activityExtras = null;
+        public Bundle[] servicesExtras;
+        public PendingAssistExtras(ActivityRecord _activity, List<ServiceRecord> _services) {
             activity = _activity;
+            services = _services;
+            numPending = services.size() + 1;
         }
         @Override
         public void run() {
-            Slog.w(TAG, "getTopActivityExtras failed: timeout retrieving from " + activity);
+            if (activityExtras == null) {
+                Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from " + activity);
+            }
+            for (int i = 0; i < services.size(); i++) {
+                if (servicesExtras[i] == null) {
+                    Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from "
+                            + services.get(i));
+                }
+            }
             synchronized (this) {
-                haveResult = true;
+                numPending = 0;
                 notifyAll();
             }
         }
     }
 
-    final ArrayList<PendingActivityExtras> mPendingActivityExtras
-            = new ArrayList<PendingActivityExtras>();
+    final ArrayList<PendingAssistExtras> mPendingAssistExtras
+            = new ArrayList<PendingAssistExtras>();
 
     /**
      * Process management.
@@ -7986,60 +8005,110 @@
         return true;
     }
 
-    public Bundle getTopActivityExtras(int requestType) {
+    public Bundle getAssistContextExtras(int requestType) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
-                "getTopActivityExtras()");
-        PendingActivityExtras pae;
+                "getAssistContextExtras()");
+        PendingAssistExtras pae;
         Bundle extras = new Bundle();
+        List<ServiceRecord> foregroundServices;
         synchronized (this) {
-            ActivityRecord activity = getFocusedStack().mResumedActivity;
-            if (activity == null) {
-                Slog.w(TAG, "getTopActivityExtras failed: no resumed activity");
-                return null;
+            Collection<ServiceRecord> allServices = mServices.mServiceMap.getAllServices(
+                    Binder.getCallingUid());
+            foregroundServices = new ArrayList<ServiceRecord>();
+            for (ServiceRecord record : allServices) {
+                if ((record.serviceInfo.flags & ServiceInfo.FLAG_PROVIDE_ASSIST_DATA) > 0 &&
+                        record.isForeground) {
+                    if (record.app == null || record.app.thread == null) {
+                        Slog.w(TAG, "getAssistContextExtras error: no process for " + record);
+                        continue;
+                    }
+                    if (record.app.pid == Binder.getCallingPid()) {
+                        Slog.w(TAG, "getAssistContextExtras error: request process same as " +
+                                record);
+                        continue;
+                    }
+                    foregroundServices.add(record);
+                }
             }
-            extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
+
+            ActivityRecord activity = getFocusedStack().mResumedActivity;
+            boolean validActivity = true;
+            if (activity == null) {
+                Slog.w(TAG, "getAssistContextExtras error: no resumed activity");
+                validActivity = false;
+            }
             if (activity.app == null || activity.app.thread == null) {
-                Slog.w(TAG, "getTopActivityExtras failed: no process for " + activity);
-                return extras;
+                Slog.w(TAG, "getAssistContextExtras error: no process for " + activity);
+                validActivity = false;
             }
             if (activity.app.pid == Binder.getCallingPid()) {
-                Slog.w(TAG, "getTopActivityExtras failed: request process same as " + activity);
-                return extras;
+                Slog.w(TAG, "getAssistContextExtras error: request process same as " + activity);
+                validActivity = false;
             }
-            pae = new PendingActivityExtras(activity);
+
+            pae = new PendingAssistExtras(activity, foregroundServices);
             try {
-                activity.app.thread.requestActivityExtras(activity.appToken, pae, requestType);
-                mPendingActivityExtras.add(pae);
-                mHandler.postDelayed(pae, PENDING_ACTIVITY_RESULT_TIMEOUT);
+                if (validActivity) {
+                    activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
+                            requestType, -1);
+                }
+                for (int i = 0; i < foregroundServices.size(); i++) {
+                    ServiceRecord record = foregroundServices.get(i);
+                    record.app.thread.requestAssistContextExtras(record, pae, requestType, i);
+                }
+                mPendingAssistExtras.add(pae);
+                mHandler.postDelayed(pae, PENDING_ASSIST_EXTRAS_TIMEOUT);
             } catch (RemoteException e) {
-                Slog.w(TAG, "getTopActivityExtras failed: crash calling " + activity);
-                return extras;
+                Slog.w(TAG, "getAssistContextExtras failed: crash fetching extras.", e);
             }
         }
         synchronized (pae) {
-            while (!pae.haveResult) {
+            while (pae.numPending > 0) {
                 try {
                     pae.wait();
                 } catch (InterruptedException e) {
                 }
             }
-            if (pae.result != null) {
-                extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, pae.result);
+            if (pae.activityExtras != null) {
+                extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, pae.activityExtras);
+                extras.putString(Intent.EXTRA_ASSIST_PACKAGE, pae.activity.packageName);
+            }
+            if (pae.numRespondedServices > 0) {
+                Bundle[] servicesExtras = new Bundle[pae.numRespondedServices];
+                String[] servicesPackages = new String[pae.numRespondedServices];
+                int extrasIndex = 0;
+                for (int i = 0; i < foregroundServices.size(); i++) {
+                    if (pae.servicesExtras[i] != null) {
+                        servicesExtras[extrasIndex] = pae.servicesExtras[i];
+                        ServiceRecord record = foregroundServices.get(i);
+                        servicesPackages[extrasIndex] = record.packageName;
+                        extrasIndex++;
+                    }
+                }
+                extras.putParcelableArray(Intent.EXTRA_ASSIST_SERVICES_CONTEXTS, servicesExtras);
+                extras.putStringArray(Intent.EXTRA_ASSIST_SERVICES_PACKAGES, servicesPackages);
             }
         }
         synchronized (this) {
-            mPendingActivityExtras.remove(pae);
+            mPendingAssistExtras.remove(pae);
             mHandler.removeCallbacks(pae);
         }
         return extras;
     }
 
-    public void reportTopActivityExtras(IBinder token, Bundle extras) {
-        PendingActivityExtras pae = (PendingActivityExtras)token;
+    public void reportAssistContextExtras(IBinder token, Bundle extras, int index) {
+        PendingAssistExtras pae = (PendingAssistExtras)token;
         synchronized (pae) {
-            pae.result = extras;
-            pae.haveResult = true;
-            pae.notifyAll();
+            if (index == TOP_ACTIVITY_ASSIST_EXTRAS_INDEX) {
+                pae.activityExtras = extras;
+            } else {
+                pae.servicesExtras[index] = extras;
+                pae.numRespondedServices++;
+            }
+            pae.numPending--;
+            if (pae.numPending == 0) {
+                pae.notifyAll();
+            }
         }
     }