1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-10 13:23:39 +00:00

PS-70 added vibrate permission to manifest. refactored scanpage code. added manual authentication key feature in scanner.

This commit is contained in:
André Bispo
2022-06-22 12:26:51 +01:00
parent 3522953b8c
commit 94f2c5a4f8
3 changed files with 72 additions and 46 deletions

View File

@@ -12,7 +12,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>

View File

@@ -29,25 +29,31 @@
<Grid
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<zxing:ZXingScannerView
x:Name="_zxing"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
AutomationId="zxingScannerView"
IsVisible="{Binding ShowScanner}"
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="3"
OnScanResult="OnScanResult"/>
<Grid
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
<BoxView
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
IsVisible="{Binding ShowScanner, Converter={StaticResource inverseBool}}"
BackgroundColor="{DynamicResource BackgroundColor}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
BackgroundColor="{DynamicResource BackgroundColor}"/>
<StackLayout
VerticalOptions="Center"
HorizontalOptions="FillAndExpand"
IsVisible="{Binding ShowScanner, Converter={StaticResource inverseBool}}"
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
@@ -59,28 +65,20 @@
Text="{u:I18n AuthenticatorKey}"
StyleClass="box-label" />
<controls:MonoEntry
x:Name="_loginTotpEntry"
x:Name="_authenticationKeyEntry"
Text="{Binding TotpAuthenticationKey}"
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False"
StyleClass="box-value" />
<Button
Text="{u:I18n AddTotp}"
StyleClass="box-button-row"/>
StyleClass="box-button-row"
Clicked="AddAuthenticationKey_OnClicked"/>
</StackLayout>
</Grid>
<Grid
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
AutomationId="zxingDefaultOverlay">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout
VerticalOptions="Center"
HorizontalOptions="FillAndExpand"
IsVisible="{Binding ShowScanner}"
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
@@ -124,7 +122,7 @@
TextColor="White" />
<Label
Text="{u:I18n CameraInstructionBottom}"
AutomationId="zxingDefaultOverlay_TopTextLabel"
AutomationId="zxingDefaultOverlay_BottomTextLabel"
HorizontalOptions="Center"
StyleClass="text-sm"
TextColor="White" />
@@ -142,5 +140,4 @@
</Label.GestureRecognizers>
</Label>
</Grid>
</Grid>
</pages:BaseContentPage>

View File

@@ -17,12 +17,15 @@ namespace Bit.App.Pages
{
private ScanPageViewModel ViewModel => BindingContext as ScanPageViewModel;
private readonly Action<string> _callback;
private CancellationTokenSource _autofocusCts;
private Task _continuousAutofocusTask;
private Color _greenColor;
private SKColor _blueSKColor;
private SKColor _greenSKColor;
private readonly Color _greenColor;
private readonly SKColor _blueSKColor;
private readonly SKColor _greenSKColor;
private readonly Stopwatch _stopwatch;
private bool _pageIsActive;
private bool _qrcodeFound;
private float _scale;
private readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
@@ -45,6 +48,8 @@ namespace Bit.App.Pages
_greenColor = ThemeManager.GetResourceColor("SuccessColor");
_greenSKColor = _greenColor.ToSKColor();
_blueSKColor = ThemeManager.GetResourceColor("PrimaryColor").ToSKColor();
_stopwatch = new Stopwatch();
_qrcodeFound = false;
}
protected override void OnAppearing()
@@ -88,16 +93,14 @@ namespace Bit.App.Pages
}
}, autofocusCts.Token);
_pageIsActive = true;
AnimationLoop();
AnimationLoopAsync();
}
protected override async void OnDisappearing()
{
_autofocusCts?.Cancel();
await _continuousAutofocusTask;
_zxing.IsScanning = false;
_pageIsActive = false;
base.OnDisappearing();
}
@@ -111,7 +114,7 @@ namespace Bit.App.Pages
{
if (text.StartsWith("otpauth://totp"))
{
await QRCodeFound();
await QrCodeFoundAsync();
_callback(text);
return;
}
@@ -123,7 +126,7 @@ namespace Bit.App.Pages
{
if (part.StartsWith("secret="))
{
await QRCodeFound();
await QrCodeFoundAsync();
_callback(part.Substring(7)?.ToUpperInvariant());
return;
}
@@ -133,7 +136,7 @@ namespace Bit.App.Pages
_callback(null);
}
private async Task QRCodeFound()
private async Task QrCodeFoundAsync()
{
_qrcodeFound = true;
Vibration.Vibrate();
@@ -149,16 +152,47 @@ namespace Bit.App.Pages
}
}
private void AddAuthenticationKey_OnClicked(object sender, EventArgs e)
{
var text = ViewModel.TotpAuthenticationKey;
if (!string.IsNullOrWhiteSpace(text))
{
if (text.StartsWith("otpauth://totp"))
{
_callback(text);
return;
}
else if (Uri.TryCreate(text, UriKind.Absolute, out Uri uri) &&
!string.IsNullOrWhiteSpace(uri?.Query))
{
var queryParts = uri.Query.Substring(1).ToLowerInvariant().Split('&');
foreach (var part in queryParts)
{
if (part.StartsWith("secret="))
{
_callback(part.Substring(7)?.ToUpperInvariant());
return;
}
}
}
}
_callback(null);
}
private void ToggleScanMode_OnTapped(object sender, EventArgs e)
{
ViewModel.ToggleScanModeCommand.Execute(null);
if (!ViewModel.ShowScanner)
{
_authenticationKeyEntry.Focus();
}
}
private void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
var info = args.Info;
var surface = args.Surface;
var canvas = surface.Canvas;
var margins = 20;
var maxSquareSize = (Math.Min(info.Height, info.Width)*0.9f - margins) * _scale;
var squareSize = maxSquareSize;
@@ -167,10 +201,10 @@ namespace Bit.App.Pages
var startYPoint = (info.Height / 2) - (squareSize / 2);
canvas.Clear(SKColors.Transparent);
using (SKPaint strokePaint = new SKPaint
using (var strokePaint = new SKPaint
{
Color = _qrcodeFound ? _greenSKColor : _blueSKColor,
StrokeWidth = 9*_scale,
StrokeWidth = 9 * _scale,
StrokeCap = SKStrokeCap.Round,
})
{
@@ -189,12 +223,7 @@ namespace Bit.App.Pages
canvas.DrawLine (startXPoint+squareSize, startYPoint+squareSize, startXPoint+squareSize, startYPoint+squareSize-lineSize, strokePaint);
}
}
Stopwatch _stopwatch = new Stopwatch();
bool _pageIsActive;
bool _qrcodeFound = false;
float _scale;
async Task AnimationLoop()
async Task AnimationLoopAsync()
{
_stopwatch.Start();
while (_pageIsActive)
@@ -203,7 +232,7 @@ namespace Bit.App.Pages
_scale = (20-(1-(float)Math.Sin(4*Math.PI*t))) / 20;
SkCanvasView.InvalidateSurface();
await Task.Delay(TimeSpan.FromSeconds(1.0 / 30));
if (_qrcodeFound && _scale > 0.98f)
if(_qrcodeFound && _scale > 0.98f)
{
_checkIcon.TextColor = _greenColor;
SkCanvasView.InvalidateSurface();