Merge "Implement issue #17906468: Allow search request to fall back to global search" into lmp-dev
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9f683e3..0e98175 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3498,14 +3498,24 @@
* <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 11470e3..6c67c09 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1929,7 +1929,7 @@
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 @@
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 @@
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 aa5fea0..b72addf 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -417,6 +417,9 @@
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 @@
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 074d343..03e7ff4 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -31,4 +31,5 @@
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 4c253f3..a40b29a 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -989,4 +989,20 @@
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 e9a114a..9c81f0a 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.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 @@
* @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 9e0483d..bb4db90 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 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 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 @@
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 @@
mHandler.postDelayed(pae, PENDING_ASSIST_EXTRAS_TIMEOUT);
} catch (RemoteException e) {
Slog.w(TAG, "getAssistContextExtras failed: crash calling " + activity);
- return extras;
+ return null;
}
+ return pae;
}
- 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) {
- mPendingAssistExtras.remove(pae);
- mHandler.removeCallbacks(pae);
- }
- return extras;
}
public void reportAssistContextExtras(IBinder token, Bundle extras) {
@@ -10503,7 +10522,38 @@
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) {
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index 5deb2b8..ddf02e9 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.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 @@
}
@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);