Add ability to start voice interaction session directly

Add internal API's for SystemUI to start a voice interaction session
directly, without using an intent.

Make the assist gesture use that ability, if available.

Change-Id: I88ce3c7514714eb45666884847193585a07417a9
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7a58c87..6a3e89e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -120,6 +120,9 @@
     <!-- Screen Capturing -->
     <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
 
+    <!-- Assist -->
+    <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index 445b499..f0e6c43 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -27,16 +27,20 @@
 import android.media.AudioAttributes;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Slog;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import com.android.internal.app.IVoiceInteractionManagerService;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarPanel;
@@ -70,6 +74,8 @@
     private float mStartDrag;
     private boolean mLaunchPending;
 
+    private IVoiceInteractionManagerService mVoiceInteractionManagerService;
+
     public SearchPanelView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -80,6 +86,14 @@
         mThreshold = context.getResources().getDimensionPixelSize(R.dimen.search_panel_threshold);
     }
 
+    private void startAssist() {
+        if (isVoiceInteractorActive()) {
+            startVoiceInteractor();
+        } else {
+            startAssistActivity();
+        }
+    }
+
     private void startAssistActivity() {
         if (!mBar.isDeviceProvisioned()) return;
 
@@ -106,6 +120,23 @@
         }
     }
 
+    private void startVoiceInteractor() {
+        try {
+            mVoiceInteractionManagerService.showSessionForActiveService();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to call showSessionForActiveService", e);
+        }
+    }
+
+    private boolean isVoiceInteractorActive() {
+        try {
+            return mVoiceInteractionManagerService.isServiceActive();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to call isServiceActive", e);
+            return false;
+        }
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -113,6 +144,9 @@
         mCircle = (SearchPanelCircleView) findViewById(R.id.search_panel_circle);
         mLogo = (ImageView) findViewById(R.id.search_logo);
         mScrim = findViewById(R.id.search_panel_scrim);
+        mVoiceInteractionManagerService = (IVoiceInteractionManagerService)
+                IVoiceInteractionManagerService.Stub.asInterface(
+                        ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
     }
 
     private void maybeSwapSearchIcon() {
@@ -320,7 +354,7 @@
             return;
         }
         mLaunching = true;
-        startAssistActivity();
+        startAssist();
         vibrate();
         mCircle.setAnimatingOut(true);
         mCircle.startExitAnimation(new Runnable() {