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
	 Philipp Crocoll
					Philipp Crocoll