Add toolbar to Settings (involves reorganization of Settings into Fragmnt which removes duplicate code in both activities)

This commit is contained in:
Philipp Crocoll 2015-08-13 17:37:01 +02:00
parent 15f73257fa
commit fabe0904c0
12 changed files with 710 additions and 603 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<fragment
android:name="keepass2android.SettingsFragment"
android:id="@+id/settings_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar" />
</RelativeLayout>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

View File

@ -18,11 +18,15 @@
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>. along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
--> -->
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android"
android:key="mainprefs">
<PreferenceScreen <PreferenceScreen
android:key="@string/db_key" android:key="@string/db_key"
android:title="@string/database" android:title="@string/database"
android:summary="@string/menu_db_settings"> android:summary="@string/menu_db_settings">
<keepass2android.ToolbarPreference
android:key="@string/db_key"
android:title="@string/database" />
<EditTextPreference <EditTextPreference
android:title="@string/database_name" android:title="@string/database_name"
android:persistent="false" android:persistent="false"
@ -72,11 +76,16 @@
android:key="@string/app_key" android:key="@string/app_key"
android:title="@string/application" android:title="@string/application"
android:summary="@string/application_settings"> android:summary="@string/application_settings">
<keepass2android.ToolbarPreference
android:key="@string/app_key"
android:title="@string/application" />
<PreferenceScreen <PreferenceScreen
android:key="@string/security_prefs_key" android:key="@string/security_prefs_key"
android:title="@string/security_prefs" android:title="@string/security_prefs"
> >
<keepass2android.ToolbarPreference
android:key="@string/security_prefs_key"
android:title="@string/security_prefs" />
<ListPreference <ListPreference
android:key="@string/clipboard_timeout_key" android:key="@string/clipboard_timeout_key"
@ -142,6 +151,9 @@
android:key="@string/display_prefs_key" android:key="@string/display_prefs_key"
android:title="@string/display_prefs" android:title="@string/display_prefs"
> >
<keepass2android.ToolbarPreference
android:key="@string/display_prefs_key"
android:title="@string/display_prefs" />
<CheckBoxPreference <CheckBoxPreference
android:enabled="true" android:enabled="true"
android:persistent="true" android:persistent="true"
@ -187,15 +199,6 @@
android:title="@string/ViewDatabaseSecure_title" android:title="@string/ViewDatabaseSecure_title"
android:key="@string/ViewDatabaseSecure_key" /> android:key="@string/ViewDatabaseSecure_key" />
<ListPreference
android:key="@string/design_key"
android:title="@string/design_title"
android:entries="@array/design_options"
android:entryValues="@array/design_values"
android:dialogTitle="@string/design_title"
android:defaultValue="@string/design_default"/>
<CheckBoxPreference <CheckBoxPreference
android:enabled="true" android:enabled="true"
android:persistent="true" android:persistent="true"
@ -209,6 +212,9 @@
android:key="@string/password_access_prefs_key" android:key="@string/password_access_prefs_key"
android:title="@string/password_access_prefs" android:title="@string/password_access_prefs"
> >
<keepass2android.ToolbarPreference
android:key="@string/password_access_prefs_key"
android:title="@string/password_access_prefs" />
<CheckBoxPreference <CheckBoxPreference
android:enabled="true" android:enabled="true"
android:persistent="true" android:persistent="true"
@ -236,8 +242,10 @@
android:key="@string/keyboardswitch_prefs_key" android:key="@string/keyboardswitch_prefs_key"
android:title="@string/keyboardswitch_prefs" android:title="@string/keyboardswitch_prefs"
android:dependency="@string/UseKp2aKeyboard_key" android:dependency="@string/UseKp2aKeyboard_key"
> >
<keepass2android.ToolbarPreference
android:key="@string/keyboardswitch_prefs_key"
android:title="@string/keyboardswitch_prefs"/>
<CheckBoxPreference <CheckBoxPreference
android:key="kp2a_switch_rooted" android:key="kp2a_switch_rooted"
android:title="@string/kp2a_switch_rooted" android:title="@string/kp2a_switch_rooted"
@ -289,6 +297,9 @@
android:key="@string/QuickUnlock_prefs_key" android:key="@string/QuickUnlock_prefs_key"
android:title="@string/QuickUnlock_prefs" android:title="@string/QuickUnlock_prefs"
> >
<keepass2android.ToolbarPreference
android:key="@string/QuickUnlock_prefs_key"
android:title="@string/QuickUnlock_prefs"/>
<CheckBoxPreference <CheckBoxPreference
android:enabled="true" android:enabled="true"
android:persistent="true" android:persistent="true"
@ -323,6 +334,9 @@
android:key="@string/FileHandling_prefs_key" android:key="@string/FileHandling_prefs_key"
android:title="@string/FileHandling_prefs" android:title="@string/FileHandling_prefs"
> >
<keepass2android.ToolbarPreference
android:key="@string/FileHandling_prefs_key"
android:title="@string/FileHandling_prefs"/>
<EditTextPreference <EditTextPreference
android:enabled="true" android:enabled="true"
@ -395,6 +409,9 @@
android:key="@string/TrayTotp_prefs_key" android:key="@string/TrayTotp_prefs_key"
android:title="@string/TrayTotp_prefs" android:title="@string/TrayTotp_prefs"
> >
<keepass2android.ToolbarPreference
android:key="@string/TrayTotp_prefs_key"
android:title="@string/TrayTotp_prefs"/>
<EditTextPreference <EditTextPreference
android:enabled="true" android:enabled="true"

