let database sync run in the background. not handling all cases yet.
This commit is contained in:
@@ -19,13 +19,199 @@ using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Java.Lang;
|
||||
using Java.Security;
|
||||
using KeePassLib.Interfaces;
|
||||
using System.Threading.Tasks;
|
||||
using Enum = System.Enum;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to run a task while a progress dialog is shown
|
||||
/// </summary>
|
||||
public class BlockingOperationRunner
|
||||
public class BackgroundOperationRunner
|
||||
{
|
||||
//singleton instance
|
||||
private static BackgroundOperationRunner _instance = null;
|
||||
|
||||
public static BackgroundOperationRunner Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new BackgroundOperationRunner();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private BackgroundOperationRunner()
|
||||
{
|
||||
//private constructor
|
||||
}
|
||||
|
||||
private readonly Queue<OperationWithFinishHandler> _taskQueue = new Queue<OperationWithFinishHandler>();
|
||||
private readonly object _taskQueueLock = new object();
|
||||
private Java.Lang.Thread? _thread = null;
|
||||
private ProgressUiAsStatusLoggerAdapter _statusLogger = null;
|
||||
|
||||
public void Run(Activity activity, IKp2aApp app, OperationWithFinishHandler operation)
|
||||
{
|
||||
lock (Instance._taskQueueLock)
|
||||
{
|
||||
_taskQueue.Enqueue(operation);
|
||||
SetNewActiveActivity(activity, app);
|
||||
|
||||
// Start thread to run the task (unless it's already running)
|
||||
if (_thread == null)
|
||||
{
|
||||
_statusLogger.StartLogging("", false);
|
||||
_thread = new Java.Lang.Thread(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
OperationWithFinishHandler task;
|
||||
lock (_taskQueueLock)
|
||||
{
|
||||
if (!_taskQueue.Any())
|
||||
{
|
||||
_thread = null;
|
||||
_statusLogger.EndLogging();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
task = _taskQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
task.Run();
|
||||
}
|
||||
|
||||
});
|
||||
_thread.Start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SetNewActiveActivity(Activity? activity, IKp2aApp app)
|
||||
{
|
||||
lock (_taskQueueLock)
|
||||
{
|
||||
var progressUi = (activity as IProgressUiProvider)?.ProgressUi;
|
||||
if (_statusLogger == null)
|
||||
{
|
||||
_statusLogger = new ProgressUiAsStatusLoggerAdapter(progressUi, app);
|
||||
}
|
||||
else
|
||||
{
|
||||
_statusLogger.SetNewProgressUi(progressUi);
|
||||
}
|
||||
|
||||
foreach (var task in _taskQueue)
|
||||
{
|
||||
task.ActiveActivity = activity;
|
||||
task.SetStatusLogger(_statusLogger);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class ProgressUiAsStatusLoggerAdapter : IKp2aStatusLogger
|
||||
{
|
||||
private IProgressUi? _progressUi;
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
private string _lastMessage = "";
|
||||
private string _lastSubMessage = "";
|
||||
private bool _isVisible = false;
|
||||
|
||||
public ProgressUiAsStatusLoggerAdapter(IProgressUi progressUi, IKp2aApp app)
|
||||
{
|
||||
_progressUi = progressUi;
|
||||
_app = app;
|
||||
}
|
||||
|
||||
public void SetNewProgressUi(IProgressUi progressUi)
|
||||
{
|
||||
_progressUi = progressUi;
|
||||
if (_isVisible)
|
||||
{
|
||||
progressUi?.Show();
|
||||
progressUi?.UpdateMessage(_lastMessage);
|
||||
progressUi?.UpdateSubMessage(_lastSubMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
progressUi?.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
public void StartLogging(string strOperation, bool bWriteOperationToLog)
|
||||
{
|
||||
_progressUi?.Show();
|
||||
_isVisible = true;
|
||||
}
|
||||
|
||||
public void EndLogging()
|
||||
{
|
||||
_progressUi?.Hide();
|
||||
_isVisible = false;
|
||||
}
|
||||
|
||||
public bool SetProgress(uint uPercent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetText(string strNewText, LogStatusType lsType)
|
||||
{
|
||||
if (strNewText.StartsWith("KP2AKEY_"))
|
||||
{
|
||||
UiStringKey key;
|
||||
if (Enum.TryParse(strNewText.Substring("KP2AKEY_".Length), true, out key))
|
||||
{
|
||||
UpdateMessage(_app.GetResourceString(key));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
UpdateMessage(strNewText);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UpdateMessage(string message)
|
||||
{
|
||||
_progressUi?.UpdateMessage(message);
|
||||
_lastMessage = message;
|
||||
}
|
||||
|
||||
public void UpdateSubMessage(string submessage)
|
||||
{
|
||||
_progressUi?.UpdateSubMessage(submessage);
|
||||
_lastSubMessage = submessage;
|
||||
}
|
||||
|
||||
public bool ContinueWork()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UpdateMessage(UiStringKey stringKey)
|
||||
{
|
||||
if (_app != null)
|
||||
UpdateMessage(_app.GetResourceString(stringKey));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Class to run a task while a progress dialog is shown
|
||||
/// </summary>
|
||||
public class BlockingOperationRunner
|
||||
{
|
||||
//for handling Activity recreation situations, we need access to the currently active task. It must hold that there is no more than one active task.
|
||||
private static BlockingOperationRunner _currentTask = null;
|
||||
|
||||
@@ -27,6 +27,20 @@ namespace keepass2android
|
||||
void UpdateMessage(UiStringKey stringKey);
|
||||
}
|
||||
|
||||
public interface IProgressUi
|
||||
{
|
||||
void Show();
|
||||
void Hide();
|
||||
void UpdateMessage(String message);
|
||||
void UpdateSubMessage(String submessage);
|
||||
}
|
||||
|
||||
public interface IProgressUiProvider
|
||||
{
|
||||
IProgressUi? ProgressUi { get; }
|
||||
}
|
||||
|
||||
|
||||
public class Kp2aNullStatusLogger : IKp2aStatusLogger
|
||||
{
|
||||
public void StartLogging(string strOperation, bool bWriteOperationToLog)
|
||||
|
||||
@@ -56,6 +56,7 @@ using Android.Util;
|
||||
using AndroidX.Core.Content;
|
||||
using Google.Android.Material.Dialog;
|
||||
using keepass2android;
|
||||
using keepass2android.views;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
@@ -97,7 +98,7 @@ namespace keepass2android
|
||||
|
||||
[Activity (Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden,
|
||||
Theme = "@style/Kp2aTheme_ActionBar")]
|
||||
public class EntryActivity : LockCloseActivity
|
||||
public class EntryActivity : LockCloseActivity, IProgressUiProvider
|
||||
{
|
||||
public const String KeyEntry = "entry";
|
||||
public const String KeyRefreshPos = "refresh_pos";
|
||||
@@ -1603,5 +1604,7 @@ namespace keepass2android
|
||||
imageViewerIntent.PutExtra("EntryKey", key);
|
||||
StartActivity(imageViewerIntent);
|
||||
}
|
||||
}
|
||||
|
||||
public IProgressUi? ProgressUi => FindViewById<BackgroundOperationContainer>(Resource.Id.background_ops_container);
|
||||
}
|
||||
}
|
||||
@@ -43,11 +43,12 @@ using keepass2android;
|
||||
using KeeTrayTOTP.Libraries;
|
||||
using AndroidX.AppCompat.Widget;
|
||||
using Google.Android.Material.Dialog;
|
||||
using keepass2android.views;
|
||||
using SearchView = AndroidX.AppCompat.Widget.SearchView;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public abstract class GroupBaseActivity : LockCloseActivity
|
||||
public abstract class GroupBaseActivity : LockCloseActivity, IProgressUiProvider
|
||||
{
|
||||
public const String KeyEntry = "entry";
|
||||
public const String KeyMode = "mode";
|
||||
@@ -1408,6 +1409,14 @@ namespace keepass2android
|
||||
{
|
||||
GroupEditActivity.Launch(this, pwGroup.ParentGroup, pwGroup);
|
||||
}
|
||||
|
||||
public IProgressUi ProgressUi
|
||||
{
|
||||
get
|
||||
{
|
||||
return FindViewById<BackgroundOperationContainer>(Resource.Id.background_ops_container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class GroupListFragment : ListFragment, AbsListView.IMultiChoiceModeListener
|
||||
|
||||
@@ -105,6 +105,7 @@ namespace keepass2android
|
||||
protected override void OnStart()
|
||||
{
|
||||
BlockingOperationRunner.SetNewActiveActivity(this);
|
||||
BackgroundOperationRunner.Instance.SetNewActiveActivity(this, App.Kp2a);
|
||||
base.OnStart();
|
||||
Kp2aLog.Log(ClassName + ".OnStart" + " " + ID);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/background_ops_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/md_theme_surfaceVariant"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/background_ops_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:text="" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/background_ops_submessage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:textSize="12sp"
|
||||
android:text="" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -4,18 +4,35 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
<LinearLayout android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
|
||||
|
||||
<keepass2android.views.BackgroundOperationContainer
|
||||
android:visibility="gone"
|
||||
android:id="@+id/background_ops_container"
|
||||
android:layout_below="@id/top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/entry_scroll"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:fillViewport="true"
|
||||
android:background="?android:attr/colorBackground"
|
||||
android:scrollbarStyle="insideOverlay">
|
||||
|
||||
<keepass2android.view.EntryContentsView
|
||||
android:id="@+id/entry_contents"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" />
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/entry_edit"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -355,29 +355,14 @@
|
||||
android:layout_above="@id/bottom_bar"
|
||||
android:background="#b8b8b8" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/background_ops_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/md_theme_surfaceVariant"
|
||||
|
||||
android:layout_below="@id/top"
|
||||
android:orientation="vertical" >
|
||||
<keepass2android.views.BackgroundOperationContainer
|
||||
android:visibility="gone"
|
||||
android:id="@+id/background_ops_container"
|
||||
android:layout_below="@id/top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:text="Synchronisierung läuft..." />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
/>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/main_content"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.OS;
|
||||
using Android.Widget;
|
||||
using keepass2android.Io;
|
||||
using KeePassLib.Serialization;
|
||||
@@ -56,17 +57,17 @@ namespace keepass2android
|
||||
OnOperationFinishedHandler onOperationFinishedHandler = new ActionOnOperationFinished(_activity, (success, message, activity) =>
|
||||
{
|
||||
if (!String.IsNullOrEmpty(message))
|
||||
App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error);
|
||||
App.Kp2a.ShowMessage(activity, message, success ? MessageSeverity.Info : MessageSeverity.Error);
|
||||
|
||||
// Tell the adapter to refresh it's list
|
||||
BaseAdapter adapter = (activity as GroupBaseActivity)?.ListAdapter;
|
||||
adapter?.NotifyDataSetChanged();
|
||||
BaseAdapter adapter = (activity as GroupBaseActivity)?.ListAdapter;
|
||||
new Handler(Looper.MainLooper).Post(() => adapter?.NotifyDataSetChanged());
|
||||
|
||||
if (App.Kp2a.CurrentDb?.OtpAuxFileIoc != null)
|
||||
{
|
||||
var task2 = new SyncOtpAuxFile(_activity, App.Kp2a.CurrentDb.OtpAuxFileIoc);
|
||||
|
||||
//TODO new BackgroundOperationRunner(App.Kp2a, activity, task2).Run(true);
|
||||
|
||||
BackgroundOperationRunner.Instance.Run(_activity, App.Kp2a, task2);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -82,8 +83,7 @@ namespace keepass2android
|
||||
task = new CheckDatabaseForChanges(_activity, App.Kp2a, onOperationFinishedHandler);
|
||||
}
|
||||
|
||||
//TODO var backgroundTaskRunner = new BackgroundOperationRunner(App.Kp2a, _activity, task);
|
||||
//TODO backgroundTaskRunner.Run();
|
||||
BackgroundOperationRunner.Instance.Run(_activity, App.Kp2a, task);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ using Android.Views;
|
||||
using Android.Widget;
|
||||
using Google.Android.Material.Dialog;
|
||||
using keepass2android;
|
||||
using KeePassLib.Interfaces;
|
||||
|
||||
namespace keepass2android.views
|
||||
{
|
||||
@@ -103,4 +104,92 @@ namespace keepass2android.views
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class BackgroundOperationContainer : LinearLayout, IProgressUi
|
||||
{
|
||||
protected BackgroundOperationContainer(IntPtr javaReference, JniHandleOwnership transfer) : base(
|
||||
javaReference, transfer)
|
||||
{
|
||||
}
|
||||
|
||||
public BackgroundOperationContainer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public BackgroundOperationContainer(Context context, IAttributeSet attrs) : base(context, attrs)
|
||||
{
|
||||
Initialize(attrs);
|
||||
}
|
||||
|
||||
public BackgroundOperationContainer(Context context, IAttributeSet attrs, int defStyle) : base(context,
|
||||
attrs, defStyle)
|
||||
{
|
||||
Initialize(attrs);
|
||||
}
|
||||
|
||||
private void Initialize(IAttributeSet attrs)
|
||||
{
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater)Context.GetSystemService(Context.LayoutInflaterService);
|
||||
inflater.Inflate(Resource.Layout.background_operation_container, this);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
new Handler(Looper.MainLooper).Post(() =>
|
||||
{
|
||||
Visibility = ViewStates.Visible;
|
||||
FindViewById<TextView>(Resource.Id.background_ops_message)!.Visibility = ViewStates.Gone;
|
||||
FindViewById<TextView>(Resource.Id.background_ops_submessage)!.Visibility = ViewStates.Gone;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
new Handler(Looper.MainLooper).Post(() =>
|
||||
{
|
||||
String activityType = Context.GetType().FullName;
|
||||
Kp2aLog.Log("Hiding background ops container in" + activityType);
|
||||
Visibility = ViewStates.Gone;
|
||||
});
|
||||
}
|
||||
|
||||
public void UpdateMessage(string message)
|
||||
{
|
||||
new Handler(Looper.MainLooper).Post(() =>
|
||||
{
|
||||
TextView messageTextView = FindViewById<TextView>(Resource.Id.background_ops_message)!;
|
||||
if (string.IsNullOrEmpty(message))
|
||||
{
|
||||
messageTextView.Visibility = ViewStates.Gone;
|
||||
}
|
||||
else
|
||||
{
|
||||
messageTextView.Visibility = ViewStates.Visible;
|
||||
messageTextView.Text = message;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void UpdateSubMessage(string submessage)
|
||||
{
|
||||
new Handler(Looper.MainLooper).Post(() =>
|
||||
{
|
||||
TextView subMessageTextView = FindViewById<TextView>(Resource.Id.background_ops_submessage)!;
|
||||
if (string.IsNullOrEmpty(submessage))
|
||||
{
|
||||
subMessageTextView.Visibility = ViewStates.Gone;
|
||||
}
|
||||
else
|
||||
{
|
||||
subMessageTextView.Visibility = ViewStates.Visible;
|
||||
subMessageTextView.Text = submessage;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user