Merge "Tweak the HotwordRecognizer API" into klp-dev

This commit is contained in:
Sandeep Siddhartha
2013-08-28 23:38:53 +00:00
committed by Android (Google) Code Review
2 changed files with 50 additions and 89 deletions

View File

@@ -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));
}

View File

@@ -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) {
checkIsCalledFromMainThread();
putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener));
}
/**
* Starts recognizing hotword. Please note that
* {@link #setRecognitionListener(HotwordRecognitionListener)} should be called beforehand,
* otherwise no notifications will be received.
*/
public void startRecognition() {
public void startRecognition(HotwordRecognitionListener listener) {
checkIsCalledFromMainThread();
if (mConnection == null) { // first time connection
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
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));
Log.e(TAG, "no selected voice recognition service");
mListener.onHotwordError(ERROR_CLIENT);
return;
} 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;