View File

@ -432,37 +432,6 @@ namespace keepass2android
activity.Finish(); activity.Finish();
} }
public static void PrepareNoDonatePreference(Context ctx, Preference preference)
{
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(ctx);
long usageCount = prefs.GetLong(ctx.GetString(Resource.String.UsageCount_key), 0);
#if DEBUG
preference.Enabled = (usageCount > 1);
#else
preference.Enabled = (usageCount > 50);
#endif
preference.PreferenceChange += delegate(object sender, Preference.PreferenceChangeEventArgs args)
{
if ((bool) args.NewValue)
{
new AlertDialog.Builder(ctx)
.SetTitle(ctx.GetString(AppNames.AppNameResource))
.SetCancelable(false)
.SetPositiveButton(Android.Resource.String.Ok, delegate(object o, DialogClickEventArgs eventArgs)
{
GotoDonateUrl(ctx);
((Dialog) o).Dismiss();
})
.SetMessage(Resource.String.NoDonateOption_question)
.Create().Show();
}
};
}
public static void PrepareDonateOptionMenu(IMenu menu, Context ctx) public static void PrepareDonateOptionMenu(IMenu menu, Context ctx)
{ {
var donateItem = menu.FindItem(Resource.Id.menu_donate); var donateItem = menu.FindItem(Resource.Id.menu_donate);
@ -474,6 +443,8 @@ namespace keepass2android
); );
} }
} }
} }
} }

View File

@ -264,6 +264,12 @@
<AndroidResource Include="Resources\layout\EntryEditButtonDelete.axml"> <AndroidResource Include="Resources\layout\EntryEditButtonDelete.axml">
<SubType>AndroidResource</SubType> <SubType>AndroidResource</SubType>
</AndroidResource> </AndroidResource>
<AndroidResource Include="Resources\layout\preference.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<AndroidResource Include="Resources\layout\toolbar.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<None Include="settings\RoundsPreference %28Kopie%29.cs"> <None Include="settings\RoundsPreference %28Kopie%29.cs">
<Visible>False</Visible> <Visible>False</Visible>
</None> </None>
@ -1310,4 +1316,19 @@
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_nav_about.png" /> <AndroidResource Include="Resources\drawable-xhdpi\ic_nav_about.png" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-mhdpi\ic_arrow_back_white_24dp.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\ic_arrow_back_white_24dp.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_arrow_back_white_24dp.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\ic_arrow_back_white_24dp.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_arrow_back_white_24dp.png" />
</ItemGroup>
</Project> </Project>

View File

