blob: 1aa0d0bf3e298776a24b97e2bf0e4ccfda5dbeaa [file] [log] [blame]
Dianne Hackborn91097de2014-04-04 18:02:06 -07001/*
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 com.android.server.voiceinteraction;
18
Dianne Hackborn18f0d352014-04-25 17:06:18 -070019import android.app.ActivityManager;
Dianne Hackborn91097de2014-04-04 18:02:06 -070020import android.app.ActivityManagerNative;
21import android.app.IActivityManager;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070022import android.content.BroadcastReceiver;
Dianne Hackborn91097de2014-04-04 18:02:06 -070023import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070026import android.content.IntentFilter;
Dianne Hackborn91097de2014-04-04 18:02:06 -070027import android.content.ServiceConnection;
28import android.content.pm.PackageManager;
Dianne Hackborn18f0d352014-04-25 17:06:18 -070029import android.os.Bundle;
Dianne Hackborn91097de2014-04-04 18:02:06 -070030import android.os.Handler;
31import android.os.IBinder;
32import android.os.RemoteException;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070033import android.os.ServiceManager;
Dianne Hackborn91097de2014-04-04 18:02:06 -070034import android.os.UserHandle;
35import android.service.voice.IVoiceInteractionService;
36import android.service.voice.IVoiceInteractionSession;
37import android.service.voice.VoiceInteractionService;
Dianne Hackborn18f0d352014-04-25 17:06:18 -070038import android.service.voice.VoiceInteractionServiceInfo;
Dianne Hackborn91097de2014-04-04 18:02:06 -070039import android.util.Slog;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070040import android.view.IWindowManager;
Sandeepd7018202014-07-10 15:15:39 -070041
Jorim Jaggi225d3b52015-04-01 11:18:57 -070042import com.android.internal.app.IVoiceInteractionSessionShowCallback;
Dianne Hackborn91097de2014-04-04 18:02:06 -070043import com.android.internal.app.IVoiceInteractor;
44
Dianne Hackborn18f0d352014-04-25 17:06:18 -070045import java.io.FileDescriptor;
46import java.io.PrintWriter;
47
Dianne Hackbornffeecb12015-02-25 11:08:11 -080048class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
Dianne Hackborn91097de2014-04-04 18:02:06 -070049 final static String TAG = "VoiceInteractionServiceManager";
50
Dianne Hackborn18f0d352014-04-25 17:06:18 -070051 final boolean mValid;
52
Dianne Hackborn91097de2014-04-04 18:02:06 -070053 final Context mContext;
54 final Handler mHandler;
55 final Object mLock;
56 final int mUser;
57 final ComponentName mComponent;
58 final IActivityManager mAm;
Dianne Hackborn18f0d352014-04-25 17:06:18 -070059 final VoiceInteractionServiceInfo mInfo;
60 final ComponentName mSessionComponentName;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070061 final IWindowManager mIWindowManager;
Dianne Hackborn91097de2014-04-04 18:02:06 -070062 boolean mBound = false;
63 IVoiceInteractionService mService;
Dianne Hackborn18f0d352014-04-25 17:06:18 -070064
Dianne Hackbornffeecb12015-02-25 11:08:11 -080065 VoiceInteractionSessionConnection mActiveSession;
Dianne Hackborn91097de2014-04-04 18:02:06 -070066
Dianne Hackbornc03c9162014-05-02 10:45:59 -070067 final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
68 @Override
69 public void onReceive(Context context, Intent intent) {
70 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
71 synchronized (mLock) {
72 if (mActiveSession != null && mActiveSession.mSession != null) {
73 try {
74 mActiveSession.mSession.closeSystemDialogs();
75 } catch (RemoteException e) {
76 }
77 }
78 }
79 }
80 }
81 };
82
Dianne Hackborn91097de2014-04-04 18:02:06 -070083 final ServiceConnection mConnection = new ServiceConnection() {
84 @Override
85 public void onServiceConnected(ComponentName name, IBinder service) {
86 synchronized (mLock) {
87 mService = IVoiceInteractionService.Stub.asInterface(service);
Dianne Hackbornfee756f2014-07-16 17:31:10 -070088 try {
89 mService.ready();
90 } catch (RemoteException e) {
91 }
Dianne Hackborn91097de2014-04-04 18:02:06 -070092 }
93 }
94
95 @Override
96 public void onServiceDisconnected(ComponentName name) {
97 mService = null;
98 }
99 };
100
101 VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock,
102 int userHandle, ComponentName service) {
103 mContext = context;
104 mHandler = handler;
105 mLock = lock;
106 mUser = userHandle;
107 mComponent = service;
108 mAm = ActivityManagerNative.getDefault();
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700109 VoiceInteractionServiceInfo info;
110 try {
111 info = new VoiceInteractionServiceInfo(context.getPackageManager(), service);
112 } catch (PackageManager.NameNotFoundException e) {
113 Slog.w(TAG, "Voice interaction service not found: " + service);
114 mInfo = null;
115 mSessionComponentName = null;
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700116 mIWindowManager = null;
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700117 mValid = false;
118 return;
119 }
120 mInfo = info;
121 if (mInfo.getParseError() != null) {
122 Slog.w(TAG, "Bad voice interaction service: " + mInfo.getParseError());
123 mSessionComponentName = null;
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700124 mIWindowManager = null;
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700125 mValid = false;
126 return;
127 }
128 mValid = true;
129 mSessionComponentName = new ComponentName(service.getPackageName(),
130 mInfo.getSessionService());
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700131 mIWindowManager = IWindowManager.Stub.asInterface(
132 ServiceManager.getService(Context.WINDOW_SERVICE));
133 IntentFilter filter = new IntentFilter();
134 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
135 mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700136 }
137
Jorim Jaggi225d3b52015-04-01 11:18:57 -0700138 public boolean showSessionLocked(int callingPid, int callingUid, Bundle args, int flags,
139 IVoiceInteractionSessionShowCallback showCallback) {
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800140 if (mActiveSession == null) {
141 mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
142 mUser, mContext, this, callingPid, callingUid);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700143 }
Jorim Jaggi225d3b52015-04-01 11:18:57 -0700144 return mActiveSession.showLocked(args, flags, showCallback);
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800145 }
146
147 public boolean hideSessionLocked(int callingPid, int callingUid) {
148 return mActiveSession.hideLocked();
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700149 }
150
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700151 public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700152 IVoiceInteractionSession session, IVoiceInteractor interactor) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700153 if (mActiveSession == null || token != mActiveSession.mToken) {
154 Slog.w(TAG, "deliverNewSession does not match active session");
155 return false;
156 }
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800157 mActiveSession.deliverNewSessionLocked(session, interactor);
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700158 return true;
159 }
160
161 public int startVoiceActivityLocked(int callingPid, int callingUid, IBinder token,
162 Intent intent, String resolvedType) {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700163 try {
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700164 if (mActiveSession == null || token != mActiveSession.mToken) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700165 Slog.w(TAG, "startVoiceActivity does not match active session");
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700166 return ActivityManager.START_CANCELED;
167 }
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700168 intent = new Intent(intent);
169 intent.addCategory(Intent.CATEGORY_VOICE);
170 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700171 return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid,
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700172 intent, resolvedType, mActiveSession.mSession, mActiveSession.mInteractor,
Jeff Hao1b012d32014-08-20 10:35:34 -0700173 0, null, null, mUser);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700174 } catch (RemoteException e) {
175 throw new IllegalStateException("Unexpected remote error", e);
176 }
177 }
178
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700179 public void setKeepAwakeLocked(int callingPid, int callingUid, IBinder token,
180 boolean keepAwake) {
181 try {
182 if (mActiveSession == null || token != mActiveSession.mToken) {
183 Slog.w(TAG, "setKeepAwake does not match active session");
184 return;
185 }
186 mAm.setVoiceKeepAwake(mActiveSession.mSession, keepAwake);
187 } catch (RemoteException e) {
188 throw new IllegalStateException("Unexpected remote error", e);
189 }
190 }
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700191
192 public void finishLocked(int callingPid, int callingUid, IBinder token) {
193 if (mActiveSession == null || token != mActiveSession.mToken) {
194 Slog.w(TAG, "finish does not match active session");
195 return;
196 }
197 mActiveSession.cancel();
198 mActiveSession = null;
199 }
200
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700201 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
202 if (!mValid) {
203 pw.print(" NOT VALID: ");
204 if (mInfo == null) {
205 pw.println("no info");
206 } else {
207 pw.println(mInfo.getParseError());
208 }
209 return;
210 }
211 pw.print(" mComponent="); pw.println(mComponent.flattenToShortString());
212 pw.print(" Session service="); pw.println(mInfo.getSessionService());
213 pw.print(" Settings activity="); pw.println(mInfo.getSettingsActivity());
214 pw.print(" mBound="); pw.print(mBound); pw.print(" mService="); pw.println(mService);
215 if (mActiveSession != null) {
216 pw.println(" Active session:");
217 mActiveSession.dump(" ", pw);
218 }
219 }
220
Dianne Hackborn91097de2014-04-04 18:02:06 -0700221 void startLocked() {
222 Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
223 intent.setComponent(mComponent);
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700224 mBound = mContext.bindServiceAsUser(intent, mConnection,
Dianne Hackborn91097de2014-04-04 18:02:06 -0700225 Context.BIND_AUTO_CREATE, new UserHandle(mUser));
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700226 if (!mBound) {
227 Slog.w(TAG, "Failed binding to voice interaction service " + mComponent);
228 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700229 }
230
231 void shutdownLocked() {
Sandeep Siddhartha8ef360f2014-07-28 16:40:11 -0700232 try {
233 if (mService != null) {
234 mService.shutdown();
235 }
236 } catch (RemoteException e) {
237 Slog.w(TAG, "RemoteException in shutdown", e);
238 }
239
Dianne Hackborn91097de2014-04-04 18:02:06 -0700240 if (mBound) {
241 mContext.unbindService(mConnection);
242 mBound = false;
243 }
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700244 if (mValid) {
245 mContext.unregisterReceiver(mBroadcastReceiver);
246 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700247 }
Sandeep Siddhartha6daae962014-07-21 10:31:34 -0700248
249 void notifySoundModelsChangedLocked() {
250 if (mService == null) {
251 Slog.w(TAG, "Not bound to voice interaction service " + mComponent);
252 }
253 try {
254 mService.soundModelsChanged();
255 } catch (RemoteException e) {
256 Slog.w(TAG, "RemoteException while calling soundModelsChanged", e);
257 }
258 }
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800259
260 @Override
261 public void sessionConnectionGone(VoiceInteractionSessionConnection connection) {
262 synchronized (mLock) {
263 finishLocked(connection.mCallingPid, connection.mCallingUid, connection.mToken);
264 }
265 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700266}