1052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa/*
2052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * Copyright (C) 2014 The Android Open Source Project
3052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa *
4052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * Licensed under the Apache License, Version 2.0 (the "License");
5052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * you may not use this file except in compliance with the License.
6052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * You may obtain a copy of the License at
7052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa *
8052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa *      http://www.apache.org/licenses/LICENSE-2.0
9052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa *
10052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * Unless required by applicable law or agreed to in writing, software
11052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * distributed under the License is distributed on an "AS IS" BASIS,
12052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * See the License for the specific language governing permissions and
14052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * limitations under the License.
15052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa */
16052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa
17052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawapackage com.android.inputmethod.latin;
18052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa
195a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheikimport android.app.DownloadManager;
20052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawaimport android.content.BroadcastReceiver;
21d913617e0cecc2628c3729933c365d76f45f5504Dan Zivkovicimport android.content.ComponentName;
22052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawaimport android.content.Context;
23052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawaimport android.content.Intent;
24a2376cd2b4fea6b655fdcdf794cf16b7bbe1a161Chieu Nguyenimport android.content.SharedPreferences;
2508f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovicimport android.content.pm.ApplicationInfo;
26d913617e0cecc2628c3729933c365d76f45f5504Dan Zivkovicimport android.content.pm.PackageManager;
275a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheikimport android.database.Cursor;
28052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawaimport android.os.Process;
29a2376cd2b4fea6b655fdcdf794cf16b7bbe1a161Chieu Nguyenimport android.preference.PreferenceManager;
30052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawaimport android.util.Log;
31052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawaimport android.view.inputmethod.InputMethodManager;
32052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawaimport android.view.inputmethod.InputMethodSubtype;
33052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa
343bc3bc7971f15438732933cfac0db6e766e6a3e9Mohammadinamul Sheikimport com.android.inputmethod.dictionarypack.DictionaryPackConstants;
355a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheikimport com.android.inputmethod.dictionarypack.DownloadManagerWrapper;
36f2eadbb497a172f602e49226a7f891d9e9097760Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardLayoutSet;
37a2376cd2b4fea6b655fdcdf794cf16b7bbe1a161Chieu Nguyenimport com.android.inputmethod.latin.settings.Settings;
38d913617e0cecc2628c3729933c365d76f45f5504Dan Zivkovicimport com.android.inputmethod.latin.setup.SetupActivity;
39052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawaimport com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
40052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa
41052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa/**
42052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * This class detects the {@link Intent#ACTION_MY_PACKAGE_REPLACED} broadcast intent when this IME
43052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * package has been replaced by a newer version of the same package. This class also detects
44052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa * {@link Intent#ACTION_BOOT_COMPLETED} and {@link Intent#ACTION_USER_INITIALIZE} broadcast intent.
45052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa *
4608f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * If this IME has already been installed in the system image and a new version of this IME has
4708f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * been installed, {@link Intent#ACTION_MY_PACKAGE_REPLACED} is received by this receiver and it
4808f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * will hide the setup wizard's icon.
4908f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic *
5008f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * If this IME has already been installed in the data partition and a new version of this IME has
5108f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * been installed, {@link Intent#ACTION_MY_PACKAGE_REPLACED} is received by this receiver but it
5208f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * will not hide the setup wizard's icon, and the icon will appear on the launcher.
5308f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic *
5408f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * If this IME hasn't been installed yet and has been newly installed, no
5508f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * {@link Intent#ACTION_MY_PACKAGE_REPLACED} will be sent and the setup wizard's icon will appear
5608f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * on the launcher.
5708f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic *
5808f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * When the device has been booted, {@link Intent#ACTION_BOOT_COMPLETED} is received by this
5908f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * receiver and it checks whether the setup wizard's icon should be appeared or not on the launcher
6008f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic * depending on which partition this IME is installed.
6108f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic *
62f2eadbb497a172f602e49226a7f891d9e9097760Tadashi G. Takaoka * When the system locale has been changed, {@link Intent#ACTION_LOCALE_CHANGED} is received by
63f2eadbb497a172f602e49226a7f891d9e9097760Tadashi G. Takaoka * this receiver and the {@link KeyboardLayoutSet}'s cache is cleared.
64052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa */
65052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawapublic final class SystemBroadcastReceiver extends BroadcastReceiver {
66052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa    private static final String TAG = SystemBroadcastReceiver.class.getSimpleName();
67052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa
68052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa    @Override
69052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa    public void onReceive(final Context context, final Intent intent) {
70052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        final String intentAction = intent.getAction();
71052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intentAction)) {
72052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa            Log.i(TAG, "Package has been replaced: " + context.getPackageName());
73052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa            // Need to restore additional subtypes because system always clears additional
74052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa            // subtypes when the package is replaced.
75052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa            RichInputMethodManager.init(context);
76052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa            final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
778a711f2a547a61b9f4f3ef3bdb79a66b618db58fTadashi G. Takaoka            final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes();
78052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa            richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
7908f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic            toggleAppIcon(context);
805a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik
815a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            // Remove all the previously scheduled downloads. This will also makes sure
825a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            // that any erroneously stuck downloads will get cleared. (b/21797386)
835a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            removeOldDownloads(context);
844e9d2608265814fc684d030b513848e671c7bb17Dan Zivkovic            // b/21797386
854e9d2608265814fc684d030b513848e671c7bb17Dan Zivkovic            // downloadLatestDictionaries(context);
86f2eadbb497a172f602e49226a7f891d9e9097760Tadashi G. Takaoka        } else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
87f2eadbb497a172f602e49226a7f891d9e9097760Tadashi G. Takaoka            Log.i(TAG, "Boot has been completed");
8808f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic            toggleAppIcon(context);
89f2eadbb497a172f602e49226a7f891d9e9097760Tadashi G. Takaoka        } else if (Intent.ACTION_LOCALE_CHANGED.equals(intentAction)) {
90f2eadbb497a172f602e49226a7f891d9e9097760Tadashi G. Takaoka            Log.i(TAG, "System locale changed");
91f2eadbb497a172f602e49226a7f891d9e9097760Tadashi G. Takaoka            KeyboardLayoutSet.onSystemLocaleChanged();
92052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        }
93052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa
94052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        // The process that hosts this broadcast receiver is invoked and remains alive even after
9508f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic        // 1) the package has been re-installed,
9608f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic        // 2) the device has just booted,
97052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        // 3) a new user has been created.
98052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        // There is no good reason to keep the process alive if this IME isn't a current IME.
9908f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic        final InputMethodManager imm = (InputMethodManager)
10008f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic                context.getSystemService(Context.INPUT_METHOD_SERVICE);
101052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        // Called to check whether this IME has been triggered by the current user or not
102052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        final boolean isInputMethodManagerValidForUserOfThisProcess =
103052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa                !imm.getInputMethodList().isEmpty();
104052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        final boolean isCurrentImeOfCurrentUser = isInputMethodManagerValidForUserOfThisProcess
105052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa                && UncachedInputMethodManagerUtils.isThisImeCurrent(context, imm);
106052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        if (!isCurrentImeOfCurrentUser) {
107052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa            final int myPid = Process.myPid();
108052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa            Log.i(TAG, "Killing my process: pid=" + myPid);
109052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa            Process.killProcess(myPid);
110052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa        }
111052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa    }
112d913617e0cecc2628c3729933c365d76f45f5504Dan Zivkovic
1135a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik    private void removeOldDownloads(Context context) {
1145a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik        try {
1155a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            Log.i(TAG, "Removing the old downloads in progress of the previous keyboard version.");
1165a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            final DownloadManagerWrapper downloadManagerWrapper = new DownloadManagerWrapper(
1175a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik                    context);
1185a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            final DownloadManager.Query q = new DownloadManager.Query();
1195a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            // Query all the download statuses except the succeeded ones.
1205a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            q.setFilterByStatus(DownloadManager.STATUS_FAILED
1215a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik                    | DownloadManager.STATUS_PAUSED
1225a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik                    | DownloadManager.STATUS_PENDING
1235a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik                    | DownloadManager.STATUS_RUNNING);
1245a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            final Cursor c = downloadManagerWrapper.query(q);
1255a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            if (c != null) {
126bf7c0106b0380bc80dd78d6026abce36b5e2ce51Mohammadinamul Sheik                for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
127bf7c0106b0380bc80dd78d6026abce36b5e2ce51Mohammadinamul Sheik                    final long downloadId = c
128bf7c0106b0380bc80dd78d6026abce36b5e2ce51Mohammadinamul Sheik                            .getLong(c.getColumnIndex(DownloadManager.COLUMN_ID));
129bf7c0106b0380bc80dd78d6026abce36b5e2ce51Mohammadinamul Sheik                    downloadManagerWrapper.remove(downloadId);
130bf7c0106b0380bc80dd78d6026abce36b5e2ce51Mohammadinamul Sheik                    Log.i(TAG, "Removed the download with Id: " + downloadId);
1315a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik                }
1325a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik                c.close();
1335a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            }
1345a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik        } catch (Exception e) {
1355a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik            Log.e(TAG, "Exception while removing old downloads.");
1365a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik        }
1375a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik    }
1385a51e4a0a8b13308f457fe5fa82c01d7e8ee7c61Mohammadinamul Sheik
1393bc3bc7971f15438732933cfac0db6e766e6a3e9Mohammadinamul Sheik    private void downloadLatestDictionaries(Context context) {
1403bc3bc7971f15438732933cfac0db6e766e6a3e9Mohammadinamul Sheik        final Intent updateIntent = new Intent(
1413bc3bc7971f15438732933cfac0db6e766e6a3e9Mohammadinamul Sheik                DictionaryPackConstants.INIT_AND_UPDATE_NOW_INTENT_ACTION);
1423bc3bc7971f15438732933cfac0db6e766e6a3e9Mohammadinamul Sheik        context.sendBroadcast(updateIntent);
1433bc3bc7971f15438732933cfac0db6e766e6a3e9Mohammadinamul Sheik    }
1443bc3bc7971f15438732933cfac0db6e766e6a3e9Mohammadinamul Sheik
145767c0bf71b9c0af7f8451d7d355f6efad21a6e5bChieu Nguyen    public static void toggleAppIcon(final Context context) {
14608f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic        final int appInfoFlags = context.getApplicationInfo().flags;
14708f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic        final boolean isSystemApp = (appInfoFlags & ApplicationInfo.FLAG_SYSTEM) > 0;
14808f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic        if (Log.isLoggable(TAG, Log.INFO)) {
14908f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic            Log.i(TAG, "toggleAppIcon() : FLAG_SYSTEM = " + isSystemApp);
15008f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic        }
151a2376cd2b4fea6b655fdcdf794cf16b7bbe1a161Chieu Nguyen        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
15208f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic        context.getPackageManager().setComponentEnabledSetting(
15308f3cdb3c87e56ac62f5ac3c573beade592b4b06Dan Zivkovic                new ComponentName(context, SetupActivity.class),
154a2376cd2b4fea6b655fdcdf794cf16b7bbe1a161Chieu Nguyen                Settings.readShowSetupWizardIcon(prefs, context)
155a2376cd2b4fea6b655fdcdf794cf16b7bbe1a161Chieu Nguyen                        ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
156a2376cd2b4fea6b655fdcdf794cf16b7bbe1a161Chieu Nguyen                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
157d913617e0cecc2628c3729933c365d76f45f5504Dan Zivkovic                PackageManager.DONT_KILL_APP);
158d913617e0cecc2628c3729933c365d76f45f5504Dan Zivkovic    }
159052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa}
160