diff options
20 files changed, 322 insertions, 16 deletions
diff --git a/api/current.txt b/api/current.txt index 1995416..81e5d4f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -57,6 +57,7 @@ package android { field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE"; field public static final java.lang.String GET_TASKS = "android.permission.GET_TASKS"; + field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO"; field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH"; field public static final java.lang.String HARDWARE_TEST = "android.permission.HARDWARE_TEST"; field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS"; @@ -2738,6 +2739,7 @@ package android.app { method public void onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder); method public boolean onPrepareOptionsMenu(android.view.Menu); method public boolean onPreparePanel(int, android.view.View, android.view.Menu); + method public void onProvideAssistData(android.os.Bundle); method protected void onRestart(); method protected void onRestoreInstanceState(android.os.Bundle); method protected void onResume(); @@ -3077,7 +3079,9 @@ package android.app { method public void onTerminate(); method public void onTrimMemory(int); method public void registerActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks); + method public void registerOnProvideAssistData(android.app.Application.OnProvideAssistData); method public void unregisterActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks); + method public void unregisterOnProvideAssistData(android.app.Application.OnProvideAssistData); } public static abstract interface Application.ActivityLifecycleCallbacks { @@ -3090,6 +3094,10 @@ package android.app { method public abstract void onActivityStopped(android.app.Activity); } + public static abstract interface Application.OnProvideAssistData { + method public abstract void onProvideAssistData(android.app.Activity, android.os.Bundle); + } + public class ApplicationErrorReport implements android.os.Parcelable { ctor public ApplicationErrorReport(); method public int describeContents(); @@ -5901,6 +5909,8 @@ package android.content { field public static final android.os.Parcelable.Creator CREATOR; field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT"; 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_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"; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index d6ddeb6..18ccd53 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1346,6 +1346,20 @@ public class Activity extends ContextThemeWrapper } /** + * This is called when the user is requesting an assist, to build a full + * {@link Intent#ACTION_ASSIST} Intent with all of the context of the current + * application. You can override this method to place into the bundle anything + * you would like to appear in the {@link Intent#EXTRA_ASSIST_CONTEXT} part + * of the assist Intent. The default implementation does nothing. + * + * <p>This function will be called after any global assist callbacks that had + * been registered with {@link Application#registerOnProvideAssistData + * Application.registerOnProvideAssistData}. + */ + public void onProvideAssistData(Bundle data) { + } + + /** * Called when you are no longer visible to the user. You will next * receive either {@link #onRestart}, {@link #onDestroy}, or nothing, * depending on later user activity. diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 61b2067..bc27a57 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1818,6 +1818,24 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case GET_TOP_ACTIVITY_EXTRAS_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + int requestType = data.readInt(); + Bundle res = getTopActivityExtras(requestType); + reply.writeNoException(); + reply.writeBundle(res); + return true; + } + + case REPORT_TOP_ACTIVITY_EXTRAS_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder token = data.readStrongBinder(); + Bundle extras = data.readBundle(); + reportTopActivityExtras(token, extras); + reply.writeNoException(); + return true; + } + } return super.onTransact(code, data, reply, flags); @@ -4149,5 +4167,30 @@ class ActivityManagerProxy implements IActivityManager return res; } + public Bundle getTopActivityExtras(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); + reply.readException(); + Bundle res = reply.readBundle(); + data.recycle(); + reply.recycle(); + return res; + } + + public void reportTopActivityExtras(IBinder token, Bundle extras) 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); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 1271645..570fb80 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -533,6 +533,12 @@ public final class ActivityThread { String pkg; CompatibilityInfo info; } + + static final class RequestActivityExtras { + IBinder activityToken; + IBinder requestToken; + int requestType; + } private native void dumpGraphicsInfo(FileDescriptor fd); @@ -1108,6 +1114,16 @@ public final class ActivityThread { queueOrSendMessage(H.UNSTABLE_PROVIDER_DIED, provider); } + @Override + public void requestActivityExtras(IBinder activityToken, IBinder requestToken, + int requestType) { + RequestActivityExtras cmd = new RequestActivityExtras(); + cmd.activityToken = activityToken; + cmd.requestToken = requestToken; + cmd.requestType = requestType; + queueOrSendMessage(H.REQUEST_ACTIVITY_EXTRAS, cmd); + } + private void printRow(PrintWriter pw, String format, Object...objs) { pw.println(String.format(format, objs)); } @@ -1173,6 +1189,7 @@ public final class ActivityThread { 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; String codeToString(int code) { if (DEBUG_MESSAGES) { switch (code) { @@ -1219,6 +1236,7 @@ public final class ActivityThread { 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"; } } return Integer.toString(code); @@ -1430,6 +1448,9 @@ public final class ActivityThread { case UNSTABLE_PROVIDER_DIED: handleUnstableProviderDied((IBinder)msg.obj, false); break; + case REQUEST_ACTIVITY_EXTRAS: + handleRequestActivityExtras((RequestActivityExtras)msg.obj); + break; } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what)); } @@ -2322,6 +2343,23 @@ public final class ActivityThread { performNewIntents(data.token, data.intents); } + public void handleRequestActivityExtras(RequestActivityExtras 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); + } + if (data.isEmpty()) { + data = null; + } + IActivityManager mgr = ActivityManagerNative.getDefault(); + try { + mgr.reportTopActivityExtras(cmd.requestToken, data); + } catch (RemoteException e) { + } + } + private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>(); /** diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index 3a67cec..132388e 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -22,6 +22,7 @@ import android.content.ComponentCallbacks; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.ContextWrapper; +import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; @@ -45,6 +46,7 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { new ArrayList<ComponentCallbacks>(); private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks = new ArrayList<ActivityLifecycleCallbacks>(); + private ArrayList<OnProvideAssistData> mAssistCallbacks = null; /** @hide */ public LoadedApk mLoadedApk; @@ -59,6 +61,21 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { void onActivityDestroyed(Activity activity); } + /** + * Callback interface for use with {@link Application#registerOnProvideAssistData} + * and {@link Application#unregisterOnProvideAssistData}. + */ + public interface OnProvideAssistData { + /** + * This is called when the user is requesting an assist, to build a full + * {@link Intent#ACTION_ASSIST} Intent with all of the context of the current + * application. You can override this method to place into the bundle anything + * you would like to appear in the {@link Intent#EXTRA_ASSIST_CONTEXT} part + * of the assist Intent. + */ + public void onProvideAssistData(Activity activity, Bundle data); + } + public Application() { super(null); } @@ -137,7 +154,24 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { mActivityLifecycleCallbacks.remove(callback); } } - + + public void registerOnProvideAssistData(OnProvideAssistData callback) { + synchronized (this) { + if (mAssistCallbacks == null) { + mAssistCallbacks = new ArrayList<OnProvideAssistData>(); + } + mAssistCallbacks.add(callback); + } + } + + public void unregisterOnProvideAssistData(OnProvideAssistData callback) { + synchronized (this) { + if (mAssistCallbacks != null) { + mAssistCallbacks.remove(callback); + } + } + } + // ------------------ Internal API ------------------ /** @@ -232,4 +266,19 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } return callbacks; } + + /* package */ void dispatchOnProvideAssistData(Activity activity, Bundle data) { + Object[] callbacks; + synchronized (this) { + if (mAssistCallbacks == null) { + return; + } + callbacks = mAssistCallbacks.toArray(); + } + if (callbacks != null) { + for (int i=0; i<callbacks.length; i++) { + ((OnProvideAssistData)callbacks[i]).onProvideAssistData(activity, data); + } + } + } } diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 63aa5f9..f0e367c 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -587,6 +587,17 @@ public abstract class ApplicationThreadNative extends Binder reply.writeNoException(); return true; } + + case REQUEST_ACTIVITY_EXTRAS_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + IBinder activityToken = data.readStrongBinder(); + IBinder requestToken = data.readStrongBinder(); + int requestType = data.readInt(); + requestActivityExtras(activityToken, requestToken, requestType); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -1185,4 +1196,15 @@ class ApplicationThreadProxy implements IApplicationThread { mRemote.transact(UNSTABLE_PROVIDER_DIED_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } + + public void requestActivityExtras(IBinder activityToken, IBinder requestToken, int requestType) + 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.recycle(); + } } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 8af17a4..baac07f 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -368,6 +368,10 @@ public interface IActivityManager extends IInterface { public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException; + public Bundle getTopActivityExtras(int requestType) throws RemoteException; + + public void reportTopActivityExtras(IBinder token, Bundle extras) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -624,4 +628,6 @@ public interface IActivityManager extends IInterface { 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; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 03a26d4..8516694 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -130,6 +130,8 @@ public interface IApplicationThread extends IInterface { 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; String descriptor = "android.app.IApplicationThread"; @@ -179,4 +181,5 @@ public interface IApplicationThread extends IInterface { 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; } diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 6382cee..7dfc589 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -846,8 +846,8 @@ public class SearchManager * * @hide */ - public Intent getAssistIntent(Context context) { - return getAssistIntent(context, UserHandle.myUserId()); + public Intent getAssistIntent(Context context, boolean inclContext) { + return getAssistIntent(context, inclContext, UserHandle.myUserId()); } /** @@ -856,7 +856,7 @@ public class SearchManager * * @hide */ - public Intent getAssistIntent(Context context, int userHandle) { + public Intent getAssistIntent(Context context, boolean inclContext, int userHandle) { try { if (mService == null) { return null; @@ -867,6 +867,13 @@ public class SearchManager } Intent intent = new Intent(Intent.ACTION_ASSIST); intent.setComponent(comp); + if (inclContext) { + IActivityManager am = ActivityManagerNative.getDefault(); + Bundle extras = am.getTopActivityExtras(0); + if (extras != null) { + intent.replaceExtras(extras); + } + } return intent; } catch (RemoteException re) { Log.e(TAG, "getAssistIntent() failed: " + re); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index b5349fd..dc367dd 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1140,14 +1140,33 @@ public class Intent implements Parcelable, Cloneable { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH"; + /** * Activity Action: Perform assist action. * <p> - * Input: nothing + * 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. * Output: nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_ASSIST = "android.intent.action.ASSIST"; + + /** + * An optional field on {@link #ACTION_ASSIST} containing the name of the current + * foreground application package at the time the assist was invoked. + */ + public static final String EXTRA_ASSIST_PACKAGE + = "android.intent.extra.ASSIST_PACKAGE"; + + /** + * An optional field on {@link #ACTION_ASSIST} containing additional contextual + * information supplied by the current foreground app at the time of the assist + * request. This is a {@link Bundle} of additional data. + */ + public static final String EXTRA_ASSIST_CONTEXT + = "android.intent.extra.ASSIST_CONTEXT"; + /** * Activity Action: List all available applications * <p>Input: Nothing. diff --git a/core/java/android/view/SimulatedDpad.java b/core/java/android/view/SimulatedDpad.java index 0a37fdd..1ee416c 100644 --- a/core/java/android/view/SimulatedDpad.java +++ b/core/java/android/view/SimulatedDpad.java @@ -182,7 +182,7 @@ class SimulatedDpad { Intent intent = ((SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT_OR_SELF); + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT_OR_SELF); if (intent != null) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a69870b..aafc4bf 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1702,6 +1702,13 @@ android:description="@string/permdesc_stopAppSwitches" android:protectionLevel="signature|system" /> + <!-- Allows an application to retrieve private information about + the current top activity, such as any assist context it can provide. --> + <permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" + android:label="@string/permlab_getTopActivityInfo" + android:description="@string/permdesc_getTopActivityInfo" + android:protectionLevel="signature" /> + <!-- Allows an application to retrieve the current state of keys and switches. This is only for use by the system. @deprecated The API that used this permission has been removed. --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index fa26089..7f0fc0b 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -784,6 +784,12 @@ another app.</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_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> + + <!-- 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. --> <string name="permdesc_runSetActivityWatcher">Allows the app to diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 14fe6af..b85121e 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -49,7 +49,8 @@ <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" /> <uses-permission android:name="android.permission.START_ANY_ACTIVITY" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> - + <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" /> + <!-- WindowManager --> <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java index c0a6f56..1f29990 100644 --- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java @@ -103,7 +103,7 @@ public class SearchPanelView extends FrameLayout implements } else { // Otherwise, keyguard isn't showing so launch it from here. Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); if (intent == null) return; try { @@ -180,7 +180,7 @@ public class SearchPanelView extends FrameLayout implements private void maybeSwapSearchIcon() { Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT); if (intent != null) { ComponentName component = intent.getComponent(); if (component == null || !mGlowPadView.replaceTargetDrawablesIfPresent(component, @@ -329,6 +329,6 @@ public class SearchPanelView extends FrameLayout implements public boolean isAssistantAvailable() { return ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT) != null; + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index b5cbdd1..35ff3d6 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2206,7 +2206,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void launchAssistAction() { sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST); Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); if (intent != null) { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java index 217e5d7..27d808b 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -1567,7 +1567,7 @@ public class KeyguardHostView extends KeyguardViewBase { public void showAssistant() { final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); if (intent == null) return; diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java index 76cbbd5..6859042 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java @@ -61,7 +61,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri case com.android.internal.R.drawable.ic_action_assist_generic: Intent assistIntent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); if (assistIntent != null) { mActivityLauncher.launchActivity(assistIntent, false, true, null, null); } else { @@ -195,7 +195,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri currentUserHandle); boolean searchActionAvailable = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT) != null; + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; mCameraDisabled = cameraDisabledByAdmin || disabledBySimState || !cameraTargetPresent || !currentUserSetup; mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent @@ -207,7 +207,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri // Update the search icon with drawable from the search .apk if (!mSearchDisabled) { Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT); if (intent != null) { // XXX Hack. We need to substitute the icon here but haven't formalized // the public API. The "_google" metadata will be going away, so diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java index fef0613..8e10528 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java @@ -1428,6 +1428,6 @@ public class KeyguardViewMediator { private boolean isAssistantAvailable() { return mSearchManager != null - && mSearchManager.getAssistIntent(mContext, UserHandle.USER_CURRENT) != null; + && mSearchManager.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d8e199b..e0046ad 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -262,6 +262,9 @@ public final class ActivityManagerService extends ActivityManagerNative // 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; + static final int MY_PID = Process.myPid(); static final String[] EMPTY_STRING_ARRAY = new String[0]; @@ -319,11 +322,32 @@ public final class ActivityManagerService extends ActivityManagerNative * Activity we have told the window manager to have key focus. */ ActivityRecord mFocusedActivity = null; + /** * List of intents that were used to start the most recent tasks. */ final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>(); + public class PendingActivityExtras extends Binder implements Runnable { + public final ActivityRecord activity; + public boolean haveResult = false; + public Bundle result = null; + public PendingActivityExtras(ActivityRecord _activity) { + activity = _activity; + } + @Override + public void run() { + Slog.w(TAG, "getTopActivityExtras failed: timeout retrieving from " + activity); + synchronized (this) { + haveResult = true; + notifyAll(); + } + } + } + + final ArrayList<PendingActivityExtras> mPendingActivityExtras + = new ArrayList<PendingActivityExtras>(); + /** * Process management. */ @@ -7451,6 +7475,63 @@ public final class ActivityManagerService extends ActivityManagerNative return KEY_DISPATCHING_TIMEOUT; } + public Bundle getTopActivityExtras(int requestType) { + enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO, + "getTopActivityExtras()"); + PendingActivityExtras pae; + Bundle extras = new Bundle(); + synchronized (this) { + ActivityRecord activity = mMainStack.mResumedActivity; + if (activity == null) { + Slog.w(TAG, "getTopActivityExtras failed: no resumed activity"); + return null; + } + extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName); + if (activity.app == null || activity.app.thread == null) { + Slog.w(TAG, "getTopActivityExtras failed: no process for " + activity); + return extras; + } + if (activity.app.pid == Binder.getCallingPid()) { + Slog.w(TAG, "getTopActivityExtras failed: request process same as " + activity); + return extras; + } + pae = new PendingActivityExtras(activity); + try { + activity.app.thread.requestActivityExtras(activity.appToken, pae, requestType); + mPendingActivityExtras.add(pae); + mHandler.postDelayed(pae, PENDING_ACTIVITY_RESULT_TIMEOUT); + } catch (RemoteException e) { + Slog.w(TAG, "getTopActivityExtras failed: crash calling " + activity); + return extras; + } + } + synchronized (pae) { + while (!pae.haveResult) { + try { + pae.wait(); + } catch (InterruptedException e) { + } + } + if (pae.result != null) { + extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, pae.result); + } + } + synchronized (this) { + mPendingActivityExtras.remove(pae); + mHandler.removeCallbacks(pae); + } + return extras; + } + + public void reportTopActivityExtras(IBinder token, Bundle extras) { + PendingActivityExtras pae = (PendingActivityExtras)token; + synchronized (pae) { + pae.result = extras; + pae.haveResult = true; + pae.notifyAll(); + } + } + public void registerProcessObserver(IProcessObserver observer) { enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER, "registerProcessObserver()"); |