@ -21,19 +21,69 @@ using Android.App;
using Android.Content; using Android.Content;
using Android.OS; using Android.OS;
using Android.Preferences; using Android.Preferences;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget; using Android.Widget;
using keepass2android.Io; using keepass2android.Io;
using Toolbar = Android.Support.V7.Widget.Toolbar;
namespace keepass2android namespace keepass2android
{ {
public class ToolbarPreference : Preference
{
#region constructors
protected ToolbarPreference(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public ToolbarPreference(Context context) : base(context)
{
}
public ToolbarPreference(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public ToolbarPreference(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
{
}
public ToolbarPreference(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
{
}
#endregion
protected override View OnCreateView(ViewGroup parent)
{
parent.SetPadding(0, 0, 0, 0);
LayoutInflater inflater = (LayoutInflater) Context.GetSystemService(Context.LayoutInflaterService);
View layout = inflater.Inflate(Resource.Layout.toolbar, parent, false);
Toolbar toolbar = (Toolbar) layout.FindViewById<Toolbar>(Resource.Id.toolbar);
toolbar.SetNavigationIcon(Resource.Drawable.ic_arrow_back_white_24dp);
toolbar.Title = Title;
toolbar.NavigationClick += (sender, args) =>
{
PreferenceScreen prefScreen = (PreferenceScreen) PreferenceManager.FindPreference(Key);
if (prefScreen == null)
throw new Exception("didn't find preference " + Key);
prefScreen.Dialog.Dismiss();
};
return layout;
}
}
/// <summary> /// <summary>
/// Activity to configure the application, without database settings. Does not require an unlocked database, or close when the database is locked /// Activity to configure the application, without database settings. Does not require an unlocked database, or close when the database is locked
/// </summary> /// </summary>
[Activity(Label = "@string/app_name", Theme = "@style/MyTheme_ActionBar")] [Activity(Label = "@string/app_name", Theme = "@style/MyTheme")]
public class AppSettingsActivity : LockingPreferenceActivity public class AppSettingsActivity : LockingActivity
{ {
private ActivityDesign _design; private ActivityDesign _design;
private KeyboardSwitchPrefManager _switchPrefManager;
public AppSettingsActivity() public AppSettingsActivity()
{ {
@ -47,223 +97,16 @@ namespace keepass2android
protected override void OnCreate(Bundle savedInstanceState) protected override void OnCreate(Bundle savedInstanceState)
{ {
_design.ApplyTheme();
base.OnCreate(savedInstanceState); base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.preference);
AddPreferencesFromResource(Resource.Xml.preferences); SetSupportActionBar(FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar));
FindPreference(GetString(Resource.String.keyfile_key)).PreferenceChange += OnRememberKeyFileHistoryChanged; FragmentManager.FindFragmentById<SettingsFragment>(Resource.Id.settings_fragment).FindPreference(GetString(Resource.String.db_key)).Enabled = false;
Preference designPref = FindPreference(GetString(Resource.String.design_key));
if (!_design.HasThemes())
{
try
{
((PreferenceScreen)FindPreference(GetString(Resource.String.display_prefs_key))).RemovePreference(designPref);
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
throw;
}
}
else
{
designPref.PreferenceChange += (sender, args) => Recreate();
}
Util.PrepareNoDonatePreference(this, FindPreference(GetString(Resource.String.NoDonateOption_key)));
Preference cachingPreference = FindPreference(GetString(Resource.String.UseOfflineCache_key));
cachingPreference.PreferenceChange += OnUseOfflineCacheChanged;
#if NoNet
try
{
((PreferenceScreen) FindPreference(GetString(Resource.String.FileHandling_prefs_key))).RemovePreference(cachingPreference);
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
}
#endif
try
{
//depending on Android version, we offer to use a transparent icon for QuickUnlock or use the notification priority (since API level 16)
Preference hideQuickUnlockTranspIconPref = FindPreference(GetString(Resource.String.QuickUnlockIconHidden_key));
Preference hideQuickUnlockIconPref = FindPreference(GetString(Resource.String.QuickUnlockIconHidden16_key));
var quickUnlockScreen = ((PreferenceScreen) FindPreference(GetString(Resource.String.QuickUnlock_prefs_key)));
if ((int) Android.OS.Build.VERSION.SdkInt >= 16)
{
quickUnlockScreen.RemovePreference(hideQuickUnlockTranspIconPref);
FindPreference(GetString(Resource.String.ShowUnlockedNotification_key)).PreferenceChange += (sender, args) => App.Kp2a.UpdateOngoingNotification();
hideQuickUnlockIconPref.PreferenceChange += OnQuickUnlockHiddenChanged;
}
else
{
//old version: only show transparent quickUnlock and no option to hide unlocked icon:
quickUnlockScreen.RemovePreference(hideQuickUnlockIconPref);
FindPreference(GetString(Resource.String.QuickUnlockIconHidden_key)).PreferenceChange +=
delegate { App.Kp2a.UpdateOngoingNotification(); };
((PreferenceScreen) FindPreference(GetString(Resource.String.display_prefs_key))).RemovePreference(
FindPreference(GetString(Resource.String.ShowUnlockedNotification_key)));
}
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
}
FindPreference(GetString(Resource.String.db_key)).Enabled = false;
_switchPrefManager = new KeyboardSwitchPrefManager(this);
PrepareSeparateNotificationsPreference(this);
} }
public static void PrepareSeparateNotificationsPreference(PreferenceActivity preferenceActivity)
{
try
{
//depending on Android version, we offer to show a combined notification (with action buttons) (since API level 16)
Preference separateNotificationsPref = preferenceActivity.FindPreference(preferenceActivity.GetString(Resource.String.ShowSeparateNotifications_key));
var passwordAccessScreen = ((PreferenceScreen)preferenceActivity.FindPreference(preferenceActivity.GetString(Resource.String.password_access_prefs_key)));
if ((int)Build.VERSION.SdkInt < 16)
{
passwordAccessScreen.RemovePreference(separateNotificationsPref);
}
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
}
}
public class KeyboardSwitchPrefManager
{
private readonly PreferenceActivity _act;
private CheckBoxPreference _switchPref;
private CheckBoxPreference _openKp2aAutoPref;
private CheckBoxPreference _openOnlyOnSearchPref;
private CheckBoxPreference _switchBackPref;
private PreferenceScreen _screen;
public KeyboardSwitchPrefManager(PreferenceActivity act)
{
this._act = act;
_switchPref = (CheckBoxPreference)_act.FindPreference("kp2a_switch_rooted");
_openKp2aAutoPref =
(CheckBoxPreference)act.FindPreference(act.GetString(Resource.String.OpenKp2aKeyboardAutomatically_key));
_openOnlyOnSearchPref =
(CheckBoxPreference)
act.FindPreference(act.GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key));
_switchBackPref =
(CheckBoxPreference)act.FindPreference(act.GetString(Resource.String.AutoSwitchBackKeyboard_key));
_screen = (PreferenceScreen)act.FindPreference(act.GetString(Resource.String.keyboardswitch_prefs_key));
EnableSwitchPreferences(_switchPref.Checked);
_switchPref.PreferenceChange += (sender, args) =>
{
bool switchOnRooted = (bool)args.NewValue;
EnableSwitchPreferences(switchOnRooted);
};
}
private void EnableSwitchPreferences(bool switchOnRooted)
{
if (!switchOnRooted)
{
if (_act.FindPreference(_act.GetString(Resource.String.OpenKp2aKeyboardAutomatically_key)) == null)
{
_screen.AddPreference(_openKp2aAutoPref);
}
if (_act.FindPreference(_act.GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key)) != null)
{
_screen.RemovePreference(_openOnlyOnSearchPref);
}
}
else
{
if (_act.FindPreference(_act.GetString(Resource.String.OpenKp2aKeyboardAutomatically_key)) != null)
{
_screen.RemovePreference(_openKp2aAutoPref);
}
if (_act.FindPreference(_act.GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key)) == null)
{
_screen.AddPreference(_openOnlyOnSearchPref);
}
}
/*_openKp2aAutoPref.Enabled = !switchOnRooted;
_openOnlyOnSearchPref.Enabled = switchOnRooted;
_switchBackPref.Enabled = switchOnRooted;*/
}
}
private void OnDesignChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs)
{
Recreate();
}
private void OnQuickUnlockHiddenChanged(object sender, Preference.PreferenceChangeEventArgs e)
{
App.Kp2a.UpdateOngoingNotification();
}
private void OnUseOfflineCacheChanged(object sender, Preference.PreferenceChangeEventArgs e)
{
//ensure the user gets a matching database
if (App.Kp2a.GetDb().Loaded && !App.Kp2a.GetDb().Ioc.IsLocalFile())
App.Kp2a.LockDatabase(false);
if (!(bool)e.NewValue)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.SetTitle(GetString(Resource.String.ClearOfflineCache_title));
builder.SetMessage(GetString(Resource.String.ClearOfflineCache_question));
builder.SetPositiveButton(App.Kp2a.GetResourceString(UiStringKey.yes), (o, args) =>
{
try
{
App.Kp2a.ClearOfflineCache();
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
Toast.MakeText(Application.Context, ex.Message, ToastLength.Long).Show();
}
}
);
builder.SetNegativeButton(App.Kp2a.GetResourceString(UiStringKey.no), (o, args) =>
{
}
);
builder.SetCancelable(false);
Dialog dialog = builder.Create();
dialog.Show();
}
}
internal static void OnRememberKeyFileHistoryChanged(object sender, Preference.PreferenceChangeEventArgs eventArgs)
{
if (!(bool)eventArgs.NewValue)
{
App.Kp2a.FileDbHelper.DeleteAllKeys();
}
}
internal static void OnShowUnlockedNotificationChanged(object sender, Preference.PreferenceChangeEventArgs eventArgs)
{
App.Kp2a.UpdateOngoingNotification();
}
} }
} }

