diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml index d7cd2594b..df5bbf0ac 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml @@ -32,8 +32,6 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:allowBackup="true" - android:defaultToDeviceProtectedStorage="true" - android:directBootAware="true" android:largeHeap="true" android:name=".CrashLoggingApplication"> @@ -41,6 +39,7 @@ diff --git a/java/src/org/futo/inputmethod/keyboard/KeyboardTheme.java b/java/src/org/futo/inputmethod/keyboard/KeyboardTheme.java index 3122e3dd9..cba99d19e 100644 --- a/java/src/org/futo/inputmethod/keyboard/KeyboardTheme.java +++ b/java/src/org/futo/inputmethod/keyboard/KeyboardTheme.java @@ -159,9 +159,7 @@ public final class KeyboardTheme implements Comparable { } public static KeyboardTheme getKeyboardTheme(final Context context) { - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - final KeyboardTheme[] availableThemeArray = getAvailableThemeArray(context); - return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT, availableThemeArray); + return KEYBOARD_THEMES[0]; } /* package private for testing */ diff --git a/java/src/org/futo/inputmethod/keyboard/MainKeyboardView.java b/java/src/org/futo/inputmethod/keyboard/MainKeyboardView.java index b407b9048..b02961ece 100644 --- a/java/src/org/futo/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/org/futo/inputmethod/keyboard/MainKeyboardView.java @@ -200,9 +200,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy PointerTracker.init(mainKeyboardViewAttr, mTimerHandler, this /* DrawingProxy */); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - final boolean forceNonDistinctMultitouch = prefs.getBoolean( - DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false); + final boolean forceNonDistinctMultitouch = false; final boolean hasDistinctMultitouch = context.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT) && !forceNonDistinctMultitouch; diff --git a/java/src/org/futo/inputmethod/latin/LatinIME.kt b/java/src/org/futo/inputmethod/latin/LatinIME.kt index 0d13ea7cd..7b1751731 100644 --- a/java/src/org/futo/inputmethod/latin/LatinIME.kt +++ b/java/src/org/futo/inputmethod/latin/LatinIME.kt @@ -1,5 +1,9 @@ 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.graphics.Color import android.inputmethodservice.InputMethodService @@ -19,7 +23,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.ColorScheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.key import androidx.compose.ui.Modifier @@ -50,6 +53,7 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import org.futo.inputmethod.latin.SuggestedWords.SuggestedWordInfo 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.DynamicThemeProvider 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.getSettingBlocking 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.theme.DarkColorScheme 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.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, LatinIMELegacy.SuggestionStripController, DynamicThemeProviderOwner { - private lateinit var mLifecycleRegistry: LifecycleRegistry private lateinit var mViewModelStore: ViewModelStore private lateinit var mSavedStateRegistryController: SavedStateRegistryController @@ -222,9 +235,14 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save jobs.clear() } + private var unlockReceiver = UnlockedBroadcastReceiver { onDeviceUnlocked() } + override fun onCreate() { super.onCreate() + val filter = IntentFilter(Intent.ACTION_USER_UNLOCKED) + registerReceiver(unlockReceiver, filter) + mLifecycleRegistry = LifecycleRegistry(this) mLifecycleRegistry.currentState = Lifecycle.State.INITIALIZED @@ -264,7 +282,10 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save latinIMELegacy.onCreate() languageModelFacilitator.launchProcessor() - languageModelFacilitator.loadHistoryLog() + + if(isDirectBootUnlocked) { + languageModelFacilitator.loadHistoryLog() + } scheduleUpdateCheckingJob(this) launchJob { uixManager.showUpdateNoticeIfNeeded() } @@ -322,6 +343,8 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save } override fun onDestroy() { + unregisterReceiver(unlockReceiver) + stopJobs() mLifecycleRegistry.currentState = Lifecycle.State.DESTROYED viewModelStore.clear() @@ -666,4 +689,22 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save get() = mSavedStateRegistryController.savedStateRegistry override val viewModelStore: ViewModelStore 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 + } } \ No newline at end of file diff --git a/java/src/org/futo/inputmethod/latin/LatinIMELegacy.java b/java/src/org/futo/inputmethod/latin/LatinIMELegacy.java index 5f30f0c3b..0de603e66 100644 --- a/java/src/org/futo/inputmethod/latin/LatinIMELegacy.java +++ b/java/src/org/futo/inputmethod/latin/LatinIMELegacy.java @@ -38,7 +38,6 @@ import android.os.Build; import android.os.Debug; import android.os.IBinder; import android.os.Message; -import android.preference.PreferenceManager; import android.text.InputType; import android.util.Log; import android.util.PrintWriterPrinter; @@ -573,7 +572,6 @@ public class LatinIMELegacy implements KeyboardActionListener, public void onCreate() { Settings.init(mInputMethodService); - DebugFlags.init(PreferenceManager.getDefaultSharedPreferences(mInputMethodService)); RichInputMethodManager.init(mInputMethodService); mRichImm = RichInputMethodManager.getInstance(); AudioAndHapticFeedbackManager.init(mInputMethodService); @@ -934,10 +932,6 @@ public class LatinIMELegacy implements KeyboardActionListener, final boolean inputTypeChanged = !currentSettingsValues.isSameInputType(editorInfo); final boolean isDifferentTextField = !restarting || inputTypeChanged; - StatsUtils.onStartInputView(editorInfo.inputType, - Settings.getInstance().getCurrent().mDisplayOrientation, - !isDifferentTextField); - // The EditorInfo might have a flag that affects fullscreen mode. // Note: This call should be done by InputMethodService? updateFullscreenMode(); diff --git a/java/src/org/futo/inputmethod/latin/RichInputMethodManager.java b/java/src/org/futo/inputmethod/latin/RichInputMethodManager.java index 513b2eb9a..4b8066210 100644 --- a/java/src/org/futo/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/org/futo/inputmethod/latin/RichInputMethodManager.java @@ -34,6 +34,7 @@ import org.futo.inputmethod.annotations.UsedForTesting; import org.futo.inputmethod.compat.InputMethodManagerCompatWrapper; import org.futo.inputmethod.compat.InputMethodSubtypeCompatUtils; 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.LanguageOnSpacebarUtils; import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils; @@ -108,7 +109,7 @@ public class RichInputMethodManager { } public InputMethodSubtype[] getAdditionalSubtypes() { - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); + final SharedPreferences prefs = PreferenceUtils.INSTANCE.getDefaultSharedPreferences(mContext); final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes( prefs, mContext.getResources()); return AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefAdditionalSubtypes); diff --git a/java/src/org/futo/inputmethod/latin/Subtypes.kt b/java/src/org/futo/inputmethod/latin/Subtypes.kt index bab67c1aa..bba072642 100644 --- a/java/src/org/futo/inputmethod/latin/Subtypes.kt +++ b/java/src/org/futo/inputmethod/latin/Subtypes.kt @@ -37,6 +37,7 @@ import okhttp3.internal.toImmutableList import org.futo.inputmethod.latin.common.Constants import org.futo.inputmethod.latin.uix.SettingsKey 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.settings.NavigationItem import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle @@ -93,6 +94,8 @@ object Subtypes { } fun addDefaultSubtypesIfNecessary(context: Context) { + if(!context.isDirectBootUnlocked) return + val currentSubtypes = context.getSettingBlocking(SubtypesSetting) if(currentSubtypes.isNotEmpty()) { removeExtensionsIfNecessary(context) @@ -116,7 +119,7 @@ object Subtypes { 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 { @@ -224,6 +227,30 @@ object Subtypes { } }.mapValues { it.value.toImmutableList() } } + + fun getDirectBootInitialLayouts(context: Context): Set { + 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 + } + } diff --git a/java/src/org/futo/inputmethod/latin/settings/Settings.java b/java/src/org/futo/inputmethod/latin/settings/Settings.java index 12486de31..f231bef7b 100644 --- a/java/src/org/futo/inputmethod/latin/settings/Settings.java +++ b/java/src/org/futo/inputmethod/latin/settings/Settings.java @@ -22,7 +22,6 @@ import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; -import android.preference.PreferenceManager; import android.util.Log; 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.R; 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.ResourceUtils; import org.futo.inputmethod.latin.utils.RunInLocale; @@ -145,7 +145,12 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang private void onCreate(final Context context) { mContext = context; mRes = context.getResources(); - mPrefs = PreferenceManager.getDefaultSharedPreferences(context); + + if(mPrefs != null) { + mPrefs.unregisterOnSharedPreferenceChangeListener(this); + } + + mPrefs = PreferenceUtils.INSTANCE.getDefaultSharedPreferences(context); mPrefs.registerOnSharedPreferenceChangeListener(this); upgradeAutocorrectionSettings(mPrefs, mRes); } diff --git a/java/src/org/futo/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/org/futo/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 7343fe275..82797b16d 100644 --- a/java/src/org/futo/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/org/futo/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -36,6 +36,7 @@ import org.futo.inputmethod.latin.RichInputMethodSubtype; import org.futo.inputmethod.latin.SuggestedWords; import org.futo.inputmethod.latin.common.ComposedData; 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.ScriptUtils; import org.futo.inputmethod.latin.utils.SuggestionResults; @@ -95,7 +96,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService super.onCreate(); mRecommendedThreshold = Float.parseFloat( getString(R.string.spellchecker_recommended_threshold_value)); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + final SharedPreferences prefs = PreferenceUtils.INSTANCE.getDefaultSharedPreferences(this); prefs.registerOnSharedPreferenceChangeListener(this); onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY); } diff --git a/java/src/org/futo/inputmethod/latin/uix/Settings.kt b/java/src/org/futo/inputmethod/latin/uix/Settings.kt index 85c1cff12..e928becd7 100644 --- a/java/src/org/futo/inputmethod/latin/uix/Settings.kt +++ b/java/src/org/futo/inputmethod/latin/uix/Settings.kt @@ -1,27 +1,147 @@ package org.futo.inputmethod.latin.uix import android.content.Context +import android.content.SharedPreferences +import android.os.UserManager +import android.preference.PreferenceManager import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.preferencesOf import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.core.stringSetPreferencesKey -import androidx.datastore.preferences.preferencesDataStore +import androidx.datastore.preferences.preferencesDataStoreFile import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.take import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking 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 -val Context.dataStore: DataStore by preferencesDataStore(name = "settings") +// Used before first unlock (direct boot) +private object DefaultDataStore : DataStore { + 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) { + val newPreferences = activePreferences.toMutablePreferences() + newPreferences[SubtypesSetting.key] = subtypes + + activePreferences = newPreferences + sharedData.emit(activePreferences) + } + + val sharedData = MutableSharedFlow(1) + + override val data: Flow + 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? = null + +// Initializes unlockedDataStore, or uses DefaultDataStore if device is still locked (direct boot) +@OptIn(DelicateCoroutinesApi::class) +val Context.dataStore: DataStore + 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 Context.getSetting(key: Preferences.Key, default: T): T { val valueFlow: Flow = diff --git a/java/src/org/futo/inputmethod/latin/uix/actions/ClipboardHistoryAction.kt b/java/src/org/futo/inputmethod/latin/uix/actions/ClipboardHistoryAction.kt index 8df8fe036..37337b40a 100644 --- a/java/src/org/futo/inputmethod/latin/uix/actions/ClipboardHistoryAction.kt +++ b/java/src/org/futo/inputmethod/latin/uix/actions/ClipboardHistoryAction.kt @@ -60,6 +60,7 @@ import org.futo.inputmethod.latin.uix.PersistentActionState import org.futo.inputmethod.latin.uix.PersistentStateInitialization import org.futo.inputmethod.latin.uix.SettingsKey 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.pages.ParagraphText import org.futo.inputmethod.latin.uix.settings.pages.PaymentSurface @@ -268,6 +269,8 @@ class ClipboardHistoryManager(val context: Context, val coroutineScope: Lifecycl } private fun saveClipboard() { + if(!context.isDirectBootUnlocked) return + coroutineScope.launch { withContext(Dispatchers.IO) { pruneOldItems() @@ -281,6 +284,8 @@ class ClipboardHistoryManager(val context: Context, val coroutineScope: Lifecycl } private suspend fun loadClipboard() { + if(!context.isDirectBootUnlocked) return + try { val file = File(context.filesDir, "clipboard.json") @@ -374,6 +379,7 @@ val ClipboardHistoryAction = Action( }, persistentStateInitialization = PersistentStateInitialization.OnKeyboardLoad, windowImpl = { manager, persistent -> + val unlocked = manager.getContext().isDirectBootUnlocked val clipboardHistoryManager = persistent as ClipboardHistoryManager manager.getLifecycleScope().launch { clipboardHistoryManager.pruneOldItems() } @@ -443,7 +449,13 @@ val ClipboardHistoryAction = Action( override fun WindowContents(keyboardShown: Boolean) { val view = LocalView.current 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 { 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.") diff --git a/java/src/org/futo/inputmethod/latin/uix/settings/Hooks.kt b/java/src/org/futo/inputmethod/latin/uix/settings/Hooks.kt index 498a8a5e6..88f0b1816 100644 --- a/java/src/org/futo/inputmethod/latin/uix/settings/Hooks.kt +++ b/java/src/org/futo/inputmethod/latin/uix/settings/Hooks.kt @@ -1,7 +1,6 @@ package org.futo.inputmethod.latin.uix.settings import android.content.SharedPreferences -import android.preference.PreferenceManager import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -20,6 +19,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext +import org.futo.inputmethod.latin.uix.PreferenceUtils import org.futo.inputmethod.latin.uix.SettingsKey import org.futo.inputmethod.latin.uix.dataStore import org.futo.inputmethod.latin.uix.getSetting @@ -94,7 +94,7 @@ fun useDataStore(key: SettingsKey, blocking: Boolean = false): DataStoreI fun useSharedPrefsGeneric(key: String, default: T, get: (SharedPreferences, String, T) -> T, put: (SharedPreferences, String, T) -> Unit): DataStoreItem { val coroutineScope = rememberCoroutineScope() val context = LocalContext.current - val sharedPrefs = remember { PreferenceManager.getDefaultSharedPreferences(context) } + val sharedPrefs = remember { PreferenceUtils.getDefaultSharedPreferences(context) } val value = remember { mutableStateOf(get(sharedPrefs, key, default)) } @@ -158,7 +158,7 @@ fun useSharedPrefsInt(key: String, default: Int): DataStoreItem { @Composable private fun SyncDataStoreToPreferences(key: SettingsKey, update: (newValue: T, editor: SharedPreferences.Editor) -> Unit) { val context = LocalContext.current - val sharedPrefs = remember { PreferenceManager.getDefaultSharedPreferences(context) } + val sharedPrefs = remember { PreferenceUtils.getDefaultSharedPreferences(context) } val value = useDataStoreValueBlocking(key) LaunchedEffect(value) { diff --git a/java/src/org/futo/inputmethod/latin/uix/settings/pages/Typing.kt b/java/src/org/futo/inputmethod/latin/uix/settings/pages/Typing.kt index 32e7d2871..9db7f96af 100644 --- a/java/src/org/futo/inputmethod/latin/uix/settings/pages/Typing.kt +++ b/java/src/org/futo/inputmethod/latin/uix/settings/pages/Typing.kt @@ -1,7 +1,6 @@ package org.futo.inputmethod.latin.uix.settings.pages import android.content.Context -import android.preference.PreferenceManager import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.gestures.detectDragGestures 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.KeyboardBottomOffsetSetting 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.SettingsKey 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) LaunchedEffect(vibration) { - val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context) + val sharedPrefs = PreferenceUtils.getDefaultSharedPreferences(context) withContext(Dispatchers.Main) { sharedPrefs.edit { putInt(PREF_VIBRATION_DURATION_SETTINGS, vibration) diff --git a/java/src/org/futo/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/org/futo/inputmethod/latin/utils/ImportantNoticeUtils.java index 19a107b77..88def87fb 100644 --- a/java/src/org/futo/inputmethod/latin/utils/ImportantNoticeUtils.java +++ b/java/src/org/futo/inputmethod/latin/utils/ImportantNoticeUtils.java @@ -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, final SettingsValues settingsValues) { // Check to see whether "Use Contacts" is enabled by the user. + /* if (!settingsValues.mUseContactsDict) { return false; } @@ -107,8 +97,8 @@ public final class ImportantNoticeUtils { if (hasContactsNoticeTimeoutPassed(context, System.currentTimeMillis())) { updateContactsNoticeShown(context); return false; - } - return true; + }*/ + return false; } public static String getSuggestContactsNoticeTitle(final Context context) { @@ -118,23 +108,11 @@ public final class ImportantNoticeUtils { @UsedForTesting static boolean hasContactsNoticeTimeoutPassed( final Context context, final long currentTimeInMillis) { - final SharedPreferences prefs = getImportantNoticePreferences(context); - if (!prefs.contains(KEY_TIMESTAMP_OF_CONTACTS_NOTICE)) { - 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; + + return false; } public static void updateContactsNoticeShown(final Context context) { - getImportantNoticePreferences(context) - .edit() - .putBoolean(KEY_SUGGEST_CONTACTS_NOTICE, true) - .remove(KEY_TIMESTAMP_OF_CONTACTS_NOTICE) - .apply(); + } } diff --git a/java/src/org/futo/inputmethod/latin/xlm/TrainingDataLog.kt b/java/src/org/futo/inputmethod/latin/xlm/TrainingDataLog.kt index 55980eede..42996283e 100644 --- a/java/src/org/futo/inputmethod/latin/xlm/TrainingDataLog.kt +++ b/java/src/org/futo/inputmethod/latin/xlm/TrainingDataLog.kt @@ -4,6 +4,7 @@ import android.content.Context import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import org.futo.inputmethod.latin.uix.isDirectBootUnlocked import java.io.File @Serializable @@ -23,6 +24,8 @@ data class HistoryLogForTraining( ) fun saveHistoryLogBackup(context: Context, log: List) { + if(!context.isDirectBootUnlocked) return + val json = Json.encodeToString(log) val file = File(context.cacheDir, "historyLog.json") @@ -30,6 +33,8 @@ fun saveHistoryLogBackup(context: Context, log: List) { } fun loadHistoryLogBackup(context: Context, to: MutableList) { + if(!context.isDirectBootUnlocked) return + try { val file = File(context.cacheDir, "historyLog.json") if(file.exists()) { diff --git a/java/src/org/futo/inputmethod/latin/xlm/TrainingWorker.kt b/java/src/org/futo/inputmethod/latin/xlm/TrainingWorker.kt index 577b15023..bcec2e568 100644 --- a/java/src/org/futo/inputmethod/latin/xlm/TrainingWorker.kt +++ b/java/src/org/futo/inputmethod/latin/xlm/TrainingWorker.kt @@ -25,6 +25,7 @@ import kotlinx.coroutines.withContext import org.futo.inputmethod.latin.R import org.futo.inputmethod.latin.uix.USE_TRANSFORMER_FINETUNING import org.futo.inputmethod.latin.uix.getSetting +import org.futo.inputmethod.latin.uix.isDirectBootUnlocked import java.io.File 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" public fun scheduleTrainingWorkerBackground(context: Context) { + if(!context.isDirectBootUnlocked) return val workManager = WorkManager.getInstance(context) workManager.cancelAllWorkByTag(WORKER_TAG) diff --git a/java/stable/java/org/futo/inputmethod/latin/CrashLoggingApplication.kt b/java/stable/java/org/futo/inputmethod/latin/CrashLoggingApplication.kt index 275a77ae6..9bbeabb33 100644 --- a/java/stable/java/org/futo/inputmethod/latin/CrashLoggingApplication.kt +++ b/java/stable/java/org/futo/inputmethod/latin/CrashLoggingApplication.kt @@ -2,6 +2,7 @@ package org.futo.inputmethod.latin import android.app.Application import android.content.Context +import android.os.UserManager import androidx.datastore.preferences.core.Preferences import org.acra.ACRA import org.acra.config.dialog @@ -12,35 +13,40 @@ import org.acra.data.StringFormat import org.acra.ktx.initAcra class CrashLoggingApplication : Application() { + + override fun attachBaseContext(base: Context?) { super.attachBaseContext(base) - initAcra { - reportFormat = StringFormat.JSON + val userManager = getSystemService(Context.USER_SERVICE) as UserManager + if(userManager.isUserUnlocked) { + println("Initializing ACRA, as user is unlocked") + initAcra { + reportFormat = StringFormat.JSON - dialog { - text = getString( - //if(BuildConfig.ENABLE_ACRA) { - // R.string.crashed_text - //} else { + dialog { + text = getString( + //if(BuildConfig.ENABLE_ACRA) { + // R.string.crashed_text + //} else { R.string.crashed_text_email - //} - ) - title = getString(R.string.crashed_title) - positiveButtonText = getString(R.string.crash_report_accept) - negativeButtonText = getString(R.string.crash_report_reject) - resTheme = android.R.style.Theme_DeviceDefault_Dialog - } + //} + ) + title = getString(R.string.crashed_title) + positiveButtonText = getString(R.string.crash_report_accept) + negativeButtonText = getString(R.string.crash_report_reject) + resTheme = android.R.style.Theme_DeviceDefault_Dialog + } - //if(BuildConfig.ENABLE_ACRA) { - // httpSender { - // uri = BuildConfig.ACRA_URL - // basicAuthLogin = BuildConfig.ACRA_USER - // basicAuthPassword = BuildConfig.ACRA_PASSWORD - // httpMethod = HttpSender.Method.POST - // } - //} else { + //if(BuildConfig.ENABLE_ACRA) { + // httpSender { + // uri = BuildConfig.ACRA_URL + // basicAuthLogin = BuildConfig.ACRA_USER + // basicAuthPassword = BuildConfig.ACRA_PASSWORD + // httpMethod = HttpSender.Method.POST + // } + //} else { mailSender { mailTo = "keyboard@futo.org" reportAsFile = true @@ -49,14 +55,23 @@ class CrashLoggingApplication : Application() { body = "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 { + var acraInitialized = false + fun logPreferences(preferences: Preferences) { - preferences.asMap().forEach { - ACRA.errorReporter.putCustomData(it.key.name, it.value.toString()) + if(acraInitialized) { + preferences.asMap().forEach { + ACRA.errorReporter.putCustomData(it.key.name, it.value.toString()) + } } } }