121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn/*
221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn * Copyright (C) 2010 The Android Open Source Project
321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn *
421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn * you may not use this file except in compliance with the License.
621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn * You may obtain a copy of the License at
721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn *
821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn *
1021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn * Unless required by applicable law or agreed to in writing, software
1121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
1221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn * See the License for the specific language governing permissions and
1421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn * limitations under the License.
1521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn */
1621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
1721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornpackage com.android.server;
1821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
1921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport com.android.internal.content.PackageMonitor;
2021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
21f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasaniimport android.app.AppGlobals;
22f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasaniimport android.content.BroadcastReceiver;
2321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport android.content.ComponentName;
2421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport android.content.Context;
2521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport android.content.Intent;
26f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasaniimport android.content.IntentFilter;
27f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasaniimport android.content.pm.IPackageManager;
2821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport android.content.pm.ResolveInfo;
2921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport android.content.pm.ServiceInfo;
3021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport android.os.Binder;
31f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasaniimport android.os.RemoteException;
32f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasaniimport android.os.UserHandle;
3321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport android.provider.Settings;
3421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport android.speech.RecognitionService;
3521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport android.text.TextUtils;
368a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog;
3721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
3821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport java.util.List;
3921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
4021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornpublic class RecognitionManagerService extends Binder {
4121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    final static String TAG = "RecognitionManagerService";
42f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
43f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    private final Context mContext;
44f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    private final MyPackageMonitor mMonitor;
45f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    private final IPackageManager mIPm;
46f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
47f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    private static final boolean DEBUG = false;
48f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
4921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    class MyPackageMonitor extends PackageMonitor {
5021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        public void onSomePackagesChanged() {
51f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            int userHandle = getChangingUserId();
52f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            if (DEBUG) Slog.i(TAG, "onSomePackagesChanged user=" + userHandle);
53f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            ComponentName comp = getCurRecognizer(userHandle);
5421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            if (comp == null) {
5521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (anyPackagesAppearing()) {
56f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                    comp = findAvailRecognizer(null, userHandle);
5721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    if (comp != null) {
58f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                        setCurRecognizer(comp, userHandle);
5921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    }
6021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                }
6121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                return;
6221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
63f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
6421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            int change = isPackageDisappearing(comp.getPackageName());
6521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            if (change == PACKAGE_PERMANENT_CHANGE
6621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    || change == PACKAGE_TEMPORARY_CHANGE) {
67f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
6821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
6921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            } else if (isPackageModified(comp.getPackageName())) {
70f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                setCurRecognizer(findAvailRecognizer(comp.getPackageName(), userHandle),
71f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                        userHandle);
7221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
7321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
7421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    }
75f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
7621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    RecognitionManagerService(Context context) {
7721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        mContext = context;
7821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        mMonitor = new MyPackageMonitor();
79f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        mMonitor.register(context, null, UserHandle.ALL, true);
80f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        mIPm = AppGlobals.getPackageManager();
81f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
82f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
8321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    }
84f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
8521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    public void systemReady() {
86f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        initForUser(UserHandle.USER_OWNER);
87f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    }
88f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
89f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    private void initForUser(int userHandle) {
90f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        if (DEBUG) Slog.i(TAG, "initForUser user=" + userHandle);
91f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        ComponentName comp = getCurRecognizer(userHandle);
9221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        if (comp != null) {
9321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            // See if the current recognizer is no longer available.
9421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            try {
95f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                mIPm.getServiceInfo(comp, 0, userHandle);
96f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            } catch (RemoteException e) {
97f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                comp = findAvailRecognizer(null, userHandle);
98ddf322915ba87ef0bf604406ae441c63b371fda0Bjorn Bringert                if (comp != null) {
99f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                    setCurRecognizer(comp, userHandle);
100ddf322915ba87ef0bf604406ae441c63b371fda0Bjorn Bringert                }
10121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
10221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        } else {
103f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            comp = findAvailRecognizer(null, userHandle);
10421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            if (comp != null) {
105f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                setCurRecognizer(comp, userHandle);
10621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
10721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
10821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    }
109f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
110f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
11121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        List<ResolveInfo> available =
112f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                mContext.getPackageManager().queryIntentServicesAsUser(
113f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                        new Intent(RecognitionService.SERVICE_INTERFACE), 0, userHandle);
11421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        int numAvailable = available.size();
115f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
11621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        if (numAvailable == 0) {
117f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            Slog.w(TAG, "no available voice recognition services found for user " + userHandle);
11821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            return null;
11921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        } else {
12021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            if (prefPackage != null) {
12121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                for (int i=0; i<numAvailable; i++) {
12221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    ServiceInfo serviceInfo = available.get(i).serviceInfo;
12321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    if (prefPackage.equals(serviceInfo.packageName)) {
12421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        return new ComponentName(serviceInfo.packageName, serviceInfo.name);
12521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    }
12621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                }
12721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
12821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            if (numAvailable > 1) {
1298a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "more than one voice recognition service found, picking first");
13021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
131f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
13221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            ServiceInfo serviceInfo = available.get(0).serviceInfo;
13321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            return new ComponentName(serviceInfo.packageName, serviceInfo.name);
13421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
13521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    }
136f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
137f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    ComponentName getCurRecognizer(int userHandle) {
138f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        String curRecognizer = Settings.Secure.getStringForUser(
13921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                mContext.getContentResolver(),
140f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle);
14121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        if (TextUtils.isEmpty(curRecognizer)) {
14221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            return null;
14321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
144f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        if (DEBUG) Slog.i(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
145f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                + " user=" + userHandle);
14621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        return ComponentName.unflattenFromString(curRecognizer);
14721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    }
148f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
149f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    void setCurRecognizer(ComponentName comp, int userHandle) {
150f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        Settings.Secure.putStringForUser(mContext.getContentResolver(),
15121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                Settings.Secure.VOICE_RECOGNITION_SERVICE,
152f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                comp != null ? comp.flattenToShortString() : "", userHandle);
153f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        if (DEBUG) Slog.i(TAG, "setCurRecognizer comp=" + comp
154f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                + " user=" + userHandle);
15521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    }
156f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani
157f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
158f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        public void onReceive(Context context, Intent intent) {
159f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            String action = intent.getAction();
160f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            if (DEBUG) Slog.i(TAG, "received " + action);
161f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
162f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
163f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                if (userHandle > 0) {
164f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                    initForUser(userHandle);
165f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani                }
166f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani            }
167f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani        }
168f80a9b2f8a841d32c7398ebbf4cba82b02e9f167Amith Yamasani    };
16921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn}
170