diff options
| author | Dianne Hackborn <hackbod@google.com> | 2014-05-02 10:45:59 -0700 |
|---|---|---|
| committer | Dianne Hackborn <hackbod@google.com> | 2014-05-05 11:18:08 -0700 |
| commit | c03c9167c2d9a1e22fb2b176b00a0524177fb037 (patch) | |
| tree | bc8045725f3384dff1c53a508041fa63f78e5ce8 /services/voiceinteraction | |
| parent | 6b003c9e3c0d3e5e31d9578e6d15facc6553e45e (diff) | |
| download | frameworks_base-c03c9167c2d9a1e22fb2b176b00a0524177fb037.zip frameworks_base-c03c9167c2d9a1e22fb2b176b00a0524177fb037.tar.gz frameworks_base-c03c9167c2d9a1e22fb2b176b00a0524177fb037.tar.bz2 | |
Further work on voice interaction services.
This makes VoiceInteractionSession a more first-class
concept. Now the flow is that a VoiceInteractionService
calls startSession() when it wants to begin a session.
This will result in a new VoiceInteractionSession via the
VoiceInteractionSessionService containing it, and the
session at that point an decide what to do. It can now
show UI, and it is what has access to the startVoiceActivity
API.
Change-Id: Ie2b85b3020ef1206d3f44b335b128d064e8f9935
Diffstat (limited to 'services/voiceinteraction')
2 files changed, 151 insertions, 38 deletions
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 045c0f6..16afc8f 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -28,6 +28,8 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Parcel; +import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.service.voice.IVoiceInteractionService; @@ -88,6 +90,21 @@ public class VoiceInteractionManagerService extends SystemService { private boolean mSafeMode; private int mCurUser; + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + try { + return super.onTransact(code, data, reply, flags); + } catch (RuntimeException e) { + // The activity manager only throws security exceptions, so let's + // log all others. + if (!(e instanceof SecurityException)) { + Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e); + } + throw e; + } + } + public void systemRunning(boolean safeMode) { mSafeMode = safeMode; @@ -97,18 +114,18 @@ public class VoiceInteractionManagerService extends SystemService { synchronized (this) { mCurUser = ActivityManager.getCurrentUser(); - switchImplementationIfNeededLocked(); + switchImplementationIfNeededLocked(false); } } public void switchUser(int userHandle) { synchronized (this) { mCurUser = userHandle; - switchImplementationIfNeededLocked(); + switchImplementationIfNeededLocked(false); } } - void switchImplementationIfNeededLocked() { + void switchImplementationIfNeededLocked(boolean force) { if (!mSafeMode) { String curService = Settings.Secure.getStringForUser( mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser); @@ -121,7 +138,7 @@ public class VoiceInteractionManagerService extends SystemService { serviceComponent = null; } } - if (mImpl == null || mImpl.mUser != mCurUser + if (force || mImpl == null || mImpl.mUser != mCurUser || !mImpl.mComponent.equals(serviceComponent)) { if (mImpl != null) { mImpl.shutdownLocked(); @@ -138,10 +155,10 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public void startVoiceActivity(Intent intent, String resolvedType, - IVoiceInteractionService service, Bundle args) { + public void startSession(IVoiceInteractionService service, Bundle args) { synchronized (this) { - if (mImpl == null || service.asBinder() != mImpl.mService.asBinder()) { + if (mImpl == null || mImpl.mService == null + || service.asBinder() != mImpl.mService.asBinder()) { throw new SecurityException( "Caller is not the current voice interaction service"); } @@ -149,8 +166,7 @@ public class VoiceInteractionManagerService extends SystemService { final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - mImpl.startVoiceActivityLocked(callingPid, callingUid, - intent, resolvedType, args); + mImpl.startSessionLocked(callingPid, callingUid, args); } finally { Binder.restoreCallingIdentity(caller); } @@ -158,12 +174,12 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public int deliverNewSession(IBinder token, IVoiceInteractionSession session, + public boolean 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; + throw new SecurityException( + "deliverNewSession without running voice interaction service"); } final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); @@ -175,7 +191,43 @@ public class VoiceInteractionManagerService extends SystemService { Binder.restoreCallingIdentity(caller); } } + } + @Override + public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) { + synchronized (this) { + if (mImpl == null) { + Slog.w(TAG, "startVoiceActivity 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.startVoiceActivityLocked(callingPid, callingUid, token, + intent, resolvedType); + } finally { + Binder.restoreCallingIdentity(caller); + } + } + } + + @Override + public void finish(IBinder token) { + synchronized (this) { + if (mImpl == null) { + Slog.w(TAG, "finish without running voice interaction service"); + return; + } + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); + final long caller = Binder.clearCallingIdentity(); + try { + mImpl.finishLocked(callingPid, callingUid, token); + } finally { + Binder.restoreCallingIdentity(caller); + } + } } @Override @@ -207,7 +259,7 @@ public class VoiceInteractionManagerService extends SystemService { @Override public void onChange(boolean selfChange) { synchronized (VoiceInteractionManagerServiceStub.this) { - switchImplementationIfNeededLocked(); + switchImplementationIfNeededLocked(false); } } } @@ -220,27 +272,25 @@ public class VoiceInteractionManagerService extends SystemService { @Override public void onHandleUserStop(Intent intent, int userHandle) { - super.onHandleUserStop(intent, userHandle); } @Override public void onPackageDisappeared(String packageName, int reason) { - super.onPackageDisappeared(packageName, reason); } @Override public void onPackageAppeared(String packageName, int reason) { - super.onPackageAppeared(packageName, reason); + if (mImpl != null && packageName.equals(mImpl.mComponent.getPackageName())) { + switchImplementationIfNeededLocked(true); + } } @Override public void onPackageModified(String packageName) { - super.onPackageModified(packageName); } @Override public void onSomePackagesChanged() { - super.onSomePackagesChanged(); } }; } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 6bbd1c1..9b6daad 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -19,9 +19,11 @@ package com.android.server.voiceinteraction; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityManager; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; @@ -30,6 +32,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionSession; @@ -37,6 +40,8 @@ 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 java.io.FileDescriptor; @@ -55,11 +60,28 @@ class VoiceInteractionManagerServiceImpl { final IActivityManager mAm; final VoiceInteractionServiceInfo mInfo; final ComponentName mSessionComponentName; + final IWindowManager mIWindowManager; boolean mBound = false; IVoiceInteractionService mService; SessionConnection mActiveSession; + final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { + synchronized (mLock) { + if (mActiveSession != null && mActiveSession.mSession != null) { + try { + mActiveSession.mSession.closeSystemDialogs(); + } catch (RemoteException e) { + } + } + } + } + } + }; + final ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { @@ -76,23 +98,26 @@ 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; + SessionConnection(Bundle args) { 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) { + if (mBound) { + try { + mIWindowManager.addWindowToken(mToken, + WindowManager.LayoutParams.TYPE_INPUT_METHOD); + } catch (RemoteException e) { + Slog.w(TAG, "Failed adding window token", e); + } + } else { Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent); } } @@ -105,7 +130,7 @@ class VoiceInteractionManagerServiceImpl { try { mService.newSession(mToken, mArgs); } catch (RemoteException e) { - Slog.w(TAG, "Failed making new session", e); + Slog.w(TAG, "Failed adding window token", e); } } } @@ -118,7 +143,19 @@ class VoiceInteractionManagerServiceImpl { public void cancel() { if (mBound) { + if (mSession != null) { + try { + mSession.destroy(); + } catch (RemoteException e) { + Slog.w(TAG, "Voice interation session already dead"); + } + } mContext.unbindService(this); + try { + mIWindowManager.removeWindowToken(mToken); + } catch (RemoteException e) { + Slog.w(TAG, "Failed removing window token", e); + } mBound = false; mService = null; mSession = null; @@ -128,8 +165,6 @@ class VoiceInteractionManagerServiceImpl { 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) { @@ -155,6 +190,7 @@ class VoiceInteractionManagerServiceImpl { Slog.w(TAG, "Voice interaction service not found: " + service); mInfo = null; mSessionComponentName = null; + mIWindowManager = null; mValid = false; return; } @@ -162,43 +198,67 @@ class VoiceInteractionManagerServiceImpl { if (mInfo.getParseError() != null) { Slog.w(TAG, "Bad voice interaction service: " + mInfo.getParseError()); mSessionComponentName = null; + mIWindowManager = null; mValid = false; return; } mValid = true; mSessionComponentName = new ComponentName(service.getPackageName(), mInfo.getSessionService()); + mIWindowManager = IWindowManager.Stub.asInterface( + ServiceManager.getService(Context.WINDOW_SERVICE)); + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + mContext.registerReceiver(mBroadcastReceiver, filter, null, handler); } - public void startVoiceActivityLocked(int callingPid, int callingUid, Intent intent, - String resolvedType, Bundle args) { + public void startSessionLocked(int callingPid, int callingUid, Bundle args) { if (mActiveSession != null) { 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 = new SessionConnection(args); } - public int deliverNewSessionLocked(int callingPid, int callingUid, IBinder token, + public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token, IVoiceInteractionSession session, IVoiceInteractor interactor) { + if (mActiveSession == null || token != mActiveSession.mToken) { + Slog.w(TAG, "deliverNewSession does not match active session"); + return false; + } + mActiveSession.mSession = session; + mActiveSession.mInteractor = interactor; + return true; + } + + public int startVoiceActivityLocked(int callingPid, int callingUid, IBinder token, + Intent intent, String resolvedType) { try { if (mActiveSession == null || token != mActiveSession.mToken) { - Slog.w(TAG, "deliverNewSession does not match active session"); + Slog.w(TAG, "startVoiceActivity does not match active session"); return ActivityManager.START_CANCELED; } - mActiveSession.mSession = session; - mActiveSession.mInteractor = interactor; + intent = new Intent(intent); + intent.addCategory(Intent.CATEGORY_VOICE); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid, - mActiveSession.mIntent, mActiveSession.mResolvedType, - mActiveSession.mSession, mActiveSession.mInteractor, + intent, resolvedType, mActiveSession.mSession, mActiveSession.mInteractor, 0, null, null, null, mUser); } catch (RemoteException e) { throw new IllegalStateException("Unexpected remote error", e); } } + + public void finishLocked(int callingPid, int callingUid, IBinder token) { + if (mActiveSession == null || token != mActiveSession.mToken) { + Slog.w(TAG, "finish does not match active session"); + return; + } + mActiveSession.cancel(); + mActiveSession = null; + } + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { if (!mValid) { pw.print(" NOT VALID: "); @@ -234,5 +294,8 @@ class VoiceInteractionManagerServiceImpl { mContext.unbindService(mConnection); mBound = false; } + if (mValid) { + mContext.unregisterReceiver(mBroadcastReceiver); + } } } |
