introduce BackgroundSyncService to keep app alive while sync is going on.
This commit is contained in:
@@ -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);
|
||||
|
@@ -142,7 +142,6 @@ namespace keepass2android
|
||||
#endif
|
||||
|
||||
bool SyncInBackgroundPreference { get; set; }
|
||||
|
||||
|
||||
void StartBackgroundSyncService();
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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);
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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" />
|
||||
|
@@ -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" />
|
||||
|
@@ -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" />
|
||||
|
||||
|
@@ -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()
|
||||
{
|
||||
|
174
src/keepass2android-app/services/BackgroundSyncService.cs
Normal file
174
src/keepass2android-app/services/BackgroundSyncService.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user