* Make OngoingNotificationsService foreground also when unlocked (to prevent the app from being killed)

* Allow to hide icon for QuickUnlock by using minimum priority notification (API level >= 16)
This commit is contained in:
Philipp Crocoll 2014-04-15 06:03:22 +02:00
parent ab41043ff1
commit 740e642965
9 changed files with 1078 additions and 981 deletions

View File

@ -515,7 +515,7 @@ namespace keepass2android
if (Success) if (Success)
{ {
// Update the ongoing notification // Update the ongoing notification
_activity.StartService(new Intent(_activity, typeof(OngoingNotificationsService))); App.Kp2a.UpdateOngoingNotification();
if (PreferenceManager.GetDefaultSharedPreferences(_activity).GetBoolean(_activity.GetString(Resource.String.RememberRecentFiles_key), _activity.Resources.GetBoolean(Resource.Boolean.RememberRecentFiles_default))) if (PreferenceManager.GetDefaultSharedPreferences(_activity).GetBoolean(_activity.GetString(Resource.String.RememberRecentFiles_key), _activity.Resources.GetBoolean(Resource.Boolean.RememberRecentFiles_default)))
{ {

File diff suppressed because it is too large Load Diff

View File

@ -83,6 +83,7 @@
<string name="QuickUnlockLength_key">QuickUnlockLength</string> <string name="QuickUnlockLength_key">QuickUnlockLength</string>
<string name="QuickUnlockLength_default">3</string> <string name="QuickUnlockLength_default">3</string>
<string name="QuickUnlockIconHidden_key">QuickUnlockIconHidden_key</string> <string name="QuickUnlockIconHidden_key">QuickUnlockIconHidden_key</string>
<string name="QuickUnlockIconHidden16_key">QuickUnlockIconHidden16_key</string>
<string name="UsageCount_key">UsageCount</string> <string name="UsageCount_key">UsageCount</string>
<string name="LastInfoVersionCode_key">LastInfoVersion</string> <string name="LastInfoVersionCode_key">LastInfoVersion</string>

View File

@ -217,6 +217,8 @@
<string name="QuickUnlockDefaultEnabled_summary">Defines whether QuickUnlock is enabled by default or not.</string> <string name="QuickUnlockDefaultEnabled_summary">Defines whether QuickUnlock is enabled by default or not.</string>
<string name="QuickUnlockIconHidden_title">Hide QuickUnlock icon</string> <string name="QuickUnlockIconHidden_title">Hide QuickUnlock icon</string>
<string name="QuickUnlockIconHidden_summary">QuickUnlock unfortunately does not work without displaying a notification icon. Select this option to use a transparent icon.</string> <string name="QuickUnlockIconHidden_summary">QuickUnlock unfortunately does not work without displaying a notification icon. Select this option to use a transparent icon.</string>
<string name="QuickUnlockIconHidden16_title">Hide QuickUnlock icon</string>
<string name="QuickUnlockIconHidden16_summary">QuickUnlock requires a notification to work properly. Select this option to display a notification without an icon.</string>
<string name="QuickUnlockLength_title">Length of QuickUnlock key</string> <string name="QuickUnlockLength_title">Length of QuickUnlock key</string>
<string name="QuickUnlockLength_summary">Maximum number of characters used as QuickUnlock password.</string> <string name="QuickUnlockLength_summary">Maximum number of characters used as QuickUnlock password.</string>
<string name="QuickUnlock_fail">QuickUnlock failed: incorrect password!</string> <string name="QuickUnlock_fail">QuickUnlock failed: incorrect password!</string>
@ -270,8 +272,8 @@
<string name="kp2a_switch_rooted">Auto-switch on rooted devices</string> <string name="kp2a_switch_rooted">Auto-switch on rooted devices</string>
<string name="kp2a_switch_rooted_summary">On rooted devices, it is possible to automatically switch to the Keepass2Android keyboard (after search for an entry or by clicking the KP2A keyboard notification) and to switch back to the previous keyboard without showing the Input method picker. This also requires to install the Secure Settings app. See the KP2A documentation for more information!</string> <string name="kp2a_switch_rooted_summary">On rooted devices, it is possible to automatically switch to the Keepass2Android keyboard (after search for an entry or by clicking the KP2A keyboard notification) and to switch back to the previous keyboard without showing the Input method picker. This also requires to install the Secure Settings app. See the KP2A documentation for more information!</string>
<string name="ShowUnlockedNotification_title">Notification while unlocked</string> <string name="ShowUnlockedNotification_title">Notification icon while unlocked</string>
<string name="ShowUnlockedNotification_summary">Show an ongoing notification while the database is unlocked.</string> <string name="ShowUnlockedNotification_summary">Show a notification icon while the database is unlocked.</string>
<string name="PreloadDatabaseEnabled_title">Pre-load database file</string> <string name="PreloadDatabaseEnabled_title">Pre-load database file</string>
<string name="PreloadDatabaseEnabled_summary">Start background loading or downloading of the database file during password entry.</string> <string name="PreloadDatabaseEnabled_summary">Start background loading or downloading of the database file during password entry.</string>

View File

@ -209,6 +209,13 @@
android:defaultValue="false" android:defaultValue="false"
android:title="@string/QuickUnlockIconHidden_title" android:title="@string/QuickUnlockIconHidden_title"
android:key="@string/QuickUnlockIconHidden_key" /> android:key="@string/QuickUnlockIconHidden_key" />
<CheckBoxPreference
android:enabled="true"
android:persistent="true"
android:summary="@string/QuickUnlockIconHidden16_summary"
android:defaultValue="true"
android:title="@string/QuickUnlockIconHidden16_title"
android:key="@string/QuickUnlockIconHidden16_key" />
</PreferenceScreen> </PreferenceScreen>
<PreferenceScreen <PreferenceScreen
android:key="@string/FileHandling_prefs_key" android:key="@string/FileHandling_prefs_key"

View File

@ -138,7 +138,12 @@ namespace keepass2android
{ {
// Start or update the notification icon service to reflect the current state // Start or update the notification icon service to reflect the current state
var ctx = Application.Context; var ctx = Application.Context;
ctx.StartService(new Intent(ctx, typeof(OngoingNotificationsService))); StartOnGoingService(ctx);
}
public static void StartOnGoingService(Context ctx)
{
ctx.StartService(new Intent(ctx, typeof (OngoingNotificationsService)));
} }
public bool DatabaseIsUnlocked public bool DatabaseIsUnlocked

View File

@ -32,6 +32,10 @@ namespace keepass2android
/// Shows database unlocked warning persistent notification /// Shows database unlocked warning persistent notification
/// Shows Quick-Unlock notification /// Shows Quick-Unlock notification
/// </summary> /// </summary>
/// This service is running as foreground service to keep the app alive even when it's not currently
/// used by the user. This ensures the database is kept in memory (until Android kills it due to low memory).
/// It is important to also have a foreground service also for the "unlocked" state because it's really
/// irritating if the db is closed while switching between apps.
[Service] [Service]
public class OngoingNotificationsService : Service public class OngoingNotificationsService : Service
{ {
@ -64,15 +68,8 @@ namespace keepass2android
// Clear current foreground status and QuickUnlock icon // Clear current foreground status and QuickUnlock icon
StopForeground(true); StopForeground(true);
if (ShowUnlockedNotification) //use foreground again to let the app not be killed too easily.
{ StartForeground(UnlockedWarningId, GetUnlockedNotification());
// No need for task to get foreground priority, we don't need any special treatment just for showing that the database is unlocked
notificationManager.Notify(UnlockedWarningId, GetUnlockedNotification());
}
else
{
notificationManager.Cancel(UnlockedWarningId);
}
} }
else else
{ {
@ -93,11 +90,6 @@ namespace keepass2android
return StartCommandResult.NotSticky; 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) public override void OnTaskRemoved(Intent rootIntent)
{ {
base.OnTaskRemoved(rootIntent); base.OnTaskRemoved(rootIntent);
@ -118,11 +110,13 @@ namespace keepass2android
Kp2aLog.Log("OngoingNotificationsService.OnDestroy"); Kp2aLog.Log("OngoingNotificationsService.OnDestroy");
// If the service is killed, then lock the database immediately (as the unlocked warning icon will no longer display). // If the service is killed, then lock the database immediately
if (App.Kp2a.DatabaseIsUnlocked) if (App.Kp2a.DatabaseIsUnlocked)
{ {
App.Kp2a.LockDatabase(); App.Kp2a.LockDatabase();
} }
//also remove any notifications of the app
notificationManager.CancelAll();
UnregisterReceiver(_screenOffReceiver); UnregisterReceiver(_screenOffReceiver);
} }
@ -139,6 +133,7 @@ namespace keepass2android
private Notification GetQuickUnlockNotification() private Notification GetQuickUnlockNotification()
{ {
int grayIconResouceId = Resource.Drawable.ic_launcher_gray; int grayIconResouceId = Resource.Drawable.ic_launcher_gray;
if ((int)Android.OS.Build.VERSION.SdkInt < 16)
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(GetString(Resource.String.QuickUnlockIconHidden_key), false)) if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(GetString(Resource.String.QuickUnlockIconHidden_key), false))
{ {
grayIconResouceId = Resource.Drawable.transparent; grayIconResouceId = Resource.Drawable.transparent;
@ -150,6 +145,19 @@ namespace keepass2android
.SetContentTitle(GetString(Resource.String.app_name)) .SetContentTitle(GetString(Resource.String.app_name))
.SetContentText(GetString(Resource.String.database_loaded_quickunlock_enabled, GetDatabaseName())); .SetContentText(GetString(Resource.String.database_loaded_quickunlock_enabled, GetDatabaseName()));
if ((int)Build.VERSION.SdkInt >= 16)
{
if (PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(GetString(Resource.String.QuickUnlockIconHidden16_key), true))
{
builder.SetPriority((int) NotificationPriority.Min);
}
else
{
builder.SetPriority((int)NotificationPriority.Default);
}
}
// Default action is to show Kp2A // Default action is to show Kp2A
builder.SetContentIntent(GetSwitchToAppPendingIntent()); builder.SetContentIntent(GetSwitchToAppPendingIntent());
// Additional action to allow locking the database // Additional action to allow locking the database
@ -174,6 +182,20 @@ namespace keepass2android
.SetContentTitle(GetString(Resource.String.app_name)) .SetContentTitle(GetString(Resource.String.app_name))
.SetContentText(GetString(Resource.String.database_loaded_unlocked, GetDatabaseName())); .SetContentText(GetString(Resource.String.database_loaded_unlocked, GetDatabaseName()));
if ((int)Build.VERSION.SdkInt >= 16)
{
if (PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(GetString(Resource.String.ShowUnlockedNotification_key),
Resources.GetBoolean(Resource.Boolean.ShowUnlockedNotification_default)))
{
builder.SetPriority((int)NotificationPriority.Default);
}
else
{
builder.SetPriority((int) NotificationPriority.Min);
}
}
// Default action is to show Kp2A // Default action is to show Kp2A
builder.SetContentIntent(GetSwitchToAppPendingIntent()); builder.SetContentIntent(GetSwitchToAppPendingIntent());
// Additional action to allow locking the database // Additional action to allow locking the database

View File

@ -52,7 +52,6 @@ namespace keepass2android
AddPreferencesFromResource(Resource.Xml.preferences); AddPreferencesFromResource(Resource.Xml.preferences);
FindPreference(GetString(Resource.String.keyfile_key)).PreferenceChange += OnRememberKeyFileHistoryChanged; FindPreference(GetString(Resource.String.keyfile_key)).PreferenceChange += OnRememberKeyFileHistoryChanged;
FindPreference(GetString(Resource.String.ShowUnlockedNotification_key)).PreferenceChange += OnShowUnlockedNotificationChanged;;
Preference designPref = FindPreference(GetString(Resource.String.design_key)); Preference designPref = FindPreference(GetString(Resource.String.design_key));
if (!_design.HasThemes()) if (!_design.HasThemes())
{ {
@ -85,7 +84,32 @@ namespace keepass2android
Kp2aLog.Log(ex.ToString()); Kp2aLog.Log(ex.ToString());
} }
#endif #endif
FindPreference(GetString(Resource.String.QuickUnlockIconHidden_key)).PreferenceChange += OnQuickUnlockHiddenChanged; 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; FindPreference(GetString(Resource.String.db_key)).Enabled = false;
} }
@ -149,8 +173,7 @@ namespace keepass2android
internal static void OnShowUnlockedNotificationChanged(object sender, Preference.PreferenceChangeEventArgs eventArgs) internal static void OnShowUnlockedNotificationChanged(object sender, Preference.PreferenceChangeEventArgs eventArgs)
{ {
var ctx = ((Preference)sender).Context; App.Kp2a.UpdateOngoingNotification();
ctx.StartService(new Intent(ctx, typeof(OngoingNotificationsService)));
} }
} }

View File

@ -124,13 +124,41 @@ namespace keepass2android
else else
{ {
// Name is reflected in notification, so update it // Name is reflected in notification, so update it
StartService(new Intent(this, typeof(OngoingNotificationsService))); App.Kp2a.UpdateOngoingNotification();
} }
})); }));
ProgressTask pt = new ProgressTask(App.Kp2a, this, save); ProgressTask pt = new ProgressTask(App.Kp2a, this, save);
pt.Run(); pt.Run();
}; };
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 += delegate { App.Kp2a.UpdateOngoingNotification(); };
}
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());
}
SetRounds(db, rounds); SetRounds(db, rounds);
Preference algorithm = FindPreference(GetString(Resource.String.algorithm_key)); Preference algorithm = FindPreference(GetString(Resource.String.algorithm_key));