add tools page for autofill service

This commit is contained in:
Kyle Spearrin 2017-11-27 17:27:11 -05:00
parent 9bbddd6aeb
commit 783c4d104c
17 changed files with 222 additions and 5 deletions

View file

@ -1,4 +1,5 @@
using Android.App; using Android.App;
using Android.Views.Autofill;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using System.Linq; using System.Linq;
using AndroidApp = Android.App.Application; using AndroidApp = Android.App.Application;
@ -13,14 +14,27 @@ namespace Bit.Android.Services
public string Build => AndroidApp.Context.ApplicationContext.PackageManager public string Build => AndroidApp.Context.ApplicationContext.PackageManager
.GetPackageInfo(AndroidApp.Context.PackageName, 0).VersionCode.ToString(); .GetPackageInfo(AndroidApp.Context.PackageName, 0).VersionCode.ToString();
public bool AutofillServiceEnabled => AutofillRunning(); public bool AutofillAccessibilityServiceEnabled => AutofillAccessibilityRunning();
public bool AutofillServiceEnabled => AutofillEnabled();
private bool AutofillRunning() private bool AutofillAccessibilityRunning()
{ {
var manager = ((ActivityManager)Xamarin.Forms.Forms.Context.GetSystemService("activity")); var manager = ((ActivityManager)Xamarin.Forms.Forms.Context.GetSystemService("activity"));
var services = manager.GetRunningServices(int.MaxValue); var services = manager.GetRunningServices(int.MaxValue);
return services.Any(s => s.Process.ToLowerInvariant().Contains("bitwarden") && return services.Any(s => s.Process.ToLowerInvariant().Contains("bitwarden") &&
s.Service.ClassName.ToLowerInvariant().Contains("autofill")); s.Service.ClassName.ToLowerInvariant().Contains("autofill"));
} }
private bool AutofillEnabled()
{
if(global::Android.OS.Build.VERSION.SdkInt < global::Android.OS.BuildVersionCodes.O)
{
return false;
}
var activity = (MainActivity)Xamarin.Forms.Forms.Context;
var afm = (AutofillManager)activity.GetSystemService(Java.Lang.Class.FromType(typeof(AutofillManager)));
return afm.IsEnabled;
}
} }
} }

View file

@ -407,5 +407,13 @@ namespace Bit.Android.Services
ActivityCompat.RequestPermissions(CrossCurrentActivity.Current.Activity, new string[] { permission }, ActivityCompat.RequestPermissions(CrossCurrentActivity.Current.Activity, new string[] { permission },
Constants.SelectFilePermissionRequestCode); Constants.SelectFilePermissionRequestCode);
} }
public void OpenAutofillSettings()
{
var activity = (MainActivity)Forms.Context;
var intent = new Intent(Settings.ActionRequestSetAutofillService);
intent.SetData(global::Android.Net.Uri.Parse("package:com.x8bit.bitwarden"));
activity.StartActivity(intent);
}
} }
} }

View file

@ -1,6 +1,7 @@
using Android.App; using Android.App;
using Android.Content.PM; using Android.Content.PM;
using Android.OS; using Android.OS;
using Android.Views.Autofill;
using Bit.App.Abstractions; using Bit.App.Abstractions;
namespace Bit.Android.Services namespace Bit.Android.Services
@ -44,5 +45,18 @@ namespace Bit.Android.Services
} }
public bool NfcEnabled => Utilities.NfcEnabled(); public bool NfcEnabled => Utilities.NfcEnabled();
public bool HasCamera => Xamarin.Forms.Forms.Context.PackageManager.HasSystemFeature(PackageManager.FeatureCamera); public bool HasCamera => Xamarin.Forms.Forms.Context.PackageManager.HasSystemFeature(PackageManager.FeatureCamera);
public bool AutofillServiceSupported => AutofillSupported();
private bool AutofillSupported()
{
if(Build.VERSION.SdkInt < BuildVersionCodes.O)
{
return false;
}
var activity = (MainActivity)Xamarin.Forms.Forms.Context;
var afm = (AutofillManager)activity.GetSystemService(Java.Lang.Class.FromType(typeof(AutofillManager)));
return afm.IsAutofillSupported;
}
} }
} }

View file

@ -4,6 +4,7 @@
{ {
string Build { get; } string Build { get; }
string Version { get; } string Version { get; }
bool AutofillAccessibilityServiceEnabled { get; }
bool AutofillServiceEnabled { get; } bool AutofillServiceEnabled { get; }
} }
} }

View file

@ -16,6 +16,7 @@ namespace Bit.App.Abstractions
void RateApp(); void RateApp();
void DismissKeyboard(); void DismissKeyboard();
void OpenAccessibilitySettings(); void OpenAccessibilitySettings();
void OpenAutofillSettings();
void LaunchApp(string appName); void LaunchApp(string appName);
} }
} }

View file

