Working, but service dies after sharing

This commit is contained in:
AlexVallat 2013-07-26 20:10:03 +01:00
parent 0006a19066
commit 8c8c94c454
20 changed files with 484 additions and 507 deletions

View File

@ -1,37 +1,27 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.18051
// This code was generated by a tool.
// Runtime Version:4.0.30319.2012
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: global::Android.Runtime.ResourceDesignerAttribute("KeePassLib2Android.Resource", IsApplication=false)]
[assembly: Android.Runtime.ResourceDesignerAttribute("KeePassLib2Android.Resource", IsApplication=false)]
namespace KeePassLib2Android
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Novell.MonoDroid.Build.Tasks", "1.0.0.0")]
public partial class Resource
{
static Resource()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
public partial class Attribute
{
static Attribute()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Attribute()
{
}
@ -43,11 +33,6 @@ namespace KeePassLib2Android
// aapt resource value: 0x7f020000
public static int library_name = 2130837504;
static String()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private String()
{
}

View File

@ -249,7 +249,7 @@ namespace keepass2android
return true;
case Resource.Id.menu_app_settings:
AppSettingsActivity.Launch(this);
DatabaseSettingsActivity.Launch(this);
return true;
case Resource.Id.menu_change_master_key:

View File

@ -39,7 +39,7 @@ namespace keepass2android
_intentReceiver = new LockCloseActivityBroadcastReceiver(this);
IntentFilter filter = new IntentFilter();
filter.AddAction(Intents.LockDatabase);
filter.AddAction(Intents.DatabaseLocked);
RegisterReceiver(_intentReceiver, filter);
}
@ -85,7 +85,7 @@ namespace keepass2android
{
switch (intent.Action)
{
case Intents.LockDatabase:
case Intents.DatabaseLocked:
_service.OnLockDatabase();
break;
}

View File

@ -43,7 +43,7 @@ namespace keepass2android
_intentReceiver = new LockCloseListActivityBroadcastReceiver(this);
IntentFilter filter = new IntentFilter();
filter.AddAction(Intents.LockDatabase);
filter.AddAction(Intents.DatabaseLocked);
RegisterReceiver(_intentReceiver, filter);
}
@ -92,7 +92,7 @@ namespace keepass2android
{
switch (intent.Action)
{
case Intents.LockDatabase:
case Intents.DatabaseLocked:
_service.OnLockDatabase();
break;
}

View File

@ -36,7 +36,7 @@ namespace keepass2android
_intentReceiver = new LockingClosePreferenceActivityBroadcastReceiver(this);
IntentFilter filter = new IntentFilter();
filter.AddAction(Intents.LockDatabase);
filter.AddAction(Intents.DatabaseLocked);
RegisterReceiver(_intentReceiver, filter);
}
@ -74,7 +74,7 @@ namespace keepass2android
{
switch (intent.Action)
{
case Intents.LockDatabase:
case Intents.DatabaseLocked:
_service.OnLockDatabase();
break;
}

View File

@ -164,7 +164,8 @@ namespace keepass2android
case KeePass.ExitForceLockAndChangeDb:
case KeePass.ExitChangeDb: // What's the difference between this and ExitForceLockAndChangeDb?
case KeePass.ExitNormal: // Returned to this screen using the Back key, treat as exiting the database
App.Kp2a.LockDatabase(false, Finish);
App.Kp2a.LockDatabase(false);
Finish();
break;
case KeePass.ExitCloseAfterTaskComplete:
SetResult(KeePass.ExitCloseAfterTaskComplete);
@ -222,7 +223,7 @@ namespace keepass2android
if (!App.Kp2a.QuickUnlockEnabled)
{
// We're exiting (probably task-killed), so stop the service, if it's still running - don't want it hanging around with an icon shown.
StopService(new Intent(this, typeof(Keepass2AndroidService)));
StopService(new Intent(this, typeof(OngoingNotificationsService)));
}
}

View File

@ -1199,47 +1199,47 @@ namespace keepass2android
// aapt resource value: 0x7f080034
public const int AboutText = 2131230772;
// aapt resource value: 0x7f080124
public const int AddingEntry = 2131231012;
// aapt resource value: 0x7f080126
public const int AddingEntry = 2131231014;
// aapt resource value: 0x7f080125
public const int AddingGroup = 2131231013;
// aapt resource value: 0x7f08011a
public const int AskDeletePermanentlyEntry = 2131231002;
// aapt resource value: 0x7f08011b
public const int AskDeletePermanentlyGroup = 2131231003;
// aapt resource value: 0x7f080127
public const int AddingGroup = 2131231015;
// aapt resource value: 0x7f08011c
public const int AskDeletePermanently_title = 2131231004;
// aapt resource value: 0x7f08011f
public const int AskDiscardChanges = 2131231007;
// aapt resource value: 0x7f080120
public const int AskDiscardChanges_title = 2131231008;
// aapt resource value: 0x7f080114
public const int AskOverwriteBinary = 2131230996;
// aapt resource value: 0x7f080117
public const int AskOverwriteBinary_no = 2131230999;
// aapt resource value: 0x7f080115
public const int AskOverwriteBinary_title = 2131230997;
// aapt resource value: 0x7f080116
public const int AskOverwriteBinary_yes = 2131230998;
// aapt resource value: 0x7f08011e
public const int AskReloadFile = 2131231006;
public const int AskDeletePermanentlyEntry = 2131231004;
// aapt resource value: 0x7f08011d
public const int AskReloadFile_title = 2131231005;
public const int AskDeletePermanentlyGroup = 2131231005;
// aapt resource value: 0x7f08011e
public const int AskDeletePermanently_title = 2131231006;
// aapt resource value: 0x7f080121
public const int AskDiscardChanges = 2131231009;
// aapt resource value: 0x7f080122
public const int AskDiscardChanges_title = 2131231010;
// aapt resource value: 0x7f080116
public const int AskOverwriteBinary = 2131230998;
// aapt resource value: 0x7f080119
public const int AskOverwriteBinary_no = 2131231001;
// aapt resource value: 0x7f080117
public const int AskOverwriteBinary_title = 2131230999;
// aapt resource value: 0x7f080118
public const int AttachFailed = 2131231000;
public const int AskOverwriteBinary_yes = 2131231000;
// aapt resource value: 0x7f080120
public const int AskReloadFile = 2131231008;
// aapt resource value: 0x7f08011f
public const int AskReloadFile_title = 2131231007;
// aapt resource value: 0x7f08011a
public const int AttachFailed = 2131231002;
// aapt resource value: 0x7f080021
public const int BinaryDirectory_default = 2131230753;
@ -1253,32 +1253,32 @@ namespace keepass2android
// aapt resource value: 0x7f0800f7
public const int BinaryDirectory_title = 2131230967;
// aapt resource value: 0x7f08013b
public const int ChangeLog = 2131231035;
// aapt resource value: 0x7f08013d
public const int ChangeLog = 2131231037;
// aapt resource value: 0x7f08013c
public const int ChangeLog_0_7 = 2131231036;
// aapt resource value: 0x7f08013a
public const int ChangeLog_0_7 = 2131231034;
// aapt resource value: 0x7f080138
public const int ChangeLog_0_8 = 2131231032;
// aapt resource value: 0x7f080137
public const int ChangeLog_0_8_1 = 2131231031;
// aapt resource value: 0x7f080136
public const int ChangeLog_0_8_2 = 2131231030;
// aapt resource value: 0x7f080135
public const int ChangeLog_0_8_3 = 2131231029;
// aapt resource value: 0x7f080134
public const int ChangeLog_0_8_4 = 2131231028;
public const int ChangeLog_0_8 = 2131231034;
// aapt resource value: 0x7f080139
public const int ChangeLog_keptDonate = 2131231033;
public const int ChangeLog_0_8_1 = 2131231033;
// aapt resource value: 0x7f080133
public const int ChangeLog_title = 2131231027;
// aapt resource value: 0x7f080138
public const int ChangeLog_0_8_2 = 2131231032;
// aapt resource value: 0x7f080137
public const int ChangeLog_0_8_3 = 2131231031;
// aapt resource value: 0x7f080136
public const int ChangeLog_0_8_4 = 2131231030;
// aapt resource value: 0x7f08013b
public const int ChangeLog_keptDonate = 2131231035;
// aapt resource value: 0x7f080135
public const int ChangeLog_title = 2131231029;
// aapt resource value: 0x7f080028
public const int CheckForFileChangesOnSave_key = 2131230760;
@ -1289,8 +1289,8 @@ namespace keepass2android
// aapt resource value: 0x7f08010c
public const int CheckForFileChangesOnSave_title = 2131230988;
// aapt resource value: 0x7f08012d
public const int CheckingTargetFileForChanges = 2131231021;
// aapt resource value: 0x7f08012f
public const int CheckingTargetFileForChanges = 2131231023;
// aapt resource value: 0x7f080049
public const int ClearClipboard = 2131230793;
@ -1301,14 +1301,14 @@ namespace keepass2android
// aapt resource value: 0x7f080035
public const int CreditsText = 2131230773;
// aapt resource value: 0x7f08012b
public const int DecodingDatabase = 2131231019;
// aapt resource value: 0x7f08012d
public const int DecodingDatabase = 2131231021;
// aapt resource value: 0x7f080126
public const int DeletingEntry = 2131231014;
// aapt resource value: 0x7f080128
public const int DeletingEntry = 2131231016;
// aapt resource value: 0x7f080127
public const int DeletingGroup = 2131231015;
// aapt resource value: 0x7f080129
public const int DeletingGroup = 2131231017;
// aapt resource value: 0x7f080082
public const int FileNotFound = 2131230850;
@ -1325,11 +1325,11 @@ namespace keepass2android
// aapt resource value: 0x7f08009f
public const int MaskedPassword = 2131230879;
// aapt resource value: 0x7f08012f
public const int MessageSyncQuestion = 2131231023;
// aapt resource value: 0x7f080131
public const int MessageSyncQuestion = 2131231025;
// aapt resource value: 0x7f080132
public const int NoOverwrite = 2131231026;
// aapt resource value: 0x7f080134
public const int NoOverwrite = 2131231028;
// aapt resource value: 0x7f08002e
public const int OpenKp2aKeyboardAutomatically_key = 2131230766;
@ -1340,8 +1340,8 @@ namespace keepass2android
// aapt resource value: 0x7f080112
public const int OpenKp2aKeyboardAutomatically_title = 2131230994;
// aapt resource value: 0x7f08012c
public const int ParsingDatabase = 2131231020;
// aapt resource value: 0x7f08012e
public const int ParsingDatabase = 2131231022;
// aapt resource value: 0x7f080022
public const int QuickUnlockDefaultEnabled_key = 2131230754;
@ -1376,8 +1376,8 @@ namespace keepass2android
// aapt resource value: 0x7f0800f1
public const int QuickUnlock_lockButton = 2131230961;
// aapt resource value: 0x7f080119
public const int RecycleBin = 2131231001;
// aapt resource value: 0x7f08011b
public const int RecycleBin = 2131231003;
// aapt resource value: 0x7f0800fc
public const int SaveAttachmentDialog_open = 2131230972;
@ -1397,8 +1397,8 @@ namespace keepass2android
// aapt resource value: 0x7f0800fd
public const int SaveAttachment_doneMessage = 2131230973;
// aapt resource value: 0x7f080128
public const int SettingPassword = 2131231016;
// aapt resource value: 0x7f08012a
public const int SettingPassword = 2131231018;
// aapt resource value: 0x7f08010f
public const int ShowCopyToClipboardNotification_summary = 2131230991;
@ -1415,6 +1415,12 @@ namespace keepass2android
// aapt resource value: 0x7f080031
public const int ShowUnlockedNotification_key = 2131230769;
// aapt resource value: 0x7f080115
public const int ShowUnlockedNotification_summary = 2131230997;
// aapt resource value: 0x7f080114
public const int ShowUnlockedNotification_title = 2131230996;
// aapt resource value: 0x7f08001d
public const int ShowUsernameInList_key = 2131230749;
@ -1427,8 +1433,8 @@ namespace keepass2android
// aapt resource value: 0x7f08002a
public const int SuggestionsURL = 2131230762;
// aapt resource value: 0x7f080130
public const int SynchronizingDatabase = 2131231024;
// aapt resource value: 0x7f080132
public const int SynchronizingDatabase = 2131231026;
// aapt resource value: 0x7f08001c
public const int TanExpiresOnUse_key = 2131230748;
@ -1439,17 +1445,17 @@ namespace keepass2android
// aapt resource value: 0x7f0800e0
public const int TanExpiresOnUse_title = 2131230944;
// aapt resource value: 0x7f08012e
public const int TitleSyncQuestion = 2131231022;
// aapt resource value: 0x7f080130
public const int TitleSyncQuestion = 2131231024;
// aapt resource value: 0x7f08012a
public const int TransformingKey = 2131231018;
// aapt resource value: 0x7f08012c
public const int TransformingKey = 2131231020;
// aapt resource value: 0x7f08002b
public const int TranslationURL = 2131230763;
// aapt resource value: 0x7f080129
public const int UndoingChanges = 2131231017;
// aapt resource value: 0x7f08012b
public const int UndoingChanges = 2131231019;
// aapt resource value: 0x7f080025
public const int UsageCount_key = 2131230757;
@ -1466,8 +1472,8 @@ namespace keepass2android
// aapt resource value: 0x7f08002d
public const int UseKp2aKeyboard_key = 2131230765;
// aapt resource value: 0x7f080131
public const int YesSynchronize = 2131231025;
// aapt resource value: 0x7f080133
public const int YesSynchronize = 2131231027;
// aapt resource value: 0x7f080032
public const int about_feedback = 2131230770;
@ -2018,8 +2024,8 @@ namespace keepass2android
// aapt resource value: 0x7f080103
public const int protection = 2131230979;
// aapt resource value: 0x7f080122
public const int rate_app = 2131231010;
// aapt resource value: 0x7f080124
public const int rate_app = 2131231012;
// aapt resource value: 0x7f0800df
public const int regular_expression = 2131230943;
@ -2111,11 +2117,11 @@ namespace keepass2android
// aapt resource value: 0x7f0800ea
public const int start_open_url = 2131230954;
// aapt resource value: 0x7f080121
public const int suggest_improvements = 2131231009;
// aapt resource value: 0x7f080123
public const int translate_app = 2131231011;
public const int suggest_improvements = 2131231011;
// aapt resource value: 0x7f080125
public const int translate_app = 2131231013;
// aapt resource value: 0x7f0800d8
public const int twofish = 2131230936;

View File

@ -229,6 +229,9 @@
<string name="ShowKp2aKeyboardNotification_summary">Make full entry accessible through the KP2A keyboard (recommended).</string>
<string name="OpenKp2aKeyboardAutomatically_title">Keyboard selection dialog</string>
<string name="OpenKp2aKeyboardAutomatically_summary">Open keyboard selection dialog when entry is available through KP2A keyboard after search.</string>
<string name="ShowUnlockedNotification_title">Notification while unlocked</string>
<string name="ShowUnlockedNotification_summary">Show an ongoing notification while the database is unlocked.</string>
<string name="AskOverwriteBinary">Do you want to overwrite the existing binary with the same name?</string>
<string name="AskOverwriteBinary_title">Overwrite existing binary?</string>

View File

@ -71,6 +71,13 @@
android:entryValues="@array/clipboard_timeout_values"
android:dialogTitle="@string/app_timeout"
android:defaultValue="@string/clipboard_timeout_default"/>
<CheckBoxPreference
android:enabled="true"
android:persistent="true"
android:summary="@string/ShowUnlockedNotification_summary"
android:defaultValue="@bool/ShowUnlockedNotification_default"
android:title="@string/ShowUnlockedNotification_title"
android:key="@string/ShowUnlockedNotification_key" />
<CheckBoxPreference
android:key="@string/maskpass_key"
android:title="@string/maskpass_title"

View File

@ -63,36 +63,10 @@ namespace keepass2android
public class Kp2aApp: IKp2aApp
{
public void LockDatabase(bool allowQuickUnlock = true)
{
if (!allowQuickUnlock)
{
QuickUnlockEnabled = false;
}
Application.Context.SendBroadcast(new Intent(Intents.LockDatabase));
}
/// <summary>
/// Locks the database, then runs the specified action once the locking has completed.
/// </summary>
/// <param name="allowQuickUnlock"></param>
/// <param name="runAfterLocked"></param>
internal void LockDatabase(bool allowQuickUnlock, Action runAfterLocked)
{
_actionsToRunAfterLock.Enqueue(runAfterLocked);
LockDatabase(allowQuickUnlock);
}
private readonly Queue<Action> _actionsToRunAfterLock = new Queue<Action>();
/// <summary>
/// Do not call this directly, instead call LockDatabase
/// </summary>
internal void LockDatabaseInternal(Keepass2AndroidService service)
{
if (_db.Loaded)
{
if (QuickUnlockEnabled &&
if (QuickUnlockEnabled && allowQuickUnlock &&
_db.KpDatabase.MasterKey.ContainsType(typeof(KcpPassword)) &&
!((KcpPassword)App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof(KcpPassword))).Password.IsEmpty)
{
@ -101,10 +75,6 @@ namespace keepass2android
Kp2aLog.Log("QuickLocking database");
QuickLocked = true;
// Start the service to show the quicklock icon
var ctx = Application.Context;
ctx.StartService(new Intent(ctx, typeof(Keepass2AndroidService)));
}
else
{
@ -125,41 +95,29 @@ namespace keepass2android
Kp2aLog.Log("Database not loaded, couldn't lock");
}
while (_actionsToRunAfterLock.Count > 0)
{
var action = _actionsToRunAfterLock.Dequeue();
action();
}
UpdateOngoingNotification();
Application.Context.SendBroadcast(new Intent(Intents.DatabaseLocked));
}
public void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, string password, string keyFile, ProgressDialogStatusLogger statusLogger)
{
_db.LoadData(this, ioConnectionInfo, memoryStream, password, keyFile, statusLogger);
var ctx = Application.Context;
ctx.StartService(new Intent(ctx, typeof(Keepass2AndroidService)));
UpdateOngoingNotification();
}
public void UnlockDatabase(Action runAfterUnlocked)
{
_actionsToRunAfterUnlock.Enqueue(runAfterUnlocked);
Application.Context.SendBroadcast(new Intent(Intents.UnlockDatabase));
}
private readonly Queue<Action> _actionsToRunAfterUnlock = new Queue<Action>();
/// <summary>
/// Do not call this directly, instead call UnlockDatabase
/// </summary>
internal void UnlockDatabaseInternal(Keepass2AndroidService service)
internal void UnlockDatabase()
{
QuickLocked = false;
while (_actionsToRunAfterUnlock.Count > 0)
{
var action = _actionsToRunAfterUnlock.Dequeue();
action();
}
UpdateOngoingNotification();
}
private void UpdateOngoingNotification()
{
// Start or update the notification icon service to reflect the current state
var ctx = Application.Context;
ctx.StartService(new Intent(ctx, typeof(OngoingNotificationsService)));
}
public bool DatabaseIsUnlocked

View File

@ -0,0 +1,25 @@
using System;
using System.Linq;
using Android.Content;
using Android.App;
namespace keepass2android
{
[BroadcastReceiver]
[IntentFilter(new[] { Intents.LockDatabase })]
public class ApplicationBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Kp2aLog.Log("Received broadcast intent: " + intent.Action);
switch (intent.Action)
{
case Intents.LockDatabase:
App.Kp2a.LockDatabase();
break;
}
}
}
}

