VoiceInteractionManagerServiceImpl.java revision 3d07c94c393831091958fe6a98811843db8973bd
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 com.android.server.voiceinteraction; 18 19import android.app.ActivityManager; 20import android.app.ActivityManagerNative; 21import android.app.IActivityManager; 22import android.content.BroadcastReceiver; 23import android.content.ComponentName; 24import android.content.Context; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.content.ServiceConnection; 28import android.content.pm.PackageManager; 29import android.os.Bundle; 30import android.os.Handler; 31import android.os.IBinder; 32import android.os.RemoteException; 33import android.os.ServiceManager; 34import android.os.UserHandle; 35import android.service.voice.IVoiceInteractionService; 36import android.service.voice.IVoiceInteractionSession; 37import android.service.voice.VoiceInteractionService; 38import android.service.voice.VoiceInteractionServiceInfo; 39import android.util.Slog; 40import android.view.IWindowManager; 41 42import com.android.internal.app.IVoiceInteractor; 43 44import java.io.FileDescriptor; 45import java.io.PrintWriter; 46 47class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback { 48 final static String TAG = "VoiceInteractionServiceManager"; 49 50 final boolean mValid; 51 52 final Context mContext; 53 final Handler mHandler; 54 final Object mLock; 55 final int mUser; 56 final ComponentName mComponent; 57 final IActivityManager mAm; 58 final VoiceInteractionServiceInfo mInfo; 59 final ComponentName mSessionComponentName; 60 final IWindowManager mIWindowManager; 61 boolean mBound = false; 62 IVoiceInteractionService mService; 63 64 VoiceInteractionSessionConnection mActiveSession; 65 66 final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 67 @Override 68 public void onReceive(Context context, Intent intent) { 69 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { 70 synchronized (mLock) { 71 if (mActiveSession != null && mActiveSession.mSession != null) { 72 try { 73 mActiveSession.mSession.closeSystemDialogs(); 74 } catch (RemoteException e) { 75 } 76 } 77 } 78 } 79 } 80 }; 81 82 final ServiceConnection mConnection = new ServiceConnection() { 83 @Override 84 public void onServiceConnected(ComponentName name, IBinder service) { 85 synchronized (mLock) { 86 mService = IVoiceInteractionService.Stub.asInterface(service); 87 try { 88 mService.ready(); 89 } catch (RemoteException e) { 90 } 91 } 92 } 93 94 @Override 95 public void onServiceDisconnected(ComponentName name) { 96 mService = null; 97 } 98 }; 99 100 VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock, 101 int userHandle, ComponentName service) { 102 mContext = context; 103 mHandler = handler; 104 mLock = lock; 105 mUser = userHandle; 106 mComponent = service; 107 mAm = ActivityManagerNative.getDefault(); 108 VoiceInteractionServiceInfo info; 109 try { 110 info = new VoiceInteractionServiceInfo(context.getPackageManager(), service); 111 } catch (PackageManager.NameNotFoundException e) { 112 Slog.w(TAG, "Voice interaction service not found: " + service); 113 mInfo = null; 114 mSessionComponentName = null; 115 mIWindowManager = null; 116 mValid = false; 117 return; 118 } 119 mInfo = info; 120 if (mInfo.getParseError() != null) { 121 Slog.w(TAG, "Bad voice interaction service: " + mInfo.getParseError()); 122 mSessionComponentName = null; 123 mIWindowManager = null; 124 mValid = false; 125 return; 126 } 127 mValid = true; 128 mSessionComponentName = new ComponentName(service.getPackageName(), 129 mInfo.getSessionService()); 130 mIWindowManager = IWindowManager.Stub.asInterface( 131 ServiceManager.getService(Context.WINDOW_SERVICE)); 132 IntentFilter filter = new IntentFilter(); 133 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 134 mContext.registerReceiver(mBroadcastReceiver, filter, null, handler); 135 } 136 137 public boolean showSessionLocked(int callingPid, int callingUid, Bundle args, int flags) { 138 if (mActiveSession == null) { 139 mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName, 140 mUser, mContext, this, callingPid, callingUid); 141 } 142 return mActiveSession.showLocked(args, flags); 143 } 144 145 public boolean hideSessionLocked(int callingPid, int callingUid) { 146 return mActiveSession.hideLocked(); 147 } 148 149 public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token, 150 IVoiceInteractionSession session, IVoiceInteractor interactor) { 151 if (mActiveSession == null || token != mActiveSession.mToken) { 152 Slog.w(TAG, "deliverNewSession does not match active session"); 153 return false; 154 } 155 mActiveSession.deliverNewSessionLocked(session, interactor); 156 return true; 157 } 158 159 public int startVoiceActivityLocked(int callingPid, int callingUid, IBinder token, 160 Intent intent, String resolvedType) { 161 try { 162 if (mActiveSession == null || token != mActiveSession.mToken) { 163 Slog.w(TAG, "startVoiceActivity does not match active session"); 164 return ActivityManager.START_CANCELED; 165 } 166 intent = new Intent(intent); 167 intent.addCategory(Intent.CATEGORY_VOICE); 168 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 169 return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid, 170 intent, resolvedType, mActiveSession.mSession, mActiveSession.mInteractor, 171 0, null, null, mUser); 172 } catch (RemoteException e) { 173 throw new IllegalStateException("Unexpected remote error", e); 174 } 175 } 176 177 public void setKeepAwakeLocked(int callingPid, int callingUid, IBinder token, 178 boolean keepAwake) { 179 try { 180 if (mActiveSession == null || token != mActiveSession.mToken) { 181 Slog.w(TAG, "setKeepAwake does not match active session"); 182 return; 183 } 184 mAm.setVoiceKeepAwake(mActiveSession.mSession, keepAwake); 185 } catch (RemoteException e) { 186 throw new IllegalStateException("Unexpected remote error", e); 187 } 188 } 189 190 public void finishLocked(int callingPid, int callingUid, IBinder token) { 191 if (mActiveSession == null || token != mActiveSession.mToken) { 192 Slog.w(TAG, "finish does not match active session"); 193 return; 194 } 195 mActiveSession.cancel(); 196 mActiveSession = null; 197 } 198 199 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { 200 if (!mValid) { 201 pw.print(" NOT VALID: "); 202 if (mInfo == null) { 203 pw.println("no info"); 204 } else { 205 pw.println(mInfo.getParseError()); 206 } 207 return; 208 } 209 pw.print(" mComponent="); pw.println(mComponent.flattenToShortString()); 210 pw.print(" Session service="); pw.println(mInfo.getSessionService()); 211 pw.print(" Settings activity="); pw.println(mInfo.getSettingsActivity()); 212 pw.print(" mBound="); pw.print(mBound); pw.print(" mService="); pw.println(mService); 213 if (mActiveSession != null) { 214 pw.println(" Active session:"); 215 mActiveSession.dump(" ", pw); 216 } 217 } 218 219 void startLocked() { 220 Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); 221 intent.setComponent(mComponent); 222 mBound = mContext.bindServiceAsUser(intent, mConnection, 223 Context.BIND_AUTO_CREATE, new UserHandle(mUser)); 224 if (!mBound) { 225 Slog.w(TAG, "Failed binding to voice interaction service " + mComponent); 226 } 227 } 228 229 void shutdownLocked() { 230 try { 231 if (mService != null) { 232 mService.shutdown(); 233 } 234 } catch (RemoteException e) { 235 Slog.w(TAG, "RemoteException in shutdown", e); 236 } 237 238 if (mBound) { 239 mContext.unbindService(mConnection); 240 mBound = false; 241 } 242 if (mValid) { 243 mContext.unregisterReceiver(mBroadcastReceiver); 244 } 245 } 246 247 void notifySoundModelsChangedLocked() { 248 if (mService == null) { 249 Slog.w(TAG, "Not bound to voice interaction service " + mComponent); 250 } 251 try { 252 mService.soundModelsChanged(); 253 } catch (RemoteException e) { 254 Slog.w(TAG, "RemoteException while calling soundModelsChanged", e); 255 } 256 } 257 258 @Override 259 public void sessionConnectionGone(VoiceInteractionSessionConnection connection) { 260 synchronized (mLock) { 261 finishLocked(connection.mCallingPid, connection.mCallingUid, connection.mToken); 262 } 263 } 264} 265