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