View File

@ -303,6 +303,9 @@ namespace keepass2android
public override void Run() {
if (Success) {
// Update the ongoing notification
_activity.StartService(new Intent(_activity, typeof(OngoingNotificationsService)));
// Add to recent files
FileDbHelper dbHelper = App.Kp2a.FileDbHelper;

View File

@ -22,11 +22,14 @@ namespace keepass2android
/// <summary>
/// Contains constants to be used in intents
/// </summary>
public class Intents {
public const String Timeout = "keepass2android.timeout";
public class Intents
{
/// <summary>Broadcast this intent to lock the database</summary>
public const String LockDatabase = "keepass2android.lock_database";
public const String UnlockDatabase = "keepass2android.unlock_database";
/// <summary>This intent will be broadcast once the database has been locked. Sensitive information displayed should be hidden and unloaded.</summary>
public const String DatabaseLocked = "keepass2android.database_locked";
public const String CopyUsername = "keepass2android.copy_username";
public const String CopyPassword = "keepass2android.copy_password";
public const String CheckKeyboard = "keepass2android.check_keyboard";

View File

@ -77,6 +77,7 @@
<Reference Include="Mono.Android.Support.v4" />
</ItemGroup>
<ItemGroup>
<Compile Include="app\ApplicationBroadcastReceiver.cs" />
<Compile Include="icons\DrawableFactory.cs" />
<Compile Include="icons\Icons.cs" />
<Compile Include="Resources\Resource.designer.cs" />
@ -86,7 +87,8 @@
<Compile Include="fileselect\FileSelectActivity.cs" />
<Compile Include="fileselect\FileDbHelper.cs" />
<Compile Include="search\SearchProvider.cs" />
<Compile Include="services\Keepass2AndroidService.cs" />
<Compile Include="services\OngoingNotificationsService.cs" />
<Compile Include="settings\DatabaseSettingsActivity.cs" />
<Compile Include="Utils\Util.cs" />
<Compile Include="intents\Intents.cs" />
<Compile Include="fileselect\BrowserDialog.cs" />

View File

@ -76,7 +76,7 @@ namespace keepass2android
_stopOnLockBroadcastReceiver = new StopOnLockBroadcastReceiver(this);
IntentFilter filter = new IntentFilter();
filter.AddAction(Intents.LockDatabase);
filter.AddAction(Intents.DatabaseLocked);
RegisterReceiver(_stopOnLockBroadcastReceiver, filter);
String uuidBytes = intent.GetStringExtra(EntryActivity.KeyEntry);
@ -386,7 +386,7 @@ namespace keepass2android
{
switch (intent.Action)
{
case Intents.LockDatabase:
case Intents.DatabaseLocked:
_service.OnLockDatabase();
break;
}

View File

@ -1,227 +0,0 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Preferences;
using Android.Support.V4.App;
using KeePassLib.Utility;
namespace keepass2android
{
/// <summary>
/// General purpose service for Keepass2Android
///
/// Manages timeout to lock the database after some idle time
/// Shows database unlocked warning persistent notification
/// Shows Quick-Unlock notification
/// </summary>
[Service]
public class Keepass2AndroidService : Service {
#region Service
private const int ServiceId = 238787;
private BroadcastReceiver _intentReceiver;
public override void OnCreate() {
base.OnCreate();
_intentReceiver = new Keepass2AndroidServiceBroadcastReceiver(this);
IntentFilter filter = new IntentFilter();
filter.AddAction(Intents.Timeout);
filter.AddAction(Intents.LockDatabase);
filter.AddAction(Intents.UnlockDatabase);
RegisterReceiver(_intentReceiver, filter);
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Kp2aLog.Log("Starting Keepass2AndroidService");
var prefs = PreferenceManager.GetDefaultSharedPreferences(this);
Notification notification = null;
if (prefs.GetBoolean(GetString(Resource.String.ShowUnlockedNotification_key), Resources.GetBoolean(Resource.Boolean.ShowUnlockedNotification_default))
&& App.Kp2a.DatabaseIsUnlocked)
{
// Show the Unlocked icon
notification = GetUnlockedNotification();
}
else if (App.Kp2a.QuickUnlockEnabled)
{
// Show the Quick Unlock icon
notification = GetQuickUnlockNotification();
}
if (notification != null)
{
if (App.Kp2a.QuickUnlockEnabled)
{
StartForeground(ServiceId, notification);
}
else
{
// Doesn't actually need to be persistent in memory, allow it to be killed as required
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(ServiceId, notification);
}
}
return StartCommandResult.NotSticky;
}
public override void OnDestroy()
{
base.OnDestroy();
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Cancel(ServiceId);
Kp2aLog.Log("Destroying Keepass2AndroidService");
UnregisterReceiver(_intentReceiver);
// The service will be stopped deliberately to cause the database to lock.
// If the service is killed, then also lock the database immediately (as timeout will no longer work, and the unlocked warning icon will no longer display)
Application.Context.SendBroadcast(new Intent(Intents.LockDatabase)); // Ensure all other listeners receive the Lock broadcast
App.Kp2a.LockDatabaseInternal(this);
}
public override IBinder OnBind(Intent intent)
{
return null;
}
#endregion
#region Timeout
private void Timeout()
{
Kp2aLog.Log("Timeout");
StopSelf();
}
#endregion
#region QuickUnlock
private Notification GetQuickUnlockNotification()
{
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.SetSmallIcon(Resource.Drawable.ic_launcher_gray)
.SetLargeIcon(BitmapFactory.DecodeResource(Resources, AppNames.LauncherIcon))
.SetContentTitle(GetText(Resource.String.app_name))
.SetContentText(GetString(Resource.String.database_loaded_quickunlock_enabled, GetDatabaseName()));
Intent startKp2aIntent = new Intent(this, typeof(KeePass));
startKp2aIntent.SetAction(Intent.ActionMain);
startKp2aIntent.AddCategory(Intent.CategoryLauncher);
PendingIntent startKp2APendingIntent =
PendingIntent.GetActivity(this, 0, startKp2aIntent, PendingIntentFlags.UpdateCurrent);
builder.SetContentIntent(startKp2APendingIntent);
return builder.Build();
}
#endregion
#region Unlocked Warning
private Notification GetUnlockedNotification()
{
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.SetOngoing(true)
.SetSmallIcon(Resource.Drawable.ic_unlocked_gray)
.SetLargeIcon(BitmapFactory.DecodeResource(Resources, Resource.Drawable.ic_launcher_red))
.SetContentTitle(GetText(Resource.String.app_name))
.SetContentText(GetString(Resource.String.database_loaded_unlocked, GetDatabaseName()));
builder.SetContentIntent(PendingIntent.GetBroadcast(this, 0, new Intent(Intents.LockDatabase), PendingIntentFlags.UpdateCurrent));
return builder.Build();
}
private static string GetDatabaseName()
{
var db = App.Kp2a.GetDb().KpDatabase;
var name = db.Name;
if (String.IsNullOrEmpty(name))
{
name = UrlUtil.StripExtension(UrlUtil.GetFileName(db.IOConnectionInfo.Path));
}
return name;
}
private void LockDatabase()
{
Kp2aLog.Log("LockDatabase");
StopSelf();
}
private void UnlockDatabase()
{
Kp2aLog.Log("UnlockDatabase");
// Replace the QuickLock icon with the Unlocked icon. QuickLockEnabled must be true, so we need a foreground service to prevent being killed
StartForeground(ServiceId, GetUnlockedNotification());
App.Kp2a.UnlockDatabaseInternal(this);
}
#endregion
[BroadcastReceiver]
private class Keepass2AndroidServiceBroadcastReceiver: BroadcastReceiver
{
public Keepass2AndroidServiceBroadcastReceiver()
{
//dummy constructor required for MonoForAndroid, not called.
throw new NotImplementedException();
}
readonly Keepass2AndroidService _service;
public Keepass2AndroidServiceBroadcastReceiver(Keepass2AndroidService service)
{
_service = service;
}
public override void OnReceive(Context context, Intent intent)
{
switch (intent.Action)
{
case Intents.Timeout:
_service.Timeout();
break;
case Intents.LockDatabase:
_service.LockDatabase();
break;
case Intents.UnlockDatabase:
_service.UnlockDatabase();
break;
}
}
}
}
}

View File

@ -0,0 +1,166 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Preferences;
using Android.Support.V4.App;
using KeePassLib.Utility;
namespace keepass2android
{
/// <summary>
/// Service for showing ongoing notifications
///
/// Shows database unlocked warning persistent notification
/// Shows Quick-Unlock notification
/// </summary>
[Service]
public class OngoingNotificationsService : Service
{
#region Service
private const int QuickUnlockId = 100;
private const int UnlockedWarningId = 200;
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Kp2aLog.Log("Starting/Updating OngoingNotificationsService. Database " + (App.Kp2a.DatabaseIsUnlocked ? "Unlocked" : (App.Kp2a.QuickLocked ? "QuickLocked" : "Locked")));
// Clear current foreground status and QuickUnlock icon
StopForeground(true);
// Set the icon to reflect the current state
if (App.Kp2a.DatabaseIsUnlocked && ShowUnlockedNotification)
{
StartForeground(UnlockedWarningId, GetUnlockedNotification());
}
else if (App.Kp2a.QuickLocked)
{
// Show the Quick Unlock notification
StartForeground(QuickUnlockId, GetQuickUnlockNotification());
}
return StartCommandResult.NotSticky;
}
private bool ShowUnlockedNotification
{
get { return PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(GetString(Resource.String.ShowUnlockedNotification_key), Resources.GetBoolean(Resource.Boolean.ShowUnlockedNotification_default)); }
}
public override void OnTaskRemoved(Intent rootIntent)
{
base.OnTaskRemoved(rootIntent);
Kp2aLog.Log("OngoingNotificationsService.OnTaskRemoved");
// If the user has closed the task (probably by swiping it out of the recent apps list) then lock the database
App.Kp2a.LockDatabase();
}
public override void OnDestroy()
{
base.OnDestroy();
Kp2aLog.Log("OngoingNotificationsService.OnDestroy2");
if (ShowUnlockedNotification)
{
// If the service is killed, then lock the database immediately (as the unlocked warning icon will no longer display).
App.Kp2a.LockDatabase();
}
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnLowMemory()
{
base.OnLowMemory();
Kp2aLog.Log("OngoingNotificationsService.OnLowMemory");
if (App.Kp2a.DatabaseIsUnlocked && !App.Kp2a.QuickUnlockEnabled)
{
// Although this is a foreground service, if it is only indicating that the database is unlocked then it isn't of foreground-importance,
// and can be killed if Android requests it (which will clear the database and free up some memory)
StopSelf();
}
}
#endregion
#region QuickUnlock
private Notification GetQuickUnlockNotification()
{
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.SetSmallIcon(Resource.Drawable.ic_launcher_gray)
.SetLargeIcon(BitmapFactory.DecodeResource(Resources, AppNames.LauncherIcon))
.SetContentTitle(GetText(Resource.String.app_name))
.SetContentText(GetString(Resource.String.database_loaded_quickunlock_enabled, GetDatabaseName()));
Intent startKp2aIntent = new Intent(this, typeof(KeePass));
startKp2aIntent.SetAction(Intent.ActionMain);
startKp2aIntent.AddCategory(Intent.CategoryLauncher);
PendingIntent startKp2APendingIntent =
PendingIntent.GetActivity(this, 0, startKp2aIntent, PendingIntentFlags.UpdateCurrent);
builder.SetContentIntent(startKp2APendingIntent);
return builder.Build();
}
#endregion
#region Unlocked Warning
private Notification GetUnlockedNotification()
{
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.SetOngoing(true)
.SetSmallIcon(Resource.Drawable.ic_unlocked_gray)
.SetLargeIcon(BitmapFactory.DecodeResource(Resources, Resource.Drawable.ic_launcher_red))
.SetContentTitle(GetText(Resource.String.app_name))
.SetContentText(GetString(Resource.String.database_loaded_unlocked, GetDatabaseName()));
builder.SetContentIntent(PendingIntent.GetBroadcast(this, 0, new Intent(Intents.LockDatabase), PendingIntentFlags.UpdateCurrent));
return builder.Build();
}
private static string GetDatabaseName()
{
var db = App.Kp2a.GetDb().KpDatabase;
var name = db.Name;
if (String.IsNullOrEmpty(name))
{
name = UrlUtil.StripExtension(UrlUtil.GetFileName(db.IOConnectionInfo.Path));
}
return name;
}
#endregion
}
}

View File

@ -16,121 +16,49 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
using System.Globalization;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Widget;
using Android.Preferences;
using KeePassLib.Cryptography.Cipher;
namespace keepass2android
{
/// <summary>
/// Activity to configure the app
/// Activity to configure the application, without database settings. Does not require an unlocked database, or close when the database is locked
/// </summary>
[Activity (Label = "@string/app_name", Theme="@style/NoTitleBar")]
public class AppSettingsActivity : LockingClosePreferenceActivity {
public static bool KeyfileDefault = false;
public static void Launch(Context ctx) {
Intent i = new Intent(ctx, typeof(AppSettingsActivity));
ctx.StartActivity(i);
public class AppSettingsActivity : LockingPreferenceActivity
{
public static void Launch(Context ctx)
{
ctx.StartActivity(new Intent(ctx, typeof(AppSettingsActivity)));
}
protected override void OnCreate(Bundle savedInstanceState) {
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
AddPreferencesFromResource(Resource.Xml.preferences);
Preference keyFile = FindPreference(GetString(Resource.String.keyfile_key));
keyFile.PreferenceChange += (sender, e) =>
FindPreference(GetString(Resource.String.keyfile_key)).PreferenceChange += OnRememberKeyFileHistoryChanged;
FindPreference(GetString(Resource.String.ShowUnlockedNotification_key)).PreferenceChange += OnShowUnlockedNotificationChanged;;
FindPreference(GetString(Resource.String.db_key)).Enabled = false;
}
internal static void OnRememberKeyFileHistoryChanged(object sender, Preference.PreferenceChangeEventArgs eventArgs)
{
if (!(bool)eventArgs.NewValue)
{
bool value = (bool) e.NewValue;
if ( ! value ) {
FileDbHelper helper = App.Kp2a.FileDbHelper;
helper.DeleteAllKeys();
}
};
if (App.Kp2a.DatabaseIsUnlocked)
{
Database db = App.Kp2a.GetDb();
Preference rounds = FindPreference(GetString(Resource.String.rounds_key));
rounds.PreferenceChange += (sender, e) => setRounds(db, e.Preference);
Preference defaultUser = FindPreference(GetString(Resource.String.default_username_key));
((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) =>
{
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();
};
Preference databaseName = FindPreference(GetString(Resource.String.database_name_key));
((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();
}
}));
ProgressTask pt = new ProgressTask(App.Kp2a, this, save);
pt.Run();
};
setRounds(db, rounds);
Preference algorithm = FindPreference(GetString(Resource.String.algorithm_key));
setAlgorithm(db, algorithm);
} else {
Preference dbSettings = FindPreference(GetString(Resource.String.db_key));
dbSettings.Enabled = false;
App.Kp2a.FileDbHelper.DeleteAllKeys();
}
}
private void setRounds(Database db, Preference rounds) {
rounds.Summary = db.KpDatabase.KeyEncryptionRounds.ToString(CultureInfo.InvariantCulture);
internal static void OnShowUnlockedNotificationChanged(object sender, Preference.PreferenceChangeEventArgs eventArgs)
{
var ctx = ((Preference)sender).Context;
ctx.StartService(new Intent(ctx, typeof(OngoingNotificationsService)));
}
private void setAlgorithm(Database db, Preference algorithm) {
algorithm.Summary = CipherPool.GlobalPool.GetCipher(db.KpDatabase.DataCipherUuid).DisplayName;
}
}
}

View File

@ -0,0 +1,121 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Globalization;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Widget;
using Android.Preferences;
using KeePassLib.Cryptography.Cipher;
namespace keepass2android
{
/// <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/NoTitleBar")]
public class DatabaseSettingsActivity : LockingClosePreferenceActivity
{
public static void Launch(Context ctx)
{
ctx.StartActivity(new Intent(ctx, typeof(DatabaseSettingsActivity)));
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
AddPreferencesFromResource(Resource.Xml.preferences);
// Re-use the change handlers for the application settings
FindPreference(GetString(Resource.String.keyfile_key)).PreferenceChange += AppSettingsActivity.OnRememberKeyFileHistoryChanged;
FindPreference(GetString(Resource.String.ShowUnlockedNotification_key)).PreferenceChange += AppSettingsActivity.OnShowUnlockedNotificationChanged;
Database db = App.Kp2a.GetDb();
Preference rounds = FindPreference(GetString(Resource.String.rounds_key));
rounds.PreferenceChange += (sender, e) => SetRounds(db, e.Preference);
Preference defaultUser = FindPreference(GetString(Resource.String.default_username_key));
((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) =>
{
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();
};
Preference databaseName = FindPreference(GetString(Resource.String.database_name_key));
((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
StartService(new Intent(this, typeof(OngoingNotificationsService)));
}
}));
ProgressTask pt = new ProgressTask(App.Kp2a, this, save);
pt.Run();
};
SetRounds(db, rounds);
Preference algorithm = FindPreference(GetString(Resource.String.algorithm_key));
SetAlgorithm(db, algorithm);
}
private void SetRounds(Database db, Preference rounds)
{
rounds.Summary = db.KpDatabase.KeyEncryptionRounds.ToString(CultureInfo.InvariantCulture);
}
private void SetAlgorithm(Database db, Preference algorithm)
{
algorithm.Summary = CipherPool.GlobalPool.GetCipher(db.KpDatabase.DataCipherUuid).DisplayName;
}
}
}

View File

@ -31,15 +31,11 @@ namespace keepass2android
private static class Timeout
{
private const int RequestId = 0;
private const long DefaultTimeout = 5 * 60 * 1000; // 5 minutes
private static PendingIntent BuildIntent(Context ctx)
{
Intent intent = new Intent(Intents.Timeout);
PendingIntent sender = PendingIntent.GetBroadcast(ctx, RequestId, intent, PendingIntentFlags.CancelCurrent);
return sender;
return PendingIntent.GetBroadcast(ctx, 0, new Intent(Intents.LockDatabase), PendingIntentFlags.UpdateCurrent);
}
public static void Start(Context ctx)