am a22d2fc3: am 57af6ac7: am d190a5ca: am 0e259ce2: am 6166a824: Merge "Implement issue #17906468: Allow search request to fall back to global search" into lmp-dev

* commit 'a22d2fc319069407d29a792e23910d8ba826ac34':
  Implement issue #17906468: Allow search request to fall back to global search
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);