721 lines
26 KiB
C#
721 lines
26 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
using Android.App;
|
|
using Android.Content;
|
|
using Android.Content.PM;
|
|
using Android.Graphics;
|
|
using Android.Graphics.Drawables;
|
|
using Android.OS;
|
|
using Android.Preferences;
|
|
using Android.Runtime;
|
|
using Android.Text;
|
|
using Android.Util;
|
|
using Android.Views;
|
|
using Android.Widget;
|
|
using Java.IO;
|
|
using Java.Net;
|
|
using keepass2android.Io;
|
|
using keepass2android.Utils;
|
|
using keepass2android;
|
|
using KeePassLib;
|
|
using KeePassLib.Keys;
|
|
using KeePassLib.Serialization;
|
|
using Console = System.Console;
|
|
using Object = Java.Lang.Object;
|
|
using AndroidX.Core.Content;
|
|
using Uri = Android.Net.Uri;
|
|
|
|
namespace keepass2android
|
|
{
|
|
[Activity(Label = AppNames.AppName,
|
|
MainLauncher = false,
|
|
Theme = "@style/Kp2aTheme_BlueNoActionBar",
|
|
Exported = true,
|
|
LaunchMode = LaunchMode.SingleInstance)] //caution, see manifest file
|
|
public class SelectCurrentDbActivity : LifecycleAwareActivity
|
|
{
|
|
private int ReqCodeOpenNewDb = 1;
|
|
|
|
private static bool IsValidIoc(AutoExecItem item)
|
|
{
|
|
IOConnectionInfo itemIoc;
|
|
if (!KeeAutoExecExt.TryGetDatabaseIoc(item, out itemIoc))
|
|
return false;
|
|
try
|
|
{
|
|
//see if we have a file storage for the given protocol
|
|
App.Kp2a.GetFileStorage(itemIoc);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public class OpenDatabaseAdapter : BaseAdapter
|
|
{
|
|
|
|
private readonly SelectCurrentDbActivity _context;
|
|
internal List<Database> _displayedDatabases;
|
|
internal List<AutoExecItem> _autoExecItems;
|
|
|
|
public OpenDatabaseAdapter(SelectCurrentDbActivity context)
|
|
{
|
|
_context = context;
|
|
Update();
|
|
|
|
}
|
|
|
|
public override Object GetItem(int position)
|
|
{
|
|
return position;
|
|
}
|
|
|
|
public override long GetItemId(int position)
|
|
{
|
|
return position;
|
|
}
|
|
|
|
|
|
|
|
public static float convertDpToPixel(float dp, Context context)
|
|
{
|
|
return Util.convertDpToPixel(dp, context);
|
|
}
|
|
|
|
|
|
public override View GetView(int position, View convertView, ViewGroup parent)
|
|
{
|
|
|
|
Button btn;
|
|
|
|
if (convertView == null)
|
|
{
|
|
// if it's not recycled, initialize some attributes
|
|
|
|
btn = new Button(_context);
|
|
btn.LayoutParameters = new GridView.LayoutParams((int) convertDpToPixel(140, _context),
|
|
(int) convertDpToPixel(150, _context));
|
|
|
|
btn.SetPadding((int) convertDpToPixel(4, _context),
|
|
(int) convertDpToPixel(20, _context),
|
|
(int) convertDpToPixel(4, _context),
|
|
(int) convertDpToPixel(4, _context));
|
|
btn.SetTextSize(ComplexUnitType.Sp, 11);
|
|
btn.SetTextColor(new Color(115, 115, 115));
|
|
btn.SetSingleLine(false);
|
|
btn.Gravity = GravityFlags.Center;
|
|
btn.Click += (sender, args) =>
|
|
{
|
|
int pos;
|
|
int.TryParse(((Button) sender).Tag.ToString(), out pos);
|
|
if (pos < _displayedDatabases.Count)
|
|
_context.OnDatabaseSelected(_displayedDatabases[pos]);
|
|
else if (pos < _displayedDatabases.Count + _autoExecItems.Count)
|
|
_context.OnAutoExecItemSelected(_autoExecItems[pos - _displayedDatabases.Count]);
|
|
else
|
|
_context.OnOpenOther();
|
|
|
|
};
|
|
}
|
|
else
|
|
{
|
|
btn = (Button) convertView;
|
|
}
|
|
|
|
btn.Tag = position.ToString();
|
|
|
|
string displayName;
|
|
Drawable drawable;
|
|
if (position < _displayedDatabases.Count)
|
|
{
|
|
var db = _displayedDatabases[position];
|
|
drawable = App.Kp2a.GetStorageIcon(Util.GetProtocolId(db.Ioc));
|
|
displayName = db.KpDatabase.Name;
|
|
displayName += "\n" + App.Kp2a.GetFileStorage(db.Ioc).GetDisplayName(db.Ioc);
|
|
btn.SetBackgroundResource(Resource.Drawable.storagetype_button_bg);
|
|
}
|
|
else if (position < _displayedDatabases.Count + _autoExecItems.Count)
|
|
{
|
|
var item = _autoExecItems[position - _displayedDatabases.Count];
|
|
drawable = App.Kp2a.GetResourceDrawable("baseline_file_open_24");
|
|
displayName = item.Entry.Strings.ReadSafe(PwDefs.TitleField);
|
|
btn.SetBackgroundResource(Resource.Drawable.storagetype_button_bg_dark);
|
|
}
|
|
else
|
|
{
|
|
btn.SetBackgroundResource(Resource.Drawable.storagetype_button_bg);
|
|
displayName = _context.GetString(Resource.String.start_open_file);
|
|
drawable = App.Kp2a.GetResourceDrawable("baseline_file_open_24");
|
|
}
|
|
|
|
var str = new SpannableString(displayName);
|
|
|
|
btn.TextFormatted = str;
|
|
//var drawable = ContextCompat.GetDrawable(context, Resource.Drawable.Icon);
|
|
btn.SetCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null);
|
|
|
|
return btn;
|
|
}
|
|
|
|
public override int Count
|
|
{
|
|
get { return _displayedDatabases.Count+_autoExecItems.Count+1; }
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
string thisDevice = KeeAutoExecExt.ThisDeviceId;
|
|
_displayedDatabases = App.Kp2a.OpenDatabases.ToList();
|
|
_autoExecItems = App.Kp2a.OpenDatabases
|
|
.SelectMany(db => KeeAutoExecExt.GetAutoExecItems(db.KpDatabase))
|
|
.Where(item =>
|
|
item.Visible
|
|
&&
|
|
KeeAutoExecExt.IsDeviceEnabled(item, thisDevice, out _)
|
|
&&
|
|
!_displayedDatabases.Any(displayedDb =>
|
|
{
|
|
IOConnectionInfo itemIoc;
|
|
return KeeAutoExecExt.TryGetDatabaseIoc(item, out itemIoc) &&
|
|
displayedDb.Ioc.IsSameFileAs(itemIoc);
|
|
})
|
|
&& IsValidIoc(item)
|
|
|
|
)
|
|
|
|
.ToList();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
private void OnAutoExecItemSelected(AutoExecItem autoExecItem)
|
|
{
|
|
KeeAutoExecExt.AutoOpenEntry(this, autoExecItem, true, new ActivityLaunchModeSimple());
|
|
}
|
|
|
|
private void OnOpenOther()
|
|
{
|
|
StartFileSelect(true, true);
|
|
}
|
|
|
|
private void OnDatabaseSelected(Database selectedDatabase)
|
|
{
|
|
App.Kp2a.CurrentDb = selectedDatabase;
|
|
LaunchingOther = true;
|
|
AppTask.LaunchFirstGroupActivity(this);
|
|
}
|
|
|
|
public override bool OnCreateOptionsMenu(IMenu menu)
|
|
{
|
|
MenuInflater inflater = MenuInflater;
|
|
inflater.Inflate(Resource.Menu.menu_selectdb, menu);
|
|
return base.OnCreateOptionsMenu(menu);
|
|
}
|
|
|
|
public override bool OnOptionsItemSelected(IMenuItem item)
|
|
{
|
|
switch (item.ItemId)
|
|
{
|
|
case Resource.Id.menu_search_advanced:
|
|
if (App.Kp2a.CurrentDb == null)
|
|
App.Kp2a.CurrentDb = App.Kp2a.OpenDatabases.First();
|
|
Intent i = new Intent(this, typeof(SearchActivity));
|
|
AppTask.ToIntent(i);
|
|
StartActivityForResult(i, 0);
|
|
return true;
|
|
case Resource.Id.menu_lock:
|
|
App.Kp2a.Lock();
|
|
return true;
|
|
case Resource.Id.menu_donate:
|
|
return Util.GotoDonateUrl(this);
|
|
case Resource.Id.menu_app_settings:
|
|
DatabaseSettingsActivity.Launch(this);
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return base.OnOptionsItemSelected(item);
|
|
}
|
|
|
|
protected override void OnCreate(Bundle savedInstanceState)
|
|
{
|
|
base.OnCreate(savedInstanceState);
|
|
SetContentView(Resource.Layout.open_db_selection);
|
|
|
|
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
|
|
|
|
SetSupportActionBar(toolbar);
|
|
|
|
SupportActionBar.Title = GetString(Resource.String.select_database);
|
|
|
|
|
|
//only load the AppTask if this is the "first" OnCreate (not because of kill/resume, i.e. savedInstanceState==null)
|
|
// and if the activity is not launched from history (i.e. recent tasks) because this would mean that
|
|
// the Activity was closed already (user cancelling the task or task complete) but is restarted due recent tasks.
|
|
// Don't re-start the task (especially bad if tak was complete already)
|
|
if (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))
|
|
{
|
|
AppTask = new NullTask();
|
|
}
|
|
else
|
|
{
|
|
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
|
|
}
|
|
|
|
_adapter = new OpenDatabaseAdapter(this);
|
|
var gridView = FindViewById<GridView>(Resource.Id.gridview);
|
|
|
|
gridView.Adapter = _adapter;
|
|
|
|
if (!string.IsNullOrEmpty(Intent.GetStringExtra(Util.KeyFilename)))
|
|
{
|
|
IOConnectionInfo ioc = new IOConnectionInfo();
|
|
Util.SetIoConnectionFromIntent(ioc, Intent);
|
|
|
|
if (App.Kp2a.TrySelectCurrentDb(ioc))
|
|
{
|
|
if (!OpenAutoExecEntries(App.Kp2a.CurrentDb))
|
|
{
|
|
LaunchingOther = true;
|
|
AppTask.CanActivateSearchViewOnStart = true;
|
|
AppTask.LaunchFirstGroupActivity(this);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//forward to password activity
|
|
Intent i = new Intent(this, typeof(PasswordActivity));
|
|
Util.PutIoConnectionToIntent(ioc, i);
|
|
i.PutExtra(PasswordActivity.KeyKeyfile, Intent.GetStringExtra(PasswordActivity.KeyKeyfile));
|
|
i.PutExtra(PasswordActivity.KeyPassword, Intent.GetStringExtra(PasswordActivity.KeyPassword));
|
|
i.PutExtra(PasswordActivity.LaunchImmediately, Intent.GetBooleanExtra(PasswordActivity.LaunchImmediately, false));
|
|
LaunchingOther = true;
|
|
StartActivityForResult(i, ReqCodeOpenNewDb);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if (Intent.Action == Intent.ActionView)
|
|
{
|
|
if (IsOtpUri(Intent.Data))
|
|
{
|
|
AppTask = new CreateEntryThenCloseTask()
|
|
{
|
|
AllFields = Newtonsoft.Json.JsonConvert.SerializeObject(new Dictionary<string, string>()
|
|
{
|
|
{ "otp", Intent.DataString }
|
|
})
|
|
};
|
|
}
|
|
else
|
|
{
|
|
GetIocFromViewIntent(Intent);
|
|
}
|
|
}
|
|
else if (Intent.Action == Intent.ActionSend)
|
|
{
|
|
ActivationCondition activationCondition = ActivationCondition.Never;
|
|
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
|
|
if (prefs.GetBoolean("kp2a_switch_rooted", false))
|
|
{
|
|
activationCondition = ActivationCondition.Always;
|
|
}
|
|
else
|
|
{
|
|
//if the app is about to be closed again (e.g. after searching for a URL and returning to the browser:
|
|
// automatically bring up the Keyboard selection dialog
|
|
if (prefs.GetBoolean(this.GetString(Resource.String.OpenKp2aKeyboardAutomatically_key), this.Resources.GetBoolean(Resource.Boolean.OpenKp2aKeyboardAutomatically_default)))
|
|
{
|
|
activationCondition = ActivationCondition.Always;
|
|
}
|
|
}
|
|
|
|
AppTask = new SearchUrlTask()
|
|
{
|
|
UrlToSearchFor = Intent.GetStringExtra(Intent.ExtraText),
|
|
ActivateKeyboard = activationCondition
|
|
};
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private bool IsOtpUri(Uri? uri)
|
|
{
|
|
return uri?.Scheme == "otpauth";
|
|
}
|
|
|
|
protected override void OnStart()
|
|
{
|
|
base.OnStart();
|
|
|
|
if (_intentReceiver == null)
|
|
{
|
|
_intentReceiver = new MyBroadcastReceiver(this);
|
|
IntentFilter filter = new IntentFilter();
|
|
filter.AddAction(Intents.DatabaseLocked);
|
|
filter.AddAction(Intent.ActionScreenOff);
|
|
ContextCompat.RegisterReceiver(this, _intentReceiver, filter, (int)ReceiverFlags.Exported);
|
|
}
|
|
}
|
|
|
|
protected override void OnStop()
|
|
{
|
|
if (_intentReceiver != null)
|
|
{
|
|
UnregisterReceiver(_intentReceiver);
|
|
_intentReceiver = null;
|
|
}
|
|
base.OnStop();
|
|
}
|
|
|
|
private bool GetIocFromViewIntent(Intent intent)
|
|
{
|
|
IOConnectionInfo ioc = new IOConnectionInfo();
|
|
|
|
//started from "view" intent (e.g. from file browser)
|
|
ioc.Path = intent.DataString;
|
|
|
|
if (ioc.Path.StartsWith("file://"))
|
|
{
|
|
ioc.Path = URLDecoder.Decode(ioc.Path.Substring(7));
|
|
|
|
if (ioc.Path.Length == 0)
|
|
{
|
|
// No file name
|
|
Toast.MakeText(this, Resource.String.FileNotFound, ToastLength.Long).Show();
|
|
return false;
|
|
}
|
|
|
|
Java.IO.File dbFile = new Java.IO.File(ioc.Path);
|
|
if (!dbFile.Exists())
|
|
{
|
|
// File does not exist
|
|
Toast.MakeText(this, Resource.String.FileNotFound, ToastLength.Long).Show();
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!ioc.Path.StartsWith("content://"))
|
|
{
|
|
Toast.MakeText(this, Resource.String.error_can_not_handle_uri, ToastLength.Long).Show();
|
|
return false;
|
|
}
|
|
IoUtil.TryTakePersistablePermissions(this.ContentResolver, intent.Data);
|
|
|
|
|
|
}
|
|
|
|
if (App.Kp2a.TrySelectCurrentDb(ioc))
|
|
{
|
|
if (OpenAutoExecEntries(App.Kp2a.CurrentDb)) return false;
|
|
LaunchingOther = true;
|
|
AppTask.CanActivateSearchViewOnStart = true;
|
|
AppTask.LaunchFirstGroupActivity(this);
|
|
}
|
|
else
|
|
{
|
|
Intent launchIntent = new Intent(this, typeof(PasswordActivity));
|
|
Util.PutIoConnectionToIntent(ioc, launchIntent);
|
|
LaunchingOther = true;
|
|
StartActivityForResult(launchIntent, ReqCodeOpenNewDb);
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
protected override void OnResume()
|
|
{
|
|
_isForeground = true;
|
|
base.OnResume();
|
|
if (!IsFinishing && !LaunchingOther)
|
|
{
|
|
if (App.Kp2a.OpenDatabases.Any() == false)
|
|
{
|
|
StartFileSelect(true);
|
|
return;
|
|
}
|
|
|
|
//database loaded
|
|
if (App.Kp2a.QuickLocked)
|
|
{
|
|
AppTask.CanActivateSearchViewOnStart = true;
|
|
var i = new Intent(this, typeof(QuickUnlock));
|
|
Util.PutIoConnectionToIntent(App.Kp2a.GetDbForQuickUnlock().Ioc, i);
|
|
Kp2aLog.Log("Starting QuickUnlock");
|
|
StartActivityForResult(i, 0);
|
|
return;
|
|
}
|
|
|
|
//see if there are any AutoOpen items to open
|
|
|
|
foreach (var db in App.Kp2a.OpenDatabases)
|
|
{
|
|
try
|
|
{
|
|
if (OpenAutoExecEntries(db)) return;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Toast.MakeText(this, "Failed to open child databases",ToastLength.Long).Show();
|
|
Kp2aLog.LogUnexpectedError(e);
|
|
}
|
|
|
|
}
|
|
|
|
//database(s) unlocked
|
|
if ((App.Kp2a.OpenDatabases.Count() == 1) || (AppTask is SearchUrlTask))
|
|
{
|
|
LaunchingOther = true;
|
|
AppTask.LaunchFirstGroupActivity(this);
|
|
return;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//more than one database open or user requested to load another db. Don't launch another activity.
|
|
_adapter.Update();
|
|
_adapter.NotifyDataSetChanged();
|
|
|
|
base.OnResume();
|
|
}
|
|
|
|
private bool OpenAutoExecEntries(Database db)
|
|
{
|
|
try
|
|
{
|
|
string thisDevice = KeeAutoExecExt.ThisDeviceId;
|
|
foreach (var autoOpenItem in KeeAutoExecExt.GetAutoExecItems(db.KpDatabase))
|
|
{
|
|
if (!autoOpenItem.Enabled)
|
|
continue;
|
|
if (!KeeAutoExecExt.IsDeviceEnabled(autoOpenItem, thisDevice, out _))
|
|
continue;
|
|
if (!IsValidIoc(autoOpenItem))
|
|
continue;
|
|
|
|
IOConnectionInfo dbIoc;
|
|
if (KeeAutoExecExt.TryGetDatabaseIoc(autoOpenItem, out dbIoc) &&
|
|
App.Kp2a.TryGetDatabase(dbIoc) == null &&
|
|
App.Kp2a.AttemptedToOpenBefore(dbIoc) == false
|
|
)
|
|
{
|
|
if (KeeAutoExecExt.AutoOpenEntry(this, autoOpenItem, false, new ActivityLaunchModeRequestCode(ReqCodeOpenNewDb)))
|
|
{
|
|
LaunchingOther = true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Kp2aLog.LogUnexpectedError(e);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected override void OnPause()
|
|
{
|
|
LaunchingOther = false;
|
|
_isForeground = false;
|
|
base.OnPause();
|
|
}
|
|
|
|
private void StartFileSelect(bool makeCurrent, bool noForwardToPassword = false)
|
|
{
|
|
Intent intent = new Intent(this, typeof(FileSelectActivity));
|
|
AppTask.ToIntent(intent);
|
|
intent.PutExtra(FileSelectActivity.NoForwardToPasswordActivity, noForwardToPassword);
|
|
intent.PutExtra("MakeCurrent", makeCurrent);
|
|
LaunchingOther = true;
|
|
StartActivityForResult(intent, ReqCodeOpenNewDb);
|
|
}
|
|
|
|
private AppTask _appTask;
|
|
private AppTask AppTask
|
|
{
|
|
get { return _appTask; }
|
|
set
|
|
{
|
|
_appTask = value;
|
|
Kp2aLog.LogTask(value, MyDebugName);
|
|
}
|
|
}
|
|
private OpenDatabaseAdapter _adapter;
|
|
private MyBroadcastReceiver _intentReceiver;
|
|
private bool _isForeground;
|
|
|
|
public override void OnBackPressed()
|
|
{
|
|
base.OnBackPressed();
|
|
if (PreferenceManager.GetDefaultSharedPreferences(this)
|
|
.GetBoolean(GetString(Resource.String.LockWhenNavigateBack_key), false))
|
|
{
|
|
App.Kp2a.Lock();
|
|
}
|
|
//by leaving the app with the back button, the user probably wants to cancel the task
|
|
//The activity might be resumed (through Android's recent tasks list), then use a NullTask:
|
|
AppTask = new NullTask();
|
|
if (!IsFinishing)
|
|
Finish();
|
|
}
|
|
|
|
public override void Finish()
|
|
{
|
|
Kp2aLog.Log($"Finishing {MyDebugName}");
|
|
base.Finish();
|
|
}
|
|
|
|
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
|
{
|
|
base.OnActivityResult(requestCode, resultCode, data);
|
|
|
|
Kp2aLog.Log($"{MyDebugName}: OnActivityResult " + resultCode + "/" + requestCode);
|
|
|
|
AppTask appTask = null;
|
|
if (AppTask.TryGetFromActivityResult(data, ref appTask))
|
|
this.AppTask = appTask;
|
|
|
|
if (requestCode == ReqCodeOpenNewDb)
|
|
{
|
|
switch ((int)resultCode)
|
|
{
|
|
case (int)Result.Ok:
|
|
|
|
string iocString = data?.GetStringExtra("ioc");
|
|
IOConnectionInfo ioc = IOConnectionInfo.UnserializeFromString(iocString);
|
|
if (App.Kp2a.TrySelectCurrentDb(ioc))
|
|
{
|
|
if (OpenAutoExecEntries(App.Kp2a.CurrentDb)) return;
|
|
LaunchingOther = true;
|
|
AppTask.CanActivateSearchViewOnStart = true;
|
|
AppTask.LaunchFirstGroupActivity(this);
|
|
}
|
|
|
|
|
|
break;
|
|
case PasswordActivity.ResultSelectOtherFile:
|
|
StartFileSelect(true, true);
|
|
break;
|
|
case (int)Result.Canceled:
|
|
if (App.Kp2a.OpenDatabases.Any() == false)
|
|
{
|
|
//don't open fileselect/password activity again
|
|
OnBackPressed();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
switch (resultCode)
|
|
{
|
|
case KeePass.ExitNormal: // Returned to this screen using the Back key
|
|
if (App.Kp2a.OpenDatabases.Count() == 1)
|
|
{
|
|
OnBackPressed();
|
|
}
|
|
break;
|
|
case KeePass.ExitLock:
|
|
// The database has already been locked. No need to immediately return to quick unlock. Especially as this causes trouble for users with face unlock
|
|
// (db immediately unlocked again) and confused some users as the biometric prompt seemed to disable the device back button or at least they didn't understand
|
|
// why they should unlock...
|
|
SetResult(KeePass.ExitClose);
|
|
if (!IsFinishing)
|
|
Finish();
|
|
break;
|
|
case KeePass.ExitLockByTimeout:
|
|
//don't finish, bring up QuickUnlock
|
|
break;
|
|
case KeePass.ExitCloseAfterTaskComplete:
|
|
// Do not lock the database
|
|
SetResult(KeePass.ExitCloseAfterTaskComplete);
|
|
if (!IsFinishing)
|
|
Finish();
|
|
break;
|
|
case KeePass.ExitClose:
|
|
SetResult(KeePass.ExitClose);
|
|
if (!IsFinishing)
|
|
Finish();
|
|
break;
|
|
case KeePass.ExitReloadDb:
|
|
|
|
if (App.Kp2a.CurrentDb!= null)
|
|
{
|
|
//remember the composite key for reloading:
|
|
var compositeKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey;
|
|
var ioc = App.Kp2a.CurrentDb.Ioc;
|
|
|
|
//lock the database:
|
|
App.Kp2a.CloseDatabase(App.Kp2a.CurrentDb);
|
|
|
|
LaunchPasswordActivityForReload(ioc, compositeKey);
|
|
}
|
|
|
|
break;
|
|
case KeePass.ExitLoadAnotherDb:
|
|
StartFileSelect(true, true);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
private void LaunchPasswordActivityForReload(IOConnectionInfo ioc, CompositeKey compositeKey)
|
|
{
|
|
LaunchingOther = true;
|
|
PasswordActivity.Launch(this, ioc, compositeKey, new ActivityLaunchModeRequestCode(ReqCodeOpenNewDb), false);
|
|
}
|
|
|
|
public bool LaunchingOther { get; set; }
|
|
|
|
|
|
private class MyBroadcastReceiver : BroadcastReceiver
|
|
{
|
|
readonly SelectCurrentDbActivity _activity;
|
|
public MyBroadcastReceiver(SelectCurrentDbActivity activity)
|
|
{
|
|
_activity = activity;
|
|
}
|
|
|
|
public override void OnReceive(Context context, Intent intent)
|
|
{
|
|
switch (intent.Action)
|
|
{
|
|
case Intents.DatabaseLocked:
|
|
_activity.OnLockDatabase();
|
|
break;
|
|
case Intent.ActionScreenOff:
|
|
App.Kp2a.OnScreenOff();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnLockDatabase()
|
|
{
|
|
//app tasks are assumed to be finished/cancelled when the database is locked
|
|
AppTask = new NullTask();
|
|
//in case we are the foreground activity, we won't get OnResume (in contrast to having other activities on top of us on the stack).
|
|
//Call it to ensure we switch to QuickUnlock/fileselect
|
|
if (_isForeground)
|
|
OnResume();
|
|
}
|
|
}
|
|
} |