VoiceInteractionSession.java revision 18f0d357f9693fe787a3e3777d8fdf01357a6e3f
1/**
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.service.voice;
18
19import android.content.Context;
20import android.os.Binder;
21import android.os.Bundle;
22import android.os.Handler;
23import android.os.IBinder;
24import android.os.Message;
25import android.os.RemoteException;
26import android.util.ArrayMap;
27import android.util.Log;
28import com.android.internal.app.IVoiceInteractor;
29import com.android.internal.app.IVoiceInteractorCallback;
30import com.android.internal.app.IVoiceInteractorRequest;
31import com.android.internal.os.HandlerCaller;
32import com.android.internal.os.SomeArgs;
33
34public abstract class VoiceInteractionSession {
35    static final String TAG = "VoiceInteractionSession";
36    static final boolean DEBUG = true;
37
38    final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
39        @Override
40        public IVoiceInteractorRequest startConfirmation(String callingPackage,
41                IVoiceInteractorCallback callback, String prompt, Bundle extras) {
42            Request request = findRequest(callback, true);
43            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_CONFIRMATION,
44                    new Caller(callingPackage, Binder.getCallingUid()), request,
45                    prompt, extras));
46            return request.mInterface;
47        }
48
49        @Override
50        public IVoiceInteractorRequest startCommand(String callingPackage,
51                IVoiceInteractorCallback callback, String command, Bundle extras) {
52            Request request = findRequest(callback, true);
53            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_COMMAND,
54                    new Caller(callingPackage, Binder.getCallingUid()), request,
55                    command, extras));
56            return request.mInterface;
57        }
58
59        @Override
60        public boolean[] supportsCommands(String callingPackage, String[] commands) {
61            Message msg = mHandlerCaller.obtainMessageIOO(MSG_SUPPORTS_COMMANDS,
62                    0, new Caller(callingPackage, Binder.getCallingUid()), commands);
63            SomeArgs args = mHandlerCaller.sendMessageAndWait(msg);
64            if (args != null) {
65                boolean[] res = (boolean[])args.arg1;
66                args.recycle();
67                return res;
68            }
69            return new boolean[commands.length];
70        }
71    };
72
73    final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
74    };
75
76    public static class Request {
77        final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() {
78            @Override
79            public void cancel() throws RemoteException {
80                mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_CANCEL, Request.this));
81            }
82        };
83        final IVoiceInteractorCallback mCallback;
84        final HandlerCaller mHandlerCaller;
85        Request(IVoiceInteractorCallback callback, HandlerCaller handlerCaller) {
86            mCallback = callback;
87            mHandlerCaller = handlerCaller;
88        }
89
90        public void sendConfirmResult(boolean confirmed, Bundle result) {
91            try {
92                if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface
93                        + " confirmed=" + confirmed + " result=" + result);
94                mCallback.deliverConfirmationResult(mInterface, confirmed, result);
95            } catch (RemoteException e) {
96            }
97        }
98
99        public void sendCommandResult(boolean complete, Bundle result) {
100            try {
101                if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface
102                        + " result=" + result);
103                mCallback.deliverCommandResult(mInterface, complete, result);
104            } catch (RemoteException e) {
105            }
106        }
107
108        public void sendCancelResult() {
109            try {
110                if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface);
111                mCallback.deliverCancel(mInterface);
112            } catch (RemoteException e) {
113            }
114        }
115    }
116
117    public static class Caller {
118        final String packageName;
119        final int uid;
120
121        Caller(String _packageName, int _uid) {
122            packageName = _packageName;
123            uid = _uid;
124        }
125    }
126
127    static final int MSG_START_CONFIRMATION = 1;
128    static final int MSG_START_COMMAND = 2;
129    static final int MSG_SUPPORTS_COMMANDS = 3;
130    static final int MSG_CANCEL = 4;
131
132    final Context mContext;
133    final HandlerCaller mHandlerCaller;
134    final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() {
135        @Override
136        public void executeMessage(Message msg) {
137            SomeArgs args = (SomeArgs)msg.obj;
138            switch (msg.what) {
139                case MSG_START_CONFIRMATION:
140                    if (DEBUG) Log.d(TAG, "onConfirm: req=" + ((Request) args.arg2).mInterface
141                            + " prompt=" + args.arg3 + " extras=" + args.arg4);
142                    onConfirm((Caller)args.arg1, (Request)args.arg2, (String)args.arg3,
143                            (Bundle)args.arg4);
144                    break;
145                case MSG_START_COMMAND:
146                    if (DEBUG) Log.d(TAG, "onCommand: req=" + ((Request) args.arg2).mInterface
147                            + " command=" + args.arg3 + " extras=" + args.arg4);
148                    onCommand((Caller) args.arg1, (Request) args.arg2, (String) args.arg3,
149                            (Bundle) args.arg4);
150                    break;
151                case MSG_SUPPORTS_COMMANDS:
152                    if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg2);
153                    args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
154                    break;
155                case MSG_CANCEL:
156                    if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
157                    onCancel((Request)args.arg1);
158                    break;
159            }
160        }
161    };
162
163    final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
164
165    public VoiceInteractionSession(Context context) {
166        this(context, new Handler());
167    }
168
169    public VoiceInteractionSession(Context context, Handler handler) {
170        mContext = context;
171        mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
172                mHandlerCallerCallback, true);
173    }
174
175    Request findRequest(IVoiceInteractorCallback callback, boolean newRequest) {
176        synchronized (this) {
177            Request req = mActiveRequests.get(callback.asBinder());
178            if (req != null) {
179                if (newRequest) {
180                    throw new IllegalArgumentException("Given request callback " + callback
181                            + " is already active");
182                }
183                return req;
184            }
185            req = new Request(callback, mHandlerCaller);
186            mActiveRequests.put(callback.asBinder(), req);
187            return req;
188        }
189    }
190
191    public abstract boolean[] onGetSupportedCommands(Caller caller, String[] commands);
192    public abstract void onConfirm(Caller caller, Request request, String prompt, Bundle extras);
193    public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
194    public abstract void onCancel(Request request);
195}
196