Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd31a483 authored by Sandeep Siddhartha's avatar Sandeep Siddhartha Committed by Android (Google) Code Review
Browse files

Merge "Tweak the HotwordRecognizer API" into klp-dev

parents dd9b079c 82339347
Loading
Loading
Loading
Loading
+4 −27
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.annotation.SdkConstant.SdkConstantType;
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;
@@ -113,8 +112,9 @@ public abstract class HotwordRecognitionService extends Service {
                listener.onHotwordError(HotwordRecognizer.ERROR_RECOGNIZER_BUSY);
                Log.w(TAG, "stopRecognition called by a different caller - ignoring");
            } else { // the correct state
                HotwordRecognitionService.this.onStopHotwordRecognition(mCurrentCallback);
                mCurrentCallback.onHotwordRecognitionStopped();
                mCurrentCallback = null;
                HotwordRecognitionService.this.onStopHotwordRecognition();
            }
        } catch (RemoteException e) { // occurs if onError fails
            if (DBG) Log.d(TAG, "onError call from stopRecognition failed");
@@ -138,27 +138,6 @@ public abstract class HotwordRecognitionService extends Service {
        super.onDestroy();
    }

    /**
     * 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.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
            return true;
        }
        try {
            Log.e(TAG, "Recognition service called without RECORD_AUDIO permissions");
            listener.onHotwordError(HotwordRecognizer.ERROR_FAILED);
        } catch (RemoteException e) {
            Log.e(TAG, "onHotwordError(ERROR_INSUFFICIENT_PERMISSIONS) message failed", e);
        }
        return false;
    }

    /**
     * Notifies the service to start a recognition.
     *
@@ -168,10 +147,8 @@ public abstract class HotwordRecognitionService extends Service {

    /**
     * Notifies the service to stop recognition.
     *
     * @param callback that receives the callbacks from the service.
     */
    public abstract void onStopHotwordRecognition(Callback callback);
    public abstract void onStopHotwordRecognition();

    /** Binder of the hotword recognition service */
    private static class RecognitionServiceBinder extends IHotwordRecognitionService.Stub {
@@ -183,7 +160,7 @@ public abstract class HotwordRecognitionService extends Service {

        public void startHotwordRecognition(IHotwordRecognitionListener listener) {
            if (DBG) Log.d(TAG, "startRecognition called by: " + listener.asBinder());
            if (mInternalService != null && mInternalService.checkPermissions(listener)) {
            if (mInternalService != null) {
                mInternalService.mHandler.sendMessage(
                        Message.obtain(mInternalService.mHandler, MSG_START_RECOGNITION, listener));
            }
+46 −62
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
@@ -82,7 +84,6 @@ public class HotwordRecognizer {
    /** action codes */
    private static final int MSG_START = 1;
    private static final int MSG_STOP = 2;
    private final static int MSG_CHANGE_LISTENER = 3;

    /** The underlying HotwordRecognitionService endpoint */
    private IHotwordRecognitionService mService;
@@ -107,9 +108,6 @@ public class HotwordRecognizer {
                case MSG_STOP:
                    handleStopRecognition();
                    break;
                case MSG_CHANGE_LISTENER:
                    handleChangeListener((HotwordRecognitionListener) msg.obj);
                    break;
            }
        }
    };
@@ -138,24 +136,38 @@ public class HotwordRecognizer {
    }

    /**
     * Factory method to create a new {@code HotwordRecognizer}. Please note that
     * {@link #setRecognitionListener(HotwordRecognitionListener)}
     * should be called before dispatching any command to the created {@code HotwordRecognizer},
     * otherwise no notifications will be received.
     * Factory method to create a new {@code HotwordRecognizer}.
     *
     * @param context in which to create {@code HotwordRecognizer}
     * @return a new {@code HotwordRecognizer}
     */
    public static HotwordRecognizer createHotwordRecognizer(final Context context) {
        return createHotwordRecognizer(context, null);
        ComponentName serviceComponent = null;
        // Resolve to a default ComponentName.
        final List<ResolveInfo> list = context.getPackageManager().queryIntentServices(
                new Intent(HotwordRecognitionService.SERVICE_INTERFACE), 0);
        for (int i = 0; i < list.size(); i++) {
            final ResolveInfo ri = list.get(i);
            if (!ri.serviceInfo.enabled) {
                continue;
            }
            if ((ri.serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM)
                    != PackageManager.MATCH_DEFAULT_ONLY) {
                serviceComponent = new ComponentName(
                        ri.serviceInfo.packageName, ri.serviceInfo.name);
                break;
            }
        }
        // If all else fails, pick the first one.
        if (serviceComponent == null && !list.isEmpty()) {
            serviceComponent =  new ComponentName(
                    list.get(0).serviceInfo.packageName, list.get(0).serviceInfo.name);
        }
        return createHotwordRecognizer(context, serviceComponent);
    }


    /**
     * Factory method to create a new {@code HotwordRecognizer}. Please note that
     * {@link #setRecognitionListener(HotwordRecognitionListener)}
     * should be called before dispatching any command to the created {@code HotwordRecognizer},
     * otherwise no notifications will be received.
     * Factory method to create a new {@code HotwordRecognizer}.
     *
     * Use this version of the method to specify a specific service to direct this
     * {@link HotwordRecognizer} to. Normally you would not use this; use
@@ -177,40 +189,26 @@ public class HotwordRecognizer {
    }

    /**
     * Sets the listener that will receive all the callbacks. The previous unfinished commands will
     * be executed with the old listener, while any following command will be executed with the new
     * listener.
     * Starts recognizing hotword and sets the listener that will receive the callbacks.
     *
     * @param listener listener that will receive all the callbacks from the created
     *        {@link HotwordRecognizer}, this must not be null.
     */
    public void setRecognitionListener(HotwordRecognitionListener listener) {
    public void startRecognition(HotwordRecognitionListener listener) {
        checkIsCalledFromMainThread();
        putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener));
        if (mConnection == null) { // first time connection
            if (listener == null) {
                throw new IllegalArgumentException("listener must not be null");
            }

    /**
     * Starts recognizing hotword. Please note that
     * {@link #setRecognitionListener(HotwordRecognitionListener)} should be called beforehand,
     * otherwise no notifications will be received.
     */
    public void startRecognition() {
        checkIsCalledFromMainThread();
        if (mConnection == null) { // first time connection
            mConnection = new Connection();

            Intent serviceIntent = new Intent(HotwordRecognitionService.SERVICE_INTERFACE);

            mListener.mInternalListener = listener;

            if (mServiceComponent == null) {
                // TODO: Resolve the ComponentName here and use it.
                String serviceComponent = null;
                if (TextUtils.isEmpty(serviceComponent)) {
                Log.e(TAG, "no selected voice recognition service");
                mListener.onHotwordError(ERROR_CLIENT);
                return;
                }
                serviceIntent.setComponent(ComponentName.unflattenFromString(serviceComponent));
            } else {
                serviceIntent.setComponent(mServiceComponent);
            }
@@ -222,17 +220,15 @@ public class HotwordRecognizer {
                mListener.onHotwordError(ERROR_CLIENT);
                return;
            }
            putMessage(Message.obtain(mHandler, MSG_START));
        } else {
            mListener.onHotwordError(ERROR_SERVICE_ALREADY_STARTED);
            return;
        }
        putMessage(Message.obtain(mHandler, MSG_START));
    }

    /**
     * Stops recognizing hotword. Please note that
     * {@link #setRecognitionListener(HotwordRecognitionListener)} should be called beforehand,
     * otherwise no notifications will be received.
     * Stops recognizing hotword.
     */
    public void stopRecognition() {
        checkIsCalledFromMainThread();
@@ -245,19 +241,6 @@ public class HotwordRecognizer {
        mServiceComponent = serviceComponent;
    }

    /**
     * Destroys the {@code HotwordRecognizer} object.
     */
    public void destroy() {
        if (mConnection != null) {
            mContext.unbindService(mConnection);
        }
        mPendingTasks.clear();
        mService = null;
        mConnection = null;
        mListener.mInternalListener = null;
    }

    private void handleStartRecognition() {
        if (!checkOpenConnection()) {
            return;
@@ -271,26 +254,27 @@ public class HotwordRecognizer {
        }
    }


    private void handleStopRecognition() {
        if (!checkOpenConnection()) {
            return;
        }
        try {
            mService.stopHotwordRecognition(mListener);
            if (mConnection != null) {
                mContext.unbindService(mConnection);
            }
            if (DBG) Log.d(TAG, "service stopRecognition command succeeded");
        } catch (final RemoteException e) {
            Log.e(TAG, "stopRecognition() failed", e);
            mListener.onHotwordError(ERROR_CLIENT);
        } finally {
            mPendingTasks.clear();
            mService = null;
            mConnection = null;
            mListener.mInternalListener = null;
        }
    }

    /** changes the listener */
    private void handleChangeListener(HotwordRecognitionListener listener) {
        if (DBG) Log.d(TAG, "handleChangeListener, listener=" + listener);
        mListener.mInternalListener = listener;
    }

    private boolean checkOpenConnection() {
        if (mService != null) {
            return true;