mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Add support for Direct Boot by loading default preferences for first unlock
This commit is contained in:
parent
7d492897cc
commit
b6206e3059
@ -32,8 +32,6 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:defaultToDeviceProtectedStorage="true"
|
|
||||||
android:directBootAware="true"
|
|
||||||
android:largeHeap="true"
|
android:largeHeap="true"
|
||||||
android:name=".CrashLoggingApplication">
|
android:name=".CrashLoggingApplication">
|
||||||
|
|
||||||
@ -41,6 +39,7 @@
|
|||||||
<service android:name=".LatinIME"
|
<service android:name=".LatinIME"
|
||||||
android:label="@string/english_ime_name"
|
android:label="@string/english_ime_name"
|
||||||
android:permission="android.permission.BIND_INPUT_METHOD"
|
android:permission="android.permission.BIND_INPUT_METHOD"
|
||||||
|
android:directBootAware="true"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.view.InputMethod"/>
|
<action android:name="android.view.InputMethod"/>
|
||||||
|
@ -159,9 +159,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static KeyboardTheme getKeyboardTheme(final Context context) {
|
public static KeyboardTheme getKeyboardTheme(final Context context) {
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
return KEYBOARD_THEMES[0];
|
||||||
final KeyboardTheme[] availableThemeArray = getAvailableThemeArray(context);
|
|
||||||
return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT, availableThemeArray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package private for testing */
|
/* package private for testing */
|
||||||
|
@ -200,9 +200,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
|
|||||||
|
|
||||||
PointerTracker.init(mainKeyboardViewAttr, mTimerHandler, this /* DrawingProxy */);
|
PointerTracker.init(mainKeyboardViewAttr, mTimerHandler, this /* DrawingProxy */);
|
||||||
|
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
final boolean forceNonDistinctMultitouch = false;
|
||||||
final boolean forceNonDistinctMultitouch = prefs.getBoolean(
|
|
||||||
DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false);
|
|
||||||
final boolean hasDistinctMultitouch = context.getPackageManager()
|
final boolean hasDistinctMultitouch = context.getPackageManager()
|
||||||
.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)
|
.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)
|
||||||
&& !forceNonDistinctMultitouch;
|
&& !forceNonDistinctMultitouch;
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package org.futo.inputmethod.latin
|
package org.futo.inputmethod.latin
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.inputmethodservice.InputMethodService
|
import android.inputmethodservice.InputMethodService
|
||||||
@ -19,7 +23,6 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.ColorScheme
|
import androidx.compose.material3.ColorScheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.key
|
import androidx.compose.runtime.key
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@ -50,6 +53,7 @@ import kotlinx.coroutines.runBlocking
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.futo.inputmethod.latin.SuggestedWords.SuggestedWordInfo
|
import org.futo.inputmethod.latin.SuggestedWords.SuggestedWordInfo
|
||||||
import org.futo.inputmethod.latin.common.Constants
|
import org.futo.inputmethod.latin.common.Constants
|
||||||
|
import org.futo.inputmethod.latin.settings.Settings
|
||||||
import org.futo.inputmethod.latin.uix.BasicThemeProvider
|
import org.futo.inputmethod.latin.uix.BasicThemeProvider
|
||||||
import org.futo.inputmethod.latin.uix.DynamicThemeProvider
|
import org.futo.inputmethod.latin.uix.DynamicThemeProvider
|
||||||
import org.futo.inputmethod.latin.uix.DynamicThemeProviderOwner
|
import org.futo.inputmethod.latin.uix.DynamicThemeProviderOwner
|
||||||
@ -67,6 +71,7 @@ import org.futo.inputmethod.latin.uix.differsFrom
|
|||||||
import org.futo.inputmethod.latin.uix.getSetting
|
import org.futo.inputmethod.latin.uix.getSetting
|
||||||
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
||||||
import org.futo.inputmethod.latin.uix.getSettingFlow
|
import org.futo.inputmethod.latin.uix.getSettingFlow
|
||||||
|
import org.futo.inputmethod.latin.uix.isDirectBootUnlocked
|
||||||
import org.futo.inputmethod.latin.uix.setSetting
|
import org.futo.inputmethod.latin.uix.setSetting
|
||||||
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
|
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
|
||||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||||
@ -76,10 +81,18 @@ import org.futo.inputmethod.latin.uix.theme.presets.VoiceInputTheme
|
|||||||
import org.futo.inputmethod.latin.xlm.LanguageModelFacilitator
|
import org.futo.inputmethod.latin.xlm.LanguageModelFacilitator
|
||||||
import org.futo.inputmethod.updates.scheduleUpdateCheckingJob
|
import org.futo.inputmethod.updates.scheduleUpdateCheckingJob
|
||||||
|
|
||||||
|
private class UnlockedBroadcastReceiver(val onDeviceUnlocked: () -> Unit) : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
println("Unlocked Broadcast Receiver: ${intent?.action}")
|
||||||
|
if (intent?.action == Intent.ACTION_USER_UNLOCKED) {
|
||||||
|
onDeviceUnlocked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner,
|
class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner,
|
||||||
LatinIMELegacy.SuggestionStripController, DynamicThemeProviderOwner {
|
LatinIMELegacy.SuggestionStripController, DynamicThemeProviderOwner {
|
||||||
|
|
||||||
|
|
||||||
private lateinit var mLifecycleRegistry: LifecycleRegistry
|
private lateinit var mLifecycleRegistry: LifecycleRegistry
|
||||||
private lateinit var mViewModelStore: ViewModelStore
|
private lateinit var mViewModelStore: ViewModelStore
|
||||||
private lateinit var mSavedStateRegistryController: SavedStateRegistryController
|
private lateinit var mSavedStateRegistryController: SavedStateRegistryController
|
||||||
@ -222,9 +235,14 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
|||||||
jobs.clear()
|
jobs.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var unlockReceiver = UnlockedBroadcastReceiver { onDeviceUnlocked() }
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
|
val filter = IntentFilter(Intent.ACTION_USER_UNLOCKED)
|
||||||
|
registerReceiver(unlockReceiver, filter)
|
||||||
|
|
||||||
mLifecycleRegistry = LifecycleRegistry(this)
|
mLifecycleRegistry = LifecycleRegistry(this)
|
||||||
mLifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
|
mLifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
|
||||||
|
|
||||||
@ -264,7 +282,10 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
|||||||
latinIMELegacy.onCreate()
|
latinIMELegacy.onCreate()
|
||||||
|
|
||||||
languageModelFacilitator.launchProcessor()
|
languageModelFacilitator.launchProcessor()
|
||||||
languageModelFacilitator.loadHistoryLog()
|
|
||||||
|
if(isDirectBootUnlocked) {
|
||||||
|
languageModelFacilitator.loadHistoryLog()
|
||||||
|
}
|
||||||
|
|
||||||
scheduleUpdateCheckingJob(this)
|
scheduleUpdateCheckingJob(this)
|
||||||
launchJob { uixManager.showUpdateNoticeIfNeeded() }
|
launchJob { uixManager.showUpdateNoticeIfNeeded() }
|
||||||
@ -322,6 +343,8 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
unregisterReceiver(unlockReceiver)
|
||||||
|
|
||||||
stopJobs()
|
stopJobs()
|
||||||
mLifecycleRegistry.currentState = Lifecycle.State.DESTROYED
|
mLifecycleRegistry.currentState = Lifecycle.State.DESTROYED
|
||||||
viewModelStore.clear()
|
viewModelStore.clear()
|
||||||
@ -666,4 +689,22 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
|||||||
get() = mSavedStateRegistryController.savedStateRegistry
|
get() = mSavedStateRegistryController.savedStateRegistry
|
||||||
override val viewModelStore: ViewModelStore
|
override val viewModelStore: ViewModelStore
|
||||||
get() = mViewModelStore
|
get() = mViewModelStore
|
||||||
|
|
||||||
|
|
||||||
|
private fun onDeviceUnlocked() {
|
||||||
|
Log.i("LatinIME", "DEVICE has UNLOCKED!!! Reloading settings...")
|
||||||
|
// Every place that called getDefaultSharedPreferences now needs to be refreshed or call it again
|
||||||
|
|
||||||
|
// Mainly Settings singleton needs to be refreshed
|
||||||
|
Settings.init(applicationContext)
|
||||||
|
Settings.getInstance().onSharedPreferenceChanged(null /* unused */, "")
|
||||||
|
latinIMELegacy.loadSettings()
|
||||||
|
recreateKeyboard()
|
||||||
|
|
||||||
|
Log.i("LatinIME", "DEVICE has UNLOCKED!!! Finished reloading: ${Settings.getInstance().current.dump()}")
|
||||||
|
|
||||||
|
languageModelFacilitator.loadHistoryLog()
|
||||||
|
|
||||||
|
// TODO: Spell checker service
|
||||||
|
}
|
||||||
}
|
}
|
@ -38,7 +38,6 @@ import android.os.Build;
|
|||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.PrintWriterPrinter;
|
import android.util.PrintWriterPrinter;
|
||||||
@ -573,7 +572,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
|||||||
|
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
Settings.init(mInputMethodService);
|
Settings.init(mInputMethodService);
|
||||||
DebugFlags.init(PreferenceManager.getDefaultSharedPreferences(mInputMethodService));
|
|
||||||
RichInputMethodManager.init(mInputMethodService);
|
RichInputMethodManager.init(mInputMethodService);
|
||||||
mRichImm = RichInputMethodManager.getInstance();
|
mRichImm = RichInputMethodManager.getInstance();
|
||||||
AudioAndHapticFeedbackManager.init(mInputMethodService);
|
AudioAndHapticFeedbackManager.init(mInputMethodService);
|
||||||
@ -934,10 +932,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
|||||||
final boolean inputTypeChanged = !currentSettingsValues.isSameInputType(editorInfo);
|
final boolean inputTypeChanged = !currentSettingsValues.isSameInputType(editorInfo);
|
||||||
final boolean isDifferentTextField = !restarting || inputTypeChanged;
|
final boolean isDifferentTextField = !restarting || inputTypeChanged;
|
||||||
|
|
||||||
StatsUtils.onStartInputView(editorInfo.inputType,
|
|
||||||
Settings.getInstance().getCurrent().mDisplayOrientation,
|
|
||||||
!isDifferentTextField);
|
|
||||||
|
|
||||||
// The EditorInfo might have a flag that affects fullscreen mode.
|
// The EditorInfo might have a flag that affects fullscreen mode.
|
||||||
// Note: This call should be done by InputMethodService?
|
// Note: This call should be done by InputMethodService?
|
||||||
updateFullscreenMode();
|
updateFullscreenMode();
|
||||||
|
@ -34,6 +34,7 @@ import org.futo.inputmethod.annotations.UsedForTesting;
|
|||||||
import org.futo.inputmethod.compat.InputMethodManagerCompatWrapper;
|
import org.futo.inputmethod.compat.InputMethodManagerCompatWrapper;
|
||||||
import org.futo.inputmethod.compat.InputMethodSubtypeCompatUtils;
|
import org.futo.inputmethod.compat.InputMethodSubtypeCompatUtils;
|
||||||
import org.futo.inputmethod.latin.settings.Settings;
|
import org.futo.inputmethod.latin.settings.Settings;
|
||||||
|
import org.futo.inputmethod.latin.uix.PreferenceUtils;
|
||||||
import org.futo.inputmethod.latin.utils.AdditionalSubtypeUtils;
|
import org.futo.inputmethod.latin.utils.AdditionalSubtypeUtils;
|
||||||
import org.futo.inputmethod.latin.utils.LanguageOnSpacebarUtils;
|
import org.futo.inputmethod.latin.utils.LanguageOnSpacebarUtils;
|
||||||
import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils;
|
import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils;
|
||||||
@ -108,7 +109,7 @@ public class RichInputMethodManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public InputMethodSubtype[] getAdditionalSubtypes() {
|
public InputMethodSubtype[] getAdditionalSubtypes() {
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
final SharedPreferences prefs = PreferenceUtils.INSTANCE.getDefaultSharedPreferences(mContext);
|
||||||
final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes(
|
final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes(
|
||||||
prefs, mContext.getResources());
|
prefs, mContext.getResources());
|
||||||
return AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefAdditionalSubtypes);
|
return AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefAdditionalSubtypes);
|
||||||
|
@ -37,6 +37,7 @@ import okhttp3.internal.toImmutableList
|
|||||||
import org.futo.inputmethod.latin.common.Constants
|
import org.futo.inputmethod.latin.common.Constants
|
||||||
import org.futo.inputmethod.latin.uix.SettingsKey
|
import org.futo.inputmethod.latin.uix.SettingsKey
|
||||||
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
||||||
|
import org.futo.inputmethod.latin.uix.isDirectBootUnlocked
|
||||||
import org.futo.inputmethod.latin.uix.setSettingBlocking
|
import org.futo.inputmethod.latin.uix.setSettingBlocking
|
||||||
import org.futo.inputmethod.latin.uix.settings.NavigationItem
|
import org.futo.inputmethod.latin.uix.settings.NavigationItem
|
||||||
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
|
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
|
||||||
@ -93,6 +94,8 @@ object Subtypes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addDefaultSubtypesIfNecessary(context: Context) {
|
fun addDefaultSubtypesIfNecessary(context: Context) {
|
||||||
|
if(!context.isDirectBootUnlocked) return
|
||||||
|
|
||||||
val currentSubtypes = context.getSettingBlocking(SubtypesSetting)
|
val currentSubtypes = context.getSettingBlocking(SubtypesSetting)
|
||||||
if(currentSubtypes.isNotEmpty()) {
|
if(currentSubtypes.isNotEmpty()) {
|
||||||
removeExtensionsIfNecessary(context)
|
removeExtensionsIfNecessary(context)
|
||||||
@ -116,7 +119,7 @@ object Subtypes {
|
|||||||
addLanguage(context, Locale.forLanguageTag("zz"), "qwerty")
|
addLanguage(context, Locale.forLanguageTag("zz"), "qwerty")
|
||||||
}
|
}
|
||||||
|
|
||||||
context.setSettingBlocking(ActiveSubtype.key, context.getSettingBlocking(SubtypesSetting).first())
|
context.setSettingBlocking(ActiveSubtype.key, context.getSettingBlocking(SubtypesSetting).firstOrNull() ?: return)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findClosestLocaleLayouts(locale: Locale): List<String> {
|
fun findClosestLocaleLayouts(locale: Locale): List<String> {
|
||||||
@ -224,6 +227,30 @@ object Subtypes {
|
|||||||
}
|
}
|
||||||
}.mapValues { it.value.toImmutableList() }
|
}.mapValues { it.value.toImmutableList() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDirectBootInitialLayouts(context: Context): Set<String> {
|
||||||
|
val layouts = mutableSetOf("en_US:")
|
||||||
|
|
||||||
|
val locales = context.resources.configuration.locales
|
||||||
|
if(locales.size() == 0) return layouts
|
||||||
|
|
||||||
|
for(i in 0 until locales.size()) {
|
||||||
|
val locale = locales.get(i).stripExtensionsIfNeeded()
|
||||||
|
val layout = findClosestLocaleLayouts(locale).firstOrNull() ?: continue
|
||||||
|
|
||||||
|
val value = subtypeToString(
|
||||||
|
InputMethodSubtypeBuilder()
|
||||||
|
.setSubtypeLocale(locale.stripExtensionsIfNeeded().toString())
|
||||||
|
.setSubtypeExtraValue("KeyboardLayoutSet=$layout")
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
|
layouts.add(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return layouts
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.futo.inputmethod.compat.BuildCompatUtils;
|
import org.futo.inputmethod.compat.BuildCompatUtils;
|
||||||
@ -30,6 +29,7 @@ import org.futo.inputmethod.latin.AudioAndHapticFeedbackManager;
|
|||||||
import org.futo.inputmethod.latin.InputAttributes;
|
import org.futo.inputmethod.latin.InputAttributes;
|
||||||
import org.futo.inputmethod.latin.R;
|
import org.futo.inputmethod.latin.R;
|
||||||
import org.futo.inputmethod.latin.common.StringUtils;
|
import org.futo.inputmethod.latin.common.StringUtils;
|
||||||
|
import org.futo.inputmethod.latin.uix.PreferenceUtils;
|
||||||
import org.futo.inputmethod.latin.utils.AdditionalSubtypeUtils;
|
import org.futo.inputmethod.latin.utils.AdditionalSubtypeUtils;
|
||||||
import org.futo.inputmethod.latin.utils.ResourceUtils;
|
import org.futo.inputmethod.latin.utils.ResourceUtils;
|
||||||
import org.futo.inputmethod.latin.utils.RunInLocale;
|
import org.futo.inputmethod.latin.utils.RunInLocale;
|
||||||
@ -145,7 +145,12 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
|
|||||||
private void onCreate(final Context context) {
|
private void onCreate(final Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mRes = context.getResources();
|
mRes = context.getResources();
|
||||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
||||||
|
if(mPrefs != null) {
|
||||||
|
mPrefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPrefs = PreferenceUtils.INSTANCE.getDefaultSharedPreferences(context);
|
||||||
mPrefs.registerOnSharedPreferenceChangeListener(this);
|
mPrefs.registerOnSharedPreferenceChangeListener(this);
|
||||||
upgradeAutocorrectionSettings(mPrefs, mRes);
|
upgradeAutocorrectionSettings(mPrefs, mRes);
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import org.futo.inputmethod.latin.RichInputMethodSubtype;
|
|||||||
import org.futo.inputmethod.latin.SuggestedWords;
|
import org.futo.inputmethod.latin.SuggestedWords;
|
||||||
import org.futo.inputmethod.latin.common.ComposedData;
|
import org.futo.inputmethod.latin.common.ComposedData;
|
||||||
import org.futo.inputmethod.latin.settings.SettingsValuesForSuggestion;
|
import org.futo.inputmethod.latin.settings.SettingsValuesForSuggestion;
|
||||||
|
import org.futo.inputmethod.latin.uix.PreferenceUtils;
|
||||||
import org.futo.inputmethod.latin.utils.AdditionalSubtypeUtils;
|
import org.futo.inputmethod.latin.utils.AdditionalSubtypeUtils;
|
||||||
import org.futo.inputmethod.latin.utils.ScriptUtils;
|
import org.futo.inputmethod.latin.utils.ScriptUtils;
|
||||||
import org.futo.inputmethod.latin.utils.SuggestionResults;
|
import org.futo.inputmethod.latin.utils.SuggestionResults;
|
||||||
@ -95,7 +96,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
|
|||||||
super.onCreate();
|
super.onCreate();
|
||||||
mRecommendedThreshold = Float.parseFloat(
|
mRecommendedThreshold = Float.parseFloat(
|
||||||
getString(R.string.spellchecker_recommended_threshold_value));
|
getString(R.string.spellchecker_recommended_threshold_value));
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
final SharedPreferences prefs = PreferenceUtils.INSTANCE.getDefaultSharedPreferences(this);
|
||||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||||
onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY);
|
onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY);
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,147 @@
|
|||||||
package org.futo.inputmethod.latin.uix
|
package org.futo.inputmethod.latin.uix
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.UserManager
|
||||||
|
import android.preference.PreferenceManager
|
||||||
import androidx.datastore.core.DataStore
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.Preferences
|
||||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||||
import androidx.datastore.preferences.core.edit
|
import androidx.datastore.preferences.core.edit
|
||||||
|
import androidx.datastore.preferences.core.preferencesOf
|
||||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
import androidx.datastore.preferences.core.stringSetPreferencesKey
|
import androidx.datastore.preferences.core.stringSetPreferencesKey
|
||||||
import androidx.datastore.preferences.preferencesDataStore
|
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.take
|
import kotlinx.coroutines.flow.take
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.futo.inputmethod.latin.ActiveSubtype
|
||||||
|
import org.futo.inputmethod.latin.Subtypes
|
||||||
|
import org.futo.inputmethod.latin.SubtypesSetting
|
||||||
|
import org.futo.inputmethod.latin.uix.theme.presets.ClassicMaterialDark
|
||||||
import org.futo.inputmethod.latin.uix.theme.presets.DynamicSystemTheme
|
import org.futo.inputmethod.latin.uix.theme.presets.DynamicSystemTheme
|
||||||
|
|
||||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
// Used before first unlock (direct boot)
|
||||||
|
private object DefaultDataStore : DataStore<Preferences> {
|
||||||
|
private var activePreferences = preferencesOf(
|
||||||
|
ActiveSubtype.key to "en_US:",
|
||||||
|
SubtypesSetting.key to setOf("en_US:"),
|
||||||
|
THEME_KEY.key to ClassicMaterialDark.key,
|
||||||
|
KeyHintsSetting.key to true
|
||||||
|
)
|
||||||
|
|
||||||
|
var subtypesInitialized = false
|
||||||
|
|
||||||
|
suspend fun updateSubtypes(subtypes: Set<String>) {
|
||||||
|
val newPreferences = activePreferences.toMutablePreferences()
|
||||||
|
newPreferences[SubtypesSetting.key] = subtypes
|
||||||
|
|
||||||
|
activePreferences = newPreferences
|
||||||
|
sharedData.emit(activePreferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
val sharedData = MutableSharedFlow<Preferences>(1)
|
||||||
|
|
||||||
|
override val data: Flow<Preferences>
|
||||||
|
get() {
|
||||||
|
return unlockedDataStore?.data ?: sharedData
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
sharedData.tryEmit(activePreferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateData(transform: suspend (t: Preferences) -> Preferences): Preferences {
|
||||||
|
return unlockedDataStore?.updateData(transform) ?: run {
|
||||||
|
val newActiveSubtype = transform(activePreferences)[ActiveSubtype.key]
|
||||||
|
if(newActiveSubtype != null && newActiveSubtype != activePreferences[ActiveSubtype.key]) {
|
||||||
|
val newPreferences = activePreferences.toMutablePreferences()
|
||||||
|
newPreferences[ActiveSubtype.key] = newActiveSubtype
|
||||||
|
activePreferences = newPreferences
|
||||||
|
sharedData.emit(newPreferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
return activePreferences
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set and used after first unlock (direct boot)
|
||||||
|
private var unlockedDataStore: DataStore<Preferences>? = null
|
||||||
|
|
||||||
|
// Initializes unlockedDataStore, or uses DefaultDataStore if device is still locked (direct boot)
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
|
val Context.dataStore: DataStore<Preferences>
|
||||||
|
get() {
|
||||||
|
val userManager = getSystemService(Context.USER_SERVICE) as UserManager
|
||||||
|
if (userManager.isUserUnlocked) {
|
||||||
|
// The device has been unlocked
|
||||||
|
return unlockedDataStore ?: run {
|
||||||
|
val newDataStore = PreferenceDataStoreFactory.create(
|
||||||
|
corruptionHandler = null,
|
||||||
|
migrations = listOf(),
|
||||||
|
scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
|
) {
|
||||||
|
applicationContext.preferencesDataStoreFile("settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
unlockedDataStore = newDataStore
|
||||||
|
|
||||||
|
// Send new values to the DefaultDataStore for any listeners
|
||||||
|
GlobalScope.launch {
|
||||||
|
newDataStore.data.collect { value ->
|
||||||
|
DefaultDataStore.sharedData.emit(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newDataStore
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The device is still locked, return default data store
|
||||||
|
|
||||||
|
if(!DefaultDataStore.subtypesInitialized) {
|
||||||
|
DefaultDataStore.subtypesInitialized = true
|
||||||
|
GlobalScope.launch {
|
||||||
|
DefaultDataStore.updateSubtypes(Subtypes.getDirectBootInitialLayouts(this@dataStore))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefaultDataStore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object PreferenceUtils {
|
||||||
|
fun getDefaultSharedPreferences(context: Context): SharedPreferences {
|
||||||
|
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||||
|
return if (userManager.isUserUnlocked) {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
} else {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context.createDeviceProtectedStorageContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val Context.isDirectBootUnlocked: Boolean
|
||||||
|
get() {
|
||||||
|
val userManager = getSystemService(Context.USER_SERVICE) as UserManager
|
||||||
|
return userManager.isUserUnlocked
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
suspend fun <T> Context.getSetting(key: Preferences.Key<T>, default: T): T {
|
suspend fun <T> Context.getSetting(key: Preferences.Key<T>, default: T): T {
|
||||||
val valueFlow: Flow<T> =
|
val valueFlow: Flow<T> =
|
||||||
|
@ -60,6 +60,7 @@ import org.futo.inputmethod.latin.uix.PersistentActionState
|
|||||||
import org.futo.inputmethod.latin.uix.PersistentStateInitialization
|
import org.futo.inputmethod.latin.uix.PersistentStateInitialization
|
||||||
import org.futo.inputmethod.latin.uix.SettingsKey
|
import org.futo.inputmethod.latin.uix.SettingsKey
|
||||||
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
||||||
|
import org.futo.inputmethod.latin.uix.isDirectBootUnlocked
|
||||||
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
||||||
import org.futo.inputmethod.latin.uix.settings.pages.ParagraphText
|
import org.futo.inputmethod.latin.uix.settings.pages.ParagraphText
|
||||||
import org.futo.inputmethod.latin.uix.settings.pages.PaymentSurface
|
import org.futo.inputmethod.latin.uix.settings.pages.PaymentSurface
|
||||||
@ -268,6 +269,8 @@ class ClipboardHistoryManager(val context: Context, val coroutineScope: Lifecycl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun saveClipboard() {
|
private fun saveClipboard() {
|
||||||
|
if(!context.isDirectBootUnlocked) return
|
||||||
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
pruneOldItems()
|
pruneOldItems()
|
||||||
@ -281,6 +284,8 @@ class ClipboardHistoryManager(val context: Context, val coroutineScope: Lifecycl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadClipboard() {
|
private suspend fun loadClipboard() {
|
||||||
|
if(!context.isDirectBootUnlocked) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val file = File(context.filesDir, "clipboard.json")
|
val file = File(context.filesDir, "clipboard.json")
|
||||||
|
|
||||||
@ -374,6 +379,7 @@ val ClipboardHistoryAction = Action(
|
|||||||
},
|
},
|
||||||
persistentStateInitialization = PersistentStateInitialization.OnKeyboardLoad,
|
persistentStateInitialization = PersistentStateInitialization.OnKeyboardLoad,
|
||||||
windowImpl = { manager, persistent ->
|
windowImpl = { manager, persistent ->
|
||||||
|
val unlocked = manager.getContext().isDirectBootUnlocked
|
||||||
val clipboardHistoryManager = persistent as ClipboardHistoryManager
|
val clipboardHistoryManager = persistent as ClipboardHistoryManager
|
||||||
|
|
||||||
manager.getLifecycleScope().launch { clipboardHistoryManager.pruneOldItems() }
|
manager.getLifecycleScope().launch { clipboardHistoryManager.pruneOldItems() }
|
||||||
@ -443,7 +449,13 @@ val ClipboardHistoryAction = Action(
|
|||||||
override fun WindowContents(keyboardShown: Boolean) {
|
override fun WindowContents(keyboardShown: Boolean) {
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
val clipboardHistory = useDataStore(ClipboardHistoryEnabled, blocking = true)
|
val clipboardHistory = useDataStore(ClipboardHistoryEnabled, blocking = true)
|
||||||
if(!clipboardHistory.value) {
|
if(!unlocked) {
|
||||||
|
ScrollableList {
|
||||||
|
PaymentSurface(isPrimary = true, title = "Device Locked") {
|
||||||
|
ParagraphText("Please unlock your device to access clipboard history")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(!clipboardHistory.value) {
|
||||||
ScrollableList {
|
ScrollableList {
|
||||||
PaymentSurface(isPrimary = true, title = "Clipboard History Inactive") {
|
PaymentSurface(isPrimary = true, title = "Clipboard History Inactive") {
|
||||||
ParagraphText("Clipboard history is not enabled. To save clipboard items, you can enable clipboard history. This will keep up to 25 items for 3 days unless pinned. Passwords and other items marked sensitive are excluded from history.")
|
ParagraphText("Clipboard history is not enabled. To save clipboard items, you can enable clipboard history. This will keep up to 25 items for 3 days unless pinned. Passwords and other items marked sensitive are excluded from history.")
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.futo.inputmethod.latin.uix.settings
|
package org.futo.inputmethod.latin.uix.settings
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.preference.PreferenceManager
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@ -20,6 +19,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.futo.inputmethod.latin.uix.PreferenceUtils
|
||||||
import org.futo.inputmethod.latin.uix.SettingsKey
|
import org.futo.inputmethod.latin.uix.SettingsKey
|
||||||
import org.futo.inputmethod.latin.uix.dataStore
|
import org.futo.inputmethod.latin.uix.dataStore
|
||||||
import org.futo.inputmethod.latin.uix.getSetting
|
import org.futo.inputmethod.latin.uix.getSetting
|
||||||
@ -94,7 +94,7 @@ fun <T> useDataStore(key: SettingsKey<T>, blocking: Boolean = false): DataStoreI
|
|||||||
fun<T> useSharedPrefsGeneric(key: String, default: T, get: (SharedPreferences, String, T) -> T, put: (SharedPreferences, String, T) -> Unit): DataStoreItem<T> {
|
fun<T> useSharedPrefsGeneric(key: String, default: T, get: (SharedPreferences, String, T) -> T, put: (SharedPreferences, String, T) -> Unit): DataStoreItem<T> {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val sharedPrefs = remember { PreferenceManager.getDefaultSharedPreferences(context) }
|
val sharedPrefs = remember { PreferenceUtils.getDefaultSharedPreferences(context) }
|
||||||
|
|
||||||
val value = remember { mutableStateOf(get(sharedPrefs, key, default)) }
|
val value = remember { mutableStateOf(get(sharedPrefs, key, default)) }
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ fun useSharedPrefsInt(key: String, default: Int): DataStoreItem<Int> {
|
|||||||
@Composable
|
@Composable
|
||||||
private fun<T> SyncDataStoreToPreferences(key: SettingsKey<T>, update: (newValue: T, editor: SharedPreferences.Editor) -> Unit) {
|
private fun<T> SyncDataStoreToPreferences(key: SettingsKey<T>, update: (newValue: T, editor: SharedPreferences.Editor) -> Unit) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val sharedPrefs = remember { PreferenceManager.getDefaultSharedPreferences(context) }
|
val sharedPrefs = remember { PreferenceUtils.getDefaultSharedPreferences(context) }
|
||||||
val value = useDataStoreValueBlocking(key)
|
val value = useDataStoreValueBlocking(key)
|
||||||
|
|
||||||
LaunchedEffect(value) {
|
LaunchedEffect(value) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.futo.inputmethod.latin.uix.settings.pages
|
package org.futo.inputmethod.latin.uix.settings.pages
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.preference.PreferenceManager
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.gestures.detectDragGestures
|
import androidx.compose.foundation.gestures.detectDragGestures
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@ -59,6 +58,7 @@ import org.futo.inputmethod.latin.uix.AndroidTextInput
|
|||||||
import org.futo.inputmethod.latin.uix.KeyHintsSetting
|
import org.futo.inputmethod.latin.uix.KeyHintsSetting
|
||||||
import org.futo.inputmethod.latin.uix.KeyboardBottomOffsetSetting
|
import org.futo.inputmethod.latin.uix.KeyboardBottomOffsetSetting
|
||||||
import org.futo.inputmethod.latin.uix.KeyboardHeightMultiplierSetting
|
import org.futo.inputmethod.latin.uix.KeyboardHeightMultiplierSetting
|
||||||
|
import org.futo.inputmethod.latin.uix.PreferenceUtils
|
||||||
import org.futo.inputmethod.latin.uix.SHOW_EMOJI_SUGGESTIONS
|
import org.futo.inputmethod.latin.uix.SHOW_EMOJI_SUGGESTIONS
|
||||||
import org.futo.inputmethod.latin.uix.SettingsKey
|
import org.futo.inputmethod.latin.uix.SettingsKey
|
||||||
import org.futo.inputmethod.latin.uix.actions.AllActions
|
import org.futo.inputmethod.latin.uix.actions.AllActions
|
||||||
@ -437,7 +437,7 @@ fun TypingScreen(navController: NavHostController = rememberNavController()) {
|
|||||||
val (vibration, _) = useDataStore(key = vibrationDurationSetting.key, default = vibrationDurationSetting.default)
|
val (vibration, _) = useDataStore(key = vibrationDurationSetting.key, default = vibrationDurationSetting.default)
|
||||||
|
|
||||||
LaunchedEffect(vibration) {
|
LaunchedEffect(vibration) {
|
||||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
val sharedPrefs = PreferenceUtils.getDefaultSharedPreferences(context)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
sharedPrefs.edit {
|
sharedPrefs.edit {
|
||||||
putInt(PREF_VIBRATION_DURATION_SETTINGS, vibration)
|
putInt(PREF_VIBRATION_DURATION_SETTINGS, vibration)
|
||||||
|
@ -69,20 +69,10 @@ public final class ImportantNoticeUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedForTesting
|
|
||||||
static SharedPreferences getImportantNoticePreferences(final Context context) {
|
|
||||||
return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@UsedForTesting
|
|
||||||
static boolean hasContactsNoticeShown(final Context context) {
|
|
||||||
return getImportantNoticePreferences(context).getBoolean(
|
|
||||||
KEY_SUGGEST_CONTACTS_NOTICE, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean shouldShowImportantNotice(final Context context,
|
public static boolean shouldShowImportantNotice(final Context context,
|
||||||
final SettingsValues settingsValues) {
|
final SettingsValues settingsValues) {
|
||||||
// Check to see whether "Use Contacts" is enabled by the user.
|
// Check to see whether "Use Contacts" is enabled by the user.
|
||||||
|
/*
|
||||||
if (!settingsValues.mUseContactsDict) {
|
if (!settingsValues.mUseContactsDict) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -107,8 +97,8 @@ public final class ImportantNoticeUtils {
|
|||||||
if (hasContactsNoticeTimeoutPassed(context, System.currentTimeMillis())) {
|
if (hasContactsNoticeTimeoutPassed(context, System.currentTimeMillis())) {
|
||||||
updateContactsNoticeShown(context);
|
updateContactsNoticeShown(context);
|
||||||
return false;
|
return false;
|
||||||
}
|
}*/
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getSuggestContactsNoticeTitle(final Context context) {
|
public static String getSuggestContactsNoticeTitle(final Context context) {
|
||||||
@ -118,23 +108,11 @@ public final class ImportantNoticeUtils {
|
|||||||
@UsedForTesting
|
@UsedForTesting
|
||||||
static boolean hasContactsNoticeTimeoutPassed(
|
static boolean hasContactsNoticeTimeoutPassed(
|
||||||
final Context context, final long currentTimeInMillis) {
|
final Context context, final long currentTimeInMillis) {
|
||||||
final SharedPreferences prefs = getImportantNoticePreferences(context);
|
|
||||||
if (!prefs.contains(KEY_TIMESTAMP_OF_CONTACTS_NOTICE)) {
|
return false;
|
||||||
prefs.edit()
|
|
||||||
.putLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE, currentTimeInMillis)
|
|
||||||
.apply();
|
|
||||||
}
|
|
||||||
final long firstDisplayTimeInMillis = prefs.getLong(
|
|
||||||
KEY_TIMESTAMP_OF_CONTACTS_NOTICE, currentTimeInMillis);
|
|
||||||
final long elapsedTime = currentTimeInMillis - firstDisplayTimeInMillis;
|
|
||||||
return elapsedTime >= TIMEOUT_OF_IMPORTANT_NOTICE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void updateContactsNoticeShown(final Context context) {
|
public static void updateContactsNoticeShown(final Context context) {
|
||||||
getImportantNoticePreferences(context)
|
|
||||||
.edit()
|
|
||||||
.putBoolean(KEY_SUGGEST_CONTACTS_NOTICE, true)
|
|
||||||
.remove(KEY_TIMESTAMP_OF_CONTACTS_NOTICE)
|
|
||||||
.apply();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import org.futo.inputmethod.latin.uix.isDirectBootUnlocked
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -23,6 +24,8 @@ data class HistoryLogForTraining(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun saveHistoryLogBackup(context: Context, log: List<HistoryLogForTraining>) {
|
fun saveHistoryLogBackup(context: Context, log: List<HistoryLogForTraining>) {
|
||||||
|
if(!context.isDirectBootUnlocked) return
|
||||||
|
|
||||||
val json = Json.encodeToString(log)
|
val json = Json.encodeToString(log)
|
||||||
|
|
||||||
val file = File(context.cacheDir, "historyLog.json")
|
val file = File(context.cacheDir, "historyLog.json")
|
||||||
@ -30,6 +33,8 @@ fun saveHistoryLogBackup(context: Context, log: List<HistoryLogForTraining>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun loadHistoryLogBackup(context: Context, to: MutableList<HistoryLogForTraining>) {
|
fun loadHistoryLogBackup(context: Context, to: MutableList<HistoryLogForTraining>) {
|
||||||
|
if(!context.isDirectBootUnlocked) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val file = File(context.cacheDir, "historyLog.json")
|
val file = File(context.cacheDir, "historyLog.json")
|
||||||
if(file.exists()) {
|
if(file.exists()) {
|
||||||
|
@ -25,6 +25,7 @@ import kotlinx.coroutines.withContext
|
|||||||
import org.futo.inputmethod.latin.R
|
import org.futo.inputmethod.latin.R
|
||||||
import org.futo.inputmethod.latin.uix.USE_TRANSFORMER_FINETUNING
|
import org.futo.inputmethod.latin.uix.USE_TRANSFORMER_FINETUNING
|
||||||
import org.futo.inputmethod.latin.uix.getSetting
|
import org.futo.inputmethod.latin.uix.getSetting
|
||||||
|
import org.futo.inputmethod.latin.uix.isDirectBootUnlocked
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@ -289,6 +290,7 @@ class TrainingWorker(val context: Context, val parameters: WorkerParameters) : C
|
|||||||
|
|
||||||
private val WORKER_TAG: String = "TRAINING_WORKER"
|
private val WORKER_TAG: String = "TRAINING_WORKER"
|
||||||
public fun scheduleTrainingWorkerBackground(context: Context) {
|
public fun scheduleTrainingWorkerBackground(context: Context) {
|
||||||
|
if(!context.isDirectBootUnlocked) return
|
||||||
val workManager = WorkManager.getInstance(context)
|
val workManager = WorkManager.getInstance(context)
|
||||||
workManager.cancelAllWorkByTag(WORKER_TAG)
|
workManager.cancelAllWorkByTag(WORKER_TAG)
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package org.futo.inputmethod.latin
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.UserManager
|
||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.Preferences
|
||||||
import org.acra.ACRA
|
import org.acra.ACRA
|
||||||
import org.acra.config.dialog
|
import org.acra.config.dialog
|
||||||
@ -12,35 +13,40 @@ import org.acra.data.StringFormat
|
|||||||
import org.acra.ktx.initAcra
|
import org.acra.ktx.initAcra
|
||||||
|
|
||||||
class CrashLoggingApplication : Application() {
|
class CrashLoggingApplication : Application() {
|
||||||
|
|
||||||
|
|
||||||
override fun attachBaseContext(base: Context?) {
|
override fun attachBaseContext(base: Context?) {
|
||||||
super.attachBaseContext(base)
|
super.attachBaseContext(base)
|
||||||
|
|
||||||
initAcra {
|
val userManager = getSystemService(Context.USER_SERVICE) as UserManager
|
||||||
reportFormat = StringFormat.JSON
|
if(userManager.isUserUnlocked) {
|
||||||
|
println("Initializing ACRA, as user is unlocked")
|
||||||
|
initAcra {
|
||||||
|
reportFormat = StringFormat.JSON
|
||||||
|
|
||||||
dialog {
|
dialog {
|
||||||
text = getString(
|
text = getString(
|
||||||
//if(BuildConfig.ENABLE_ACRA) {
|
//if(BuildConfig.ENABLE_ACRA) {
|
||||||
// R.string.crashed_text
|
// R.string.crashed_text
|
||||||
//} else {
|
//} else {
|
||||||
R.string.crashed_text_email
|
R.string.crashed_text_email
|
||||||
//}
|
//}
|
||||||
)
|
)
|
||||||
title = getString(R.string.crashed_title)
|
title = getString(R.string.crashed_title)
|
||||||
positiveButtonText = getString(R.string.crash_report_accept)
|
positiveButtonText = getString(R.string.crash_report_accept)
|
||||||
negativeButtonText = getString(R.string.crash_report_reject)
|
negativeButtonText = getString(R.string.crash_report_reject)
|
||||||
resTheme = android.R.style.Theme_DeviceDefault_Dialog
|
resTheme = android.R.style.Theme_DeviceDefault_Dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//if(BuildConfig.ENABLE_ACRA) {
|
//if(BuildConfig.ENABLE_ACRA) {
|
||||||
// httpSender {
|
// httpSender {
|
||||||
// uri = BuildConfig.ACRA_URL
|
// uri = BuildConfig.ACRA_URL
|
||||||
// basicAuthLogin = BuildConfig.ACRA_USER
|
// basicAuthLogin = BuildConfig.ACRA_USER
|
||||||
// basicAuthPassword = BuildConfig.ACRA_PASSWORD
|
// basicAuthPassword = BuildConfig.ACRA_PASSWORD
|
||||||
// httpMethod = HttpSender.Method.POST
|
// httpMethod = HttpSender.Method.POST
|
||||||
// }
|
// }
|
||||||
//} else {
|
//} else {
|
||||||
mailSender {
|
mailSender {
|
||||||
mailTo = "keyboard@futo.org"
|
mailTo = "keyboard@futo.org"
|
||||||
reportAsFile = true
|
reportAsFile = true
|
||||||
@ -49,14 +55,23 @@ class CrashLoggingApplication : Application() {
|
|||||||
body =
|
body =
|
||||||
"I experienced this crash. My version: ${BuildConfig.VERSION_NAME}.\n\n(Enter details here if necessary)"
|
"I experienced this crash. My version: ${BuildConfig.VERSION_NAME}.\n\n(Enter details here if necessary)"
|
||||||
}
|
}
|
||||||
//}
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
acraInitialized = true
|
||||||
|
} else {
|
||||||
|
println("Skipping ACRA, as user is locked")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
var acraInitialized = false
|
||||||
|
|
||||||
fun logPreferences(preferences: Preferences) {
|
fun logPreferences(preferences: Preferences) {
|
||||||
preferences.asMap().forEach {
|
if(acraInitialized) {
|
||||||
ACRA.errorReporter.putCustomData(it.key.name, it.value.toString())
|
preferences.asMap().forEach {
|
||||||
|
ACRA.errorReporter.putCustomData(it.key.name, it.value.toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user