Loading Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -201,6 +201,7 @@ LOCAL_SRC_FILES += \ core/java/android/service/trust/ITrustAgentServiceCallback.aidl \ core/java/android/service/voice/IVoiceInteractionService.aidl \ core/java/android/service/voice/IVoiceInteractionSession.aidl \ core/java/android/service/voice/IVoiceInteractionSessionService.aidl \ core/java/android/service/wallpaper/IWallpaperConnection.aidl \ core/java/android/service/wallpaper/IWallpaperEngine.aidl \ core/java/android/service/wallpaper/IWallpaperService.aidl \ Loading api/current.txt +30 −13 Original line number Diff line number Diff line Loading @@ -1009,6 +1009,7 @@ package android { field public static final int selectedDateVerticalBar = 16843591; // 0x1010347 field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342 field public static final int sequence = 16843815; // 0x1010427 field public static final int sessionService = 16843850; // 0x101044a field public static final int settingsActivity = 16843301; // 0x1010225 field public static final int shadowColor = 16843105; // 0x1010161 field public static final int shadowDx = 16843106; // 0x1010162 Loading Loading @@ -1663,10 +1664,14 @@ package android { field public static final int decelerate_cubic = 17563651; // 0x10c0003 field public static final int decelerate_quad = 17563649; // 0x10c0001 field public static final int decelerate_quint = 17563653; // 0x10c0005 field public static final int fast_out_linear_in = 17563663; // 0x10c000f field public static final int fast_out_slow_in = 17563661; // 0x10c000d field public static final int fast_out_linear_in = 17563667; // 0x10c0013 field public static final int fast_out_slow_in = 17563665; // 0x10c0011 field public static final int l_resource_pad1 = 17563664; // 0x10c0010 field public static final int l_resource_pad2 = 17563663; // 0x10c000f field public static final int l_resource_pad3 = 17563662; // 0x10c000e field public static final int l_resource_pad4 = 17563661; // 0x10c000d field public static final int linear = 17563659; // 0x10c000b field public static final int linear_out_slow_in = 17563662; // 0x10c000e field public static final int linear_out_slow_in = 17563666; // 0x10c0012 field public static final int overshoot = 17563656; // 0x10c0008 } Loading Loading @@ -4842,20 +4847,26 @@ package android.app { } public class VoiceInteractor { method public android.app.VoiceInteractor.Request startCommand(android.app.VoiceInteractor.Callback, java.lang.String, android.os.Bundle); method public android.app.VoiceInteractor.Request startConfirmation(android.app.VoiceInteractor.Callback, java.lang.String, android.os.Bundle); method public boolean submitRequest(android.app.VoiceInteractor.Request); method public boolean[] supportsCommands(java.lang.String[]); } public static class VoiceInteractor.Callback { ctor public VoiceInteractor.Callback(); method public void onCancel(android.app.VoiceInteractor.Request); method public void onCommandResult(android.app.VoiceInteractor.Request, android.os.Bundle); method public void onConfirmationResult(android.app.VoiceInteractor.Request, boolean, android.os.Bundle); public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request { ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle); method public void onCommandResult(android.os.Bundle); } public static class VoiceInteractor.Request { public static class VoiceInteractor.ConfirmationRequest extends android.app.VoiceInteractor.Request { ctor public VoiceInteractor.ConfirmationRequest(java.lang.CharSequence, android.os.Bundle); method public void onConfirmationResult(boolean, android.os.Bundle); } public static abstract class VoiceInteractor.Request { ctor public VoiceInteractor.Request(); method public void cancel(); method public android.app.Activity getActivity(); method public android.content.Context getContext(); method public void onCancel(); } public final class WallpaperInfo implements android.os.Parcelable { Loading Loading @@ -24919,7 +24930,7 @@ package android.service.voice { public class VoiceInteractionService extends android.app.Service { ctor public VoiceInteractionService(); method public android.os.IBinder onBind(android.content.Intent); method public void startVoiceActivity(android.content.Intent, android.service.voice.VoiceInteractionSession); method public void startVoiceActivity(android.content.Intent, android.os.Bundle); 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"; } Loading @@ -24938,10 +24949,16 @@ package android.service.voice { public static class VoiceInteractionSession.Request { method public void sendCancelResult(); method public void sendCommandResult(android.os.Bundle); method public void sendCommandResult(boolean, android.os.Bundle); method public void sendConfirmResult(boolean, android.os.Bundle); } public abstract class VoiceInteractionSessionService extends android.app.Service { ctor public VoiceInteractionSessionService(); method public android.os.IBinder onBind(android.content.Intent); method public abstract android.service.voice.VoiceInteractionSession onNewSession(android.os.Bundle); } } package android.service.wallpaper { core/java/android/app/Activity.java +1 −1 Original line number Diff line number Diff line Loading @@ -5454,7 +5454,7 @@ public class Activity extends ContextThemeWrapper mEmbeddedID = id; mLastNonConfigurationInstances = lastNonConfigurationInstances; mVoiceInteractor = voiceInteractor != null ? new VoiceInteractor(this, voiceInteractor, Looper.myLooper()) : null; ? new VoiceInteractor(this, this, voiceInteractor, Looper.myLooper()) : null; mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), Loading core/java/android/app/VoiceInteractor.java +151 −111 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.IVoiceInteractorCallback; Loading @@ -39,179 +40,218 @@ public class VoiceInteractor { static final boolean DEBUG = true; final Context mContext; final Activity mActivity; final IVoiceInteractor mInteractor; final HandlerCaller mHandlerCaller; final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() { @Override public void executeMessage(Message msg) { SomeArgs args = (SomeArgs)msg.obj; Request request; switch (msg.what) { case MSG_CONFIRMATION_RESULT: request = pullRequest((IVoiceInteractorRequest)args.arg1, true); if (DEBUG) Log.d(TAG, "onConfirmResult: req=" + ((IVoiceInteractorRequest)args.arg2).asBinder() + " confirmed=" + msg.arg1 + " result=" + args.arg3); ((Callback)args.arg1).onConfirmationResult( findRequest((IVoiceInteractorRequest)args.arg2), msg.arg1 != 0, (Bundle)args.arg3); + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request + " confirmed=" + msg.arg1 + " result=" + args.arg2); if (request != null) { ((ConfirmationRequest)request).onConfirmationResult(msg.arg1 != 0, (Bundle) args.arg2); request.clear(); } break; case MSG_COMMAND_RESULT: request = pullRequest((IVoiceInteractorRequest)args.arg1, msg.arg1 != 0); if (DEBUG) Log.d(TAG, "onCommandResult: req=" + ((IVoiceInteractorRequest)args.arg2).asBinder() + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request + " result=" + args.arg2); ((Callback)args.arg1).onCommandResult( findRequest((IVoiceInteractorRequest) args.arg2), (Bundle) args.arg3); if (request != null) { ((CommandRequest)request).onCommandResult((Bundle) args.arg2); if (msg.arg1 != 0) { request.clear(); } } break; case MSG_CANCEL_RESULT: request = pullRequest((IVoiceInteractorRequest)args.arg1, true); if (DEBUG) Log.d(TAG, "onCancelResult: req=" + ((IVoiceInteractorRequest)args.arg2).asBinder()); ((Callback)args.arg1).onCancel( findRequest((IVoiceInteractorRequest) args.arg2)); + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request); if (request != null) { request.onCancel(); request.clear(); } break; } } }; final WeakHashMap<IBinder, Request> mActiveRequests = new WeakHashMap<IBinder, Request>(); static final int MSG_CONFIRMATION_RESULT = 1; static final int MSG_COMMAND_RESULT = 2; static final int MSG_CANCEL_RESULT = 3; public static class Request { final IVoiceInteractorRequest mRequestInterface; Request(IVoiceInteractorRequest requestInterface) { mRequestInterface = requestInterface; } public void cancel() { try { mRequestInterface.cancel(); } catch (RemoteException e) { Log.w(TAG, "Voice interactor has died", e); } } } public static class Callback { VoiceInteractor mInteractor; final IVoiceInteractorCallback.Stub mWrapper = new IVoiceInteractorCallback.Stub() { final IVoiceInteractorCallback.Stub mCallback = new IVoiceInteractorCallback.Stub() { @Override public void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed, Bundle result) { mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageIOOO( MSG_CONFIRMATION_RESULT, confirmed ? 1 : 0, Callback.this, request, result)); mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO( MSG_CONFIRMATION_RESULT, confirmed ? 1 : 0, request, result)); } @Override public void deliverCommandResult(IVoiceInteractorRequest request, Bundle result) { mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageOOO( MSG_COMMAND_RESULT, Callback.this, request, result)); public void deliverCommandResult(IVoiceInteractorRequest request, boolean complete, Bundle result) { mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO( MSG_COMMAND_RESULT, complete ? 1 : 0, request, result)); } @Override public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException { mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageOO( MSG_CANCEL_RESULT, Callback.this, request)); mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO( MSG_CANCEL_RESULT, request)); } }; public void onConfirmationResult(Request request, boolean confirmed, Bundle result) { } final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>(); static final int MSG_CONFIRMATION_RESULT = 1; static final int MSG_COMMAND_RESULT = 2; static final int MSG_CANCEL_RESULT = 3; public void onCommandResult(Request request, Bundle result) { public static abstract class Request { IVoiceInteractorRequest mRequestInterface; Context mContext; Activity mActivity; public Request() { } public void onCancel(Request request) { public void cancel() { try { mRequestInterface.cancel(); } catch (RemoteException e) { Log.w(TAG, "Voice interactor has died", e); } } VoiceInteractor(Context context, IVoiceInteractor interactor, Looper looper) { mContext = context; mInteractor = interactor; mHandlerCaller = new HandlerCaller(context, looper, mHandlerCallerCallback, true); public Context getContext() { return mContext; } Request storeRequest(IVoiceInteractorRequest request) { synchronized (mActiveRequests) { Request req = new Request(request); mActiveRequests.put(request.asBinder(), req); return req; } public Activity getActivity() { return mActivity; } Request findRequest(IVoiceInteractorRequest request) { synchronized (mActiveRequests) { Request req = mActiveRequests.get(request.asBinder()); if (req == null) { throw new IllegalStateException("Received callback without active request: " + request); public void onCancel() { } return req; void clear() { mRequestInterface = null; mContext = null; mActivity = null; } abstract IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, IVoiceInteractorCallback callback) throws RemoteException; } public static class ConfirmationRequest extends Request { final CharSequence mPrompt; final Bundle mExtras; /** * Asynchronously confirms an operation with the user via the trusted system * VoiceinteractionService. This allows an Activity to complete an unsafe operation that * Confirms an operation with the user via the trusted system * VoiceInteractionService. This allows an Activity to complete an unsafe operation that * would require the user to touch the screen when voice interaction mode is not enabled. * The result of the confirmation will be returned by calling the * {@link Callback#onConfirmationResult Callback.onConfirmationResult} method. * The result of the confirmation will be returned through an asynchronous call to * either {@link #onConfirmationResult(boolean, android.os.Bundle)} or * {@link #onCancel()}. * * In some cases this may be a simple yes / no confirmation or the confirmation could * <p>In some cases this may be a simple yes / no confirmation or the confirmation could * include context information about how the action will be completed * (e.g. booking a cab might include details about how long until the cab arrives) so the user * can give informed consent. * @param callback Required callback target for interaction results. * @param prompt Optional confirmation text to read to the user as the action being confirmed. * (e.g. booking a cab might include details about how long until the cab arrives) * so the user can give a confirmation. * @param prompt Optional confirmation text to read to the user as the action being * confirmed. * @param extras Additional optional information. * @return Returns a new {@link Request} object representing this operation. */ public Request startConfirmation(Callback callback, String prompt, Bundle extras) { try { callback.mInteractor = this; Request req = storeRequest(mInteractor.startConfirmation( mContext.getOpPackageName(), callback.mWrapper, prompt, extras)); if (DEBUG) Log.d(TAG, "startConfirmation: req=" + req.mRequestInterface.asBinder() + " prompt=" + prompt + " extras=" + extras); return req; } catch (RemoteException e) { throw new RuntimeException("Voice interactor has died", e); public ConfirmationRequest(CharSequence prompt, Bundle extras) { mPrompt = prompt; mExtras = extras; } public void onConfirmationResult(boolean confirmed, Bundle result) { } IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, IVoiceInteractorCallback callback) throws RemoteException { return interactor.startConfirmation(packageName, callback, mPrompt.toString(), mExtras); } } public static class CommandRequest extends Request { final String mCommand; final Bundle mArgs; /** * Asynchronously executes a command using the trusted system VoiceinteractionService. * Execute a command using the trusted system VoiceInteractionService. * This allows an Activity to request additional information from the user needed to * complete an action (e.g. booking a table might have several possible times that the * user could select from or an app might need the user to agree to a terms of service). * The result of the confirmation will be returned through an asynchronous call to * either {@link #onCommandResult(android.os.Bundle)} or * {@link #onCancel()}. * * The command is a string that describes the generic operation to be performed. * <p>The command is a string that describes the generic operation to be performed. * The command will determine how the properties in extras are interpreted and the set of * available commands is expected to grow over time. An example might be * "com.google.voice.commands.REQUEST_NUMBER_BAGS" to request the number of bags as part of * airline check-in. (This is not an actual working example.) * The result of the command will be returned by calling the * {@link Callback#onCommandResult Callback.onCommandResult} method. * * @param callback Required callback target for interaction results. * @param command * @param extras * @return Returns a new {@link Request} object representing this operation. * @param command The desired command to perform. * @param args Additional arguments to control execution of the command. */ public Request startCommand(Callback callback, String command, Bundle extras) { try { callback.mInteractor = this; Request req = storeRequest(mInteractor.startCommand( mContext.getOpPackageName(), callback.mWrapper, command, extras)); if (DEBUG) Log.d(TAG, "startCommand: req=" + req.mRequestInterface.asBinder() + " command=" + command + " extras=" + extras); public CommandRequest(String command, Bundle args) { mCommand = command; mArgs = args; } public void onCommandResult(Bundle result) { } IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, IVoiceInteractorCallback callback) throws RemoteException { return interactor.startConfirmation(packageName, callback, mCommand, mArgs); } } VoiceInteractor(Context context, Activity activity, IVoiceInteractor interactor, Looper looper) { mContext = context; mActivity = activity; mInteractor = interactor; mHandlerCaller = new HandlerCaller(context, looper, mHandlerCallerCallback, true); } Request pullRequest(IVoiceInteractorRequest request, boolean complete) { synchronized (mActiveRequests) { Request req = mActiveRequests.get(request.asBinder()); if (req != null && complete) { mActiveRequests.remove(request.asBinder()); } return req; } } public boolean submitRequest(Request request) { try { IVoiceInteractorRequest ireq = request.submit(mInteractor, mContext.getOpPackageName(), mCallback); request.mRequestInterface = ireq; request.mContext = mContext; request.mActivity = mActivity; synchronized (mActiveRequests) { mActiveRequests.put(ireq.asBinder(), request); } return true; } catch (RemoteException e) { throw new RuntimeException("Voice interactor has died", e); Log.w(TAG, "Remove voice interactor service died", e); return false; } } Loading core/java/android/service/voice/IVoiceInteractionSessionService.aidl 0 → 100644 +28 −0 Original line number Diff line number Diff line /* * 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); } Loading
Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -201,6 +201,7 @@ LOCAL_SRC_FILES += \ core/java/android/service/trust/ITrustAgentServiceCallback.aidl \ core/java/android/service/voice/IVoiceInteractionService.aidl \ core/java/android/service/voice/IVoiceInteractionSession.aidl \ core/java/android/service/voice/IVoiceInteractionSessionService.aidl \ core/java/android/service/wallpaper/IWallpaperConnection.aidl \ core/java/android/service/wallpaper/IWallpaperEngine.aidl \ core/java/android/service/wallpaper/IWallpaperService.aidl \ Loading
api/current.txt +30 −13 Original line number Diff line number Diff line Loading @@ -1009,6 +1009,7 @@ package android { field public static final int selectedDateVerticalBar = 16843591; // 0x1010347 field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342 field public static final int sequence = 16843815; // 0x1010427 field public static final int sessionService = 16843850; // 0x101044a field public static final int settingsActivity = 16843301; // 0x1010225 field public static final int shadowColor = 16843105; // 0x1010161 field public static final int shadowDx = 16843106; // 0x1010162 Loading Loading @@ -1663,10 +1664,14 @@ package android { field public static final int decelerate_cubic = 17563651; // 0x10c0003 field public static final int decelerate_quad = 17563649; // 0x10c0001 field public static final int decelerate_quint = 17563653; // 0x10c0005 field public static final int fast_out_linear_in = 17563663; // 0x10c000f field public static final int fast_out_slow_in = 17563661; // 0x10c000d field public static final int fast_out_linear_in = 17563667; // 0x10c0013 field public static final int fast_out_slow_in = 17563665; // 0x10c0011 field public static final int l_resource_pad1 = 17563664; // 0x10c0010 field public static final int l_resource_pad2 = 17563663; // 0x10c000f field public static final int l_resource_pad3 = 17563662; // 0x10c000e field public static final int l_resource_pad4 = 17563661; // 0x10c000d field public static final int linear = 17563659; // 0x10c000b field public static final int linear_out_slow_in = 17563662; // 0x10c000e field public static final int linear_out_slow_in = 17563666; // 0x10c0012 field public static final int overshoot = 17563656; // 0x10c0008 } Loading Loading @@ -4842,20 +4847,26 @@ package android.app { } public class VoiceInteractor { method public android.app.VoiceInteractor.Request startCommand(android.app.VoiceInteractor.Callback, java.lang.String, android.os.Bundle); method public android.app.VoiceInteractor.Request startConfirmation(android.app.VoiceInteractor.Callback, java.lang.String, android.os.Bundle); method public boolean submitRequest(android.app.VoiceInteractor.Request); method public boolean[] supportsCommands(java.lang.String[]); } public static class VoiceInteractor.Callback { ctor public VoiceInteractor.Callback(); method public void onCancel(android.app.VoiceInteractor.Request); method public void onCommandResult(android.app.VoiceInteractor.Request, android.os.Bundle); method public void onConfirmationResult(android.app.VoiceInteractor.Request, boolean, android.os.Bundle); public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request { ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle); method public void onCommandResult(android.os.Bundle); } public static class VoiceInteractor.Request { public static class VoiceInteractor.ConfirmationRequest extends android.app.VoiceInteractor.Request { ctor public VoiceInteractor.ConfirmationRequest(java.lang.CharSequence, android.os.Bundle); method public void onConfirmationResult(boolean, android.os.Bundle); } public static abstract class VoiceInteractor.Request { ctor public VoiceInteractor.Request(); method public void cancel(); method public android.app.Activity getActivity(); method public android.content.Context getContext(); method public void onCancel(); } public final class WallpaperInfo implements android.os.Parcelable { Loading Loading @@ -24919,7 +24930,7 @@ package android.service.voice { public class VoiceInteractionService extends android.app.Service { ctor public VoiceInteractionService(); method public android.os.IBinder onBind(android.content.Intent); method public void startVoiceActivity(android.content.Intent, android.service.voice.VoiceInteractionSession); method public void startVoiceActivity(android.content.Intent, android.os.Bundle); 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"; } Loading @@ -24938,10 +24949,16 @@ package android.service.voice { public static class VoiceInteractionSession.Request { method public void sendCancelResult(); method public void sendCommandResult(android.os.Bundle); method public void sendCommandResult(boolean, android.os.Bundle); method public void sendConfirmResult(boolean, android.os.Bundle); } public abstract class VoiceInteractionSessionService extends android.app.Service { ctor public VoiceInteractionSessionService(); method public android.os.IBinder onBind(android.content.Intent); method public abstract android.service.voice.VoiceInteractionSession onNewSession(android.os.Bundle); } } package android.service.wallpaper {
core/java/android/app/Activity.java +1 −1 Original line number Diff line number Diff line Loading @@ -5454,7 +5454,7 @@ public class Activity extends ContextThemeWrapper mEmbeddedID = id; mLastNonConfigurationInstances = lastNonConfigurationInstances; mVoiceInteractor = voiceInteractor != null ? new VoiceInteractor(this, voiceInteractor, Looper.myLooper()) : null; ? new VoiceInteractor(this, this, voiceInteractor, Looper.myLooper()) : null; mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), Loading
core/java/android/app/VoiceInteractor.java +151 −111 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.IVoiceInteractorCallback; Loading @@ -39,179 +40,218 @@ public class VoiceInteractor { static final boolean DEBUG = true; final Context mContext; final Activity mActivity; final IVoiceInteractor mInteractor; final HandlerCaller mHandlerCaller; final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() { @Override public void executeMessage(Message msg) { SomeArgs args = (SomeArgs)msg.obj; Request request; switch (msg.what) { case MSG_CONFIRMATION_RESULT: request = pullRequest((IVoiceInteractorRequest)args.arg1, true); if (DEBUG) Log.d(TAG, "onConfirmResult: req=" + ((IVoiceInteractorRequest)args.arg2).asBinder() + " confirmed=" + msg.arg1 + " result=" + args.arg3); ((Callback)args.arg1).onConfirmationResult( findRequest((IVoiceInteractorRequest)args.arg2), msg.arg1 != 0, (Bundle)args.arg3); + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request + " confirmed=" + msg.arg1 + " result=" + args.arg2); if (request != null) { ((ConfirmationRequest)request).onConfirmationResult(msg.arg1 != 0, (Bundle) args.arg2); request.clear(); } break; case MSG_COMMAND_RESULT: request = pullRequest((IVoiceInteractorRequest)args.arg1, msg.arg1 != 0); if (DEBUG) Log.d(TAG, "onCommandResult: req=" + ((IVoiceInteractorRequest)args.arg2).asBinder() + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request + " result=" + args.arg2); ((Callback)args.arg1).onCommandResult( findRequest((IVoiceInteractorRequest) args.arg2), (Bundle) args.arg3); if (request != null) { ((CommandRequest)request).onCommandResult((Bundle) args.arg2); if (msg.arg1 != 0) { request.clear(); } } break; case MSG_CANCEL_RESULT: request = pullRequest((IVoiceInteractorRequest)args.arg1, true); if (DEBUG) Log.d(TAG, "onCancelResult: req=" + ((IVoiceInteractorRequest)args.arg2).asBinder()); ((Callback)args.arg1).onCancel( findRequest((IVoiceInteractorRequest) args.arg2)); + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request); if (request != null) { request.onCancel(); request.clear(); } break; } } }; final WeakHashMap<IBinder, Request> mActiveRequests = new WeakHashMap<IBinder, Request>(); static final int MSG_CONFIRMATION_RESULT = 1; static final int MSG_COMMAND_RESULT = 2; static final int MSG_CANCEL_RESULT = 3; public static class Request { final IVoiceInteractorRequest mRequestInterface; Request(IVoiceInteractorRequest requestInterface) { mRequestInterface = requestInterface; } public void cancel() { try { mRequestInterface.cancel(); } catch (RemoteException e) { Log.w(TAG, "Voice interactor has died", e); } } } public static class Callback { VoiceInteractor mInteractor; final IVoiceInteractorCallback.Stub mWrapper = new IVoiceInteractorCallback.Stub() { final IVoiceInteractorCallback.Stub mCallback = new IVoiceInteractorCallback.Stub() { @Override public void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed, Bundle result) { mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageIOOO( MSG_CONFIRMATION_RESULT, confirmed ? 1 : 0, Callback.this, request, result)); mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO( MSG_CONFIRMATION_RESULT, confirmed ? 1 : 0, request, result)); } @Override public void deliverCommandResult(IVoiceInteractorRequest request, Bundle result) { mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageOOO( MSG_COMMAND_RESULT, Callback.this, request, result)); public void deliverCommandResult(IVoiceInteractorRequest request, boolean complete, Bundle result) { mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO( MSG_COMMAND_RESULT, complete ? 1 : 0, request, result)); } @Override public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException { mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageOO( MSG_CANCEL_RESULT, Callback.this, request)); mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO( MSG_CANCEL_RESULT, request)); } }; public void onConfirmationResult(Request request, boolean confirmed, Bundle result) { } final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>(); static final int MSG_CONFIRMATION_RESULT = 1; static final int MSG_COMMAND_RESULT = 2; static final int MSG_CANCEL_RESULT = 3; public void onCommandResult(Request request, Bundle result) { public static abstract class Request { IVoiceInteractorRequest mRequestInterface; Context mContext; Activity mActivity; public Request() { } public void onCancel(Request request) { public void cancel() { try { mRequestInterface.cancel(); } catch (RemoteException e) { Log.w(TAG, "Voice interactor has died", e); } } VoiceInteractor(Context context, IVoiceInteractor interactor, Looper looper) { mContext = context; mInteractor = interactor; mHandlerCaller = new HandlerCaller(context, looper, mHandlerCallerCallback, true); public Context getContext() { return mContext; } Request storeRequest(IVoiceInteractorRequest request) { synchronized (mActiveRequests) { Request req = new Request(request); mActiveRequests.put(request.asBinder(), req); return req; } public Activity getActivity() { return mActivity; } Request findRequest(IVoiceInteractorRequest request) { synchronized (mActiveRequests) { Request req = mActiveRequests.get(request.asBinder()); if (req == null) { throw new IllegalStateException("Received callback without active request: " + request); public void onCancel() { } return req; void clear() { mRequestInterface = null; mContext = null; mActivity = null; } abstract IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, IVoiceInteractorCallback callback) throws RemoteException; } public static class ConfirmationRequest extends Request { final CharSequence mPrompt; final Bundle mExtras; /** * Asynchronously confirms an operation with the user via the trusted system * VoiceinteractionService. This allows an Activity to complete an unsafe operation that * Confirms an operation with the user via the trusted system * VoiceInteractionService. This allows an Activity to complete an unsafe operation that * would require the user to touch the screen when voice interaction mode is not enabled. * The result of the confirmation will be returned by calling the * {@link Callback#onConfirmationResult Callback.onConfirmationResult} method. * The result of the confirmation will be returned through an asynchronous call to * either {@link #onConfirmationResult(boolean, android.os.Bundle)} or * {@link #onCancel()}. * * In some cases this may be a simple yes / no confirmation or the confirmation could * <p>In some cases this may be a simple yes / no confirmation or the confirmation could * include context information about how the action will be completed * (e.g. booking a cab might include details about how long until the cab arrives) so the user * can give informed consent. * @param callback Required callback target for interaction results. * @param prompt Optional confirmation text to read to the user as the action being confirmed. * (e.g. booking a cab might include details about how long until the cab arrives) * so the user can give a confirmation. * @param prompt Optional confirmation text to read to the user as the action being * confirmed. * @param extras Additional optional information. * @return Returns a new {@link Request} object representing this operation. */ public Request startConfirmation(Callback callback, String prompt, Bundle extras) { try { callback.mInteractor = this; Request req = storeRequest(mInteractor.startConfirmation( mContext.getOpPackageName(), callback.mWrapper, prompt, extras)); if (DEBUG) Log.d(TAG, "startConfirmation: req=" + req.mRequestInterface.asBinder() + " prompt=" + prompt + " extras=" + extras); return req; } catch (RemoteException e) { throw new RuntimeException("Voice interactor has died", e); public ConfirmationRequest(CharSequence prompt, Bundle extras) { mPrompt = prompt; mExtras = extras; } public void onConfirmationResult(boolean confirmed, Bundle result) { } IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, IVoiceInteractorCallback callback) throws RemoteException { return interactor.startConfirmation(packageName, callback, mPrompt.toString(), mExtras); } } public static class CommandRequest extends Request { final String mCommand; final Bundle mArgs; /** * Asynchronously executes a command using the trusted system VoiceinteractionService. * Execute a command using the trusted system VoiceInteractionService. * This allows an Activity to request additional information from the user needed to * complete an action (e.g. booking a table might have several possible times that the * user could select from or an app might need the user to agree to a terms of service). * The result of the confirmation will be returned through an asynchronous call to * either {@link #onCommandResult(android.os.Bundle)} or * {@link #onCancel()}. * * The command is a string that describes the generic operation to be performed. * <p>The command is a string that describes the generic operation to be performed. * The command will determine how the properties in extras are interpreted and the set of * available commands is expected to grow over time. An example might be * "com.google.voice.commands.REQUEST_NUMBER_BAGS" to request the number of bags as part of * airline check-in. (This is not an actual working example.) * The result of the command will be returned by calling the * {@link Callback#onCommandResult Callback.onCommandResult} method. * * @param callback Required callback target for interaction results. * @param command * @param extras * @return Returns a new {@link Request} object representing this operation. * @param command The desired command to perform. * @param args Additional arguments to control execution of the command. */ public Request startCommand(Callback callback, String command, Bundle extras) { try { callback.mInteractor = this; Request req = storeRequest(mInteractor.startCommand( mContext.getOpPackageName(), callback.mWrapper, command, extras)); if (DEBUG) Log.d(TAG, "startCommand: req=" + req.mRequestInterface.asBinder() + " command=" + command + " extras=" + extras); public CommandRequest(String command, Bundle args) { mCommand = command; mArgs = args; } public void onCommandResult(Bundle result) { } IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, IVoiceInteractorCallback callback) throws RemoteException { return interactor.startConfirmation(packageName, callback, mCommand, mArgs); } } VoiceInteractor(Context context, Activity activity, IVoiceInteractor interactor, Looper looper) { mContext = context; mActivity = activity; mInteractor = interactor; mHandlerCaller = new HandlerCaller(context, looper, mHandlerCallerCallback, true); } Request pullRequest(IVoiceInteractorRequest request, boolean complete) { synchronized (mActiveRequests) { Request req = mActiveRequests.get(request.asBinder()); if (req != null && complete) { mActiveRequests.remove(request.asBinder()); } return req; } } public boolean submitRequest(Request request) { try { IVoiceInteractorRequest ireq = request.submit(mInteractor, mContext.getOpPackageName(), mCallback); request.mRequestInterface = ireq; request.mContext = mContext; request.mActivity = mActivity; synchronized (mActiveRequests) { mActiveRequests.put(ireq.asBinder(), request); } return true; } catch (RemoteException e) { throw new RuntimeException("Voice interactor has died", e); Log.w(TAG, "Remove voice interactor service died", e); return false; } } Loading
core/java/android/service/voice/IVoiceInteractionSessionService.aidl 0 → 100644 +28 −0 Original line number Diff line number Diff line /* * 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); }