@ -7,5 +7,6 @@
float Scale { get; } float Scale { get; }
bool NfcEnabled { get; } bool NfcEnabled { get; }
bool HasCamera { get; } bool HasCamera { get; }
bool AutofillServiceSupported { get; }
} }
} }

View file

@ -182,6 +182,7 @@
<Compile Include="Pages\Settings\SettingsEditFolderPage.cs" /> <Compile Include="Pages\Settings\SettingsEditFolderPage.cs" />
<Compile Include="Pages\Lock\LockFingerprintPage.cs" /> <Compile Include="Pages\Lock\LockFingerprintPage.cs" />
<Compile Include="Pages\Settings\SettingsAboutPage.cs" /> <Compile Include="Pages\Settings\SettingsAboutPage.cs" />
<Compile Include="Pages\Tools\ToolsAutofillServicePage2.cs" />
<Compile Include="Pages\Tools\ToolsAutofillServicePage.cs" /> <Compile Include="Pages\Tools\ToolsAutofillServicePage.cs" />
<Compile Include="Pages\Tools\ToolsExtensionPage.cs" /> <Compile Include="Pages\Tools\ToolsExtensionPage.cs" />
<Compile Include="Pages\Tools\ToolsPasswordGeneratorSettingsPage.cs" /> <Compile Include="Pages\Tools\ToolsPasswordGeneratorSettingsPage.cs" />

View file

@ -200,7 +200,7 @@ namespace Bit.App.Pages
private void UpdateEnabled() private void UpdateEnabled()
{ {
ScrollView.Content = _appInfoService.AutofillServiceEnabled ? EnabledStackLayout : DisabledStackLayout; ScrollView.Content = _appInfoService.AutofillAccessibilityServiceEnabled ? EnabledStackLayout : DisabledStackLayout;
} }
private Label BuildServiceLabel() private Label BuildServiceLabel()

View file

@ -0,0 +1,153 @@
using System;
using Bit.App.Controls;
using Xamarin.Forms;
using XLabs.Ioc;
using Bit.App.Abstractions;
using Bit.App.Resources;
namespace Bit.App.Pages
{
public class ToolsAutofillServicePage2 : ExtendedContentPage
{
private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly IAppInfoService _appInfoService;
private readonly IDeviceActionService _deviceActionService;
private bool _pageDisappeared = false;
public ToolsAutofillServicePage2()
{
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
_appInfoService = Resolver.Resolve<IAppInfoService>();
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
Init();
}
public StackLayout EnabledStackLayout { get; set; }
public StackLayout DisabledStackLayout { get; set; }
public ScrollView ScrollView { get; set; }
public void Init()
{
var enabledFs = new FormattedString();
var statusSpan = new Span { Text = string.Concat(AppResources.Status, " ") };
enabledFs.Spans.Add(statusSpan);
enabledFs.Spans.Add(new Span
{
Text = AppResources.Enabled,
ForegroundColor = Color.Green,
FontAttributes = FontAttributes.Bold,
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))
});
var statusEnabledLabel = new Label
{
FormattedText = enabledFs,
HorizontalTextAlignment = TextAlignment.Center,
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
TextColor = Color.Black
};
var disabledFs = new FormattedString();
disabledFs.Spans.Add(statusSpan);
disabledFs.Spans.Add(new Span
{
Text = AppResources.Disabled,
ForegroundColor = Color.FromHex("c62929"),
FontAttributes = FontAttributes.Bold,
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))
});
var statusDisabledLabel = new Label
{
FormattedText = disabledFs,
HorizontalTextAlignment = TextAlignment.Center,
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
TextColor = Color.Black
};
DisabledStackLayout = new StackLayout
{
Children = { BuildServiceLabel(), statusDisabledLabel, BuildGoButton() },
Orientation = StackOrientation.Vertical,
Spacing = 20,
Padding = new Thickness(20, 30),
VerticalOptions = LayoutOptions.FillAndExpand
};
EnabledStackLayout = new StackLayout
{
Children = { BuildServiceLabel(), statusEnabledLabel },
Orientation = StackOrientation.Vertical,
Spacing = 20,
Padding = new Thickness(20, 30),
VerticalOptions = LayoutOptions.FillAndExpand
};
ScrollView = new ScrollView { Content = DisabledStackLayout };
UpdateEnabled();
Device.StartTimer(new TimeSpan(0, 0, 3), () =>
{
if(_pageDisappeared)
{
return false;
}
UpdateEnabled();
return true;
});
Title = AppResources.AutofillService;
Content = ScrollView;
}
protected override void OnAppearing()
{
_pageDisappeared = false;
base.OnAppearing();
}
protected override void OnDisappearing()
{
_pageDisappeared = true;
base.OnDisappearing();
}
private void UpdateEnabled()
{
ScrollView.Content = _appInfoService.AutofillServiceEnabled ? EnabledStackLayout : DisabledStackLayout;
}
private Label BuildServiceLabel()
{
return new Label
{
Text = AppResources.AutofillDescription,
VerticalOptions = LayoutOptions.Start,
HorizontalTextAlignment = TextAlignment.Center,
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label))
};
}
private ExtendedButton BuildGoButton()
{
return new ExtendedButton
{
Text = AppResources.BitwardenAutofillServiceOpenSettings,
Command = new Command(() =>
{
_googleAnalyticsService.TrackAppEvent("OpenAutofillSettings");
_deviceActionService.OpenAutofillSettings();
}),
VerticalOptions = LayoutOptions.End,
HorizontalOptions = LayoutOptions.Fill,
Style = (Style)Application.Current.Resources["btn-primary"],
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Button))
};
}
}
}

