Fix Progress dialog crash on tombstoning (#1682)

* Changed ProgressDialog because deprecated and improved the dismissal of the dialog in order for it not to crash the app on certain situations

* Removed android version check given that our minimum is greater that the check
This commit is contained in:
Federico Maccaroni 2022-01-21 20:14:48 -03:00 committed by GitHub
parent 137c762e40
commit 5a6aec51f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 146 additions and 15 deletions

View File

@ -191,6 +191,7 @@
<AndroidResource Include="Resources\drawable-v23\splash_screen.xml" />
<AndroidResource Include="Resources\drawable-v23\splash_screen_dark.xml" />
<AndroidResource Include="Resources\drawable\switch_thumb.xml" />
<AndroidResource Include="Resources\layout\progress_dialog_layout.xml" />
<AndroidResource Include="Resources\layout\Tabbar.axml" />
<AndroidResource Include="Resources\layout\Toolbar.axml" />
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_centerInParent="true"
android:orientation="horizontal">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="10dp" />
<TextView
android:id="@+id/txtLoading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:gravity="center|left"
android:textSize="18sp" />
</LinearLayout>
</RelativeLayout>

View File

@ -13,6 +13,7 @@ using Android.OS;
using Android.Provider;
using Android.Text;
using Android.Text.Method;
using Android.Views;
using Android.Views.Autofill;
using Android.Views.InputMethods;
using Android.Webkit;
@ -27,6 +28,7 @@ using Bit.Core.Enums;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Bit.Droid.Autofill;
using Bit.Droid.Utilities;
using Plugin.CurrentActivity;
namespace Bit.Droid.Services
@ -37,7 +39,9 @@ namespace Bit.Droid.Services
private readonly IMessagingService _messagingService;
private readonly IBroadcasterService _broadcasterService;
private readonly Func<IEventService> _eventServiceFunc;
private ProgressDialog _progressDialog;
private AlertDialog _progressDialog;
object _progressDialogLock = new object();
private bool _cameraPermissionsDenied;
private Toast _toast;
private string _userAgent;
@ -108,22 +112,101 @@ namespace Bit.Droid.Services
{
await HideLoadingAsync();
}
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
_progressDialog = new ProgressDialog(activity);
_progressDialog.SetMessage(text);
_progressDialog.SetCancelable(false);
var activity = CrossCurrentActivity.Current.Activity;
var inflater = (LayoutInflater)activity.GetSystemService(Context.LayoutInflaterService);
var dialogView = inflater.Inflate(Resource.Layout.progress_dialog_layout, null);
var txtLoading = dialogView.FindViewById<TextView>(Resource.Id.txtLoading);
txtLoading.Text = text;
txtLoading.SetTextColor(ThemeHelpers.TextColor);
_progressDialog = new AlertDialog.Builder(activity)
.SetView(dialogView)
.SetCancelable(false)
.Create();
_progressDialog.Show();
}
public Task HideLoadingAsync()
{
if (_progressDialog != null)
// Based on https://github.com/redth-org/AndHUD/blob/master/AndHUD/AndHUD.cs
lock (_progressDialogLock)
{
_progressDialog.Dismiss();
_progressDialog.Dispose();
_progressDialog = null;
if (_progressDialog is null)
{
return Task.CompletedTask;
}
void actionDismiss()
{
try
{
if (IsAlive(_progressDialog) && IsAlive(_progressDialog.Window))
{
_progressDialog.Hide();
_progressDialog.Dismiss();
}
}
catch
{
// ignore
}
_progressDialog = null;
}
// First try the SynchronizationContext
if (Application.SynchronizationContext != null)
{
Application.SynchronizationContext.Send(state => actionDismiss(), null);
return Task.CompletedTask;
}
// Otherwise try OwnerActivity on dialog
var ownerActivity = _progressDialog?.OwnerActivity;
if (IsAlive(ownerActivity))
{
ownerActivity.RunOnUiThread(actionDismiss);
return Task.CompletedTask;
}
// Otherwise try get it from the Window Context
if (_progressDialog?.Window?.Context is Activity windowActivity && IsAlive(windowActivity))
{
windowActivity.RunOnUiThread(actionDismiss);
return Task.CompletedTask;
}
// Finally if all else fails, let's see if current activity is MainActivity
if (CrossCurrentActivity.Current.Activity is MainActivity activity && IsAlive(activity))
{
activity.RunOnUiThread(actionDismiss);
return Task.CompletedTask;
}
return Task.CompletedTask;
}
return Task.FromResult(0);
}
bool IsAlive(Java.Lang.Object @object)
{
if (@object == null)
return false;
if (@object.Handle == IntPtr.Zero)
return false;
if (@object is Activity activity)
{
if (activity.IsFinishing)
return false;
if (activity.IsDestroyed)
return false;
}
return true;
}
public bool OpenFile(byte[] fileData, string id, string fileName)

View File

@ -36,6 +36,10 @@ namespace Bit.Droid.Utilities
{
get => ThemeManager.GetResourceColor("SwitchThumbColor").ToAndroid();
}
public static Color TextColor
{
get => ThemeManager.GetResourceColor("TextColor").ToAndroid();
}
public static void SetAppearance(string theme, bool osDarkModeEnabled)
{

View File

@ -13,7 +13,9 @@ using System.Threading.Tasks;
using Bit.App.Controls;
using Bit.Core;
using Xamarin.Forms;
using View = Xamarin.Forms.View;
#if !FDROID
using Microsoft.AppCenter.Crashes;
#endif
namespace Bit.App.Pages
{
@ -494,9 +496,12 @@ namespace Bit.App.Pages
try
{
await _deviceActionService.ShowLoadingAsync(AppResources.Saving);
await _cipherService.SaveWithServerAsync(cipher);
Cipher.Id = cipher.Id;
await _deviceActionService.HideLoadingAsync();
_platformUtilsService.ShowToast("success", null,
EditMode && !CloneMode ? AppResources.ItemUpdated : AppResources.NewItemCreated);
_messagingService.Send(EditMode && !CloneMode ? "editedCipher" : "addedCipher", Cipher.Id);
@ -512,19 +517,30 @@ namespace Bit.App.Pages
{
ViewPage?.UpdateCipherId(this.Cipher.Id);
}
await Page.Navigation.PopModalAsync();
// if the app is tombstoned then PopModalAsync would throw index out of bounds
if (Page.Navigation?.ModalStack?.Count > 0)
{
await Page.Navigation.PopModalAsync();
}
}
return true;
}
catch (ApiException e)
catch (ApiException apiEx)
{
await _deviceActionService.HideLoadingAsync();
if (e?.Error != null)
if (apiEx?.Error != null)
{
await _platformUtilsService.ShowDialogAsync(e.Error.GetSingleMessage(),
await _platformUtilsService.ShowDialogAsync(apiEx.Error.GetSingleMessage(),
AppResources.AnErrorHasOccurred);
}
}
catch(Exception genex)
{
#if !FDROID
Crashes.TrackError(genex);
#endif
await _deviceActionService.HideLoadingAsync();
}
return false;
}