diff options
author | 2024-12-16 21:45:41 -0500 | |
---|---|---|
committer | 2025-01-11 14:17:35 -0500 | |
commit | e9a0e66716dab4dd3184d009d8920de1961efdfa (patch) | |
tree | 02dcc096643d74645bf28459c2834c3d4a2ad7f2 /java/src/com/android/inputmethod/dictionarypack/DictionaryService.java | |
parent | fb3b9360d70596d7e921de8bf7d3ca99564a077e (diff) | |
download | latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.gz latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.xz latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.zip |
Rename to Kelar Keyboard (org.kelar.inputmethod.latin)
Diffstat (limited to 'java/src/com/android/inputmethod/dictionarypack/DictionaryService.java')
-rw-r--r-- | java/src/com/android/inputmethod/dictionarypack/DictionaryService.java | 280 |
1 files changed, 0 insertions, 280 deletions
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java deleted file mode 100644 index 5ab55bc44..000000000 --- a/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java +++ /dev/null @@ -1,280 +0,0 @@ -/** - * Copyright (C) 2011 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.inputmethod.dictionarypack; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.util.Log; -import android.widget.Toast; - -import com.android.inputmethod.latin.BinaryDictionaryFileDumper; -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.common.LocaleUtils; - -import java.util.Locale; -import java.util.Random; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nonnull; - -/** - * Service that handles background tasks for the dictionary provider. - * - * This service provides the context for the long-running operations done by the - * dictionary provider. Those include: - * - Checking for the last update date and scheduling the next update. This runs every - * day around midnight, upon reception of the DATE_CHANGED_INTENT_ACTION broadcast. - * Every four days, it schedules an update of the metadata with the alarm manager. - * - Issuing the order to update the metadata. This runs every four days, between 0 and - * 6, upon reception of the UPDATE_NOW_INTENT_ACTION broadcast sent by the alarm manager - * as a result of the above action. - * - Handling a download that just ended. These come in two flavors: - * - Metadata is finished downloading. We should check whether there are new dictionaries - * available, and download those that we need that have new versions. - * - A dictionary file finished downloading. We should put the file ready for a client IME - * to access, and mark the current state as such. - */ -public final class DictionaryService extends Service { - private static final String TAG = DictionaryService.class.getSimpleName(); - - /** - * The package name, to use in the intent actions. - */ - private static final String PACKAGE_NAME = "com.android.inputmethod.latin"; - - /** - * The action of the date changing, used to schedule a periodic freshness check - */ - private static final String DATE_CHANGED_INTENT_ACTION = - Intent.ACTION_DATE_CHANGED; - - /** - * The action of displaying a toast to warn the user an automatic download is starting. - */ - /* package */ static final String SHOW_DOWNLOAD_TOAST_INTENT_ACTION = - PACKAGE_NAME + ".SHOW_DOWNLOAD_TOAST_INTENT_ACTION"; - - /** - * A locale argument, as a String. - */ - /* package */ static final String LOCALE_INTENT_ARGUMENT = "locale"; - - /** - * How often, in milliseconds, we want to update the metadata. This is a - * floor value; actually, it may happen several hours later, or even more. - */ - private static final long UPDATE_FREQUENCY_MILLIS = TimeUnit.DAYS.toMillis(4); - - /** - * We are waked around midnight, local time. We want to wake between midnight and 6 am, - * roughly. So use a random time between 0 and this delay. - */ - private static final int MAX_ALARM_DELAY_MILLIS = (int)TimeUnit.HOURS.toMillis(6); - - /** - * How long we consider a "very long time". If no update took place in this time, - * the content provider will trigger an update in the background. - */ - private static final long VERY_LONG_TIME_MILLIS = TimeUnit.DAYS.toMillis(14); - - /** - * After starting a download, how long we wait before considering it may be stuck. After this - * period is elapsed, if the keyboard tries to download again, then we cancel and re-register - * the request; if it's within this time, we just leave it be. - * It's important to note that we do not re-submit the request merely because the time is up. - * This is only to decide whether to cancel the old one and re-requesting when the keyboard - * fires a new request for the same data. - */ - public static final long NO_CANCEL_DOWNLOAD_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(30); - - /** - * An executor that serializes tasks given to it. - */ - private ThreadPoolExecutor mExecutor; - private static final int WORKER_THREAD_TIMEOUT_SECONDS = 15; - - @Override - public void onCreate() { - // By default, a thread pool executor does not timeout its core threads, so it will - // never kill them when there isn't any work to do any more. That would mean the service - // can never die! By creating it this way and calling allowCoreThreadTimeOut, we allow - // the single thread to time out after WORKER_THREAD_TIMEOUT_SECONDS = 15 seconds, allowing - // the process to be reclaimed by the system any time after that if it's not doing - // anything else. - // Executors#newSingleThreadExecutor creates a ThreadPoolExecutor but it returns the - // superclass ExecutorService which does not have the #allowCoreThreadTimeOut method, - // so we can't use that. - mExecutor = new ThreadPoolExecutor(1 /* corePoolSize */, 1 /* maximumPoolSize */, - WORKER_THREAD_TIMEOUT_SECONDS /* keepAliveTime */, - TimeUnit.SECONDS /* unit for keepAliveTime */, - new LinkedBlockingQueue<Runnable>() /* workQueue */); - mExecutor.allowCoreThreadTimeOut(true); - } - - @Override - public void onDestroy() { - } - - @Override - public IBinder onBind(Intent intent) { - // This service cannot be bound - return null; - } - - /** - * Executes an explicit command. - * - * This is the entry point for arbitrary commands that are executed upon reception of certain - * events that should be executed on the context of this service. The supported commands are: - * - Check last update time and possibly schedule an update of the data for later. - * This is triggered every day, upon reception of the DATE_CHANGED_INTENT_ACTION broadcast. - * - Update data NOW. - * This is normally received upon trigger of the scheduled update. - * - Handle a finished download. - * This executes the actions that must be taken after a file (metadata or dictionary data - * has been downloaded (or failed to download). - * The commands that can be spun an another thread will be executed serially, in order, on - * a worker thread that is created on demand and terminates after a short while if there isn't - * any work left to do. - */ - @Override - public synchronized int onStartCommand(final Intent intent, final int flags, - final int startId) { - final DictionaryService self = this; - if (SHOW_DOWNLOAD_TOAST_INTENT_ACTION.equals(intent.getAction())) { - final String localeString = intent.getStringExtra(LOCALE_INTENT_ARGUMENT); - if (localeString == null) { - Log.e(TAG, "Received " + intent.getAction() + " without locale; skipped"); - } else { - // This is a UI action, it can't be run in another thread - showStartDownloadingToast( - this, LocaleUtils.constructLocaleFromString(localeString)); - } - } else { - // If it's a command that does not require UI, arrange for the work to be done on a - // separate thread, so that we can return right away. The executor will spawn a thread - // if necessary, or reuse a thread that has become idle as appropriate. - // DATE_CHANGED or UPDATE_NOW are examples of commands that can be done on another - // thread. - mExecutor.submit(new Runnable() { - @Override - public void run() { - dispatchBroadcast(self, intent); - // Since calls to onStartCommand are serialized, the submissions to the executor - // are serialized. That means we are guaranteed to call the stopSelfResult() - // in the same order that we got them, so we don't need to take care of the - // order. - stopSelfResult(startId); - } - }); - } - return Service.START_REDELIVER_INTENT; - } - - static void dispatchBroadcast(final Context context, final Intent intent) { - final String action = intent.getAction(); - if (DATE_CHANGED_INTENT_ACTION.equals(action)) { - // This happens when the date of the device changes. This normally happens - // at midnight local time, but it may happen if the user changes the date - // by hand or something similar happens. - checkTimeAndMaybeSetupUpdateAlarm(context); - } else if (DictionaryPackConstants.UPDATE_NOW_INTENT_ACTION.equals(action)) { - // Intent to trigger an update now. - UpdateHandler.tryUpdate(context); - } else if (DictionaryPackConstants.INIT_AND_UPDATE_NOW_INTENT_ACTION.equals(action)) { - // Initialize the client Db. - final String mClientId = context.getString(R.string.dictionary_pack_client_id); - BinaryDictionaryFileDumper.initializeClientRecordHelper(context, mClientId); - - // Updates the metadata and the download the dictionaries. - UpdateHandler.tryUpdate(context); - } else { - UpdateHandler.downloadFinished(context, intent); - } - } - - /** - * Setups an alarm to check for updates if an update is due. - */ - private static void checkTimeAndMaybeSetupUpdateAlarm(final Context context) { - // Of all clients, if the one that hasn't been updated for the longest - // is still more recent than UPDATE_FREQUENCY_MILLIS, do nothing. - if (!isLastUpdateAtLeastThisOld(context, UPDATE_FREQUENCY_MILLIS)) return; - - PrivateLog.log("Date changed - registering alarm"); - AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); - - // Best effort to wake between midnight and MAX_ALARM_DELAY_MILLIS in the morning. - // It doesn't matter too much if this is very inexact. - final long now = System.currentTimeMillis(); - final long alarmTime = now + new Random().nextInt(MAX_ALARM_DELAY_MILLIS); - final Intent updateIntent = new Intent(DictionaryPackConstants.UPDATE_NOW_INTENT_ACTION); - // Set the package name to ensure the PendingIntent is only delivered to trusted components - updateIntent.setPackage(context.getPackageName()); - int pendingIntentFlags = PendingIntent.FLAG_CANCEL_CURRENT; - if (android.os.Build.VERSION.SDK_INT >= 23) { - pendingIntentFlags |= PendingIntent.FLAG_IMMUTABLE; - } - final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, - updateIntent, pendingIntentFlags); - - // We set the alarm in the type that doesn't forcefully wake the device - // from sleep, but fires the next time the device actually wakes for any - // other reason. - if (null != alarmManager) alarmManager.set(AlarmManager.RTC, alarmTime, pendingIntent); - } - - /** - * Utility method to decide whether the last update is older than a certain time. - * - * @return true if at least `time' milliseconds have elapsed since last update, false otherwise. - */ - private static boolean isLastUpdateAtLeastThisOld(final Context context, final long time) { - final long now = System.currentTimeMillis(); - final long lastUpdate = MetadataDbHelper.getOldestUpdateTime(context); - PrivateLog.log("Last update was " + lastUpdate); - return lastUpdate + time < now; - } - - /** - * Refreshes data if it hasn't been refreshed in a very long time. - * - * This will check the last update time, and if it's been more than VERY_LONG_TIME_MILLIS, - * update metadata now - and possibly take subsequent update actions. - */ - public static void updateNowIfNotUpdatedInAVeryLongTime(final Context context) { - if (!isLastUpdateAtLeastThisOld(context, VERY_LONG_TIME_MILLIS)) return; - UpdateHandler.tryUpdate(context); - } - - /** - * Shows a toast informing the user that an automatic dictionary download is starting. - */ - private static void showStartDownloadingToast(final Context context, - @Nonnull final Locale locale) { - final String toastText = String.format( - context.getString(R.string.toast_downloading_suggestions), - locale.getDisplayName()); - Toast.makeText(context, toastText, Toast.LENGTH_LONG).show(); - } -} |