diff options
8 files changed, 170 insertions, 28 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 9f683e3891ab..0e98175637cd 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -3498,14 +3498,24 @@ public class Activity extends ContextThemeWrapper * <p>You can override this function to force global search, e.g. in response to a dedicated * search key, or to block search entirely (by simply returning false). * - * @return Returns {@code true} if search launched, and {@code false} if activity blocks it. - * The default implementation always returns {@code true}. + * <p>Note: when running in a {@link Configuration#UI_MODE_TYPE_TELEVISION}, the default + * implementation changes to simply return false and you must supply your own custom + * implementation if you want to support search.</p> + * + * @return Returns {@code true} if search launched, and {@code false} if the activity does + * not respond to search. The default implementation always returns {@code true}, except + * when in {@link Configuration#UI_MODE_TYPE_TELEVISION} mode where it returns false. * * @see android.app.SearchManager */ public boolean onSearchRequested() { - startSearch(null, false, null, false); - return true; + if ((getResources().getConfiguration().uiMode&Configuration.UI_MODE_TYPE_MASK) + != Configuration.UI_MODE_TYPE_TELEVISION) { + startSearch(null, false, null, false); + return true; + } else { + return false; + } } /** diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 11470e336b65..6c67c0996817 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1929,7 +1929,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IIntentSender r = IIntentSender.Stub.asInterface( - data.readStrongBinder()); + data.readStrongBinder()); boolean res = isIntentSenderTargetedToPackage(r); reply.writeNoException(); reply.writeInt(res ? 1 : 0); @@ -2102,6 +2102,18 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case LAUNCH_ASSIST_INTENT_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + Intent intent = Intent.CREATOR.createFromParcel(data); + int requestType = data.readInt(); + String hint = data.readString(); + int userHandle = data.readInt(); + boolean res = launchAssistIntent(intent, requestType, hint, userHandle); + reply.writeNoException(); + reply.writeInt(res ? 1 : 0); + return true; + } + case KILL_UID_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int uid = data.readInt(); @@ -5039,6 +5051,23 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + intent.writeToParcel(data, 0); + data.writeInt(requestType); + data.writeString(hint); + data.writeInt(userHandle); + mRemote.transact(LAUNCH_ASSIST_INTENT_TRANSACTION, data, reply, 0); + reply.readException(); + boolean res = reply.readInt() != 0; + data.recycle(); + reply.recycle(); + return res; + } + public void killUid(int uid, String reason) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index aa5fea0a9e1e..b72addfa87f3 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -417,6 +417,9 @@ public interface IActivityManager extends IInterface { public void reportAssistContextExtras(IBinder token, Bundle extras) throws RemoteException; + public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) + throws RemoteException; + public void killUid(int uid, String reason) throws RemoteException; public void hang(IBinder who, boolean allowRestart) throws RemoteException; @@ -777,4 +780,5 @@ public interface IActivityManager extends IInterface { int RELEASE_SOME_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+236; int BOOT_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+237; int GET_TASK_DESCRIPTION_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+238; + int LAUNCH_ASSIST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+239; } diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl index 074d34398379..03e7ff462300 100644 --- a/core/java/android/app/ISearchManager.aidl +++ b/core/java/android/app/ISearchManager.aidl @@ -31,4 +31,5 @@ interface ISearchManager { ComponentName getGlobalSearchActivity(); ComponentName getWebSearchActivity(); ComponentName getAssistIntent(int userHandle); + boolean launchAssistAction(int requestType, String hint, int userHandle); } diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 4c253f3b6017..a40b29a25d7d 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -989,4 +989,20 @@ public class SearchManager return null; } } + + /** + * Launch an assist action for the current top activity. + * @hide + */ + public boolean launchAssistAction(int requestType, String hint, int userHandle) { + try { + if (mService == null) { + return false; + } + return mService.launchAssistAction(requestType, hint, userHandle); + } catch (RemoteException re) { + Log.e(TAG, "launchAssistAction() failed: " + re); + return false; + } + } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index e9a114ac6fc3..9c81f0a94856 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -22,6 +22,8 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.*; +import android.app.SearchManager; +import android.os.UserHandle; import com.android.internal.R; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; @@ -4004,13 +4006,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @return true if search window opened */ private boolean launchDefaultSearch() { + boolean result; final Callback cb = getCallback(); if (cb == null || isDestroyed()) { - return false; + result = false; } else { sendCloseSystemWindows("search"); - return cb.onSearchRequested(); + result = cb.onSearchRequested(); + } + if (!result && (getContext().getResources().getConfiguration().uiMode + & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) { + // On TVs, if the app doesn't implement search, we want to launch assist. + return ((SearchManager)getContext().getSystemService(Context.SEARCH_SERVICE)) + .launchAssistAction(0, null, UserHandle.myUserId()); } + return result; } @Override diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9e0483d2e00b..bb4db90c700a 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -434,10 +434,19 @@ public final class ActivityManagerService extends ActivityManagerNative public class PendingAssistExtras extends Binder implements Runnable { public final ActivityRecord activity; + public final Bundle extras; + public final Intent intent; + public final String hint; + public final int userHandle; public boolean haveResult = false; public Bundle result = null; - public PendingAssistExtras(ActivityRecord _activity) { + public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent, + String _hint, int _userHandle) { activity = _activity; + extras = _extras; + intent = _intent; + hint = _hint; + userHandle = _userHandle; } @Override public void run() { @@ -10449,6 +10458,31 @@ public final class ActivityManagerService extends ActivityManagerNative } public Bundle getAssistContextExtras(int requestType) { + PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, + UserHandle.getCallingUserId()); + if (pae == null) { + return null; + } + synchronized (pae) { + while (!pae.haveResult) { + try { + pae.wait(); + } catch (InterruptedException e) { + } + } + if (pae.result != null) { + pae.extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, pae.result); + } + } + synchronized (this) { + mPendingAssistExtras.remove(pae); + mHandler.removeCallbacks(pae); + } + return pae.extras; + } + + private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint, + int userHandle) { enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO, "getAssistContextExtras()"); PendingAssistExtras pae; @@ -10462,13 +10496,13 @@ public final class ActivityManagerService extends ActivityManagerNative extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName); if (activity.app == null || activity.app.thread == null) { Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity); - return extras; + return null; } if (activity.app.pid == Binder.getCallingPid()) { Slog.w(TAG, "getAssistContextExtras failed: request process same as " + activity); - return extras; + return null; } - pae = new PendingAssistExtras(activity); + pae = new PendingAssistExtras(activity, extras, intent, hint, userHandle); try { activity.app.thread.requestAssistContextExtras(activity.appToken, pae, requestType); @@ -10476,25 +10510,10 @@ public final class ActivityManagerService extends ActivityManagerNative mHandler.postDelayed(pae, PENDING_ASSIST_EXTRAS_TIMEOUT); } catch (RemoteException e) { Slog.w(TAG, "getAssistContextExtras 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); + return null; } + return pae; } - synchronized (this) { - mPendingAssistExtras.remove(pae); - mHandler.removeCallbacks(pae); - } - return extras; } public void reportAssistContextExtras(IBinder token, Bundle extras) { @@ -10503,9 +10522,40 @@ public final class ActivityManagerService extends ActivityManagerNative pae.result = extras; pae.haveResult = true; pae.notifyAll(); + if (pae.intent == null) { + // Caller is just waiting for the result. + return; + } + } + + // We are now ready to launch the assist activity. + synchronized (this) { + boolean exists = mPendingAssistExtras.remove(pae); + mHandler.removeCallbacks(pae); + if (!exists) { + // Timed out. + return; + } + } + pae.intent.replaceExtras(extras); + if (pae.hint != null) { + pae.intent.putExtra(pae.hint, true); + } + pae.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_SINGLE_TOP + | Intent.FLAG_ACTIVITY_CLEAR_TOP); + closeSystemDialogs("assist"); + try { + mContext.startActivityAsUser(pae.intent, new UserHandle(pae.userHandle)); + } catch (ActivityNotFoundException e) { + Slog.w(TAG, "No activity to handle assist action.", e); } } + public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) { + return enqueueAssistContext(requestType, intent, hint, userHandle) != null; + } + public void registerProcessObserver(IProcessObserver observer) { enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER, "registerProcessObserver()"); diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java index 5deb2b838e07..ddf02e9df8c5 100644 --- a/services/core/java/com/android/server/search/SearchManagerService.java +++ b/services/core/java/com/android/server/search/SearchManagerService.java @@ -17,7 +17,9 @@ package com.android.server.search; import android.app.ActivityManager; +import android.app.ActivityManagerNative; import android.app.AppGlobals; +import android.app.IActivityManager; import android.app.ISearchManager; import android.app.SearchManager; import android.app.SearchableInfo; @@ -32,6 +34,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.ContentObserver; import android.os.Binder; +import android.os.Bundle; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; @@ -262,6 +265,25 @@ public class SearchManagerService extends ISearchManager.Stub { } @Override + public boolean launchAssistAction(int requestType, String hint, int userHandle) { + ComponentName comp = getAssistIntent(userHandle); + if (comp == null) { + return false; + } + long ident = Binder.clearCallingIdentity(); + try { + Intent intent = new Intent(Intent.ACTION_ASSIST); + intent.setComponent(comp); + IActivityManager am = ActivityManagerNative.getDefault(); + return am.launchAssistIntent(intent, requestType, hint, userHandle); + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } + return true; + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); |