View file

@ -15,11 +15,13 @@ namespace Bit.App.Pages
{ {
private readonly IUserDialogs _userDialogs; private readonly IUserDialogs _userDialogs;
private readonly IGoogleAnalyticsService _googleAnalyticsService; private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly IDeviceInfoService _deviceInfoService;
public ToolsPage() public ToolsPage()
{ {
_userDialogs = Resolver.Resolve<IUserDialogs>(); _userDialogs = Resolver.Resolve<IUserDialogs>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>(); _googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
Init(); Init();
} }
@ -116,7 +118,14 @@ namespace Bit.App.Pages
private void AutofillCell_Tapped(object sender, EventArgs e) private void AutofillCell_Tapped(object sender, EventArgs e)
{ {
Navigation.PushModalAsync(new ExtendedNavigationPage(new ToolsAutofillServicePage())); if(_deviceInfoService.AutofillServiceSupported)
{
Navigation.PushModalAsync(new ExtendedNavigationPage(new ToolsAutofillServicePage2()));
}
else
{
Navigation.PushModalAsync(new ExtendedNavigationPage(new ToolsAutofillServicePage()));
}
} }
private void ExtensionCell_Tapped(object sender, EventArgs e) private void ExtensionCell_Tapped(object sender, EventArgs e)

View file

@ -242,7 +242,7 @@ namespace Bit.App.Pages
DisplayAlert(AppResources.BitwardenAppExtension, AppResources.BitwardenAppExtensionAlert, DisplayAlert(AppResources.BitwardenAppExtension, AppResources.BitwardenAppExtensionAlert,
AppResources.Ok); AppResources.Ok);
} }
else if(Device.RuntimePlatform == Device.Android && !_appInfoService.AutofillServiceEnabled) else if(Device.RuntimePlatform == Device.Android && !_appInfoService.AutofillAccessibilityServiceEnabled)
{ {
DisplayAlert(AppResources.BitwardenAutofillService, AppResources.BitwardenAutofillServiceAlert, DisplayAlert(AppResources.BitwardenAutofillService, AppResources.BitwardenAutofillServiceAlert,
AppResources.Ok); AppResources.Ok);

View file

@ -16,6 +16,7 @@ namespace Bit.UWP.Services
} }
} }
public bool AutofillAccessibilityServiceEnabled => false;
public bool AutofillServiceEnabled => false; public bool AutofillServiceEnabled => false;
} }
} }

View file

@ -55,6 +55,11 @@ namespace Bit.UWP.Services
} }
} }
public void OpenAutofillSettings()
{
throw new NotImplementedException();
}
public Task SelectFileAsync() public Task SelectFileAsync()
{ {
var picker = new Windows.Storage.Pickers.FileOpenPicker var picker = new Windows.Storage.Pickers.FileOpenPicker

View file

@ -39,5 +39,7 @@ namespace Bit.UWP.Services
return cameraList?.Any() ?? false; return cameraList?.Any() ?? false;
} }
} }
public bool AutofillServiceSupported => false;
} }
} }

View file

@ -24,5 +24,6 @@ namespace Bit.iOS.Core.Services
public float Scale => (float)UIScreen.MainScreen.Scale; public float Scale => (float)UIScreen.MainScreen.Scale;
public bool NfcEnabled => false; public bool NfcEnabled => false;
public bool HasCamera => true; public bool HasCamera => true;
public bool AutofillServiceSupported => false;
} }
} }

View file

@ -8,6 +8,7 @@ namespace Bit.iOS.Services
{ {
public string Build => NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString(); public string Build => NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString();
public string Version => NSBundle.MainBundle.InfoDictionary["CFBundleShortVersionString"].ToString(); public string Version => NSBundle.MainBundle.InfoDictionary["CFBundleShortVersionString"].ToString();
public bool AutofillAccessibilityServiceEnabled => false;
public bool AutofillServiceEnabled => false; public bool AutofillServiceEnabled => false;
} }
} }

View file

@ -250,5 +250,10 @@ namespace Bit.iOS.Services
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public void OpenAutofillSettings()
{
throw new NotImplementedException();
}
} }
} }