am b05b4086: Merge "Add permission checks and unhide the Hotword recognition APIs" into klp-dev

* commit 'b05b408614767fb60295830d6bf557b33252498e':
  Add permission checks and unhide the Hotword recognition APIs
diff --git a/core/java/android/speech/hotword/HotwordRecognitionListener.java b/core/java/android/speech/hotword/HotwordRecognitionListener.java
index 8e62373..8a32654 100644
--- a/core/java/android/speech/hotword/HotwordRecognitionListener.java
+++ b/core/java/android/speech/hotword/HotwordRecognitionListener.java
@@ -16,7 +16,6 @@
 
 package android.speech.hotword;
 
-import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Bundle;
 
@@ -47,9 +46,10 @@
 
     /**
      * Called back when hotword is detected.
-     * The action tells the client what action to take, post hotword-detection.
+     *
+     * @param intent for the activity to launch, post hotword detection.
      */
-    void onHotwordRecognized(PendingIntent intent);
+    void onHotwordRecognized(Intent intent);
 
     /**
      * Called when the HotwordRecognitionService encounters an error.
diff --git a/core/java/android/speech/hotword/HotwordRecognitionService.java b/core/java/android/speech/hotword/HotwordRecognitionService.java
index 521d06d..c70bdab 100644
--- a/core/java/android/speech/hotword/HotwordRecognitionService.java
+++ b/core/java/android/speech/hotword/HotwordRecognitionService.java
@@ -21,6 +21,7 @@
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -31,7 +32,6 @@
 /**
  * This class provides a base class for hotword detection service implementations.
  * This class should be extended only if you wish to implement a new hotword recognizer.
- * {@hide}
  */
 public abstract class HotwordRecognitionService extends Service {
     /**
@@ -45,8 +45,7 @@
     private static final String TAG = "HotwordRecognitionService";
 
     /** Debugging flag */
-    // TODO: Turn off.
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     private static final int MSG_START_RECOGNITION = 1;
     private static final int MSG_STOP_RECOGNITION = 2;
@@ -160,7 +159,7 @@
 
         public void startHotwordRecognition(IHotwordRecognitionListener listener) {
             if (DBG) Log.d(TAG, "startRecognition called by: " + listener.asBinder());
-            if (mInternalService != null) {
+            if (mInternalService != null && mInternalService.checkPermissions(listener)) {
                 mInternalService.mHandler.sendMessage(
                         Message.obtain(mInternalService.mHandler, MSG_START_RECOGNITION, listener));
             }
@@ -168,7 +167,7 @@
 
         public void stopHotwordRecognition(IHotwordRecognitionListener listener) {
             if (DBG) Log.d(TAG, "stopRecognition called by: " + listener.asBinder());
-            if (mInternalService != null) {
+            if (mInternalService != null && mInternalService.checkPermissions(listener)) {
                 mInternalService.mHandler.sendMessage(
                         Message.obtain(mInternalService.mHandler, MSG_STOP_RECOGNITION, listener));
             }
@@ -180,6 +179,27 @@
     }
 
     /**
+     * Checks whether the caller has sufficient permissions
+     *
+     * @param listener to send the error message to in case of error.
+     * @return {@code true} if the caller has enough permissions, {@code false} otherwise.
+     */
+    private boolean checkPermissions(IHotwordRecognitionListener listener) {
+        if (DBG) Log.d(TAG, "checkPermissions");
+        if (checkCallingOrSelfPermission(android.Manifest.permission.HOTWORD_RECOGNITION) ==
+                PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+        try {
+            Log.e(TAG, "Recognition service called without HOTWORD_RECOGNITION permissions");
+            listener.onHotwordError(HotwordRecognizer.ERROR_FAILED);
+        } catch (RemoteException e) {
+            Log.e(TAG, "onHotwordError(ERROR_FAILED) message failed", e);
+        }
+        return false;
+    }
+
+    /**
      * This class acts passes on the callbacks received from the Hotword service
      * to the listener.
      */
@@ -216,10 +236,11 @@
 
         /**
          * Called back when hotword is detected.
-         * The action tells the client what action to take, post hotword-detection.
+         *
+         * @param intent for the activity to launch, post hotword detection.
          */
-        public void onHotwordRecognized(PendingIntent intent) throws RemoteException {
-            mListener.onHotwordRecognized(intent);
+        public void onHotwordRecognized(Intent activityIntent) throws RemoteException {
+            mListener.onHotwordRecognized(activityIntent);
         }
 
         /**
diff --git a/core/java/android/speech/hotword/HotwordRecognizer.java b/core/java/android/speech/hotword/HotwordRecognizer.java
index 82cec10..939c11d 100644
--- a/core/java/android/speech/hotword/HotwordRecognizer.java
+++ b/core/java/android/speech/hotword/HotwordRecognizer.java
@@ -45,8 +45,7 @@
  */
 public class HotwordRecognizer {
     /** DEBUG value to enable verbose debug prints */
-    // TODO: Turn off.
-    private final static boolean DBG = true;
+    private final static boolean DBG = false;
 
     /** Log messages identifier */
     private static final String TAG = "HotwordRecognizer";
@@ -81,6 +80,9 @@
     /** The service received concurrent start calls */
     public static final int ERROR_SERVICE_ALREADY_STARTED = 6;
 
+    /** Hotword recognition is unavailable on the device */
+    public static final int ERROR_UNAVAILABLE = 7;
+
     /** action codes */
     private static final int MSG_START = 1;
     private static final int MSG_STOP = 2;
@@ -354,7 +356,7 @@
                         mInternalListener.onHotwordEvent(msg.arg1, (Bundle) msg.obj);
                         break;
                     case MSG_ON_RECOGNIZED:
-                        mInternalListener.onHotwordRecognized((PendingIntent) msg.obj);
+                        mInternalListener.onHotwordRecognized((Intent) msg.obj);
                         break;
                     case MSG_ON_ERROR:
                         mInternalListener.onHotwordError((Integer) msg.obj);
@@ -380,8 +382,8 @@
         }
 
         @Override
-        public void onHotwordRecognized(PendingIntent intent) throws RemoteException {
-            Message.obtain(mInternalHandler, MSG_ON_RECOGNIZED, intent)
+        public void onHotwordRecognized(Intent activityIntent) throws RemoteException {
+            Message.obtain(mInternalHandler, MSG_ON_RECOGNIZED, activityIntent)
                     .sendToTarget();
         }
 
diff --git a/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl b/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl
index 49c5233..4ea2e8e0 100644
--- a/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl
+++ b/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl
@@ -16,7 +16,7 @@
 
 package android.speech.hotword;
 
-import android.app.PendingIntent;
+import android.content.Intent;
 import android.os.Bundle;
 
 /**
@@ -47,9 +47,10 @@
 
     /**
      * Called back when hotword is detected.
-     * The action tells the client what action to take, post hotword-detection.
+     *
+     * @param intent for the activity to launch, post hotword detection.
      */
-    void onHotwordRecognized(in PendingIntent intent);
+    void onHotwordRecognized(in Intent intent);
 
     /**
      * Called when the HotwordRecognitionService encounters an error.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 83a0c56..2e47928 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2444,6 +2444,13 @@
         android:description="@string/permdesc_accessNetworkConditions"
         android:protectionLevel="signature|system" />
 
+    <!-- Allows an application to request HotwordRecognition.
+         @hide This is not a third-party API (intended for system apps). -->
+    <permission android:name="android.permission.HOTWORD_RECOGNITION"
+        android:label="@string/permlab_hotwordRecognition"
+        android:description="@string/permdesc_hotwordRecognition"
+        android:protectionLevel="signature|system" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index aa04bf6..68acd8c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1911,6 +1911,11 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessNetworkConditions">Allows an application to listen for observations on network conditions. Should never be needed for normal apps.</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_hotwordRecognition">request hotword recognition</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_hotwordRecognition">Allows an application to request for hotword recognition. Should never be needed for normal apps.</string>
+
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->