mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-14 22:12:46 +00:00
fix crash when using credential protected preferences too early
This commit is contained in:
parent
d0dc242a28
commit
d983b469fe
6 changed files with 42 additions and 19 deletions
|
@ -135,9 +135,13 @@ private fun upgradesWhenComingFromOldAppName(context: Context) {
|
||||||
additionalSubtypes.add(it.replace(localeString, localeString.constructLocale().toLanguageTag()))
|
additionalSubtypes.add(it.replace(localeString, localeString.constructLocale().toLanguageTag()))
|
||||||
}
|
}
|
||||||
Settings.writePrefAdditionalSubtypes(prefs, additionalSubtypes.joinToString(";"))
|
Settings.writePrefAdditionalSubtypes(prefs, additionalSubtypes.joinToString(";"))
|
||||||
// move pinned clips to credential protected storage
|
// move pinned clips to credential protected storage if device is not locked (should never happen)
|
||||||
if (!prefs.contains(Settings.PREF_PINNED_CLIPS)) return
|
if (!prefs.contains(Settings.PREF_PINNED_CLIPS)) return
|
||||||
|
try {
|
||||||
val defaultPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
val defaultPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
defaultPrefs.edit { putString(Settings.PREF_PINNED_CLIPS, prefs.getString(Settings.PREF_PINNED_CLIPS, "")) }
|
defaultPrefs.edit { putString(Settings.PREF_PINNED_CLIPS, prefs.getString(Settings.PREF_PINNED_CLIPS, "")) }
|
||||||
prefs.edit { remove(Settings.PREF_PINNED_CLIPS) }
|
prefs.edit { remove(Settings.PREF_PINNED_CLIPS) }
|
||||||
|
} catch (_: IllegalStateException) {
|
||||||
|
// SharedPreferences in credential encrypted storage are not available until after user is unlocked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ class ClipboardHistoryManager(
|
||||||
|
|
||||||
// pinned clips are stored in default shared preferences, not in device protected preferences!
|
// pinned clips are stored in default shared preferences, not in device protected preferences!
|
||||||
private fun loadPinnedClips() {
|
private fun loadPinnedClips() {
|
||||||
val pinnedClipString = Settings.readPinnedClipString(PreferenceManager.getDefaultSharedPreferences(latinIME))
|
val pinnedClipString = Settings.readPinnedClipString(latinIME)
|
||||||
if (pinnedClipString.isEmpty()) return
|
if (pinnedClipString.isEmpty()) return
|
||||||
val pinnedClips: List<ClipboardHistoryEntry> = Json.decodeFromString(pinnedClipString)
|
val pinnedClips: List<ClipboardHistoryEntry> = Json.decodeFromString(pinnedClipString)
|
||||||
latinIME.mHandler.postUpdateClipboardPinnedClips(pinnedClips)
|
latinIME.mHandler.postUpdateClipboardPinnedClips(pinnedClips)
|
||||||
|
@ -141,7 +141,7 @@ class ClipboardHistoryManager(
|
||||||
|
|
||||||
private fun savePinnedClips() {
|
private fun savePinnedClips() {
|
||||||
val pinnedClips = Json.encodeToString(historyEntries.filter { it.isPinned })
|
val pinnedClips = Json.encodeToString(historyEntries.filter { it.isPinned })
|
||||||
Settings.writePinnedClipString(PreferenceManager.getDefaultSharedPreferences(latinIME), pinnedClips)
|
Settings.writePinnedClipString(latinIME, pinnedClips)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnHistoryChangeListener {
|
interface OnHistoryChangeListener {
|
||||||
|
|
|
@ -304,7 +304,7 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
||||||
if (backupFilePatterns.any { path.matches(it) })
|
if (backupFilePatterns.any { path.matches(it) })
|
||||||
files.add(file)
|
files.add(file)
|
||||||
}
|
}
|
||||||
val protectedFilesDir = DeviceProtectedUtils.getDeviceProtectedContext(requireContext()).filesDir
|
val protectedFilesDir = DeviceProtectedUtils.getFilesDir(requireContext())
|
||||||
val protectedFilesPath = protectedFilesDir.path + File.separator
|
val protectedFilesPath = protectedFilesDir.path + File.separator
|
||||||
val protectedFiles = mutableListOf<File>()
|
val protectedFiles = mutableListOf<File>()
|
||||||
protectedFilesDir.walk().forEach { file ->
|
protectedFilesDir.walk().forEach { file ->
|
||||||
|
@ -351,7 +351,7 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
||||||
ZipInputStream(inputStream).use { zip ->
|
ZipInputStream(inputStream).use { zip ->
|
||||||
var entry: ZipEntry? = zip.nextEntry
|
var entry: ZipEntry? = zip.nextEntry
|
||||||
val filesDir = requireContext().filesDir?.path ?: return
|
val filesDir = requireContext().filesDir?.path ?: return
|
||||||
val deviceProtectedFilesDir = DeviceProtectedUtils.getDeviceProtectedContext(requireContext()).filesDir?.path ?: return
|
val deviceProtectedFilesDir = DeviceProtectedUtils.getFilesDir(requireContext()).path
|
||||||
Settings.getInstance().stopListener()
|
Settings.getInstance().stopListener()
|
||||||
while (entry != null) {
|
while (entry != null) {
|
||||||
if (entry.name.startsWith("unprotected${File.separator}")) {
|
if (entry.name.startsWith("unprotected${File.separator}")) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.view.Gravity;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import helium314.keyboard.keyboard.KeyboardTheme;
|
import helium314.keyboard.keyboard.KeyboardTheme;
|
||||||
import helium314.keyboard.keyboard.internal.keyboard_parser.LocaleKeyTextsKt;
|
import helium314.keyboard.keyboard.internal.keyboard_parser.LocaleKeyTextsKt;
|
||||||
|
@ -477,12 +478,23 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
|
||||||
return prefs.getInt(PREF_LAST_SHOWN_EMOJI_CATEGORY_PAGE_ID, defValue);
|
return prefs.getInt(PREF_LAST_SHOWN_EMOJI_CATEGORY_PAGE_ID, defValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String readPinnedClipString(final SharedPreferences prefs) {
|
public static String readPinnedClipString(final Context context) {
|
||||||
|
try {
|
||||||
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
return prefs.getString(PREF_PINNED_CLIPS, "");
|
return prefs.getString(PREF_PINNED_CLIPS, "");
|
||||||
|
} catch (final IllegalStateException e) {
|
||||||
|
// SharedPreferences in credential encrypted storage are not available until after user is unlocked
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writePinnedClipString(final SharedPreferences prefs, final String clips) {
|
public static void writePinnedClipString(final Context context, final String clips) {
|
||||||
|
try {
|
||||||
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
prefs.edit().putString(PREF_PINNED_CLIPS, clips).apply();
|
prefs.edit().putString(PREF_PINNED_CLIPS, clips).apply();
|
||||||
|
} catch (final IllegalStateException e) {
|
||||||
|
// SharedPreferences in credential encrypted storage are not available until after user is unlocked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ArrayList<ToolbarKey> readPinnedKeys(final SharedPreferences prefs) {
|
public static ArrayList<ToolbarKey> readPinnedKeys(final SharedPreferences prefs) {
|
||||||
|
@ -539,7 +551,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getLayoutsDir(final Context context) {
|
public static File getLayoutsDir(final Context context) {
|
||||||
return new File(DeviceProtectedUtils.getDeviceProtectedContext(context).getFilesDir(), "layouts");
|
return new File(DeviceProtectedUtils.getFilesDir(context), "layouts");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable public static Drawable readUserBackgroundImage(final Context context, final boolean night) {
|
@Nullable public static Drawable readUserBackgroundImage(final Context context, final boolean night) {
|
||||||
|
@ -561,8 +573,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getCustomBackgroundFile(final Context context, final boolean night) {
|
public static File getCustomBackgroundFile(final Context context, final boolean night) {
|
||||||
return new File(DeviceProtectedUtils.getDeviceProtectedContext(context).getFilesDir(),
|
return new File(DeviceProtectedUtils.getFilesDir(context), "custom_background_image" + (night ? "_night" : ""));
|
||||||
"custom_background_image" + (night ? "_night" : ""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean readDayNightPref(final SharedPreferences prefs, final Resources res) {
|
public static boolean readDayNightPref(final SharedPreferences prefs, final Resources res) {
|
||||||
|
|
|
@ -12,6 +12,8 @@ import android.os.Build;
|
||||||
|
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
public final class DeviceProtectedUtils {
|
public final class DeviceProtectedUtils {
|
||||||
|
|
||||||
static final String TAG = DeviceProtectedUtils.class.getSimpleName();
|
static final String TAG = DeviceProtectedUtils.class.getSimpleName();
|
||||||
|
@ -33,11 +35,16 @@ public final class DeviceProtectedUtils {
|
||||||
return prefs;
|
return prefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Context getDeviceProtectedContext(final Context context) {
|
// keep this private to avoid accidental use of device protected context anywhere in the app
|
||||||
|
private static Context getDeviceProtectedContext(final Context context) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return context;
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return context;
|
||||||
return context.isDeviceProtectedStorage() ? context : context.createDeviceProtectedStorageContext();
|
return context.isDeviceProtectedStorage() ? context : context.createDeviceProtectedStorageContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static File getFilesDir(final Context context) {
|
||||||
|
return getDeviceProtectedContext(context).getFilesDir();
|
||||||
|
}
|
||||||
|
|
||||||
private DeviceProtectedUtils() {
|
private DeviceProtectedUtils() {
|
||||||
// This utility class is not publicly instantiable.
|
// This utility class is not publicly instantiable.
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,8 +63,7 @@ public final class JniUtils {
|
||||||
if (app != null) {
|
if (app != null) {
|
||||||
// we want the default preferences, because storing the checksum in device protected storage is discouraged
|
// we want the default preferences, because storing the checksum in device protected storage is discouraged
|
||||||
// see https://developer.android.com/reference/android/content/Context#createDeviceProtectedStorageContext()
|
// see https://developer.android.com/reference/android/content/Context#createDeviceProtectedStorageContext()
|
||||||
// todo: test what happens on an encrypted phone after reboot (don't have one...)
|
// if device is locked, this will throw an IllegalStateException
|
||||||
// does the app restart after unlocking, or is gesture typing unavailable?
|
|
||||||
wantedChecksum = PreferenceManager.getDefaultSharedPreferences(app).getString(Settings.PREF_LIBRARY_CHECKSUM, wantedChecksum);
|
wantedChecksum = PreferenceManager.getDefaultSharedPreferences(app).getString(Settings.PREF_LIBRARY_CHECKSUM, wantedChecksum);
|
||||||
}
|
}
|
||||||
final String checksum = ChecksumCalculator.INSTANCE.checksum(new FileInputStream(userSuppliedLibrary));
|
final String checksum = ChecksumCalculator.INSTANCE.checksum(new FileInputStream(userSuppliedLibrary));
|
||||||
|
@ -79,6 +78,8 @@ public final class JniUtils {
|
||||||
sHaveGestureLib = false;
|
sHaveGestureLib = false;
|
||||||
}
|
}
|
||||||
} catch (Throwable t) { // catch everything, maybe provided library simply doesn't work
|
} catch (Throwable t) { // catch everything, maybe provided library simply doesn't work
|
||||||
|
if (!(t instanceof IllegalStateException) || !"SharedPreferences in credential encrypted storage are not available until after user is unlocked".equals(t.getMessage()))
|
||||||
|
// but don't log if device is locked, here we expect the exception and only load system library, if possible
|
||||||
Log.w(TAG, "Could not load user-supplied library", t);
|
Log.w(TAG, "Could not load user-supplied library", t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue