introduce BackgroundSyncService to keep app alive while sync is going on.

This commit is contained in:
Philipp Crocoll
2025-05-13 12:38:21 +02:00
parent cfb185b53d
commit aa2e4b856d
24 changed files with 299 additions and 75 deletions

View File

@@ -23,6 +23,7 @@ using Java.Security;
using KeePassLib.Interfaces;
using System.Threading.Tasks;
using Enum = System.Enum;
using Thread = Java.Lang.Thread;
namespace keepass2android
{
@@ -54,12 +55,12 @@ namespace keepass2android
private Java.Lang.Thread? _thread = null;
private ProgressUiAsStatusLoggerAdapter _statusLogger = null;
public void Run(Activity activity, IKp2aApp app, OperationWithFinishHandler operation)
public void Run(Context context, IKp2aApp app, OperationWithFinishHandler operation)
{
lock (Instance._taskQueueLock)
{
_taskQueue.Enqueue(operation);
SetNewActiveActivity(activity, app);
SetNewActiveContext(context, app);
// Start thread to run the task (unless it's already running)
if (_thread == null)
@@ -94,11 +95,18 @@ namespace keepass2android
}
public void SetNewActiveActivity(Activity? activity, IKp2aApp app)
public void SetNewActiveContext(Context? context, IKp2aApp app)
{
lock (_taskQueueLock)
{
var progressUi = (activity as IProgressUiProvider)?.ProgressUi;
if (context == null && _thread != null)
{
//this will register the service as new active context
app.StartBackgroundSyncService();
return;
}
var progressUi = (context as IProgressUiProvider)?.ProgressUi;
if (_statusLogger == null)
{
_statusLogger = new ProgressUiAsStatusLoggerAdapter(progressUi, app);
@@ -110,7 +118,7 @@ namespace keepass2android
foreach (var task in _taskQueue)
{
task.ActiveActivity = activity;
task.ActiveContext = context;
task.SetStatusLogger(_statusLogger);
}
@@ -242,7 +250,7 @@ namespace keepass2android
}
_activeActivity = value;
if (_task != null)
_task.ActiveActivity = _activeActivity;
_task.ActiveContext = _activeActivity;
if (_activeActivity != null)
{
SetupProgressDialog(_app);

View File

@@ -142,7 +142,6 @@ namespace keepass2android
#endif
bool SyncInBackgroundPreference { get; set; }
void StartBackgroundSyncService();
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -15,7 +16,7 @@ namespace KeePass.Util
string errorMessage = e.Message;
if (e is Java.Lang.Exception javaException)
{
errorMessage = javaException.LocalizedMessage ?? javaException.Message ?? errorMessage;
errorMessage = javaException.Message ?? errorMessage;
}
return errorMessage;

View File

@@ -12,11 +12,11 @@ namespace keepass2android
{
public class SynchronizeCachedDatabase: OperationWithFinishHandler
{
private readonly Activity _context;
private readonly Context _context;
private readonly IKp2aApp _app;
private SaveDb _saveDb;
public SynchronizeCachedDatabase(Activity context, IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler)
public SynchronizeCachedDatabase(Context context, IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler)
: base(context, operationFinishedHandler)
{
_context = context;
@@ -64,7 +64,7 @@ namespace keepass2android
if (cachingFileStorage.HasLocalChanges(ioc))
{
//conflict! need to merge
_saveDb = new SaveDb(_context, _app, new ActionOnOperationFinished(ActiveActivity, (success, result, activity) =>
_saveDb = new SaveDb(_context, _app, new ActionOnOperationFinished(ActiveContext, (success, result, activity) =>
{
if (!success)
{

View File

@@ -17,22 +17,23 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
using System;
using Android.App;
using Android.Content;
using Android.OS;
namespace keepass2android
{
public class ActionOnOperationFinished: OnOperationFinishedHandler
{
public delegate void ActionToPerformOnFinsh(bool success, String message, Activity activeActivity);
public delegate void ActionToPerformOnFinsh(bool success, String message, Context activeContext);
readonly ActionToPerformOnFinsh _actionToPerform;
public ActionOnOperationFinished(Activity activity, ActionToPerformOnFinsh actionToPerform) : base(activity, null, null)
public ActionOnOperationFinished(Context context, ActionToPerformOnFinsh actionToPerform) : base(context, null, null)
{
_actionToPerform = actionToPerform;
}
public ActionOnOperationFinished(Activity activity, ActionToPerformOnFinsh actionToPerform, OnOperationFinishedHandler operationFinishedHandler) : base(activity, operationFinishedHandler)
public ActionOnOperationFinished(Context context, ActionToPerformOnFinsh actionToPerform, OnOperationFinishedHandler operationFinishedHandler) : base(context, operationFinishedHandler)
{
_actionToPerform = actionToPerform;
}
@@ -46,10 +47,10 @@ namespace keepass2android
Message = "";
if (Handler != null)
{
Handler.Post(() => {_actionToPerform(Success, Message, ActiveActivity);});
Handler.Post(() => {_actionToPerform(Success, Message, ActiveContext);});
}
else
_actionToPerform(Success, Message, AllowInactiveActivity ? (ActiveActivity ?? PreviouslyActiveActivity) : ActiveActivity);
_actionToPerform(Success, Message, AllowInactiveActivity ? (ActiveContext ?? PreviouslyActiveContext) : ActiveContext);
base.Run();
}
}

View File

@@ -215,7 +215,7 @@ namespace keepass2android
Android.Util.Log.Debug("KP2A", "Calling PerformDelete..");
PerformDelete(touchedGroups, permanentlyDeletedGroups);
_operationFinishedHandler = new ActionOnOperationFinished(ActiveActivity,(success, message, activity) =>
_operationFinishedHandler = new ActionOnOperationFinished(ActiveContext,(success, message, activity) =>
{
if (success)
{

View File

@@ -169,7 +169,7 @@ namespace keepass2android
if (requiresSubsequentSync)
{
var syncTask = new SynchronizeCachedDatabase(ActiveActivity, _app, new ActionOnOperationFinished(ActiveActivity,
var syncTask = new SynchronizeCachedDatabase(ActiveContext, _app, new ActionOnOperationFinished(ActiveContext,
(success, message, activeActivity) =>
{
if (!String.IsNullOrEmpty(message))
@@ -177,7 +177,7 @@ namespace keepass2android
})
);
BackgroundOperationRunner.Instance.Run(ActiveActivity, _app, syncTask);
BackgroundOperationRunner.Instance.Run(ActiveContext, _app, syncTask);
}
Finish(true, _format.SuccessMessage);

View File

@@ -123,7 +123,7 @@ namespace keepass2android.database.edit
int indexToSave = 0;
bool allSavesSuccess = true;
void ContinueSave(bool success, string message, Activity activeActivity)
void ContinueSave(bool success, string message, Context activeActivity)
{
allSavesSuccess &= success;
indexToSave++;
@@ -140,7 +140,7 @@ namespace keepass2android.database.edit
}
SaveDb save = new SaveDb(_ctx, _app, allDatabasesToSave[0], new ActionOnOperationFinished(ActiveActivity, ContinueSave), false);
SaveDb save = new SaveDb(_ctx, _app, allDatabasesToSave[0], new ActionOnOperationFinished(ActiveContext, ContinueSave), false);
save.SetStatusLogger(StatusLogger);
save.ShowDatabaseIocInStatus = allDatabasesToSave.Count > 1;
save.Run();

View File

@@ -41,7 +41,7 @@ namespace keepass2android
protected OnOperationFinishedHandler NextOnOperationFinishedHandler;
protected Handler Handler;
private IKp2aStatusLogger _statusLogger = new Kp2aNullStatusLogger(); //default: no logging but not null -> can be used whenever desired
private Activity _activeActivity, _previouslyActiveActivity;
private Context _activeContext, _previouslyActiveContext;
public IKp2aStatusLogger StatusLogger
@@ -50,50 +50,50 @@ namespace keepass2android
set { _statusLogger = value; }
}
public Activity ActiveActivity
public Context ActiveContext
{
get { return _activeActivity; }
get { return _activeContext; }
set
{
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
if (_activeContext != null && _activeContext != _previouslyActiveContext)
{
_previouslyActiveActivity = _activeActivity;
_previouslyActiveContext = _activeContext;
}
_activeActivity = value;
_activeContext = value;
if (NextOnOperationFinishedHandler != null)
{
NextOnOperationFinishedHandler.ActiveActivity = value;
NextOnOperationFinishedHandler.ActiveContext = value;
}
}
}
public Activity PreviouslyActiveActivity
public Context PreviouslyActiveContext
{
get { return _previouslyActiveActivity; }
get { return _previouslyActiveContext; }
}
protected OnOperationFinishedHandler(Activity activeActivity, Handler handler)
protected OnOperationFinishedHandler(Context activeContext, Handler handler)
{
ActiveActivity = activeActivity;
ActiveContext = activeContext;
NextOnOperationFinishedHandler = null;
Handler = handler;
}
protected OnOperationFinishedHandler(Activity activeActivity, OnOperationFinishedHandler operationFinishedHandler, Handler handler)
protected OnOperationFinishedHandler(Context activeContext, OnOperationFinishedHandler operationFinishedHandler, Handler handler)
{
ActiveActivity = activeActivity;
ActiveContext = activeContext;
NextOnOperationFinishedHandler = operationFinishedHandler;
Handler = handler;
}
protected OnOperationFinishedHandler(Activity activeActivity, OnOperationFinishedHandler operationFinishedHandler)
protected OnOperationFinishedHandler(Context activeContext, OnOperationFinishedHandler operationFinishedHandler)
{
ActiveActivity = activeActivity;
ActiveContext = activeContext;
NextOnOperationFinishedHandler = operationFinishedHandler;
Handler = null;
}

View File

@@ -26,11 +26,11 @@ namespace keepass2android
protected OnOperationFinishedHandler _operationFinishedHandler;
public IKp2aStatusLogger StatusLogger = new Kp2aNullStatusLogger(); //default: empty but not null
private Activity _activeActivity;
private Context _activeContext;
protected OperationWithFinishHandler(Activity activeActivity, OnOperationFinishedHandler operationFinishedHandler)
protected OperationWithFinishHandler(Context activeContext, OnOperationFinishedHandler operationFinishedHandler)
{
_activeActivity = activeActivity;
_activeContext = activeContext;
_operationFinishedHandler = operationFinishedHandler;
}
@@ -40,14 +40,14 @@ namespace keepass2android
set { _operationFinishedHandler = value; }
}
public Activity ActiveActivity
public Context ActiveContext
{
get { return _activeActivity; }
get { return _activeContext; }
set
{
_activeActivity = value;
_activeContext = value;
if (_operationFinishedHandler != null)
_operationFinishedHandler.ActiveActivity = _activeActivity;
_operationFinishedHandler.ActiveContext = _activeContext;
}
}

View File

@@ -64,7 +64,7 @@ namespace keepass2android
/// <param name="operationFinishedHandler"></param>
/// <param name="dontSave"></param>
/// <param name="streamForOrigFile">Stream for reading the data from the (changed) original location</param>
public SaveDb(Activity ctx, IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler, Database db, bool dontSave, Stream streamForOrigFile)
public SaveDb(Context ctx, IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler, Database db, bool dontSave, Stream streamForOrigFile)
: base(ctx, operationFinishedHandler)
{
_db = db;
@@ -214,7 +214,7 @@ namespace keepass2android
{
if (requiresSubsequentSync)
{
var syncTask = new SynchronizeCachedDatabase(ActiveActivity, _app, new ActionOnOperationFinished(ActiveActivity,
var syncTask = new SynchronizeCachedDatabase(ActiveContext, _app, new ActionOnOperationFinished(ActiveContext,
(success, message, activeActivity) =>
{
if (!System.String.IsNullOrEmpty(message))
@@ -222,7 +222,7 @@ namespace keepass2android
})
);
BackgroundOperationRunner.Instance.Run(ActiveActivity, _app, syncTask);
BackgroundOperationRunner.Instance.Run(ActiveContext, _app, syncTask);
}
Finish(true);
}

View File

@@ -73,7 +73,7 @@ namespace keepass2android
pm.MasterKey = newKey;
// Save Database
_operationFinishedHandler = new AfterSave(ActiveActivity, previousKey, previousMasterKeyChanged, pm, operationFinishedHandler);
_operationFinishedHandler = new AfterSave(ActiveContext, previousKey, previousMasterKeyChanged, pm, operationFinishedHandler);
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, operationFinishedHandler, _dontSave);
save.SetStatusLogger(StatusLogger);
save.Run();
@@ -84,7 +84,7 @@ namespace keepass2android
private readonly DateTime _previousKeyChanged;
private readonly PwDatabase _db;
public AfterSave(Activity activity, CompositeKey backup, DateTime previousKeyChanged, PwDatabase db, OnOperationFinishedHandler operationFinishedHandler): base(activity, operationFinishedHandler) {
public AfterSave(Context context, CompositeKey backup, DateTime previousKeyChanged, PwDatabase db, OnOperationFinishedHandler operationFinishedHandler): base(context, operationFinishedHandler) {
_previousKeyChanged = previousKeyChanged;
_backup = backup;
_db = db;

View File

@@ -526,10 +526,14 @@ namespace keepass2android
App.Kp2a.DirtyGroups.Add(parent);
}
var saveTask = new SaveDb(this, App.Kp2a, App.Kp2a.FindDatabaseForElement(Entry), new ActionOnOperationFinished(this, (success, message, activity) =>
var saveTask = new SaveDb(this, App.Kp2a, App.Kp2a.FindDatabaseForElement(Entry), new ActionOnOperationFinished(this, (success, message, context) =>
{
activity.SetResult(KeePass.ExitRefresh);
activity.Finish();
if (context is Activity activity)
{
activity.SetResult(KeePass.ExitRefresh);
activity.Finish();
}
}));
BlockingOperationRunner pt = new BlockingOperationRunner(App.Kp2a, this, saveTask);

View File

@@ -521,13 +521,13 @@ namespace keepass2android
OperationWithFinishHandler runnable;
ActionOnOperationFinished closeOrShowError = new ActionOnOperationFinished(this, (success, message, activity) => {
ActionOnOperationFinished closeOrShowError = new ActionOnOperationFinished(this, (success, message, context) => {
if (success)
{
activity?.Finish();
(context as Activity)?.Finish();
} else
{
OnOperationFinishedHandler.DisplayMessage(activity, message, true);
OnOperationFinishedHandler.DisplayMessage(context, message, true);
//Re-initialize for editing:
State.EditMode.InitializeEntry(State.Entry);
}

View File

@@ -26,13 +26,13 @@ namespace keepass2android
protected override void SaveFile(IOConnectionInfo ioc)
{
var exportDb = new ExportDatabaseActivity.ExportDb(_activity, App.Kp2a, new ActionOnOperationFinished(_activity, (success, message, activity) =>
var exportDb = new ExportDatabaseActivity.ExportDb(_activity, App.Kp2a, new ActionOnOperationFinished(_activity, (success, message, context) =>
{
if (!success)
App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error);
App.Kp2a.ShowMessage(context, message, MessageSeverity.Error);
else
App.Kp2a.ShowMessage(activity, _activity.GetString(Resource.String.export_database_successful), MessageSeverity.Info);
activity.Finish();
App.Kp2a.ShowMessage(context, _activity.GetString(Resource.String.export_database_successful), MessageSeverity.Info);
(context as Activity)?.Finish();
}
), _ffp, ioc);
BlockingOperationRunner pt = new BlockingOperationRunner(App.Kp2a, _activity, exportDb);

View File

@@ -667,10 +667,10 @@ namespace keepass2android
return true;
}
private void IocSelected(Activity activity, IOConnectionInfo ioc)
private void IocSelected(Context context, IOConnectionInfo ioc)
{
if (OnOpen != null)
OnOpen(activity, ioc);
OnOpen(context, ioc);
}
public bool StartFileChooser(string defaultPath)

View File

@@ -1305,11 +1305,11 @@ namespace keepass2android
{
if (Success)
{
((GroupBaseActivity)ActiveActivity)?.RefreshIfDirty();
((GroupBaseActivity)ActiveContext)?.RefreshIfDirty();
}
else
{
DisplayMessage(ActiveActivity);
DisplayMessage(ActiveContext);
}
}
}
@@ -1325,13 +1325,13 @@ namespace keepass2android
{
if (Success)
{
((GroupBaseActivity)ActiveActivity)?.RefreshIfDirty();
((GroupBaseActivity)ActiveContext)?.RefreshIfDirty();
}
else
{
Handler.Post(() =>
{
App.Kp2a.ShowMessage(ActiveActivity ?? LocaleManager.LocalizedAppContext, "Unrecoverable error: " + Message, MessageSeverity.Error);
App.Kp2a.ShowMessage(ActiveContext ?? LocaleManager.LocalizedAppContext, "Unrecoverable error: " + Message, MessageSeverity.Error);
});
App.Kp2a.Lock(false);
@@ -1671,7 +1671,7 @@ namespace keepass2android
}
int dbIndex = 0;
Action<bool, string, Activity> action = null;
Action<bool, string, Context> action = null;
action = (success, message, activeActivity) =>
{
if (success)

View File

@@ -105,7 +105,7 @@ namespace keepass2android
protected override void OnStart()
{
BlockingOperationRunner.SetNewActiveActivity(this);
BackgroundOperationRunner.Instance.SetNewActiveActivity(this, App.Kp2a);
BackgroundOperationRunner.Instance.SetNewActiveContext(this, App.Kp2a);
base.OnStart();
Kp2aLog.Log(ClassName + ".OnStart" + " " + ID);
}

View File

@@ -266,6 +266,7 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" android:maxSdkVersion="22" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" android:maxSdkVersion="22" />
<uses-permission android:name="keepass2android.keepass2android_debug.permission.KP2aInternalFileBrowsing" />

View File

@@ -278,6 +278,7 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" android:maxSdkVersion="22" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" android:maxSdkVersion="22" />
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />

View File

@@ -257,6 +257,9 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-feature android:name="android.hardware.camera" android:required="false" />

View File

@@ -56,6 +56,9 @@ using GoogleDriveAppDataFileStorage = keepass2android.Io.GoogleDriveAppDataFileS
using PCloudFileStorage = keepass2android.Io.PCloudFileStorage;
using static keepass2android.Util;
using static Android.Provider.Telephony.MmsSms;
using AndroidX.Lifecycle;
using Java.Interop;
using keepass2android.services;
#endif
#endif
@@ -1174,6 +1177,13 @@ namespace keepass2android
}
}
public void StartBackgroundSyncService()
{
Intent intent = new Intent(App.Context, typeof(BackgroundSyncService));
intent.SetAction(BackgroundSyncService.ActionStart);
App.Context.StartService(intent);
}
/// <summary>
/// true if the app is used in offline mode
/// </summary>
@@ -1365,7 +1375,8 @@ namespace keepass2android
[Application(Debuggable = true, Label = AppNames.AppName)]
#endif
#endif
public class App : Application {
public class App : Application, ILifecycleObserver
{
public override void OnConfigurationChanged(Android.Content.Res.Configuration newConfig)
{
@@ -1398,8 +1409,9 @@ namespace keepass2android
InitThaiCalendarCrashFix();
base.OnCreate();
ProcessLifecycleOwner.Get().Lifecycle.AddObserver(this);
Kp2aLog.Log("Creating application "+PackageName+". Version=" + PackageManager.GetPackageInfo(PackageName, 0).VersionCode);
Kp2aLog.Log("Creating application "+PackageName+". Version=" + PackageManager.GetPackageInfo(PackageName, 0).VersionCode);
CreateNotificationChannels();
@@ -1411,12 +1423,32 @@ namespace keepass2android
intentFilter.AddAction(Intents.LockDatabaseByTimeout);
intentFilter.AddAction(Intents.CloseDatabase);
ContextCompat.RegisterReceiver(Context, broadcastReceiver, intentFilter, (int)ReceiverFlags.Exported);
//ZXing.Net.Mobile.Forms.Android.Platform.Init();
}
private ApplicationBroadcastReceiver broadcastReceiver = new ApplicationBroadcastReceiver();
[Lifecycle.Event.OnStop]
[Export]
public void OnAppBackgrounded()
{
Kp2aLog.Log("Going to background");
BackgroundOperationRunner.Instance.SetNewActiveContext(null, Kp2a);
}
[Lifecycle.Event.OnStart]
[Export]
public void OnAppForegrounded()
{
Kp2aLog.Log("Going to foreground");
StopBackgroundSyncService();
}
private void StopBackgroundSyncService()
{
Intent stopServiceIntent = new Intent(Context, typeof(BackgroundSyncService));
stopServiceIntent.SetAction(BackgroundSyncService.ActionStop);
Context.StartService(stopServiceIntent);
}
private void CreateNotificationChannels()
{

View File

@@ -0,0 +1,174 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using System;
using System.Threading;
using System.Threading.Tasks;
using AndroidX.Core.App;
using Android.Content.PM;
using Microsoft.Graph.Models;
namespace keepass2android.services
{
[Service(ForegroundServiceType = ForegroundService.TypeDataSync)]
public class BackgroundSyncService : Service, IProgressUiProvider, IProgressUi
{
private const string ChannelId = "BackgroundSyncServiceChannel";
private const int NotificationId = 1;
private const string Tag = "BackgroundSyncService";
private CancellationTokenSource _cts;
private string _message;
private string _submessage;
public override void OnCreate()
{
base.OnCreate();
Log.Debug(Tag, "OnCreate");
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
if (intent.Action == ActionStop)
{
Log.Debug(Tag, "OnStartCommand: STOP");
StopForeground(StopForegroundFlags.Remove);
StopSelf();
return StartCommandResult.NotSticky;
}
Log.Debug(Tag, "OnStartCommand");
try
{
_cts = new CancellationTokenSource();
CreateNotificationChannel();
StartForeground(NotificationId, BuildNotification());
BackgroundOperationRunner.Instance.SetNewActiveContext(this, App.Kp2a);
return StartCommandResult.Sticky;
}
catch (Exception ex)
{
Log.Error(Tag, ex.ToString());
StopForeground(StopForegroundFlags.Remove);
StopSelf();
return StartCommandResult.NotSticky;
}
}
private Notification BuildNotification()
{
Intent notificationIntent = new Intent(this, typeof(FileSelectActivity));
PendingIntent pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent,
PendingIntentFlags.Immutable);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ChannelId)
.SetSmallIcon(Resource.Drawable.ic_launcher_gray)
.SetPriority(NotificationCompat.PriorityLow)
.SetSilent(true)
.SetContentIntent(pendingIntent)
.SetProgress(100,0, true)
.SetOngoing(true);
if (!string.IsNullOrEmpty(_message))
{
builder.SetContentTitle(_message);
}
if (!string.IsNullOrEmpty(_submessage))
{
builder.SetContentText(_submessage);
}
return builder.Build();
}
private void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
//TODO
var channelName = "Foreground Service Channel";
var channelDescription = "Channel for foreground service";
var channelImportance = NotificationImportance.Default;
var channel = new NotificationChannel(ChannelId, channelName, channelImportance)
{
Description = channelDescription
};
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
}
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnDestroy()
{
base.OnDestroy();
Log.Debug(Tag, "OnDestroy");
if (_cts != null)
{
_cts.Cancel();
_cts.Dispose();
}
}
public IProgressUi? ProgressUi
{
get { return this; }
}
public static string ActionStop => "STOP";
public static string ActionStart => "START";
public void Show()
{
}
public void Hide()
{
CloseNotification();
StopSelf();
StopForeground(StopForegroundFlags.Remove);
}
private void CloseNotification()
{
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Cancel(NotificationId);
}
public void UpdateMessage(string message)
{
_message = message;
UpdateNotification();
}
private void UpdateNotification()
{
var notification = BuildNotification();
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(NotificationId, notification);
}
public void UpdateSubMessage(string submessage)
{
_submessage = submessage;
UpdateNotification();
}
}
}

View File

@@ -71,14 +71,14 @@ namespace keepass2android
protected override void SaveFile(IOConnectionInfo ioc)
{
var exportKeyfile = new ExportKeyfile(_activity, App.Kp2a, new ActionOnOperationFinished(_activity,
(success, message, activity) =>
(success, message, context) =>
{
if (!success)
App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error);
App.Kp2a.ShowMessage(context, message, MessageSeverity.Error);
else
App.Kp2a.ShowMessage(activity, _activity.GetString(Resource.String.export_keyfile_successful),
App.Kp2a.ShowMessage(context, _activity.GetString(Resource.String.export_keyfile_successful),
MessageSeverity.Info);
activity.Finish();
(context as Activity)?.Finish();
}
), ioc);
BlockingOperationRunner pt = new BlockingOperationRunner(App.Kp2a, _activity, exportKeyfile);