This commit is contained in:
Philipp Crocoll
2021-11-11 12:12:24 +01:00
parent adb0865aa7
commit 81c4477453
22 changed files with 273 additions and 124 deletions

View File

@@ -66,16 +66,16 @@ namespace keepass2android
public override string GetTitle(string key)
{
if (key == strVisible)
return Application.Context.GetString(Resource.String.Visible_title);
return LocaleManager.LocalizedAppContext.GetString(Resource.String.Visible_title);
if (key == strEnabled)
return Application.Context.GetString(Resource.String.child_db_Enabled_title);
return LocaleManager.LocalizedAppContext.GetString(Resource.String.child_db_Enabled_title);
if (key == strUiKeyFile)
return Application.Context.GetString(Resource.String.keyfile_heading);
return LocaleManager.LocalizedAppContext.GetString(Resource.String.keyfile_heading);
if (key == strUiDatabaseFile)
return Application.Context.GetString(Resource.String.database_file_heading);
return LocaleManager.LocalizedAppContext.GetString(Resource.String.database_file_heading);
if (key.StartsWith(strUiIfDevice))
{
return Application.Context.GetString(Resource.String.if_device_text,new Object[]{key.Substring(strUiIfDevice.Length)});
return LocaleManager.LocalizedAppContext.GetString(Resource.String.if_device_text,new Object[]{key.Substring(strUiIfDevice.Length)});
}
return key;
}

View File

@@ -459,7 +459,7 @@ namespace keepass2android
_activity.StartActivityForResult(i, _requestCode);
#else
Toast.MakeText(Application.Context, "File chooser is excluded!", ToastLength.Long).Show();
Toast.MakeText(LocaleManager.LocalizedAppContext, "File chooser is excluded!", ToastLength.Long).Show();
#endif
return true;
}

View File

@@ -1250,7 +1250,7 @@ namespace keepass2android
{
Handler.Post(() =>
{
Toast.MakeText(ActiveActivity ?? Application.Context, "Unrecoverable error: " + Message, ToastLength.Long).Show();
Toast.MakeText(ActiveActivity ?? LocaleManager.LocalizedAppContext, "Unrecoverable error: " + Message, ToastLength.Long).Show();
});
App.Kp2a.Lock(false);

View File

@@ -61,7 +61,7 @@ namespace keepass2android
{
if (_thisDevice != null)
return _thisDevice;
String android_id = Settings.Secure.GetString(Application.Context.ContentResolver, Settings.Secure.AndroidId);
String android_id = Settings.Secure.GetString(LocaleManager.LocalizedAppContext.ContentResolver, Settings.Secure.AndroidId);
string deviceName = Build.Manufacturer+" "+Build.Model;
_thisDevice = deviceName + " (" + android_id + ")";
@@ -315,7 +315,7 @@ namespace keepass2android
try { ck.AddUserKey(new KcpKeyFile(strAbs)); }
catch (InvalidOperationException)
{
Toast.MakeText(Application.Context,Resource.String.error_adding_keyfile,ToastLength.Long).Show();
Toast.MakeText(LocaleManager.LocalizedAppContext,Resource.String.error_adding_keyfile,ToastLength.Long).Show();
return false;
}
catch (Exception) { throw; }

View File

@@ -28,6 +28,10 @@ namespace keepass2android
public abstract class LifecycleAwareActivity : AndroidX.AppCompat.App.AppCompatActivity
{
protected override void AttachBaseContext(Context baseContext)
{
base.AttachBaseContext(LocaleManager.setLocale(baseContext));
}
protected LifecycleAwareActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
@@ -86,7 +90,9 @@ namespace keepass2android
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Kp2aLog.Log(ClassName+".OnCreate" + " " + ID);
Kp2aLog.Log(ClassName+":apptask="+Intent.GetStringExtra("KP2A_APP_TASK_TYPE") + " " + ID);
}

View File

@@ -37,7 +37,7 @@ namespace keepass2android
};
FindViewById<Button>(Resource.Id.disable_secure_screen_check).Click += (sender, args) =>
{
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
prefs.Edit()
.PutBoolean("no_secure_display_check", true)
.Commit();

View File

@@ -67,6 +67,7 @@
<string name="omitbackup_key">omitbackup</string>
<string name="list_size_key">list_size</string>
<string name="design_key">design_key</string>
<string name="app_language_pref_key">app_language_pref_key</string>
<string name="sort_key_old">sort_key</string>
<string name="sort_key">sort_key_new</string>
<string name="sortgroups_key">sortgroups_key</string>

View File

@@ -81,6 +81,7 @@
<string name="copy_password">Select to copy password to clipboard</string>
<string name="copy_totp">Select to copy TOTP to clipboard</string>
<string name="available_through_keyboard">Entry is available through KP2A Keyboard</string>
<string name="app_language_pref_title">App language</string>
<string name="entry_is_available">is available</string>
<string name="not_possible_im_picker">Could not open dialog to select input method. Please activate keyboard manually.</string>
<string name="please_activate_keyboard">Please enable the Keepass2Android keyboard in your system settings.</string>
@@ -92,6 +93,7 @@
<string name="disclaimer_formal">Keepass2Android comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under the conditions of the GPL version 2 or later.</string>
<string name="ellipsis">\u2026</string>
<string name="copy_to_clipboard">Copy to clipboard</string>
<string name="SystemLanguage">System language</string>
<string name="fingerprint_description">Please authenticate to continue</string>
<string name="fingerprint_fatal">Cannot setup Biometric Unlock:</string>
<string name="fingerprint_not_recognized">Biometric authentication failed. Try again</string>
@@ -824,6 +826,7 @@
<string-array name="ChangeLog_1_09b">
<item>Fix disappearing autofill prompt in Firefox</item>
<item>Integrate autofill suggestions with keyboard (requires Android 11+)</item>
<item>Allow to change app language in settings</item>
</string-array>

View File

@@ -280,6 +280,12 @@
android:dialogTitle="@string/design_title"
android:defaultValue="@string/design_default"/>
<ListPreference
android:key="@string/app_language_pref_key"
android:title="@string/app_language_pref_title"
android:dialogTitle="@string/app_language_pref_title"
/>
<CheckBoxPreference
android:enabled="true"

View File

@@ -26,7 +26,7 @@ namespace keepass2android
return null;
foreach (ITotpPluginAdapter adapter in _pluginAdapters)
{
TotpData totpData = adapter.GetTotpData(entry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()), Application.Context, false);
TotpData totpData = adapter.GetTotpData(entry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()), LocaleManager.LocalizedAppContext, false);
if (totpData.IsTotpEntry)
{
return totpData;
@@ -47,7 +47,7 @@ namespace keepass2android
{
TotpData totpData = adapter.GetTotpData(
App.Kp2a.LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key),
pair => pair.Value.ReadString()), Application.Context, false);
pair => pair.Value.ReadString()), LocaleManager.LocalizedAppContext, false);
if (totpData.IsTotpEntry)
{
return adapter;
@@ -67,7 +67,7 @@ namespace keepass2android
{
var adapter = TryGetAdapter(App.Kp2a.LastOpenedEntry);
if (adapter != null)
new UpdateTotpTimerTask(Application.Context, adapter).Run();
new UpdateTotpTimerTask(LocaleManager.LocalizedAppContext, adapter).Run();
}
}
}

