diff options
author | Dianne Hackborn <hackbod@google.com> | 2014-04-25 17:06:18 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2014-04-28 10:54:15 -0700 |
commit | 18f0d357f9693fe787a3e3777d8fdf01357a6e3f (patch) | |
tree | 87ffa17a98fa81355a37e25b2c7fc649ffc4e9be /core/java/android/service | |
parent | 01c70711d5e4f1c3405bcd169be70605e92166f2 (diff) | |
download | frameworks_base-18f0d357f9693fe787a3e3777d8fdf01357a6e3f.zip frameworks_base-18f0d357f9693fe787a3e3777d8fdf01357a6e3f.tar.gz frameworks_base-18f0d357f9693fe787a3e3777d8fdf01357a6e3f.tar.bz2 |
Rework some of the voice interaction APIs.
On the app side, requests are now composed by subclassing
from various types of Request objects.
On the service side, starting a voice interaction session
involves starting another service that will then manage the
session. This leads the service design much more to what
we want, where the long-running main service is very tiny
and all the heavy-weight transient session work is elsewhere
in another process.
Change-Id: I46c074c6fe27b6c1cf2583c6d216aed1de2f1143
Diffstat (limited to 'core/java/android/service')
5 files changed, 241 insertions, 6 deletions
diff --git a/core/java/android/service/voice/IVoiceInteractionSessionService.aidl b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl new file mode 100644 index 0000000..2519442 --- /dev/null +++ b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2014 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 android.service.voice; + +import android.os.Bundle; + +import android.service.voice.IVoiceInteractionSession; + +/** + * @hide + */ +oneway interface IVoiceInteractionSessionService { + void newSession(IBinder token, in Bundle args); +} diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index ed93b74..d005890 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -21,6 +21,7 @@ import android.app.Instrumentation; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -50,12 +51,11 @@ public class VoiceInteractionService extends Service { IVoiceInteractionManagerService mSystemService; - public void startVoiceActivity(Intent intent, VoiceInteractionSession session) { + public void startVoiceActivity(Intent intent, Bundle sessionArgs) { try { - int res = mSystemService.startVoiceActivity(intent, + mSystemService.startVoiceActivity(intent, intent.resolveType(getContentResolver()), - mInterface, session.mSession, session.mInteractor); - Instrumentation.checkStartActivityResult(res, intent); + mInterface, sessionArgs); } catch (RemoteException e) { } } diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java new file mode 100644 index 0000000..a909ead --- /dev/null +++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014 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 android.service.voice; + +import android.Manifest; +import android.content.ComponentName; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.speech.RecognitionService; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Xml; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide */ +public class VoiceInteractionServiceInfo { + static final String TAG = "VoiceInteractionServiceInfo"; + + private String mParseError; + + private ServiceInfo mServiceInfo; + private String mSessionService; + private String mSettingsActivity; + + public VoiceInteractionServiceInfo(PackageManager pm, ComponentName comp) + throws PackageManager.NameNotFoundException { + this(pm, pm.getServiceInfo(comp, PackageManager.GET_META_DATA)); + } + + public VoiceInteractionServiceInfo(PackageManager pm, ServiceInfo si) { + if (!Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) { + mParseError = "Service does not require permission " + + Manifest.permission.BIND_VOICE_INTERACTION; + return; + } + + XmlResourceParser parser = null; + try { + parser = si.loadXmlMetaData(pm, VoiceInteractionService.SERVICE_META_DATA); + if (parser == null) { + mParseError = "No " + VoiceInteractionService.SERVICE_META_DATA + + " meta-data for " + si.packageName; + return; + } + + Resources res = pm.getResourcesForApplication(si.applicationInfo); + + AttributeSet attrs = Xml.asAttributeSet(parser); + + int type; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + + String nodeName = parser.getName(); + if (!"voice-interaction-service".equals(nodeName)) { + mParseError = "Meta-data does not start with voice-interaction-service tag"; + return; + } + + TypedArray array = res.obtainAttributes(attrs, + com.android.internal.R.styleable.VoiceInteractionService); + mSessionService = array.getString( + com.android.internal.R.styleable.VoiceInteractionService_sessionService); + mSettingsActivity = array.getString( + com.android.internal.R.styleable.VoiceInteractionService_settingsActivity); + array.recycle(); + if (mSessionService == null) { + mParseError = "No sessionService specified"; + return; + } + } catch (XmlPullParserException e) { + mParseError = "Error parsing voice interation service meta-data: " + e; + Log.w(TAG, "error parsing voice interaction service meta-data", e); + return; + } catch (IOException e) { + mParseError = "Error parsing voice interation service meta-data: " + e; + Log.w(TAG, "error parsing voice interaction service meta-data", e); + return; + } catch (PackageManager.NameNotFoundException e) { + mParseError = "Error parsing voice interation service meta-data: " + e; + Log.w(TAG, "error parsing voice interaction service meta-data", e); + return; + } finally { + if (parser != null) parser.close(); + } + mServiceInfo = si; + } + + public String getParseError() { + return mParseError; + } + + public ServiceInfo getServiceInfo() { + return mServiceInfo; + } + + public String getSessionService() { + return mSessionService; + } + + public String getSettingsActivity() { + return mSettingsActivity; + } +} diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 59544be..963b6b4 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -96,11 +96,11 @@ public abstract class VoiceInteractionSession { } } - public void sendCommandResult(Bundle result) { + public void sendCommandResult(boolean complete, Bundle result) { try { if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface + " result=" + result); - mCallback.deliverCommandResult(mInterface, result); + mCallback.deliverCommandResult(mInterface, complete, result); } catch (RemoteException e) { } } diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java new file mode 100644 index 0000000..40e5bba --- /dev/null +++ b/core/java/android/service/voice/VoiceInteractionSessionService.java @@ -0,0 +1,82 @@ +/** + * Copyright (C) 2014 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 android.service.voice; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import com.android.internal.app.IVoiceInteractionManagerService; +import com.android.internal.os.HandlerCaller; +import com.android.internal.os.SomeArgs; + +public abstract class VoiceInteractionSessionService extends Service { + + static final int MSG_NEW_SESSION = 1; + + IVoiceInteractionManagerService mSystemService; + + IVoiceInteractionSessionService mInterface = new IVoiceInteractionSessionService.Stub() { + public void newSession(IBinder token, Bundle args) { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(MSG_NEW_SESSION, + token, args)); + + } + }; + + HandlerCaller mHandlerCaller; + final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() { + @Override + public void executeMessage(Message msg) { + SomeArgs args = (SomeArgs)msg.obj; + switch (msg.what) { + case MSG_NEW_SESSION: + doNewSession((IBinder)args.arg1, (Bundle)args.arg2); + break; + } + } + }; + + @Override + public void onCreate() { + super.onCreate(); + mSystemService = IVoiceInteractionManagerService.Stub.asInterface( + ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); + mHandlerCaller = new HandlerCaller(this, Looper.myLooper(), + mHandlerCallerCallback, true); + } + + public abstract VoiceInteractionSession onNewSession(Bundle args); + + @Override + public IBinder onBind(Intent intent) { + return mInterface.asBinder(); + } + + void doNewSession(IBinder token, Bundle args) { + VoiceInteractionSession session = onNewSession(args); + try { + mSystemService.deliverNewSession(token, session.mSession, session.mInteractor); + } catch (RemoteException e) { + } + } +} |