View File

@ -22,6 +22,7 @@ using Android.Content;
using Android.OS; using Android.OS;
using Android.Widget; using Android.Widget;
using Android.Preferences; using Android.Preferences;
using Android.Views;
using Java.IO; using Java.IO;
using KeePassLib.Cryptography.Cipher; using KeePassLib.Cryptography.Cipher;
using KeePassLib.Keys; using KeePassLib.Keys;
@ -32,135 +33,119 @@ using keepass2android.Utils;
namespace keepass2android namespace keepass2android
{ {
/// <summary> //http://stackoverflow.com/a/27422401/292233
/// Activity to configure the application and database settings. The database must be unlocked, and this activity will close if it becomes locked. public class SettingsFragment : PreferenceFragment
/// </summary>
[Activity(Label = "@string/app_name", Theme = "@style/MyTheme_ActionBar")]
public class DatabaseSettingsActivity : LockingClosePreferenceActivity
{ {
private ActivityDesign _design;
private AppSettingsActivity.KeyboardSwitchPrefManager _switchPrefManager;
public DatabaseSettingsActivity() public class KeyboardSwitchPrefManager
{ {
_design = new ActivityDesign(this); private readonly Activity _act;
private CheckBoxPreference _switchPref;
private CheckBoxPreference _openKp2aAutoPref;
private CheckBoxPreference _openOnlyOnSearchPref;
private CheckBoxPreference _switchBackPref;
private PreferenceScreen _screen;
private PreferenceFragment _fragment;
public KeyboardSwitchPrefManager(PreferenceFragment fragment)
{
var act = fragment.Activity;
this._act = act;
this._fragment = fragment;
_switchPref = (CheckBoxPreference)_fragment.FindPreference("kp2a_switch_rooted");
_openKp2aAutoPref =
(CheckBoxPreference)_fragment.FindPreference(act.GetString(Resource.String.OpenKp2aKeyboardAutomatically_key));
_openOnlyOnSearchPref =
(CheckBoxPreference)
_fragment.FindPreference(act.GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key));
_switchBackPref =
(CheckBoxPreference)_fragment.FindPreference(act.GetString(Resource.String.AutoSwitchBackKeyboard_key));
_screen = (PreferenceScreen)_fragment.FindPreference(act.GetString(Resource.String.keyboardswitch_prefs_key));
EnableSwitchPreferences(_switchPref.Checked);
_switchPref.PreferenceChange += (sender, args) =>
{
bool switchOnRooted = (bool)args.NewValue;
EnableSwitchPreferences(switchOnRooted);
};
} }
public static void Launch(Activity ctx)
private void EnableSwitchPreferences(bool switchOnRooted)
{ {
ctx.StartActivity(new Intent(ctx, typeof(DatabaseSettingsActivity))); if (!switchOnRooted)
{
if (_fragment.FindPreference(_act.GetString(Resource.String.OpenKp2aKeyboardAutomatically_key)) == null)
{
_screen.AddPreference(_openKp2aAutoPref);
}
if (_fragment.FindPreference(_act.GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key)) != null)
{
_screen.RemovePreference(_openOnlyOnSearchPref);
}
}
else
{
{
_screen.RemovePreference(_openKp2aAutoPref);
}
if (_fragment.FindPreference(_act.GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key)) == null)
{
_screen.AddPreference(_openOnlyOnSearchPref);
}
}
/*_openKp2aAutoPref.Enabled = !switchOnRooted;
_openOnlyOnSearchPref.Enabled = switchOnRooted;
_switchBackPref.Enabled = switchOnRooted;*/
}
} }
protected override void OnCreate(Bundle savedInstanceState) private KeyboardSwitchPrefManager _switchPrefManager;
{
_design.ApplyTheme();
void OnRememberKeyFileHistoryChanged(object sender, Preference.PreferenceChangeEventArgs eventArgs)
{
if (!(bool)eventArgs.NewValue)
{
App.Kp2a.FileDbHelper.DeleteAllKeys();
}
}
void OnShowUnlockedNotificationChanged(object sender, Preference.PreferenceChangeEventArgs eventArgs)
{
App.Kp2a.UpdateOngoingNotification();
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState); base.OnCreate(savedInstanceState);
AddPreferencesFromResource(Resource.Xml.preferences); AddPreferencesFromResource(Resource.Xml.preferences);
// Re-use the change handlers for the application settings // Re-use the change handlers for the application settings
FindPreference(GetString(Resource.String.keyfile_key)).PreferenceChange += AppSettingsActivity.OnRememberKeyFileHistoryChanged; FindPreference(GetString(Resource.String.keyfile_key)).PreferenceChange += OnRememberKeyFileHistoryChanged;
FindPreference(GetString(Resource.String.ShowUnlockedNotification_key)).PreferenceChange += AppSettingsActivity.OnShowUnlockedNotificationChanged; FindPreference(GetString(Resource.String.ShowUnlockedNotification_key)).PreferenceChange += OnShowUnlockedNotificationChanged;
Util.PrepareNoDonatePreference(this, FindPreference(GetString(Resource.String.NoDonateOption_key))); PrepareNoDonatePreference(Activity, FindPreference(GetString(Resource.String.NoDonateOption_key)));
Preference designPref = FindPreference(GetString(Resource.String.design_key));
if (!_design.HasThemes())
{
try
{
((PreferenceScreen)FindPreference(GetString(Resource.String.display_prefs_key))).RemovePreference(designPref);
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
throw;
}
}
else
{
designPref.PreferenceChange += (sender, args) => Recreate();
}
Database db = App.Kp2a.GetDb(); Database db = App.Kp2a.GetDb();
if (db.Loaded)
{
Preference rounds = FindPreference(GetString(Resource.String.rounds_key)); Preference rounds = FindPreference(GetString(Resource.String.rounds_key));
rounds.PreferenceChange += (sender, e) => SetRounds(db, e.Preference); rounds.PreferenceChange += (sender, e) => SetRounds(db, e.Preference);
rounds.Enabled = db.CanWrite; rounds.Enabled = db.CanWrite;
SetRounds(db, rounds);
Preference defaultUser = FindPreference(GetString(Resource.String.default_username_key)); PrepareDefaultUsername(db);
if (!db.DatabaseFormat.HasDefaultUsername) PrepareDatabaseName(db);
{ PrepareMasterPassword();
((PreferenceScreen) FindPreference(GetString(Resource.String.db_key))).RemovePreference(defaultUser);
}
else
{
defaultUser.Enabled = db.CanWrite;
((EditTextPreference)defaultUser).EditText.Text = db.KpDatabase.DefaultUserName;
((EditTextPreference)defaultUser).Text = db.KpDatabase.DefaultUserName;
defaultUser.PreferenceChange += (sender, e) =>
{
DateTime previousUsernameChanged = db.KpDatabase.DefaultUserNameChanged;
String previousUsername = db.KpDatabase.DefaultUserName;
db.KpDatabase.DefaultUserName = e.NewValue.ToString();
SaveDb save = new SaveDb(this, App.Kp2a, new ActionOnFinish((success, message) => Preference algorithm = FindPreference(GetString(Resource.String.algorithm_key));
{ SetAlgorithm(db, algorithm);
if (!success)
{
db.KpDatabase.DefaultUserName = previousUsername;
db.KpDatabase.DefaultUserNameChanged = previousUsernameChanged;
Toast.MakeText(this, message, ToastLength.Long).Show();
}
}));
ProgressTask pt = new ProgressTask(App.Kp2a, this, save);
pt.Run();
};
} UpdateImportDbPref();
UpdateImportKeyfilePref();
Preference databaseName = FindPreference(GetString(Resource.String.database_name_key));
if (!db.DatabaseFormat.HasDatabaseName)
{
((PreferenceScreen) FindPreference(GetString(Resource.String.db_key))).RemovePreference(databaseName);
}
else
{
databaseName.Enabled = db.CanWrite;
((EditTextPreference) databaseName).EditText.Text = db.KpDatabase.Name;
((EditTextPreference) databaseName).Text = db.KpDatabase.Name;
databaseName.PreferenceChange += (sender, e) =>
{
DateTime previousNameChanged = db.KpDatabase.NameChanged;
String previousName = db.KpDatabase.Name;
db.KpDatabase.Name = e.NewValue.ToString();
SaveDb save = new SaveDb(this, App.Kp2a, new ActionOnFinish((success, message) =>
{
if (!success)
{
db.KpDatabase.Name = previousName;
db.KpDatabase.NameChanged = previousNameChanged;
Toast.MakeText(this, message, ToastLength.Long).Show();
}
else
{
// Name is reflected in notification, so update it
App.Kp2a.UpdateOngoingNotification();
}
}));
ProgressTask pt = new ProgressTask(App.Kp2a, this, save);
pt.Run();
};
}
Preference changeMaster = FindPreference(GetString(Resource.String.master_pwd_key));
if (App.Kp2a.GetDb().CanWrite)
{
changeMaster.Enabled = true;
changeMaster.PreferenceClick += delegate {
new SetPasswordDialog(this).Show();
};
} }
try try
@ -191,21 +176,205 @@ namespace keepass2android
Kp2aLog.Log(ex.ToString()); Kp2aLog.Log(ex.ToString());
} }
SetRounds(db, rounds);
Preference algorithm = FindPreference(GetString(Resource.String.algorithm_key));
SetAlgorithm(db, algorithm);
UpdateImportDbPref();
UpdateImportKeyfilePref();
//AppSettingsActivity.PrepareKeyboardSwitchingPreferences(this); //AppSettingsActivity.PrepareKeyboardSwitchingPreferences(this);
_switchPrefManager = new AppSettingsActivity.KeyboardSwitchPrefManager(this); _switchPrefManager = new KeyboardSwitchPrefManager(this);
AppSettingsActivity.PrepareSeparateNotificationsPreference(this); PrepareSeparateNotificationsPreference();
Preference cachingPreference = FindPreference(GetString(Resource.String.UseOfflineCache_key));
cachingPreference.PreferenceChange += OnUseOfflineCacheChanged;
#if NoNet
try
{
((PreferenceScreen) FindPreference(GetString(Resource.String.FileHandling_prefs_key))).RemovePreference(cachingPreference);
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
}
#endif
try
{
//depending on Android version, we offer to use a transparent icon for QuickUnlock or use the notification priority (since API level 16)
Preference hideQuickUnlockTranspIconPref = FindPreference(GetString(Resource.String.QuickUnlockIconHidden_key));
Preference hideQuickUnlockIconPref = FindPreference(GetString(Resource.String.QuickUnlockIconHidden16_key));
var quickUnlockScreen = ((PreferenceScreen)FindPreference(GetString(Resource.String.QuickUnlock_prefs_key)));
if ((int)Android.OS.Build.VERSION.SdkInt >= 16)
{
quickUnlockScreen.RemovePreference(hideQuickUnlockTranspIconPref);
FindPreference(GetString(Resource.String.ShowUnlockedNotification_key)).PreferenceChange += (sender, args) => App.Kp2a.UpdateOngoingNotification();
hideQuickUnlockIconPref.PreferenceChange += OnQuickUnlockHiddenChanged;
}
else
{
//old version: only show transparent quickUnlock and no option to hide unlocked icon:
quickUnlockScreen.RemovePreference(hideQuickUnlockIconPref);
FindPreference(GetString(Resource.String.QuickUnlockIconHidden_key)).PreferenceChange +=
delegate { App.Kp2a.UpdateOngoingNotification(); };
((PreferenceScreen)FindPreference(GetString(Resource.String.display_prefs_key))).RemovePreference(
FindPreference(GetString(Resource.String.ShowUnlockedNotification_key)));
}
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
}
}
private void PrepareMasterPassword()
{
Preference changeMaster = FindPreference(GetString(Resource.String.master_pwd_key));
if (App.Kp2a.GetDb().CanWrite)
{
changeMaster.Enabled = true;
changeMaster.PreferenceClick += delegate { new SetPasswordDialog(Activity).Show(); };
}
}
private void PrepareDatabaseName(Database db)
{
Preference databaseName = FindPreference(GetString(Resource.String.database_name_key));
if (!db.DatabaseFormat.HasDatabaseName)
{
((PreferenceScreen) FindPreference(GetString(Resource.String.db_key))).RemovePreference(databaseName);
}
else
{
databaseName.Enabled = db.CanWrite;
((EditTextPreference) databaseName).EditText.Text = db.KpDatabase.Name;
((EditTextPreference) databaseName).Text = db.KpDatabase.Name;
databaseName.PreferenceChange += (sender, e) =>
{
DateTime previousNameChanged = db.KpDatabase.NameChanged;
String previousName = db.KpDatabase.Name;
db.KpDatabase.Name = e.NewValue.ToString();
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish((success, message) =>
{
if (!success)
{
db.KpDatabase.Name = previousName;
db.KpDatabase.NameChanged = previousNameChanged;
Toast.MakeText(Activity, message, ToastLength.Long).Show();
}
else
{
// Name is reflected in notification, so update it
App.Kp2a.UpdateOngoingNotification();
}
}));
ProgressTask pt = new ProgressTask(App.Kp2a, Activity, save);
pt.Run();
};
}
}
private void PrepareDefaultUsername(Database db)
{
Preference defaultUser = FindPreference(GetString(Resource.String.default_username_key));
if (!db.DatabaseFormat.HasDefaultUsername)
{
((PreferenceScreen) FindPreference(GetString(Resource.String.db_key))).RemovePreference(defaultUser);
}
else
{
defaultUser.Enabled = db.CanWrite;
((EditTextPreference) defaultUser).EditText.Text = db.KpDatabase.DefaultUserName;
((EditTextPreference) defaultUser).Text = db.KpDatabase.DefaultUserName;
defaultUser.PreferenceChange += (sender, e) =>
{
DateTime previousUsernameChanged = db.KpDatabase.DefaultUserNameChanged;
String previousUsername = db.KpDatabase.DefaultUserName;
db.KpDatabase.DefaultUserName = e.NewValue.ToString();
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish((success, message) =>
{
if (!success)
{
db.KpDatabase.DefaultUserName = previousUsername;
db.KpDatabase.DefaultUserNameChanged = previousUsernameChanged;
Toast.MakeText(Activity, message, ToastLength.Long).Show();
}
}));
ProgressTask pt = new ProgressTask(App.Kp2a, Activity, save);
pt.Run();
};
}
}
public void PrepareSeparateNotificationsPreference()
{
try
{
//depending on Android version, we offer to show a combined notification (with action buttons) (since API level 16)
Preference separateNotificationsPref = FindPreference(Activity.GetString(Resource.String.ShowSeparateNotifications_key));
var passwordAccessScreen = ((PreferenceScreen)FindPreference(Activity.GetString(Resource.String.password_access_prefs_key)));
if ((int)Build.VERSION.SdkInt < 16)
{
passwordAccessScreen.RemovePreference(separateNotificationsPref);
}
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
}
}
private void OnQuickUnlockHiddenChanged(object sender, Preference.PreferenceChangeEventArgs e)
{
App.Kp2a.UpdateOngoingNotification();
}
private void OnUseOfflineCacheChanged(object sender, Preference.PreferenceChangeEventArgs e)
{
//ensure the user gets a matching database
if (App.Kp2a.GetDb().Loaded && !App.Kp2a.GetDb().Ioc.IsLocalFile())
App.Kp2a.LockDatabase(false);
if (!(bool)e.NewValue)
{
AlertDialog.Builder builder = new AlertDialog.Builder(Activity);
builder.SetTitle(GetString(Resource.String.ClearOfflineCache_title));
builder.SetMessage(GetString(Resource.String.ClearOfflineCache_question));
builder.SetPositiveButton(App.Kp2a.GetResourceString(UiStringKey.yes), (o, args) =>
{
try
{
App.Kp2a.ClearOfflineCache();
}
catch (Exception ex)
{
Kp2aLog.Log(ex.ToString());
Toast.MakeText(Application.Context, ex.Message, ToastLength.Long).Show();
}
}
);
builder.SetNegativeButton(App.Kp2a.GetResourceString(UiStringKey.no), (o, args) =>
{
}
);
builder.SetCancelable(false);
Dialog dialog = builder.Create();
dialog.Show();
}
} }
private void UpdateImportKeyfilePref() private void UpdateImportKeyfilePref()
{ {
var prefs = PreferenceManager.GetDefaultSharedPreferences(this); var prefs = PreferenceManager.GetDefaultSharedPreferences(Activity);
var rememberKeyfile = prefs.GetBoolean(GetString(Resource.String.keyfile_key), Resources.GetBoolean(Resource.Boolean.keyfile_default)); var rememberKeyfile = prefs.GetBoolean(GetString(Resource.String.keyfile_key), Resources.GetBoolean(Resource.Boolean.keyfile_default));
Preference importDb = FindPreference("import_keyfile_prefs"); Preference importDb = FindPreference("import_keyfile_prefs");
@ -221,7 +390,7 @@ namespace keepass2android
if (masterKey.ContainsType(typeof(KcpKeyFile))) if (masterKey.ContainsType(typeof(KcpKeyFile)))
{ {
IOConnectionInfo iocKeyfile = ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc; IOConnectionInfo iocKeyfile = ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc;
if (iocKeyfile.IsLocalFile() && IoUtil.IsInInternalDirectory(iocKeyfile.Path, this)) if (iocKeyfile.IsLocalFile() && IoUtil.IsInInternalDirectory(iocKeyfile.Path, Activity))
{ {
importDb.Enabled = false; importDb.Enabled = false;
importDb.Summary = GetString(Resource.String.FileIsInInternalDirectory); importDb.Summary = GetString(Resource.String.FileIsInInternalDirectory);
@ -255,7 +424,7 @@ namespace keepass2android
return () => return () =>
{ {
UpdateImportKeyfilePref(); UpdateImportKeyfilePref();
var builder = new AlertDialog.Builder(this); var builder = new AlertDialog.Builder(Activity);
builder builder
.SetMessage(Resource.String.KeyfileMoved); .SetMessage(Resource.String.KeyfileMoved);
builder.SetPositiveButton(Android.Resource.String.Ok, (sender, args) => { }); builder.SetPositiveButton(Android.Resource.String.Ok, (sender, args) => { });
@ -271,7 +440,7 @@ namespace keepass2android
{ {
return () => return () =>
{ {
Toast.MakeText(this, App.Kp2a.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, ToastLength.Long).Show(); Toast.MakeText(Activity, App.Kp2a.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, ToastLength.Long).Show();
}; };
} }
@ -279,7 +448,7 @@ namespace keepass2android
}; };
new SimpleLoadingDialog(this, GetString(Resource.String.CopyingFile), false, new SimpleLoadingDialog(Activity, GetString(Resource.String.CopyingFile), false,
copyAndReturnPostExecute copyAndReturnPostExecute
).Execute(); ).Execute();
@ -295,7 +464,7 @@ namespace keepass2android
} }
else else
{ {
if (IoUtil.IsInInternalDirectory(App.Kp2a.GetDb().Ioc.Path, this)) if (IoUtil.IsInInternalDirectory(App.Kp2a.GetDb().Ioc.Path, Activity))
{ {
importDb.Summary = GetString(Resource.String.FileIsInInternalDirectory); importDb.Summary = GetString(Resource.String.FileIsInInternalDirectory);
importDb.Enabled = false; importDb.Enabled = false;
@ -318,11 +487,11 @@ namespace keepass2android
var newIoc = ImportFileToInternalDirectory(sourceIoc); var newIoc = ImportFileToInternalDirectory(sourceIoc);
return () => return () =>
{ {
var builder = new AlertDialog.Builder(this); var builder = new AlertDialog.Builder(Activity);
builder builder
.SetMessage(Resource.String.DatabaseFileMoved); .SetMessage(Resource.String.DatabaseFileMoved);
builder.SetPositiveButton(Android.Resource.String.Ok, (sender, args) => builder.SetPositiveButton(Android.Resource.String.Ok, (sender, args) =>
PasswordActivity.Launch(this, newIoc, new NullTask())); PasswordActivity.Launch(Activity, newIoc, new NullTask()));
builder.Show(); builder.Show();
}; };
@ -335,7 +504,7 @@ namespace keepass2android
{ {
return () => return () =>
{ {
Toast.MakeText(this, App.Kp2a.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, ToastLength.Long).Show(); Toast.MakeText(Activity, App.Kp2a.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, ToastLength.Long).Show();
}; };
} }
@ -343,7 +512,7 @@ namespace keepass2android
}; };
new SimpleLoadingDialog(this, GetString(Resource.String.CopyingFile), false, new SimpleLoadingDialog(Activity, GetString(Resource.String.CopyingFile), false,
copyAndReturnPostExecute copyAndReturnPostExecute
).Execute(); ).Execute();
@ -355,7 +524,7 @@ namespace keepass2android
targetPath = targetPath.Trim("|\\?*<\":>+[]/'".ToCharArray()); targetPath = targetPath.Trim("|\\?*<\":>+[]/'".ToCharArray());
if (targetPath == "") if (targetPath == "")
targetPath = "imported"; targetPath = "imported";
if (new File(FilesDir, targetPath).Exists()) if (new File(Activity.FilesDir, targetPath).Exists())
{ {
int c = 1; int c = 1;
var ext = UrlUtil.GetExtension(targetPath); var ext = UrlUtil.GetExtension(targetPath);
@ -366,14 +535,15 @@ namespace keepass2android
targetPath = filenameWithoutExt + c; targetPath = filenameWithoutExt + c;
if (!String.IsNullOrEmpty(ext)) if (!String.IsNullOrEmpty(ext))
targetPath += "." + ext; targetPath += "." + ext;
} while (new File(FilesDir, targetPath).Exists()); } while (new File(Activity.FilesDir, targetPath).Exists());
} }
var targetIoc = IOConnectionInfo.FromPath(new File(FilesDir, targetPath).CanonicalPath); var targetIoc = IOConnectionInfo.FromPath(new File(Activity.FilesDir, targetPath).CanonicalPath);
IoUtil.Copy(targetIoc, sourceIoc, App.Kp2a); IoUtil.Copy(targetIoc, sourceIoc, App.Kp2a);
return targetIoc; return targetIoc;
} }
private void SetRounds(Database db, Preference rounds) private void SetRounds(Database db, Preference rounds)
{ {
rounds.Summary = db.KpDatabase.KeyEncryptionRounds.ToString(CultureInfo.InvariantCulture); rounds.Summary = db.KpDatabase.KeyEncryptionRounds.ToString(CultureInfo.InvariantCulture);
@ -383,6 +553,66 @@ namespace keepass2android
{ {
algorithm.Summary = CipherPool.GlobalPool.GetCipher(db.KpDatabase.DataCipherUuid).DisplayName; algorithm.Summary = CipherPool.GlobalPool.GetCipher(db.KpDatabase.DataCipherUuid).DisplayName;
} }
public void PrepareNoDonatePreference(Context ctx, Preference preference)
{
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(ctx);
long usageCount = prefs.GetLong(ctx.GetString(Resource.String.UsageCount_key), 0);
#if DEBUG
preference.Enabled = (usageCount > 1);
#else
preference.Enabled = (usageCount > 50);
#endif
preference.PreferenceChange += delegate(object sender, Preference.PreferenceChangeEventArgs args)
{
if ((bool)args.NewValue)
{
new AlertDialog.Builder(ctx)
.SetTitle(ctx.GetString(AppNames.AppNameResource))
.SetCancelable(false)
.SetPositiveButton(Android.Resource.String.Ok, delegate(object o, DialogClickEventArgs eventArgs)
{
Util.GotoDonateUrl(ctx);
((Dialog)o).Dismiss();
})
.SetMessage(Resource.String.NoDonateOption_question)
.Create().Show();
}
};
}
}
/// <summary>
/// Activity to configure the application and database settings. The database must be unlocked, and this activity will close if it becomes locked.
/// </summary>
[Activity(Label = "@string/app_name", Theme = "@style/MyTheme")]
public class DatabaseSettingsActivity : LockCloseActivity
{
public DatabaseSettingsActivity()
{
}
public static void Launch(Activity ctx)
{
ctx.StartActivity(new Intent(ctx, typeof(DatabaseSettingsActivity)));
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.preference);
SetSupportActionBar(FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar));
}
} }
} }