View File

@@ -41,12 +41,79 @@ using KeePassLib.Security;
using KeePassLib.Serialization;
using Uri = Android.Net.Uri;
namespace keepass2android
{
public class LocaleManager
{
public static Context LocalizedAppContext
{
get
{
//the standard way of setting locale on the app context is through Application.AttachBaseContext,
//but because of https://bugzilla.xamarin.com/11/11182/bug.html this doesn't work
return setLocale(Application.Context);
}
}
public static Context setLocale(Context c)
{
return setNewLocale(c, getLanguage(c));
}
public static Context setNewLocale(Context c, String language)
{
return updateResources(c, language);
}
static string _language;
public static string Language
{
get { return _language; }
set { _language = value;languageLoaded = true;
}
}
static bool languageLoaded = false;
public static String getLanguage(Context c)
{
if (!languageLoaded)
{
var language = PreferenceManager.GetDefaultSharedPreferences(c).GetString(c.GetString(Resource.String.app_language_pref_key), null);
Language = language;
}
return Language;
}
private static Context updateResources(Context context, String language)
{
if (language == null)
return context;
Java.Util.Locale locale = new Java.Util.Locale(language);
Java.Util.Locale.Default = locale;
Resources res = context.Resources;
Configuration config = new Configuration(res.Configuration);
if ((int)Build.VERSION.SdkInt >= 17)
{
config.SetLocale(locale);
context = context.CreateConfigurationContext(config);
}
else
{
config.Locale = locale;
res.UpdateConfiguration(config, res.DisplayMetrics);
}
return context;
}
}
public class Util {
public const String KeyFilename = "fileName";
public const String KeyFilename = "fileName";
public const String KeyServerusername = "serverCredUser";
public const String KeyServerpassword = "serverCredPwd";
public const String KeyServercredmode = "serverCredRememberMode";
@@ -253,7 +320,7 @@ namespace keepass2android
* @return True if an Intent with the specified action can be sent and
* responded to, false otherwise.
*/
static bool IsIntentAvailable(Context context, String action, String type, List<String> categories )
static bool IsIntentAvailable(Context context, String action, String type, List<String> categories )
{
PackageManager packageManager = context.PackageManager;
Intent intent = new Intent(action);

View File

@@ -109,7 +109,10 @@ namespace keepass2android
/// </summary>
public class Kp2aApp: IKp2aApp, ICacheSupervisor
{
public void Lock(bool allowQuickUnlock = true, bool lockWasTriggeredByTimeout = false)
public void Lock(bool allowQuickUnlock = true, bool lockWasTriggeredByTimeout = false)
{
if (OpenDatabases.Any())
{
@@ -122,7 +125,7 @@ namespace keepass2android
Kp2aLog.Log("QuickLocking database");
QuickLocked = true;
LastOpenedEntry = null;
BroadcastDatabaseAction(Application.Context, Strings.ActionLockDatabase);
BroadcastDatabaseAction(LocaleManager.LocalizedAppContext, Strings.ActionLockDatabase);
}
else
{
@@ -133,7 +136,7 @@ namespace keepass2android
{
Kp2aLog.Log("Locking database");
BroadcastDatabaseAction(Application.Context, Strings.ActionCloseDatabase);
BroadcastDatabaseAction(LocaleManager.LocalizedAppContext, Strings.ActionCloseDatabase);
// Couldn't quick-lock, so unload database(s) instead
_openAttempts.Clear();
@@ -153,7 +156,7 @@ namespace keepass2android
var intent = new Intent(Intents.DatabaseLocked);
if (lockWasTriggeredByTimeout)
intent.PutExtra("ByTimeout", true);
Application.Context.SendBroadcast(intent);
LocaleManager.LocalizedAppContext.SendBroadcast(intent);
}
@@ -178,8 +181,8 @@ namespace keepass2android
public Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compositeKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat, bool makeCurrent)
{
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
var createBackup = prefs.GetBoolean(Application.Context.GetString(Resource.String.CreateBackups_key), true)
var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
var createBackup = prefs.GetBoolean(LocaleManager.LocalizedAppContext.GetString(Resource.String.CreateBackups_key), true)
&& !(new LocalFileStorage(this).IsLocalBackup(ioConnectionInfo));
MemoryStream backupCopy = new MemoryStream();
@@ -216,8 +219,8 @@ namespace keepass2android
if (createBackup)
{
statusLogger.UpdateMessage(Application.Context.GetString(Resource.String.UpdatingBackup));
Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(Application.Context);
statusLogger.UpdateMessage(LocaleManager.LocalizedAppContext.GetString(Resource.String.UpdatingBackup));
Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(LocaleManager.LocalizedAppContext);
string baseDisplayName = App.Kp2a.GetFileStorage(ioConnectionInfo).GetDisplayName(ioConnectionInfo);
string targetPath = baseDisplayName;
var charsToRemove = "|\\?*<\":>+[]/'";
@@ -242,7 +245,7 @@ namespace keepass2android
Java.Lang.Object baseIocDisplayName = baseDisplayName;
string keyfile = App.Kp2a.FileDbHelper.GetKeyFileForFile(ioConnectionInfo.Path);
App.Kp2a.StoreOpenedFileAsRecent(targetIoc, keyfile, false, Application.Context.
App.Kp2a.StoreOpenedFileAsRecent(targetIoc, keyfile, false, LocaleManager.LocalizedAppContext.
GetString(Resource.String.LocalBackupOf, new Java.Lang.Object[]{baseIocDisplayName}));
prefs.Edit()
@@ -298,13 +301,13 @@ namespace keepass2android
UpdateOngoingNotification();
BroadcastDatabaseAction(Application.Context, Strings.ActionUnlockDatabase);
BroadcastDatabaseAction(LocaleManager.LocalizedAppContext, Strings.ActionUnlockDatabase);
}
public void UpdateOngoingNotification()
{
// Start or update the notification icon service to reflect the current state
var ctx = Application.Context;
var ctx = LocaleManager.LocalizedAppContext;
if (DatabaseIsUnlocked || QuickLocked)
{
ContextCompat.StartForegroundService(ctx, new Intent(ctx, typeof(OngoingNotificationsService)));
@@ -333,7 +336,7 @@ namespace keepass2android
//Set KeyLength of QuickUnlock at time of enabling.
//This is important to not allow an attacker to set the length to 1 when QuickUnlock is started already.
var ctx = Application.Context;
var ctx = LocaleManager.LocalizedAppContext;
var prefs = PreferenceManager.GetDefaultSharedPreferences(ctx);
QuickUnlockKeyLength = Math.Max(1, int.Parse(prefs.GetString(ctx.GetString(Resource.String.QuickUnlockLength_key), ctx.GetString(Resource.String.QuickUnlockLength_default))));
}
@@ -429,7 +432,7 @@ namespace keepass2android
public bool GetBooleanPreference(PreferenceKey key)
{
Context ctx = Application.Context;
Context ctx = LocaleManager.LocalizedAppContext;
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(ctx);
switch (key)
{
@@ -504,7 +507,7 @@ namespace keepass2android
var field = typeof(Resource.String).GetField(key);
if (field == null)
throw new Exception("Invalid key " + key);
return Application.Context.GetString((int)field.GetValue(null));
return LocaleManager.LocalizedAppContext.GetString((int)field.GetValue(null));
}
public Drawable GetStorageIcon(string protocolId)
@@ -523,7 +526,7 @@ namespace keepass2android
var field = typeof(Resource.Drawable).GetField(key);
if (field == null)
throw new Exception("Invalid key " + key);
return Application.Context.Resources.GetDrawable((int)field.GetValue(null));
return LocaleManager.LocalizedAppContext.Resources.GetDrawable((int)field.GetValue(null));
}
public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey, EventHandler<DialogClickEventArgs> yesHandler, EventHandler<DialogClickEventArgs> noHandler, EventHandler<DialogClickEventArgs> cancelHandler, Context ctx, string messageSuffix)
@@ -667,7 +670,7 @@ namespace keepass2android
if (DatabaseCacheEnabled && allowCache)
{
fileStorage = new CachingFileStorage(innerFileStorage, Application.Context, this);
fileStorage = new CachingFileStorage(innerFileStorage, LocaleManager.LocalizedAppContext, this);
}
else
{
@@ -705,20 +708,20 @@ namespace keepass2android
_fileStorages = new List<IFileStorage>
{
new AndroidContentStorage(Application.Context),
new AndroidContentStorage(LocaleManager.LocalizedAppContext),
#if !EXCLUDE_JAVAFILESTORAGE
#if !NoNet
new DropboxFileStorage(Application.Context, this),
new DropboxAppFolderFileStorage(Application.Context, this),
GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Application.Context)==ConnectionResult.Success ? new GoogleDriveFileStorage(Application.Context, this) : null,
new OneDriveFileStorage(Application.Context, this),
new DropboxFileStorage(LocaleManager.LocalizedAppContext, this),
new DropboxAppFolderFileStorage(LocaleManager.LocalizedAppContext, this),
GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(LocaleManager.LocalizedAppContext)==ConnectionResult.Success ? new GoogleDriveFileStorage(LocaleManager.LocalizedAppContext, this) : null,
new OneDriveFileStorage(LocaleManager.LocalizedAppContext, this),
new OneDrive2FullFileStorage(),
new OneDrive2MyFilesFileStorage(),
new OneDrive2AppFolderFileStorage(),
new SftpFileStorage(Application.Context, this),
new NetFtpFileStorage(Application.Context, this),
new SftpFileStorage(LocaleManager.LocalizedAppContext, this),
new NetFtpFileStorage(LocaleManager.LocalizedAppContext, this),
new WebDavFileStorage(this),
new PCloudFileStorage(Application.Context, this),
new PCloudFileStorage(LocaleManager.LocalizedAppContext, this),
//new LegacyWebDavStorage(this),
//new LegacyFtpStorage(this),
#endif
@@ -783,12 +786,12 @@ namespace keepass2android
private ValidationMode GetValidationMode()
{
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
ValidationMode validationMode = ValidationMode.Warn;
string strValMode = prefs.GetString(Application.Context.Resources.GetString(Resource.String.AcceptAllServerCertificates_key),
Application.Context.Resources.GetString(Resource.String.AcceptAllServerCertificates_default));
string strValMode = prefs.GetString(LocaleManager.LocalizedAppContext.Resources.GetString(Resource.String.AcceptAllServerCertificates_key),
LocaleManager.LocalizedAppContext.Resources.GetString(Resource.String.AcceptAllServerCertificates_default));
if (strValMode == "IGNORE")
validationMode = ValidationMode.Ignore;
@@ -801,8 +804,8 @@ namespace keepass2android
{
get
{
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
return prefs.GetBoolean(Application.Context.GetString(Resource.String.CheckForDuplicateUuids_key), true);
var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
return prefs.GetBoolean(LocaleManager.LocalizedAppContext.GetString(Resource.String.CheckForDuplicateUuids_key), true);
}
}
@@ -849,7 +852,7 @@ namespace keepass2android
#endif
private void ShowValidationWarning(string error)
{
ShowToast(Application.Context.GetString(Resource.String.CertificateWarning, error));
ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.CertificateWarning, error));
}
@@ -901,7 +904,7 @@ namespace keepass2android
internal void ShowToast(string message)
{
var handler = new Handler(Looper.MainLooper);
handler.Post(() => { var toast = Toast.MakeText(Application.Context, message, ToastLength.Long);
handler.Post(() => { var toast = Toast.MakeText(LocaleManager.LocalizedAppContext, message, ToastLength.Long);
toast.SetGravity(GravityFlags.Center, 0, 0);
toast.Show();
});
@@ -910,7 +913,7 @@ namespace keepass2android
public void CouldntSaveToRemote(IOConnectionInfo ioc, Exception e)
{
var errorMessage = GetErrorMessageForFileStorageException(e);
ShowToast(Application.Context.GetString(Resource.String.CouldNotSaveToRemote, errorMessage));
ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.CouldNotSaveToRemote, errorMessage));
}
private string GetErrorMessageForFileStorageException(Exception e)
@@ -928,33 +931,33 @@ namespace keepass2android
public void CouldntOpenFromRemote(IOConnectionInfo ioc, Exception ex)
{
var errorMessage = GetErrorMessageForFileStorageException(ex);
ShowToast(Application.Context.GetString(Resource.String.CouldNotLoadFromRemote, errorMessage));
ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.CouldNotLoadFromRemote, errorMessage));
}
public void UpdatedCachedFileOnLoad(IOConnectionInfo ioc)
{
ShowToast(Application.Context.GetString(Resource.String.UpdatedCachedFileOnLoad,
new Java.Lang.Object[] { Application.Context.GetString(Resource.String.database_file) }));
ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.UpdatedCachedFileOnLoad,
new Java.Lang.Object[] { LocaleManager.LocalizedAppContext.GetString(Resource.String.database_file) }));
}
public void UpdatedRemoteFileOnLoad(IOConnectionInfo ioc)
{
ShowToast(Application.Context.GetString(Resource.String.UpdatedRemoteFileOnLoad));
ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.UpdatedRemoteFileOnLoad));
}
public void NotifyOpenFromLocalDueToConflict(IOConnectionInfo ioc)
{
ShowToast(Application.Context.GetString(Resource.String.NotifyOpenFromLocalDueToConflict));
ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.NotifyOpenFromLocalDueToConflict));
}
public void LoadedFromRemoteInSync(IOConnectionInfo ioc)
{
ShowToast(Application.Context.GetString(Resource.String.LoadedFromRemoteInSync));
ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.LoadedFromRemoteInSync));
}
public void ClearOfflineCache()
{
new CachingFileStorage(new LocalFileStorage(this), Application.Context, this).ClearCache();
new CachingFileStorage(new LocalFileStorage(this), LocaleManager.LocalizedAppContext, this).ClearCache();
}
public IFileStorage GetFileStorage(string protocolId)
@@ -978,7 +981,7 @@ namespace keepass2android
if (DatabaseCacheEnabled)
{
return new OtpAuxCachingFileStorage(innerFileStorage, Application.Context, new OtpAuxCacheSupervisor(this));
return new OtpAuxCachingFileStorage(innerFileStorage, LocaleManager.LocalizedAppContext, new OtpAuxCacheSupervisor(this));
}
else
{
@@ -991,8 +994,8 @@ namespace keepass2android
{
get
{
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
bool cacheEnabled = prefs.GetBoolean(Application.Context.Resources.GetString(Resource.String.UseOfflineCache_key),
var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
bool cacheEnabled = prefs.GetBoolean(LocaleManager.LocalizedAppContext.Resources.GetString(Resource.String.UseOfflineCache_key),
#if NoNet
false
#else
@@ -1007,14 +1010,14 @@ namespace keepass2android
{
get
{
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
return prefs.GetBoolean(Application.Context.GetString(Resource.String.OfflineMode_key), false);
var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
return prefs.GetBoolean(LocaleManager.LocalizedAppContext.GetString(Resource.String.OfflineMode_key), false);
}
set
{
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
ISharedPreferencesEditor edit = prefs.Edit();
edit.PutBoolean(Application.Context.GetString(Resource.String.OfflineMode_key), value);
edit.PutBoolean(LocaleManager.LocalizedAppContext.GetString(Resource.String.OfflineMode_key), value);
edit.Commit();
}
@@ -1035,9 +1038,9 @@ namespace keepass2android
public void OnScreenOff()
{
if (PreferenceManager.GetDefaultSharedPreferences(Application.Context)
if (PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext)
.GetBoolean(
Application.Context.GetString(Resource.String.LockWhenScreenOff_key),
LocaleManager.LocalizedAppContext.GetString(Resource.String.LockWhenScreenOff_key),
false))
{
App.Kp2a.Lock();
@@ -1172,7 +1175,13 @@ namespace keepass2android
#endif
public class App : Application {
public const string NotificationChannelIdUnlocked = "channel_db_unlocked_5";
public override void OnConfigurationChanged(Android.Content.Res.Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
LocaleManager.setLocale(this);
}
public const string NotificationChannelIdUnlocked = "channel_db_unlocked_5";
public const string NotificationChannelIdQuicklocked = "channel_db_quicklocked_5";
public const string NotificationChannelIdEntry = "channel_db_entry_5";

View File

@@ -549,7 +549,7 @@ namespace keepass2android
{
Context ctx = activity;
if (ctx == null)
ctx = Application.Context;
ctx = LocaleManager.LocalizedAppContext;
if ((ShowUserNotifications == ShowUserNotificationsMode.Always)
|| ((ShowUserNotifications == ShowUserNotificationsMode.WhenTotp) && new Kp2aTotp().TryGetAdapter(new PwEntryOutput(activity.Entry, App.Kp2a.CurrentDb)) != null))

View File

@@ -26,8 +26,8 @@ namespace keepass2android
public void UpdatedCachedFileOnLoad(IOConnectionInfo ioc)
{
_app.ShowToast(Application.Context.GetString(Resource.String.UpdatedCachedFileOnLoad,
new Java.Lang.Object[] { Application.Context.GetString(Resource.String.otp_aux_file) }));
_app.ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.UpdatedCachedFileOnLoad,
new Java.Lang.Object[] { LocaleManager.LocalizedAppContext.GetString(Resource.String.otp_aux_file) }));
}
public void UpdatedRemoteFileOnLoad(IOConnectionInfo ioc)
@@ -48,12 +48,12 @@ namespace keepass2android
public void ResolvedCacheConflictByUsingRemote(IOConnectionInfo ioc)
{
_app.ShowToast(Application.Context.GetString(Resource.String.ResolvedCacheConflictByUsingRemoteOtpAux));
_app.ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.ResolvedCacheConflictByUsingRemoteOtpAux));
}
public void ResolvedCacheConflictByUsingLocal(IOConnectionInfo ioc)
{
_app.ShowToast(Application.Context.GetString(Resource.String.ResolvedCacheConflictByUsingLocalOtpAux));
_app.ShowToast(LocaleManager.LocalizedAppContext.GetString(Resource.String.ResolvedCacheConflictByUsingLocalOtpAux));
}
}
}

View File

@@ -75,8 +75,8 @@ private static Drawable _blank;
{
get
{
var context = Application.Context;
string packageName = PreferenceManager.GetDefaultSharedPreferences(Application.Context).GetString("IconSetKey", context.PackageName);
var context = LocaleManager.LocalizedAppContext;
string packageName = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext).GetString("IconSetKey", context.PackageName);
//assume that at the momemt only the built in icons are white
return packageName == context.PackageName;
}
@@ -99,7 +99,7 @@ private static Drawable _blank;
Drawable draw;
if (!_standardIconMap.TryGetValue(dictKey, out draw))
{
string packageName = PreferenceManager.GetDefaultSharedPreferences(Application.Context).GetString("IconSetKey", context.PackageName);
string packageName = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext).GetString("IconSetKey", context.PackageName);
Resources res;
try
@@ -111,7 +111,7 @@ private static Drawable _blank;
//can happen after uninstalling icons
packageName = context.PackageName;
res = context.PackageManager.GetResourcesForApplication(packageName);
PreferenceManager.GetDefaultSharedPreferences(Application.Context)
PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext)
.Edit()
.PutString("IconSetKey", packageName)
.Commit();

View File

@@ -137,7 +137,7 @@ namespace keepass2android.search
Database database = databases[databaseIndex];
var iconDrawable = database.DrawableFactory.GetIconDrawable(App.Context, database.KpDatabase, iconId, customIconUuid, false) as BitmapDrawable;
var iconDrawable = database.DrawableFactory.GetIconDrawable(LocaleManager.LocalizedAppContext, database.KpDatabase, iconId, customIconUuid, false) as BitmapDrawable;
if (iconDrawable?.Bitmap != null)
{
@@ -152,7 +152,7 @@ namespace keepass2android.search
copiedCanvas.DrawBitmap(original, 0f, 0f, null);
var bitmap = copy;
float maxSize = convertDpToPixel(60, App.Context);
float maxSize = convertDpToPixel(60, LocaleManager.LocalizedAppContext);
float scale = Math.Min(maxSize / bitmap.Width, maxSize / bitmap.Height);
var scaleWidth = (int)(bitmap.Width * scale);
var scaleHeight = (int)(bitmap.Height * scale);
@@ -366,7 +366,7 @@ namespace keepass2android.search
value = value.Replace("\r", "");
if (intlResourceId > 0)
{
return Application.Context.GetString(intlResourceId) + ": "+value;
return LocaleManager.LocalizedAppContext.GetString(intlResourceId) + ": "+value;
}
return context.Key + ": " + value;
}

View File

@@ -39,6 +39,11 @@ namespace keepass2android.services.AutofillBase
public abstract class AutofillServiceBase: AutofillService
{
protected override void AttachBaseContext(Context baseContext)
{
base.AttachBaseContext(LocaleManager.setLocale(baseContext));
}
//use a lock to avoid returning a response several times in buggy Firefox during one connection: this avoids flickering
//and disappearing of the autofill prompt.
//Instead of using a boolean lock, we use a "time-out lock" which is cleared after a few seconds

View File

@@ -49,6 +49,11 @@ namespace keepass2android
[Service]
public class CopyToClipboardService : Service
{
protected override void AttachBaseContext(Context baseContext)
{
base.AttachBaseContext(LocaleManager.setLocale(baseContext));
}
class PasswordAccessNotificationBuilder
{
private readonly Context _ctx;

View File

@@ -136,15 +136,15 @@ namespace keepass2android.services.Kp2aAutofill
{PwDefs.PasswordField, new List<string>{View.AutofillHintPassword}},
{PwDefs.UrlField, new List<string>{W3cHints.URL}},
{
Application.Context.GetString(Resource.String.TemplateField_CreditCard_CVV),
LocaleManager.LocalizedAppContext.GetString(Resource.String.TemplateField_CreditCard_CVV),
new List<string>{View.AutofillHintCreditCardSecurityCode}
},
{
Application.Context.GetString(Resource.String.TemplateField_CreditCard_Owner),
LocaleManager.LocalizedAppContext.GetString(Resource.String.TemplateField_CreditCard_Owner),
new List<string>{W3cHints.CC_NAME}
},
{Application.Context.GetString(Resource.String.TemplateField_Number), new List<string>{View.AutofillHintCreditCardNumber}},
{Application.Context.GetString(Resource.String.TemplateField_IdCard_Name), new List<string>{View.AutofillHintName}},
{LocaleManager.LocalizedAppContext.GetString(Resource.String.TemplateField_Number), new List<string>{View.AutofillHintCreditCardNumber}},
{LocaleManager.LocalizedAppContext.GetString(Resource.String.TemplateField_IdCard_Name), new List<string>{View.AutofillHintName}},
};
return result;
}

View File

@@ -39,6 +39,10 @@ namespace keepass2android
[Service]
public class OngoingNotificationsService : Service
{
protected override void AttachBaseContext(Context baseContext)
{
base.AttachBaseContext(LocaleManager.setLocale(baseContext));
}
private ScreenOffReceiver _screenOffReceiver;
#region Service

View File

@@ -39,6 +39,7 @@ using keepass2android.Utils;
using KeePassLib;
using KeePassLib.Cryptography.KeyDerivation;
using KeePassLib.Interfaces;
using System.Collections.Generic;
namespace keepass2android
{
@@ -170,10 +171,42 @@ namespace keepass2android
//use system notification channels to control notification visibility
unlockedNotificationPref.Parent.RemovePreference(unlockedNotificationPref);
}
FindPreference(GetString(Resource.String.DebugLog_key)).PreferenceChange += OnDebugLogChanged;
FindPreference(GetString(Resource.String.DebugLog_send_key)).PreferenceClick += OnSendDebug;
FindPreference(GetString(Resource.String.DebugLog_send_key)).PreferenceClick += OnSendDebug;
HashSet<string> supportedLocales = new HashSet<string>() { "en", "af", "ar", "az", "be", "bg", "ca", "cs", "da", "de", "el", "es", "eu", "fa", "fi", "fr", "gl", "he", "hr", "hu", "id", "in", "it", "iw", "ja", "ko", "ml", "nb", "nl", "nn", "no", "pl", "pt", "ro", "ru", "si", "sk", "sl", "sr", "sv", "tr", "uk", "vi", "zh" };
ListPreference appLanguagePref = (ListPreference)FindPreference(GetString(Resource.String.app_language_pref_key));
var localesByCode = new System.Collections.Generic.Dictionary<string, List<Java.Util.Locale>>();
foreach (var loc in Java.Util.Locale.GetAvailableLocales())
{
if (!supportedLocales.Contains(loc.Language))
continue;
if (!localesByCode.ContainsKey(loc.Language))
{
localesByCode[loc.Language] = new List<Java.Util.Locale>();
}
localesByCode[loc.Language].Add(loc);
}
var localesByCodeUnique = localesByCode.Select(l => new KeyValuePair<string, Java.Util.Locale>(l.Key, l.Value.First())).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
List<KeyValuePair<string, List<Java.Util.Locale>>> codesWithMultiple = localesByCode.Where(l => l.Value.Count > 1).ToList();
List<KeyValuePair<string, Java.Util.Locale>> localesByLanguageList = localesByCodeUnique
.OrderBy(kvp => kvp.Value.DisplayLanguage).ToList();
appLanguagePref.SetEntries(localesByLanguageList.Select(kvp => kvp.Value.DisplayLanguage).ToArray());
appLanguagePref.SetEntryValues(localesByLanguageList.Select(kvp => kvp.Value.Language).ToArray());
string languageCode = appLanguagePref.Value;
string summary = GetDisplayLanguage(localesByCodeUnique, languageCode);
((ListPreference)FindPreference(GetString(Resource.String.app_language_pref_key))).Summary = summary;
appLanguagePref.PreferenceChange += (sender, args) =>
{
((ListPreference)FindPreference(GetString(Resource.String.app_language_pref_key))).Summary = GetDisplayLanguage(localesByCodeUnique, (string)args.NewValue);
LocaleManager.Language = (string)args.NewValue;
};
UpdateAutofillPref();
@@ -184,7 +217,7 @@ namespace keepass2android
{
var intent = new Intent(Settings.ActionRequestSetAutofillService);
if (((AutofillManager) Activity.GetSystemService(Java.Lang.Class.FromType(typeof(AutofillManager))))
if (((AutofillManager)Activity.GetSystemService(Java.Lang.Class.FromType(typeof(AutofillManager))))
.HasEnabledAutofillServices)
{
intent.SetData(Android.Net.Uri.Parse("package:" + Context.PackageName + "notexisting")); //if we use our package name, the activity won't launch
@@ -218,45 +251,45 @@ namespace keepass2android
PrepareNoDonatePreference(Activity, FindPreference(GetString(Resource.String.NoDonateOption_key)));
PrepareNoDonationReminderPreference(Activity, ((PreferenceScreen)FindPreference(GetString(Resource.String.display_prefs_key))), FindPreference(GetString(Resource.String.NoDonationReminder_key)));
PrepareNoDonationReminderPreference(Activity, ((PreferenceScreen)FindPreference(GetString(Resource.String.display_prefs_key))), FindPreference(GetString(Resource.String.NoDonationReminder_key)));
FindPreference(GetString(Resource.String.design_key)).PreferenceChange += (sender, args) => Activity.Recreate();
FindPreference(GetString(Resource.String.design_key)).PreferenceChange += (sender, args) => Activity.Recreate();
Database db = App.Kp2a.CurrentDb;
if (db != null)
{
ListPreference kdfPref = (ListPreference) FindPreference(GetString(Resource.String.kdf_key));
kdfPref.SetEntries(KdfPool.Engines.Select(eng => eng.Name).ToArray());
string[] kdfValues = KdfPool.Engines.Select(eng => eng.Uuid.ToHexString()).ToArray();
kdfPref.SetEntryValues(kdfValues);
kdfPref.SetValueIndex(kdfValues.Select((v, i) => new {kdf = v, index = i}).First(el => el.kdf == db.KpDatabase.KdfParameters.KdfUuid.ToHexString()).index);
kdfPref.PreferenceChange += OnKdfChange;
aesRounds = FindPreference(GetString(Resource.String.rounds_key));
argon2rounds = FindPreference("argon2rounds");
argon2memory = FindPreference("argon2memory");
argon2parallelism = FindPreference("argon2parallelism");
ListPreference kdfPref = (ListPreference)FindPreference(GetString(Resource.String.kdf_key));
kdfPref.SetEntries(KdfPool.Engines.Select(eng => eng.Name).ToArray());
string[] kdfValues = KdfPool.Engines.Select(eng => eng.Uuid.ToHexString()).ToArray();
kdfPref.SetEntryValues(kdfValues);
kdfPref.SetValueIndex(kdfValues.Select((v, i) => new { kdf = v, index = i }).First(el => el.kdf == db.KpDatabase.KdfParameters.KdfUuid.ToHexString()).index);
kdfPref.PreferenceChange += OnKdfChange;
aesRounds.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
argon2rounds.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
argon2memory.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
argon2parallelism.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
aesRounds = FindPreference(GetString(Resource.String.rounds_key));
argon2rounds = FindPreference("argon2rounds");
argon2memory = FindPreference("argon2memory");
argon2parallelism = FindPreference("argon2parallelism");
aesRounds.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
argon2rounds.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
argon2memory.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
argon2parallelism.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
UpdateKdfScreen();
UpdateKdfScreen();
PrepareDefaultUsername(db);
PrepareDatabaseName(db);
PrepareMasterPassword();
PrepareTemplates(db);
PrepareTemplates(db);
ListPreference algorithmPref = (ListPreference)FindPreference(GetString(Resource.String.algorithm_key));
algorithmPref.SetEntries(CipherPool.GlobalPool.Engines.Select(eng => eng.DisplayName).ToArray());
string[] algoValues = CipherPool.GlobalPool.Engines.Select(eng => eng.CipherUuid.ToHexString()).ToArray();
algorithmPref.SetEntryValues(algoValues);
algorithmPref.SetValueIndex(algoValues.Select((v, i) => new { kdf = v, index = i }).First(el => el.kdf == db.KpDatabase.DataCipherUuid.ToHexString()).index);
algorithmPref.PreferenceChange += AlgorithmPrefChange;
algorithmPref.Summary =
CipherPool.GlobalPool.GetCipher(App.Kp2a.CurrentDb.KpDatabase.DataCipherUuid).DisplayName;
algorithmPref.SetEntries(CipherPool.GlobalPool.Engines.Select(eng => eng.DisplayName).ToArray());
string[] algoValues = CipherPool.GlobalPool.Engines.Select(eng => eng.CipherUuid.ToHexString()).ToArray();
algorithmPref.SetEntryValues(algoValues);
algorithmPref.SetValueIndex(algoValues.Select((v, i) => new { kdf = v, index = i }).First(el => el.kdf == db.KpDatabase.DataCipherUuid.ToHexString()).index);
algorithmPref.PreferenceChange += AlgorithmPrefChange;
algorithmPref.Summary =
CipherPool.GlobalPool.GetCipher(App.Kp2a.CurrentDb.KpDatabase.DataCipherUuid).DisplayName;
UpdateImportDbPref();
UpdateImportKeyfilePref();
}
@@ -292,26 +325,36 @@ namespace keepass2android
}
catch (Exception ex)
{
Kp2aLog.LogUnexpectedError(ex);
Kp2aLog.LogUnexpectedError(ex);
}
//AppSettingsActivity.PrepareKeyboardSwitchingPreferences(this);
_switchPrefManager = new KeyboardSwitchPrefManager(this);
PrepareSeparateNotificationsPreference();
FindPreference("IconSetKey").PreferenceChange += (sender, args) =>
{
if (App.Kp2a.CurrentDb!= null)
App.Kp2a.CurrentDb.DrawableFactory.Clear();
FindPreference("IconSetKey").PreferenceChange += (sender, args) =>
{
if (App.Kp2a.CurrentDb != null)
App.Kp2a.CurrentDb.DrawableFactory.Clear();
};
};
Preference cachingPreference = FindPreference(GetString(Resource.String.UseOfflineCache_key));
cachingPreference.PreferenceChange += OnUseOfflineCacheChanged;
}
private string GetDisplayLanguage(Dictionary<string, Java.Util.Locale> localesByCode, string languageCode)
{
return languageCode != null && localesByCode.ContainsKey(languageCode) ? localesByCode[languageCode]?.DisplayLanguage : GetString(Resource.String.SystemLanguage);
}
private void AppLanguagePref_PreferenceChange(object sender, Preference.PreferenceChangeEventArgs e)
{
throw new NotImplementedException();
}
private void UpdateAutofillPref()
@@ -625,7 +668,7 @@ namespace keepass2android
catch (Exception ex)
{
Kp2aLog.LogUnexpectedError(ex);
Toast.MakeText(Application.Context, ex.Message, ToastLength.Long).Show();
Toast.MakeText(LocaleManager.LocalizedAppContext, ex.Message, ToastLength.Long).Show();
}
}
);

View File

@@ -67,7 +67,7 @@ namespace keepass2android
AlarmManager am = (AlarmManager)ctx.GetSystemService(Context.AlarmService);
Kp2aLog.Log("Timeout start");
am.Set(AlarmType.Rtc, triggerTime, BuildPendingBroadcastIntent(App.Context));
am.Set(AlarmType.Rtc, triggerTime, BuildPendingBroadcastIntent(LocaleManager.LocalizedAppContext));
}
public static void ResumingApp(Context ctx)
@@ -77,7 +77,7 @@ namespace keepass2android
AlarmManager am = (AlarmManager)ctx.GetSystemService(Context.AlarmService);
//cancel alarm
Kp2aLog.Log("Timeout cancel");
am.Cancel(BuildPendingBroadcastIntent(App.Context));
am.Cancel(BuildPendingBroadcastIntent(LocaleManager.LocalizedAppContext));
App.Kp2a.TimeoutTime = DateTime.MaxValue;
}