2016-05-02 09:52:09 +03:00
|
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Bit.App.Abstractions;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
using Bit.App.Pages;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
using Xamarin.Forms;
|
2016-05-21 19:32:34 +03:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using Plugin.Fingerprint.Abstractions;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Plugin.Settings.Abstractions;
|
2016-06-17 07:01:25 +03:00
|
|
|
|
using Bit.App.Controls;
|
2016-07-02 01:54:00 +03:00
|
|
|
|
using Plugin.Connectivity.Abstractions;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using Acr.UserDialogs;
|
2016-08-06 08:43:48 +03:00
|
|
|
|
using XLabs.Ioc;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
|
|
|
|
namespace Bit.App
|
|
|
|
|
{
|
|
|
|
|
public class App : Application
|
|
|
|
|
{
|
|
|
|
|
private readonly IDatabaseService _databaseService;
|
2016-07-02 01:54:00 +03:00
|
|
|
|
private readonly IConnectivity _connectivity;
|
|
|
|
|
private readonly IUserDialogs _userDialogs;
|
2016-07-01 03:08:34 +03:00
|
|
|
|
private readonly ISyncService _syncService;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
private readonly IAuthService _authService;
|
2016-05-21 19:32:34 +03:00
|
|
|
|
private readonly IFingerprint _fingerprint;
|
|
|
|
|
private readonly ISettings _settings;
|
2016-07-20 06:29:32 +03:00
|
|
|
|
private readonly ILockService _lockService;
|
2016-08-04 07:06:09 +03:00
|
|
|
|
private readonly IGoogleAnalyticsService _googleAnalyticsService;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-05-21 19:32:34 +03:00
|
|
|
|
public App(
|
|
|
|
|
IAuthService authService,
|
2016-07-02 01:54:00 +03:00
|
|
|
|
IConnectivity connectivity,
|
|
|
|
|
IUserDialogs userDialogs,
|
2016-05-21 19:32:34 +03:00
|
|
|
|
IDatabaseService databaseService,
|
2016-07-01 03:08:34 +03:00
|
|
|
|
ISyncService syncService,
|
2016-05-21 19:32:34 +03:00
|
|
|
|
IFingerprint fingerprint,
|
2016-07-20 01:46:39 +03:00
|
|
|
|
ISettings settings,
|
2016-08-04 07:06:09 +03:00
|
|
|
|
ILockService lockService,
|
|
|
|
|
IGoogleAnalyticsService googleAnalyticsService)
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
|
|
|
|
_databaseService = databaseService;
|
2016-07-02 01:54:00 +03:00
|
|
|
|
_connectivity = connectivity;
|
|
|
|
|
_userDialogs = userDialogs;
|
2016-07-01 03:08:34 +03:00
|
|
|
|
_syncService = syncService;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
_authService = authService;
|
2016-05-21 19:32:34 +03:00
|
|
|
|
_fingerprint = fingerprint;
|
|
|
|
|
_settings = settings;
|
2016-07-20 06:29:32 +03:00
|
|
|
|
_lockService = lockService;
|
2016-08-04 07:06:09 +03:00
|
|
|
|
_googleAnalyticsService = googleAnalyticsService;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-06-17 07:01:25 +03:00
|
|
|
|
SetStyles();
|
|
|
|
|
|
2016-05-02 09:52:09 +03:00
|
|
|
|
if(authService.IsAuthenticated)
|
|
|
|
|
{
|
2016-05-03 00:50:16 +03:00
|
|
|
|
MainPage = new MainPage();
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-08-30 06:50:22 +03:00
|
|
|
|
MainPage = new ExtendedNavigationPage(new HomePage());
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-01 03:08:34 +03:00
|
|
|
|
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, args) =>
|
|
|
|
|
{
|
|
|
|
|
await CheckLockAsync(args);
|
2016-07-07 05:33:50 +03:00
|
|
|
|
await Task.Run(() => IncrementalSyncAsync()).ConfigureAwait(false);
|
2016-07-01 03:08:34 +03:00
|
|
|
|
});
|
|
|
|
|
|
2016-08-17 07:39:42 +03:00
|
|
|
|
MessagingCenter.Subscribe<Application, bool>(Current, "Lock", (sender, args) =>
|
2016-05-21 19:32:34 +03:00
|
|
|
|
{
|
2016-08-17 07:39:42 +03:00
|
|
|
|
Device.BeginInvokeOnMainThread(async () => await CheckLockAsync(args));
|
2016-05-21 19:32:34 +03:00
|
|
|
|
});
|
2016-07-20 01:46:39 +03:00
|
|
|
|
|
|
|
|
|
MessagingCenter.Subscribe<Application, string>(Current, "Logout", (sender, args) =>
|
|
|
|
|
{
|
2016-07-20 05:00:28 +03:00
|
|
|
|
Device.BeginInvokeOnMainThread(() => Logout(args));
|
2016-07-20 01:46:39 +03:00
|
|
|
|
});
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-02 01:54:00 +03:00
|
|
|
|
protected async override void OnStart()
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
|
|
|
|
// Handle when your app starts
|
2016-07-02 01:54:00 +03:00
|
|
|
|
await CheckLockAsync(false);
|
2016-05-02 09:52:09 +03:00
|
|
|
|
_databaseService.CreateTables();
|
2016-07-07 05:33:50 +03:00
|
|
|
|
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
|
2016-05-21 19:32:34 +03:00
|
|
|
|
|
|
|
|
|
Debug.WriteLine("OnStart");
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnSleep()
|
|
|
|
|
{
|
|
|
|
|
// Handle when your app sleeps
|
2016-05-21 19:32:34 +03:00
|
|
|
|
Debug.WriteLine("OnSleep");
|
2016-06-05 05:35:03 +03:00
|
|
|
|
|
2016-08-24 07:15:13 +03:00
|
|
|
|
if(Device.OS == TargetPlatform.Android && !TopPageIsLock())
|
2016-06-05 05:35:03 +03:00
|
|
|
|
{
|
2016-08-09 02:00:36 +03:00
|
|
|
|
_settings.AddOrUpdateValue(Constants.LastActivityDate, DateTime.UtcNow);
|
2016-06-05 05:35:03 +03:00
|
|
|
|
}
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-02 01:54:00 +03:00
|
|
|
|
protected async override void OnResume()
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
2016-08-27 21:36:32 +03:00
|
|
|
|
base.OnResume();
|
|
|
|
|
|
|
|
|
|
// workaround for app compat bug
|
|
|
|
|
// ref https://forums.xamarin.com/discussion/62414/app-resuming-results-in-crash-with-formsappcompatactivity
|
|
|
|
|
await Task.Delay(10);
|
|
|
|
|
|
2016-05-02 09:52:09 +03:00
|
|
|
|
// Handle when your app resumes
|
2016-05-21 19:32:34 +03:00
|
|
|
|
Debug.WriteLine("OnResume");
|
2016-06-05 05:35:03 +03:00
|
|
|
|
|
|
|
|
|
if(Device.OS == TargetPlatform.Android)
|
|
|
|
|
{
|
2016-07-02 01:54:00 +03:00
|
|
|
|
await CheckLockAsync(false);
|
2016-06-05 05:35:03 +03:00
|
|
|
|
}
|
2016-06-07 04:13:00 +03:00
|
|
|
|
|
2016-06-08 02:19:21 +03:00
|
|
|
|
var lockPinPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as LockPinPage;
|
|
|
|
|
if(lockPinPage != null)
|
2016-06-07 04:13:00 +03:00
|
|
|
|
{
|
2016-08-26 04:43:47 +03:00
|
|
|
|
lockPinPage.PinControl.Entry.FocusWithDelay();
|
2016-06-07 04:13:00 +03:00
|
|
|
|
}
|
2016-05-21 19:32:34 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-07 05:33:50 +03:00
|
|
|
|
private async Task IncrementalSyncAsync()
|
|
|
|
|
{
|
|
|
|
|
if(_connectivity.IsConnected)
|
|
|
|
|
{
|
|
|
|
|
var attempt = 0;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2016-08-17 07:39:42 +03:00
|
|
|
|
await _syncService.IncrementalSyncAsync(TimeSpan.FromMinutes(30)).ConfigureAwait(false);
|
2016-07-07 05:33:50 +03:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
catch(WebException)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine("Failed to incremental sync.");
|
|
|
|
|
if(attempt >= 1)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
await Task.Delay(1000);
|
|
|
|
|
}
|
|
|
|
|
attempt++;
|
|
|
|
|
}
|
2016-08-20 01:42:27 +03:00
|
|
|
|
catch(Exception e) when(e is TaskCanceledException || e is OperationCanceledException)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine("Cancellation exception.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-07-07 05:33:50 +03:00
|
|
|
|
} while(attempt <= 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine("Not connected.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task FullSyncAsync()
|
|
|
|
|
{
|
|
|
|
|
if(_connectivity.IsConnected)
|
|
|
|
|
{
|
|
|
|
|
var attempt = 0;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2016-08-17 07:39:42 +03:00
|
|
|
|
await _syncService.FullSyncAsync().ConfigureAwait(false);
|
2016-07-07 05:33:50 +03:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
catch(WebException)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine("Failed to full sync.");
|
|
|
|
|
if(attempt >= 1)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
await Task.Delay(1000);
|
|
|
|
|
}
|
|
|
|
|
attempt++;
|
|
|
|
|
}
|
2016-08-20 01:42:27 +03:00
|
|
|
|
catch(Exception e) when(e is TaskCanceledException || e is OperationCanceledException)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine("Cancellation exception.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-07-07 05:33:50 +03:00
|
|
|
|
} while(attempt <= 1);
|
|
|
|
|
}
|
2016-08-20 01:42:27 +03:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine("Not connected.");
|
|
|
|
|
}
|
2016-07-07 05:33:50 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-06 08:43:48 +03:00
|
|
|
|
private async void Logout(string logoutMessage)
|
2016-07-20 01:46:39 +03:00
|
|
|
|
{
|
|
|
|
|
_authService.LogOut();
|
2016-08-06 08:43:48 +03:00
|
|
|
|
|
2016-08-04 07:32:37 +03:00
|
|
|
|
_googleAnalyticsService.TrackAppEvent("LoggedOut");
|
2016-08-04 07:06:09 +03:00
|
|
|
|
_googleAnalyticsService.RefreshUserId();
|
2016-08-06 08:43:48 +03:00
|
|
|
|
|
2016-08-30 06:50:22 +03:00
|
|
|
|
Current.MainPage = new ExtendedNavigationPage(new HomePage());
|
2016-07-20 01:46:39 +03:00
|
|
|
|
if(!string.IsNullOrWhiteSpace(logoutMessage))
|
|
|
|
|
{
|
2016-07-26 07:38:41 +03:00
|
|
|
|
_userDialogs.Toast(logoutMessage);
|
2016-07-20 01:46:39 +03:00
|
|
|
|
}
|
2016-08-06 22:21:59 +03:00
|
|
|
|
|
|
|
|
|
var deviceApiRepository = Resolver.Resolve<IDeviceApiRepository>();
|
|
|
|
|
var appIdService = Resolver.Resolve<IAppIdService>();
|
|
|
|
|
_settings.Remove(Constants.PushLastRegistrationDate);
|
|
|
|
|
await Task.Run(() => deviceApiRepository.PutClearTokenAsync(appIdService.AppId)).ConfigureAwait(false);
|
2016-07-20 01:46:39 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-22 06:26:35 +03:00
|
|
|
|
private async Task CheckLockAsync(bool forceLock)
|
2016-05-21 19:32:34 +03:00
|
|
|
|
{
|
2016-08-24 07:15:13 +03:00
|
|
|
|
if(TopPageIsLock())
|
|
|
|
|
{
|
|
|
|
|
// already locked
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-20 06:29:32 +03:00
|
|
|
|
var lockType = _lockService.GetLockType(forceLock);
|
2016-06-28 03:56:59 +03:00
|
|
|
|
var currentPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as ExtendedNavigationPage;
|
2016-07-20 06:29:32 +03:00
|
|
|
|
switch(lockType)
|
2016-05-22 05:50:15 +03:00
|
|
|
|
{
|
2016-07-20 06:29:32 +03:00
|
|
|
|
case Enums.LockType.Fingerprint:
|
2016-08-24 07:15:13 +03:00
|
|
|
|
await Current.MainPage.Navigation.PushModalAsync(new ExtendedNavigationPage(new LockFingerprintPage(!forceLock)), false);
|
2016-07-20 06:29:32 +03:00
|
|
|
|
break;
|
|
|
|
|
case Enums.LockType.PIN:
|
2016-08-26 04:43:47 +03:00
|
|
|
|
await Current.MainPage.Navigation.PushModalAsync(new ExtendedNavigationPage(new LockPinPage()), false);
|
2016-07-20 06:29:32 +03:00
|
|
|
|
break;
|
|
|
|
|
case Enums.LockType.Password:
|
2016-08-24 07:15:13 +03:00
|
|
|
|
await Current.MainPage.Navigation.PushModalAsync(new ExtendedNavigationPage(new LockPasswordPage()), false);
|
2016-07-20 06:29:32 +03:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2016-05-21 19:32:34 +03:00
|
|
|
|
}
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
2016-06-17 07:01:25 +03:00
|
|
|
|
|
2016-08-24 07:15:13 +03:00
|
|
|
|
private bool TopPageIsLock()
|
|
|
|
|
{
|
|
|
|
|
var currentPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as ExtendedNavigationPage;
|
|
|
|
|
if((currentPage?.CurrentPage as LockFingerprintPage) != null)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if((currentPage?.CurrentPage as LockPinPage) != null)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if((currentPage?.CurrentPage as LockPasswordPage) != null)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-17 07:01:25 +03:00
|
|
|
|
private void SetStyles()
|
|
|
|
|
{
|
|
|
|
|
var gray = Color.FromHex("333333");
|
|
|
|
|
var grayLight = Color.FromHex("777777");
|
|
|
|
|
var grayLighter = Color.FromHex("d2d6de");
|
|
|
|
|
var primaryColor = Color.FromHex("3c8dbc");
|
2016-06-23 06:50:38 +03:00
|
|
|
|
var primaryColorAccent = Color.FromHex("286090");
|
2016-06-17 07:01:25 +03:00
|
|
|
|
|
|
|
|
|
Resources = new ResourceDictionary();
|
|
|
|
|
|
|
|
|
|
// Labels
|
|
|
|
|
|
|
|
|
|
Resources.Add("text-muted", new Style(typeof(Label))
|
|
|
|
|
{
|
|
|
|
|
Setters = {
|
|
|
|
|
new Setter { Property = Label.TextColorProperty, Value = grayLight }
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Buttons
|
|
|
|
|
|
|
|
|
|
Resources.Add("btn-default", new Style(typeof(Button))
|
|
|
|
|
{
|
|
|
|
|
Setters = {
|
|
|
|
|
new Setter { Property = Button.TextColorProperty, Value = gray }
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2016-06-23 06:50:38 +03:00
|
|
|
|
Resources.Add("btn-primary", new Style(typeof(Button))
|
|
|
|
|
{
|
|
|
|
|
Setters = {
|
|
|
|
|
new Setter { Property = Button.TextColorProperty, Value = Color.White },
|
|
|
|
|
new Setter { Property = Button.BackgroundColorProperty, Value = primaryColor },
|
|
|
|
|
new Setter { Property = Button.FontAttributesProperty, Value = FontAttributes.Bold },
|
|
|
|
|
new Setter { Property = Button.BorderRadiusProperty, Value = 0 }
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Resources.Add("btn-primaryAccent", new Style(typeof(Button))
|
|
|
|
|
{
|
|
|
|
|
Setters = {
|
|
|
|
|
new Setter { Property = Button.TextColorProperty, Value = primaryColorAccent }
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2016-06-24 06:03:00 +03:00
|
|
|
|
Resources.Add("btn-white", new Style(typeof(Button))
|
|
|
|
|
{
|
|
|
|
|
Setters = {
|
|
|
|
|
new Setter { Property = Button.BackgroundColorProperty, Value = Color.White },
|
|
|
|
|
new Setter { Property = Button.TextColorProperty, Value = primaryColor },
|
|
|
|
|
new Setter { Property = Button.FontAttributesProperty, Value = FontAttributes.Bold },
|
|
|
|
|
new Setter { Property = Button.BorderRadiusProperty, Value = 0 }
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2016-06-17 07:01:25 +03:00
|
|
|
|
Resources.Add(new Style(typeof(Button))
|
|
|
|
|
{
|
|
|
|
|
Setters = {
|
|
|
|
|
new Setter { Property = Button.TextColorProperty, Value = primaryColor }
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2016-08-18 15:43:55 +03:00
|
|
|
|
Resources.Add(new Style(typeof(ExtendedButton))
|
|
|
|
|
{
|
|
|
|
|
Setters = {
|
|
|
|
|
new Setter { Property = Button.TextColorProperty, Value = primaryColor }
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2016-06-17 07:01:25 +03:00
|
|
|
|
// List View
|
|
|
|
|
|
|
|
|
|
Resources.Add(new Style(typeof(ListView))
|
|
|
|
|
{
|
|
|
|
|
Setters = {
|
|
|
|
|
new Setter { Property = ListView.SeparatorColorProperty, Value = grayLighter }
|
|
|
|
|
}
|
|
|
|
|
});
|
2016-07-12 06:55:16 +03:00
|
|
|
|
|
|
|
|
|
// Search Bar
|
|
|
|
|
|
|
|
|
|
Resources.Add(new Style(typeof(SearchBar))
|
|
|
|
|
{
|
|
|
|
|
Setters = {
|
|
|
|
|
new Setter { Property = SearchBar.CancelButtonColorProperty, Value = primaryColor }
|
|
|
|
|
}
|
|
|
|
|
});
|
2016-06-17 07:01:25 +03:00
|
|
|
|
}
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
}
|