summaryrefslogtreecommitdiffstats
path: root/services/voiceinteraction
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2014-04-25 17:06:18 -0700
committerDianne Hackborn <hackbod@google.com>2014-04-28 10:54:15 -0700
commit18f0d357f9693fe787a3e3777d8fdf01357a6e3f (patch)
tree87ffa17a98fa81355a37e25b2c7fc649ffc4e9be /services/voiceinteraction
parent01c70711d5e4f1c3405bcd169be70605e92166f2 (diff)
downloadframeworks_base-18f0d357f9693fe787a3e3777d8fdf01357a6e3f.zip
frameworks_base-18f0d357f9693fe787a3e3777d8fdf01357a6e3f.tar.gz
frameworks_base-18f0d357f9693fe787a3e3777d8fdf01357a6e3f.tar.bz2
Rework some of the voice interaction APIs.
On the app side, requests are now composed by subclassing from various types of Request objects. On the service side, starting a voice interaction session involves starting another service that will then manage the session. This leads the service design much more to what we want, where the long-running main service is very tiny and all the heavy-weight transient session work is elsewhere in another process. Change-Id: I46c074c6fe27b6c1cf2583c6d216aed1de2f1143
Diffstat (limited to 'services/voiceinteraction')
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java50
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java169
2 files changed, 185 insertions, 34 deletions
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 9e2bcab..045c0f6 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -16,14 +16,18 @@
package com.android.server.voiceinteraction;
+import android.Manifest;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionService;
@@ -134,9 +138,8 @@ public class VoiceInteractionManagerService extends SystemService {
}
@Override
- public int startVoiceActivity(Intent intent, String resolvedType,
- IVoiceInteractionService service,
- IVoiceInteractionSession session, IVoiceInteractor interactor) {
+ public void startVoiceActivity(Intent intent, String resolvedType,
+ IVoiceInteractionService service, Bundle args) {
synchronized (this) {
if (mImpl == null || service.asBinder() != mImpl.mService.asBinder()) {
throw new SecurityException(
@@ -146,8 +149,8 @@ public class VoiceInteractionManagerService extends SystemService {
final int callingUid = Binder.getCallingUid();
final long caller = Binder.clearCallingIdentity();
try {
- return mImpl.startVoiceActivityLocked(callingPid, callingUid,
- intent, resolvedType, session, interactor);
+ mImpl.startVoiceActivityLocked(callingPid, callingUid,
+ intent, resolvedType, args);
} finally {
Binder.restoreCallingIdentity(caller);
}
@@ -155,8 +158,43 @@ public class VoiceInteractionManagerService extends SystemService {
}
@Override
+ public int deliverNewSession(IBinder token, IVoiceInteractionSession session,
+ IVoiceInteractor interactor) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "deliverNewSession without running voice interaction service");
+ return ActivityManager.START_CANCELED;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session,
+ interactor);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump PowerManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+ synchronized (this) {
+ pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n");
+ if (mImpl == null) {
+ pw.println(" (No active implementation)");
+ return;
+ }
+ mImpl.dumpLocked(fd, pw, args);
+ }
}
class SettingsObserver extends ContentObserver {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index af8ae1e..6bbd1c1 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.voiceinteraction;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.content.ComponentName;
@@ -24,29 +25,40 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.IVoiceInteractionSessionService;
import android.service.voice.VoiceInteractionService;
+import android.service.voice.VoiceInteractionServiceInfo;
import android.util.Slog;
import com.android.internal.app.IVoiceInteractor;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
class VoiceInteractionManagerServiceImpl {
final static String TAG = "VoiceInteractionServiceManager";
+ final boolean mValid;
+
final Context mContext;
final Handler mHandler;
final Object mLock;
final int mUser;
final ComponentName mComponent;
final IActivityManager mAm;
+ final VoiceInteractionServiceInfo mInfo;
+ final ComponentName mSessionComponentName;
boolean mBound = false;
IVoiceInteractionService mService;
- IVoiceInteractionSession mActiveSession;
- IVoiceInteractor mActiveInteractor;
+
+ SessionConnection mActiveSession;
final ServiceConnection mConnection = new ServiceConnection() {
@Override
@@ -62,6 +74,72 @@ class VoiceInteractionManagerServiceImpl {
}
};
+ final class SessionConnection implements ServiceConnection {
+ final IBinder mToken = new Binder();
+ final Intent mIntent;
+ final String mResolvedType;
+ final Bundle mArgs;
+ boolean mBound;
+ IVoiceInteractionSessionService mService;
+ IVoiceInteractionSession mSession;
+ IVoiceInteractor mInteractor;
+
+ SessionConnection(Intent intent, String resolvedType, Bundle args) {
+ mIntent = intent;
+ mResolvedType = resolvedType;
+ mArgs = args;
+ Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
+ serviceIntent.setComponent(mSessionComponentName);
+ mBound = mContext.bindServiceAsUser(serviceIntent, this,
+ Context.BIND_AUTO_CREATE, new UserHandle(mUser));
+ if (!mBound) {
+ Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mService = IVoiceInteractionSessionService.Stub.asInterface(service);
+ if (mActiveSession == this) {
+ try {
+ mService.newSession(mToken, mArgs);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed making new session", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ }
+
+ public void cancel() {
+ if (mBound) {
+ mContext.unbindService(this);
+ mBound = false;
+ mService = null;
+ mSession = null;
+ mInteractor = null;
+ }
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mToken="); pw.println(mToken);
+ pw.print(prefix); pw.print("mIntent="); pw.println(mIntent);
+ pw.print(" mResolvedType="); pw.println(mResolvedType);
+ pw.print(prefix); pw.print("mArgs="); pw.println(mArgs);
+ pw.print(prefix); pw.print("mBound="); pw.println(mBound);
+ if (mBound) {
+ pw.print(prefix); pw.print("mService="); pw.println(mService);
+ pw.print(prefix); pw.print("mSession="); pw.println(mSession);
+ pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor);
+ }
+ }
+ };
+
VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock,
int userHandle, ComponentName service) {
mContext = context;
@@ -70,50 +148,85 @@ class VoiceInteractionManagerServiceImpl {
mUser = userHandle;
mComponent = service;
mAm = ActivityManagerNative.getDefault();
- }
-
- public int startVoiceActivityLocked(int callingPid, int callingUid, Intent intent,
- String resolvedType, IVoiceInteractionSession session, IVoiceInteractor interactor) {
- if (session == null) {
- throw new NullPointerException("session is null");
+ VoiceInteractionServiceInfo info;
+ try {
+ info = new VoiceInteractionServiceInfo(context.getPackageManager(), service);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Voice interaction service not found: " + service);
+ mInfo = null;
+ mSessionComponentName = null;
+ mValid = false;
+ return;
}
- if (interactor == null) {
- throw new NullPointerException("interactor is null");
+ mInfo = info;
+ if (mInfo.getParseError() != null) {
+ Slog.w(TAG, "Bad voice interaction service: " + mInfo.getParseError());
+ mSessionComponentName = null;
+ mValid = false;
+ return;
}
+ mValid = true;
+ mSessionComponentName = new ComponentName(service.getPackageName(),
+ mInfo.getSessionService());
+ }
+
+ public void startVoiceActivityLocked(int callingPid, int callingUid, Intent intent,
+ String resolvedType, Bundle args) {
if (mActiveSession != null) {
- // XXX cancel current session.
+ mActiveSession.cancel();
+ mActiveSession = null;
}
+ mActiveSession = new SessionConnection(intent, resolvedType, args);
intent.addCategory(Intent.CATEGORY_VOICE);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- mActiveSession = session;
- mActiveInteractor = interactor;
+ }
+
+ public int deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
+ IVoiceInteractionSession session, IVoiceInteractor interactor) {
try {
+ if (mActiveSession == null || token != mActiveSession.mToken) {
+ Slog.w(TAG, "deliverNewSession does not match active session");
+ return ActivityManager.START_CANCELED;
+ }
+ mActiveSession.mSession = session;
+ mActiveSession.mInteractor = interactor;
return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid,
- intent, resolvedType, mActiveSession, mActiveInteractor,
+ mActiveSession.mIntent, mActiveSession.mResolvedType,
+ mActiveSession.mSession, mActiveSession.mInteractor,
0, null, null, null, mUser);
} catch (RemoteException e) {
throw new IllegalStateException("Unexpected remote error", e);
}
}
- void startLocked() {
- Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
- intent.setComponent(mComponent);
- try {
- ServiceInfo si = mContext.getPackageManager().getServiceInfo(mComponent, 0);
- if (!android.Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) {
- Slog.w(TAG, "Not using voice interaction service " + mComponent
- + ": does not require permission "
- + android.Manifest.permission.BIND_VOICE_INTERACTION);
- return;
+ public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!mValid) {
+ pw.print(" NOT VALID: ");
+ if (mInfo == null) {
+ pw.println("no info");
+ } else {
+ pw.println(mInfo.getParseError());
}
- } catch (PackageManager.NameNotFoundException e) {
- Slog.w(TAG, "Unable to find voice interaction service: " + mComponent, e);
return;
}
- mContext.bindServiceAsUser(intent, mConnection,
+ pw.print(" mComponent="); pw.println(mComponent.flattenToShortString());
+ pw.print(" Session service="); pw.println(mInfo.getSessionService());
+ pw.print(" Settings activity="); pw.println(mInfo.getSettingsActivity());
+ pw.print(" mBound="); pw.print(mBound); pw.print(" mService="); pw.println(mService);
+ if (mActiveSession != null) {
+ pw.println(" Active session:");
+ mActiveSession.dump(" ", pw);
+ }
+ }
+
+ void startLocked() {
+ Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
+ intent.setComponent(mComponent);
+ mBound = mContext.bindServiceAsUser(intent, mConnection,
Context.BIND_AUTO_CREATE, new UserHandle(mUser));
- mBound = true;
+ if (!mBound) {
+ Slog.w(TAG, "Failed binding to voice interaction service " + mComponent);
+ }
}
void shutdownLocked() {