diff --git a/api/current.txt b/api/current.txt index de5b1e6b89f00..00ee7a8dd36f4 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 92f0f4d61a803..626dfd08f9b01 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 7f9693fbe62ba..7b84cb4c82ff5 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 a8c0c4c04559e..797457a305361 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 54a3a0a65283f..0c01b259a33f8 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,19 +139,24 @@ 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 a3a2ca1f47e61..4cf0e4ca87652 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. * *
A voice interaction session can be self-contained, ultimately calling {@link #finish}
* when done. It can also initiate voice interactions with applications by calling
@@ -150,6 +149,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,
@@ -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,41 +543,28 @@ 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 {
- 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.showSessionFromSession(mToken, null, 0);
+ } catch (RemoteException e) {
}
}
- public void hideWindow() {
- if (mWindowVisible) {
- mWindow.hide();
- mWindowVisible = false;
+ public void hide() {
+ try {
+ mSystemService.hideSessionFromSession(mToken);
+ } catch (RemoteException e) {
}
}
+ /** TODO: remove */
+ public void showWindow() {
+ }
+
+ /** TODO: remove */
+ public void hideWindow() {
+ }
+
/**
* You can call this to customize the theme used by your IME's window.
* This must be set before {@link #onCreate}, so you
@@ -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 6d904207d1b4e..8f549a6b5fc08 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 fd990d798ea78..6b8c49cc82fc6 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);
}
@@ -423,6 +423,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) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index e80f702d6b770..9e92867349ce1 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 0000000000000..e2b47c38a462c
--- /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 adf572c8f2396..36d5d984ba42f 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="">