blob: 9e2bcab1f1cd35c739a6c6ce48e2ac38524e77ba [file] [log] [blame]
/*
* 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 com.android.server.voiceinteraction;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.os.Binder;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
import android.util.Slog;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.server.SystemService;
import com.android.server.UiThread;
import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
* SystemService that publishes an IVoiceInteractionManagerService.
*/
public class VoiceInteractionManagerService extends SystemService {
static final String TAG = "VoiceInteractionManagerService";
final Context mContext;
final ContentResolver mResolver;
public VoiceInteractionManagerService(Context context) {
super(context);
mContext = context;
mResolver = context.getContentResolver();
}
@Override
public void onStart() {
publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
mServiceStub.systemRunning(isSafeMode());
}
}
@Override
public void onSwitchUser(int userHandle) {
mServiceStub.switchUser(userHandle);
}
// implementation entry point and binder service
private final VoiceInteractionManagerServiceStub mServiceStub
= new VoiceInteractionManagerServiceStub();
class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
VoiceInteractionManagerServiceImpl mImpl;
private boolean mSafeMode;
private int mCurUser;
public void systemRunning(boolean safeMode) {
mSafeMode = safeMode;
mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
UserHandle.ALL, true);
new SettingsObserver(UiThread.getHandler());
synchronized (this) {
mCurUser = ActivityManager.getCurrentUser();
switchImplementationIfNeededLocked();
}
}
public void switchUser(int userHandle) {
synchronized (this) {
mCurUser = userHandle;
switchImplementationIfNeededLocked();
}
}
void switchImplementationIfNeededLocked() {
if (!mSafeMode) {
String curService = Settings.Secure.getStringForUser(
mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
ComponentName serviceComponent = null;
if (curService != null && !curService.isEmpty()) {
try {
serviceComponent = ComponentName.unflattenFromString(curService);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
serviceComponent = null;
}
}
if (mImpl == null || mImpl.mUser != mCurUser
|| !mImpl.mComponent.equals(serviceComponent)) {
if (mImpl != null) {
mImpl.shutdownLocked();
}
if (serviceComponent != null) {
mImpl = new VoiceInteractionManagerServiceImpl(mContext,
UiThread.getHandler(), this, mCurUser, serviceComponent);
mImpl.startLocked();
} else {
mImpl = null;
}
}
}
}
@Override
public int startVoiceActivity(Intent intent, String resolvedType,
IVoiceInteractionService service,
IVoiceInteractionSession session, IVoiceInteractor interactor) {
synchronized (this) {
if (mImpl == null || service.asBinder() != mImpl.mService.asBinder()) {
throw new SecurityException(
"Caller is not the current voice interaction service");
}
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long caller = Binder.clearCallingIdentity();
try {
return mImpl.startVoiceActivityLocked(callingPid, callingUid,
intent, resolvedType, session, interactor);
} finally {
Binder.restoreCallingIdentity(caller);
}
}
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
}
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.VOICE_INTERACTION_SERVICE), false, this);
}
@Override public void onChange(boolean selfChange) {
synchronized (VoiceInteractionManagerServiceStub.this) {
switchImplementationIfNeededLocked();
}
}
}
PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
return super.onHandleForceStop(intent, packages, uid, doit);
}
@Override
public void onHandleUserStop(Intent intent, int userHandle) {
super.onHandleUserStop(intent, userHandle);
}
@Override
public void onPackageDisappeared(String packageName, int reason) {
super.onPackageDisappeared(packageName, reason);
}
@Override
public void onPackageAppeared(String packageName, int reason) {
super.onPackageAppeared(packageName, reason);
}
@Override
public void onPackageModified(String packageName) {
super.onPackageModified(packageName);
}
@Override
public void onSomePackagesChanged() {
super.onSomePackagesChanged();
}
};
}
}