summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt6
-rw-r--r--api/system-current.txt6
-rw-r--r--core/java/android/app/VoiceInteractor.java4
-rw-r--r--core/java/android/service/voice/IVoiceInteractionSession.aidl2
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java15
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java148
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl4
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java40
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java156
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java285
-rw-r--r--tests/VoiceInteraction/AndroidManifest.xml3
-rw-r--r--tests/VoiceInteraction/res/layout/test_interaction.xml7
-rw-r--r--tests/VoiceInteraction/res/values/strings.xml1
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java2
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java5
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java52
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java11
17 files changed, 536 insertions, 211 deletions
diff --git a/api/current.txt b/api/current.txt
index de5b1e6..00ee7a8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27656,7 +27656,7 @@ package android.service.voice {
method public android.os.IBinder onBind(android.content.Intent);
method public void onReady();
method public void onShutdown();
- method public void startSession(android.os.Bundle, int);
+ method public void showSession(android.os.Bundle, int);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
field public static final int START_WITH_ASSIST = 1; // 0x1
@@ -27668,6 +27668,7 @@ package android.service.voice {
method public void finish();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
+ method public void hide();
method public void hideWindow();
method public void onAbortVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
method public void onBackPressed();
@@ -27682,14 +27683,17 @@ package android.service.voice {
method public void onDestroy();
method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
method public void onHandleAssist(android.os.Bundle);
+ method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
method public boolean onKeyLongPress(int, android.view.KeyEvent);
method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
method public boolean onKeyUp(int, android.view.KeyEvent);
+ method public void onShow(android.os.Bundle, int);
method public void onTaskFinished(android.content.Intent, int);
method public void onTaskStarted(android.content.Intent, int);
method public void setContentView(android.view.View);
method public void setTheme(int);
+ method public void show();
method public void showWindow();
method public void startVoiceActivity(android.content.Intent);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 92f0f4d..626dfd0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -29345,7 +29345,7 @@ package android.service.voice {
method public android.os.IBinder onBind(android.content.Intent);
method public void onReady();
method public void onShutdown();
- method public void startSession(android.os.Bundle, int);
+ method public void showSession(android.os.Bundle, int);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
field public static final int START_WITH_ASSIST = 1; // 0x1
@@ -29357,6 +29357,7 @@ package android.service.voice {
method public void finish();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
+ method public void hide();
method public void hideWindow();
method public void onAbortVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
method public void onBackPressed();
@@ -29371,14 +29372,17 @@ package android.service.voice {
method public void onDestroy();
method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
method public void onHandleAssist(android.os.Bundle);
+ method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
method public boolean onKeyLongPress(int, android.view.KeyEvent);
method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
method public boolean onKeyUp(int, android.view.KeyEvent);
+ method public void onShow(android.os.Bundle, int);
method public void onTaskFinished(android.content.Intent, int);
method public void onTaskStarted(android.content.Intent, int);
method public void setContentView(android.view.View);
method public void setTheme(int);
+ method public void show();
method public void showWindow();
method public void startVoiceActivity(android.content.Intent);
}
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 7f9693f..7b84cb4 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -156,8 +156,8 @@ public class VoiceInteractor {
@Override
public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException {
- mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(
- MSG_CANCEL_RESULT, request));
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(
+ MSG_CANCEL_RESULT, request, null));
}
};
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index a8c0c4c..797457a 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -23,6 +23,8 @@ import android.os.Bundle;
* @hide
*/
oneway interface IVoiceInteractionSession {
+ void show(in Bundle sessionArgs, int flags);
+ void hide();
void handleAssist(in Bundle assistData);
void taskStarted(in Intent intent, int taskId);
void taskFinished(in Intent intent, int taskId);
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 54a3a0a..0c01b25 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -71,7 +71,7 @@ public class VoiceInteractionService extends Service {
public static final String SERVICE_META_DATA = "android.voice_interaction";
/**
- * Flag for use with {@link #startSession}: request that the session be started with
+ * Flag for use with {@link #showSession: request that the session be started with
* assist data from the currently focused activity.
*/
public static final int START_WITH_ASSIST = 1<<0;
@@ -139,20 +139,25 @@ public class VoiceInteractionService extends Service {
}
/**
- * Initiate the execution of a new {@link android.service.voice.VoiceInteractionSession}.
+ * Request that the associated {@link android.service.voice.VoiceInteractionSession} be
+ * shown to the user, starting it if necessary.
* @param args Arbitrary arguments that will be propagated to the session.
*/
- public void startSession(Bundle args, int flags) {
+ public void showSession(Bundle args, int flags) {
if (mSystemService == null) {
throw new IllegalStateException("Not available until onReady() is called");
}
try {
- mSystemService.startSession(mInterface, args, flags);
+ mSystemService.showSession(mInterface, args, flags);
} catch (RemoteException e) {
}
}
/** @hide */
+ public void startSession(Bundle args, int flags) {
+ showSession(args, flags);
+ }
+ /** @hide */
public void startSession(Bundle args) {
startSession(args, 0);
}
@@ -174,7 +179,7 @@ public class VoiceInteractionService extends Service {
/**
* Called during service initialization to tell you when the system is ready
* to receive interaction from it. You should generally do initialization here
- * rather than in {@link #onCreate}. Methods such as {@link #startSession} and
+ * rather than in {@link #onCreate}. Methods such as {@link #showSession} and
* {@link #createAlwaysOnHotwordDetector}
* will not be operational until this point.
*/
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index a3a2ca1..4cf0e4c 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -53,10 +53,9 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
/**
* An active voice interaction session, providing a facility for the implementation
- * to interact with the user in the voice interaction layer. This interface is no shown
- * by default, but you can request that it be shown with {@link #showWindow()}, which
- * will result in a later call to {@link #onCreateContentView()} in which the UI can be
- * built
+ * to interact with the user in the voice interaction layer. The user interface is
+ * initially shown by default, and can be created be overriding {@link #onCreateContentView()}
+ * in which the UI can be built.
*
* <p>A voice interaction session can be self-contained, ultimately calling {@link #finish}
* when done. It can also initiate voice interactions with applications by calling
@@ -151,6 +150,17 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
@Override
+ public void show(Bundle sessionArgs, int flags) {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_SHOW,
+ flags, sessionArgs));
+ }
+
+ @Override
+ public void hide() {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_HIDE));
+ }
+
+ @Override
public void handleAssist(Bundle assistBundle) {
mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_ASSIST,
assistBundle));
@@ -284,6 +294,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
static final int MSG_DESTROY = 103;
static final int MSG_HANDLE_ASSIST = 104;
+ static final int MSG_SHOW = 105;
+ static final int MSG_HIDE = 106;
class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
@Override
@@ -324,9 +336,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
break;
case MSG_CANCEL:
- args = (SomeArgs)msg.obj;
- if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
- onCancel((Request)args.arg1);
+ if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
+ onCancel((Request)msg.obj);
break;
case MSG_TASK_STARTED:
if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
@@ -350,6 +361,15 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
if (DEBUG) Log.d(TAG, "onHandleAssist: " + (Bundle)msg.obj);
onHandleAssist((Bundle) msg.obj);
break;
+ case MSG_SHOW:
+ if (DEBUG) Log.d(TAG, "doShow: args=" + msg.obj
+ + " flags=" + msg.arg1);
+ doShow((Bundle) msg.obj, msg.arg1);
+ break;
+ case MSG_HIDE:
+ if (DEBUG) Log.d(TAG, "doHide");
+ doHide();
+ break;
}
}
@@ -457,6 +477,45 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
onCreate(args, startFlags);
}
+ void doShow(Bundle args, int flags) {
+ if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
+ + " mWindowVisible=" + mWindowVisible);
+
+ if (mInShowWindow) {
+ Log.w(TAG, "Re-entrance in to showWindow");
+ return;
+ }
+
+ try {
+ mInShowWindow = true;
+ if (!mWindowVisible) {
+ if (!mWindowAdded) {
+ mWindowAdded = true;
+ View v = onCreateContentView();
+ if (v != null) {
+ setContentView(v);
+ }
+ }
+ }
+ onShow(args, flags);
+ if (!mWindowVisible) {
+ mWindowVisible = true;
+ mWindow.show();
+ }
+ } finally {
+ mWindowWasVisible = true;
+ mInShowWindow = false;
+ }
+ }
+
+ void doHide() {
+ if (mWindowVisible) {
+ mWindow.hide();
+ mWindowVisible = false;
+ onHide();
+ }
+ }
+
void doDestroy() {
onDestroy();
if (mInitialized) {
@@ -484,39 +543,26 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
}
- public void showWindow() {
- if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
- + " mWindowVisible=" + mWindowVisible);
-
- if (mInShowWindow) {
- Log.w(TAG, "Re-entrance in to showWindow");
- return;
+ public void show() {
+ try {
+ mSystemService.showSessionFromSession(mToken, null, 0);
+ } catch (RemoteException e) {
}
+ }
+ public void hide() {
try {
- mInShowWindow = true;
- if (!mWindowVisible) {
- mWindowVisible = true;
- if (!mWindowAdded) {
- mWindowAdded = true;
- View v = onCreateContentView();
- if (v != null) {
- setContentView(v);
- }
- }
- mWindow.show();
- }
- } finally {
- mWindowWasVisible = true;
- mInShowWindow = false;
+ mSystemService.hideSessionFromSession(mToken);
+ } catch (RemoteException e) {
}
}
+ /** TODO: remove */
+ public void showWindow() {
+ }
+
+ /** TODO: remove */
public void hideWindow() {
- if (mWindowVisible) {
- mWindow.hide();
- mWindowVisible = false;
- }
}
/**
@@ -611,15 +657,33 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
- * Initiatize a new session.
+ * Initiatize a new session. The given args and showFlags are the initial values
+ * passed to {@link VoiceInteractionService#showSession VoiceInteractionService.showSession},
+ * if possible. Normally you should handle these in {@link #onShow}.
+ */
+ public void onCreate(Bundle args, int showFlags) {
+ onCreate(args);
+ }
+
+ /**
+ * Called when the session UI is going to be shown. This is called after
+ * {@link #onCreateContentView} (if the session's content UI needed to be created) and
+ * immediately prior to the window being shown. This may be called while the window
+ * is already shown, if a show request has come in while it is shown, to allow you to
+ * update the UI to match the new show arguments.
*
* @param args The arguments that were supplied to
- * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}.
- * @param startFlags The start flags originally provided to
- * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}.
+ * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
+ * @param showFlags The show flags originally provided to
+ * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
*/
- public void onCreate(Bundle args, int startFlags) {
- onCreate(args);
+ public void onShow(Bundle args, int showFlags) {
+ }
+
+ /**
+ * Called immediately after stopping to show the session UI.
+ */
+ public void onHide() {
}
/**
@@ -663,7 +727,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
public void onBackPressed() {
- finish();
+ hide();
}
/**
@@ -672,7 +736,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
* calls {@link #finish}.
*/
public void onCloseSystemDialogs() {
- finish();
+ hide();
}
/**
@@ -717,7 +781,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
* @param taskId Unique ID of the finished task.
*/
public void onTaskFinished(Intent intent, int taskId) {
- finish();
+ hide();
}
/**
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 6d90420..8f549a6 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -26,9 +26,11 @@ import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
interface IVoiceInteractionManagerService {
- void startSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags);
+ void showSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags);
boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
IVoiceInteractor interactor);
+ boolean showSessionFromSession(IBinder token, in Bundle sessionArgs, int flags);
+ boolean hideSessionFromSession(IBinder token);
int startVoiceActivity(IBinder token, in Intent intent, String resolvedType);
void finish(IBinder token);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index fd990d7..6b8c49c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -385,7 +385,7 @@ public class VoiceInteractionManagerService extends SystemService {
}
@Override
- public void startSession(IVoiceInteractionService service, Bundle args, int flags) {
+ public void showSession(IVoiceInteractionService service, Bundle args, int flags) {
synchronized (this) {
if (mImpl == null || mImpl.mService == null
|| service.asBinder() != mImpl.mService.asBinder()) {
@@ -396,7 +396,7 @@ public class VoiceInteractionManagerService extends SystemService {
final int callingUid = Binder.getCallingUid();
final long caller = Binder.clearCallingIdentity();
try {
- mImpl.startSessionLocked(callingPid, callingUid, args, flags);
+ mImpl.showSessionLocked(callingPid, callingUid, args, flags);
} finally {
Binder.restoreCallingIdentity(caller);
}
@@ -424,6 +424,42 @@ public class VoiceInteractionManagerService extends SystemService {
}
@Override
+ public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "showSessionFromSession without running voice interaction service");
+ return false;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.showSessionLocked(callingPid, callingUid, sessionArgs, flags);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
+ public boolean hideSessionFromSession(IBinder token) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "hideSessionFromSession without running voice interaction service");
+ return false;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.hideSessionLocked(callingPid, callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
synchronized (this) {
if (mImpl == null) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index e80f702..9e92867 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -26,7 +26,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -35,20 +34,17 @@ import android.os.ServiceManager;
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 android.view.IWindowManager;
-import android.view.WindowManager;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.os.IResultReceiver;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-class VoiceInteractionManagerServiceImpl {
+class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
final static String TAG = "VoiceInteractionServiceManager";
final boolean mValid;
@@ -65,7 +61,7 @@ class VoiceInteractionManagerServiceImpl {
boolean mBound = false;
IVoiceInteractionService mService;
- SessionConnection mActiveSession;
+ VoiceInteractionSessionConnection mActiveSession;
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -101,124 +97,6 @@ class VoiceInteractionManagerServiceImpl {
}
};
- final class SessionConnection implements ServiceConnection {
- final IBinder mToken = new Binder();
- final Bundle mArgs;
- final int mFlags;
- boolean mBound;
- IVoiceInteractionSessionService mService;
- IVoiceInteractionSession mSession;
- IVoiceInteractor mInteractor;
- boolean mHaveAssistData;
- Bundle mAssistData;
-
- final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
- @Override
- public void send(int resultCode, Bundle resultData) throws RemoteException {
- synchronized (mLock) {
- mHaveAssistData = true;
- mAssistData = resultData;
- if (mSession != null) {
- try {
- mSession.handleAssist(resultData);
- } catch (RemoteException e) {
- }
- }
- }
- }
- };
-
- SessionConnection(Bundle args, int flags) {
- mArgs = args;
- mFlags = flags;
- Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
- serviceIntent.setComponent(mSessionComponentName);
- mBound = mContext.bindServiceAsUser(serviceIntent, this,
- Context.BIND_AUTO_CREATE, new UserHandle(mUser));
- if (mBound) {
- try {
- mIWindowManager.addWindowToken(mToken,
- WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed adding window token", e);
- }
- if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
- try {
- mAm.requestAssistContextExtras(0, mAssistReceiver);
- } catch (RemoteException e) {
- }
- } else {
- mHaveAssistData = true;
- }
- } else {
- 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, mFlags);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed adding window token", e);
- }
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
-
- public void cancel() {
- if (mBound) {
- if (mSession != null) {
- try {
- mSession.destroy();
- } catch (RemoteException e) {
- Slog.w(TAG, "Voice interation session already dead");
- }
- }
- if (mSession != null) {
- try {
- mAm.finishVoiceTask(mSession);
- } catch (RemoteException e) {
- }
- }
- mContext.unbindService(this);
- try {
- mIWindowManager.removeWindowToken(mToken);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed removing window token", e);
- }
- 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("mArgs="); pw.println(mArgs);
- pw.print(prefix); pw.print("mFlags=0x"); pw.println(Integer.toHexString(mFlags));
- 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);
- }
- pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData);
- if (mHaveAssistData) {
- pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
- }
- }
- };
-
VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock,
int userHandle, ComponentName service) {
mContext = context;
@@ -256,12 +134,16 @@ class VoiceInteractionManagerServiceImpl {
mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
}
- public void startSessionLocked(int callingPid, int callingUid, Bundle args, int flags) {
- if (mActiveSession != null) {
- mActiveSession.cancel();
- mActiveSession = null;
+ public boolean showSessionLocked(int callingPid, int callingUid, Bundle args, int flags) {
+ if (mActiveSession == null) {
+ mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
+ mUser, mContext, this, callingPid, callingUid);
}
- mActiveSession = new SessionConnection(args, flags);
+ return mActiveSession.showLocked(args, flags);
+ }
+
+ public boolean hideSessionLocked(int callingPid, int callingUid) {
+ return mActiveSession.hideLocked();
}
public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
@@ -270,14 +152,7 @@ class VoiceInteractionManagerServiceImpl {
Slog.w(TAG, "deliverNewSession does not match active session");
return false;
}
- mActiveSession.mSession = session;
- mActiveSession.mInteractor = interactor;
- if (mActiveSession.mHaveAssistData) {
- try {
- session.handleAssist(mActiveSession.mAssistData);
- } catch (RemoteException e) {
- }
- }
+ mActiveSession.deliverNewSessionLocked(session, interactor);
return true;
}
@@ -367,4 +242,11 @@ class VoiceInteractionManagerServiceImpl {
Slog.w(TAG, "RemoteException while calling soundModelsChanged", e);
}
}
+
+ @Override
+ public void sessionConnectionGone(VoiceInteractionSessionConnection connection) {
+ synchronized (mLock) {
+ finishLocked(connection.mCallingPid, connection.mCallingUid, connection.mToken);
+ }
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
new file mode 100644
index 0000000..e2b47c3
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.voiceinteraction;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.IVoiceInteractionSessionService;
+import android.service.voice.VoiceInteractionService;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.os.IResultReceiver;
+
+import java.io.PrintWriter;
+
+final class VoiceInteractionSessionConnection implements ServiceConnection {
+ final static String TAG = "VoiceInteractionServiceManager";
+
+ final IBinder mToken = new Binder();
+ final Object mLock;
+ final ComponentName mSessionComponentName;
+ final Intent mBindIntent;
+ final int mUser;
+ final Context mContext;
+ final Callback mCallback;
+ final int mCallingPid;
+ final int mCallingUid;
+ final IActivityManager mAm;
+ final IWindowManager mIWindowManager;
+ boolean mShown;
+ Bundle mShowArgs;
+ int mShowFlags;
+ boolean mBound;
+ boolean mFullyBound;
+ boolean mCanceled;
+ IVoiceInteractionSessionService mService;
+ IVoiceInteractionSession mSession;
+ IVoiceInteractor mInteractor;
+ boolean mHaveAssistData;
+ Bundle mAssistData;
+
+ public interface Callback {
+ public void sessionConnectionGone(VoiceInteractionSessionConnection connection);
+ }
+
+ final ServiceConnection mFullConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ };
+
+ final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+ @Override
+ public void send(int resultCode, Bundle resultData) throws RemoteException {
+ synchronized (mLock) {
+ if (mShown) {
+ if (mSession != null) {
+ try {
+ mSession.handleAssist(resultData);
+ } catch (RemoteException e) {
+ }
+ } else {
+ mHaveAssistData = true;
+ mAssistData = resultData;
+ }
+ }
+ }
+ }
+ };
+
+ public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user,
+ Context context, Callback callback, int callingPid, int callingUid) {
+ mLock = lock;
+ mSessionComponentName = component;
+ mUser = user;
+ mContext = context;
+ mCallback = callback;
+ mCallingPid = callingPid;
+ mCallingUid = callingUid;
+ mAm = ActivityManagerNative.getDefault();
+ mIWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
+ mBindIntent.setComponent(mSessionComponentName);
+ mBound = mContext.bindServiceAsUser(mBindIntent, this,
+ Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
+ if (mBound) {
+ try {
+ mIWindowManager.addWindowToken(mToken,
+ WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed adding window token", e);
+ }
+ } else {
+ Slog.w(TAG, "Failed binding to voice interaction session service "
+ + mSessionComponentName);
+ }
+ }
+
+ public boolean showLocked(Bundle args, int flags) {
+ if (mBound) {
+ if (!mFullyBound) {
+ mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
+ Context.BIND_AUTO_CREATE|Context.BIND_TREAT_LIKE_ACTIVITY,
+ new UserHandle(mUser));
+ }
+ mShown = true;
+ mShowArgs = args;
+ mShowFlags = flags;
+ if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
+ try {
+ mAm.requestAssistContextExtras(0, mAssistReceiver);
+ } catch (RemoteException e) {
+ }
+ } else {
+ mHaveAssistData = false;
+ mAssistData = null;
+ }
+ if (mSession != null) {
+ try {
+ mSession.show(mShowArgs, mShowFlags);
+ mShowArgs = null;
+ mShowFlags = 0;
+ } catch (RemoteException e) {
+ }
+ if (mHaveAssistData) {
+ try {
+ mSession.handleAssist(mAssistData);
+ mAssistData = null;
+ mHaveAssistData = false;
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public boolean hideLocked() {
+ if (mBound) {
+ if (mShown) {
+ mShown = false;
+ mShowArgs = null;
+ mShowFlags = 0;
+ mHaveAssistData = false;
+ mAssistData = null;
+ if (mSession != null) {
+ try {
+ mSession.hide();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ if (mFullyBound) {
+ mContext.unbindService(mFullConnection);
+ mFullyBound = false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public boolean deliverNewSessionLocked(IVoiceInteractionSession session,
+ IVoiceInteractor interactor) {
+ mSession = session;
+ mInteractor = interactor;
+ if (mShown) {
+ try {
+ session.show(mShowArgs, mShowFlags);
+ mShowArgs = null;
+ mShowFlags = 0;
+ } catch (RemoteException e) {
+ }
+ if (mHaveAssistData) {
+ try {
+ session.handleAssist(mAssistData);
+ mAssistData = null;
+ mHaveAssistData = false;
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mService = IVoiceInteractionSessionService.Stub.asInterface(service);
+ if (!mCanceled) {
+ try {
+ mService.newSession(mToken, mShowArgs, mShowFlags);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed adding window token", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mCallback.sessionConnectionGone(this);
+ mService = null;
+ }
+
+ public void cancel() {
+ mCanceled = true;
+ if (mBound) {
+ if (mSession != null) {
+ try {
+ mSession.destroy();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Voice interation session already dead");
+ }
+ }
+ if (mSession != null) {
+ try {
+ mAm.finishVoiceTask(mSession);
+ } catch (RemoteException e) {
+ }
+ }
+ mContext.unbindService(this);
+ try {
+ mIWindowManager.removeWindowToken(mToken);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed removing window token", e);
+ }
+ mBound = false;
+ mService = null;
+ mSession = null;
+ mInteractor = null;
+ }
+ if (mFullyBound) {
+ mContext.unbindService(mFullConnection);
+ mFullyBound = false;
+ }
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mToken="); pw.println(mToken);
+ pw.print(prefix); pw.print("mShown="); pw.println(mShown);
+ pw.print(prefix); pw.print("mShowArgs="); pw.println(mShowArgs);
+ pw.print(prefix); pw.print("mShowFlags=0x"); pw.println(Integer.toHexString(mShowFlags));
+ 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);
+ }
+ pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData);
+ if (mHaveAssistData) {
+ pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
+ }
+ }
+};
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index adf572c..36d5d98 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -16,7 +16,8 @@
android:label="Test Assist Proxy"
android:theme="@android:style/Theme.NoDisplay"
android:excludeFromRecents="true"
- android:noHistory="true">
+ android:noHistory="true"
+ android:taskAffinity="">
<intent-filter>
<action android:name="android.intent.action.ASSIST" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml
index c4e280e..f4648b5 100644
--- a/tests/VoiceInteraction/res/layout/test_interaction.xml
+++ b/tests/VoiceInteraction/res/layout/test_interaction.xml
@@ -48,4 +48,11 @@
android:text="@string/abortVoice"
/>
+ <Button android:id="@+id/cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/cancelVoice"
+ />
+
</LinearLayout>
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
index 7eec90c..9f99c97 100644
--- a/tests/VoiceInteraction/res/values/strings.xml
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -22,6 +22,7 @@
<string name="complete">Complete</string>
<string name="abortVoice">Abort Voice</string>
<string name="completeVoice">Complete Voice</string>
+ <string name="cancelVoice">Cancel</string>
</resources>
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
index fc04ff5..6a99351 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
@@ -29,6 +29,6 @@ public class AssistProxyActivity extends Activity {
Intent intent = new Intent(this, MainInteractionService.class);
intent.setAction(Intent.ACTION_ASSIST);
intent.putExtras(getIntent());
- startService(new Intent(this, MainInteractionService.class));
+ startService(intent);
}
}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 5d5ae2f..d35bc5c 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -57,6 +57,11 @@ public class AssistVisualizer extends View {
}
}
+ public void clearAssistData() {
+ mAssistData = null;
+ mTextRects.clear();
+ }
+
void buildTextRects(AssistData.ViewNode root, int parentLeft, int parentTop) {
if (root.getVisibility() != View.VISIBLE) {
return;
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 1aeb98a..1e30aff 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -49,6 +49,7 @@ public class MainInteractionSession extends VoiceInteractionSession
static final int STATE_COMMAND = 3;
static final int STATE_ABORT_VOICE = 4;
static final int STATE_COMPLETE_VOICE = 5;
+ static final int STATE_DONE=6;
int mState = STATE_IDLE;
Request mPendingRequest;
@@ -60,12 +61,26 @@ public class MainInteractionSession extends VoiceInteractionSession
@Override
public void onCreate(Bundle args, int startFlags) {
super.onCreate(args);
- showWindow();
+ }
+
+ @Override
+ public void onShow(Bundle args, int showFlags) {
+ super.onShow(args, showFlags);
+ mState = STATE_IDLE;
mStartIntent = args.getParcelable("intent");
Bundle assist = args.getBundle("assist");
- if (assist != null) {
- parseAssistData(assist);
+ parseAssistData(assist);
+ updateState();
+ }
+
+ @Override
+ public void onHide() {
+ super.onHide();
+ if (mAssistVisualizer != null) {
+ mAssistVisualizer.clearAssistData();
}
+ mState = STATE_DONE;
+ updateState();
}
@Override
@@ -86,7 +101,6 @@ public class MainInteractionSession extends VoiceInteractionSession
mCompleteButton.setOnClickListener(this);
mAbortButton = (Button)mContentView.findViewById(R.id.abort);
mAbortButton.setOnClickListener(this);
- updateState();
return mContentView;
}
@@ -100,23 +114,35 @@ public class MainInteractionSession extends VoiceInteractionSession
}
void parseAssistData(Bundle assistBundle) {
- Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
- if (assistContext != null) {
- mAssistData = AssistData.getAssistData(assistContext);
- mAssistData.dump();
- if (mAssistVisualizer != null) {
- mAssistVisualizer.setAssistData(mAssistData);
+ if (assistBundle != null) {
+ Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
+ if (assistContext != null) {
+ mAssistData = AssistData.getAssistData(assistContext);
+ mAssistData.dump();
+ if (mAssistVisualizer != null) {
+ mAssistVisualizer.setAssistData(mAssistData);
+ }
+ return;
}
}
+ if (mAssistVisualizer != null) {
+ mAssistVisualizer.clearAssistData();
+ }
}
void updateState() {
if (mState == STATE_IDLE) {
mTopContent.setVisibility(View.VISIBLE);
mBottomContent.setVisibility(View.GONE);
+ mAssistVisualizer.setVisibility(View.VISIBLE);
+ } else if (mState == STATE_DONE) {
+ mTopContent.setVisibility(View.GONE);
+ mBottomContent.setVisibility(View.GONE);
+ mAssistVisualizer.setVisibility(View.GONE);
} else {
mTopContent.setVisibility(View.GONE);
mBottomContent.setVisibility(View.VISIBLE);
+ mAssistVisualizer.setVisibility(View.GONE);
}
mStartButton.setEnabled(mState == STATE_IDLE);
mConfirmButton.setEnabled(mState == STATE_CONFIRM || mState == STATE_COMMAND);
@@ -136,18 +162,12 @@ public class MainInteractionSession extends VoiceInteractionSession
mPendingRequest.sendCommandResult(true, null);
}
mPendingRequest = null;
- mState = STATE_IDLE;
- updateState();
} else if (v == mAbortButton) {
mPendingRequest.sendAbortVoiceResult(null);
mPendingRequest = null;
- mState = STATE_IDLE;
- updateState();
} else if (v== mCompleteButton) {
mPendingRequest.sendCompleteVoiceResult(null);
mPendingRequest = null;
- mState = STATE_IDLE;
- updateState();
}
}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index 8522cdc..023e0ec 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -31,8 +31,10 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
static final String TAG = "TestInteractionActivity";
VoiceInteractor mInteractor;
+ VoiceInteractor.Request mCurrentRequest = null;
Button mAbortButton;
Button mCompleteButton;
+ Button mCancelButton;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -56,9 +58,11 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
mAbortButton.setOnClickListener(this);
mCompleteButton = (Button)findViewById(R.id.complete);
mCompleteButton.setOnClickListener(this);
+ mCancelButton = (Button)findViewById(R.id.cancel);
+ mCancelButton.setOnClickListener(this);
mInteractor = getVoiceInteractor();
- VoiceInteractor.ConfirmationRequest req = new VoiceInteractor.ConfirmationRequest(
+ mCurrentRequest = new VoiceInteractor.ConfirmationRequest(
"This is a confirmation", null) {
@Override
public void onCancel() {
@@ -72,7 +76,7 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
getActivity().finish();
}
};
- mInteractor.submitRequest(req);
+ mInteractor.submitRequest(mCurrentRequest);
}
@Override
@@ -112,6 +116,9 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
}
};
mInteractor.submitRequest(req);
+ } else if (v == mCancelButton && mCurrentRequest != null) {
+ Log.i(TAG, "Cancel request");
+ mCurrentRequest.cancel();
}
}