mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-27 12:26:31 +01:00
Replaced accessibility service notification with in-line overlay. (#695)
* Replaced accessibility service notification with in-line overlay. Requires draw-over permission to be enabled (will prompt if not, though this will be enhanced in subsequent commits) * Updated with requested changes * Fix for FDroid build
This commit is contained in:
parent
c33728d418
commit
21c7b486ff
@ -1,9 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.Content.Res;
|
||||||
|
using Android.Graphics;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
|
using Android.Provider;
|
||||||
|
using Android.Views;
|
||||||
using Android.Views.Accessibility;
|
using Android.Views.Accessibility;
|
||||||
|
using Android.Widget;
|
||||||
|
using Bit.App.Resources;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
|
using Plugin.CurrentActivity;
|
||||||
|
|
||||||
namespace Bit.Droid.Accessibility
|
namespace Bit.Droid.Accessibility
|
||||||
{
|
{
|
||||||
@ -260,5 +268,88 @@ namespace Bit.Droid.Accessibility
|
|||||||
{
|
{
|
||||||
return allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
|
return allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean OverlayPermitted(Context context)
|
||||||
|
{
|
||||||
|
if(Build.VERSION.SdkInt >= BuildVersionCodes.M)
|
||||||
|
{
|
||||||
|
return Settings.CanDrawOverlays(context.ApplicationContext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO do older android versions require a check?
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean OpenOverlaySettings(Context context, string packageName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var intent = new Intent(Settings.ActionManageOverlayPermission);
|
||||||
|
intent.SetPackage(packageName);
|
||||||
|
intent.SetFlags(ActivityFlags.NewTask);
|
||||||
|
context.StartActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinearLayout GetOverlayView(Context context)
|
||||||
|
{
|
||||||
|
var inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
|
||||||
|
var view = (LinearLayout)inflater.Inflate(Resource.Layout.autofill_listitem, null);
|
||||||
|
var text1 = (TextView)view.FindViewById(Resource.Id.text1);
|
||||||
|
var text2 = (TextView)view.FindViewById(Resource.Id.text2);
|
||||||
|
var icon = (ImageView)view.FindViewById(Resource.Id.icon);
|
||||||
|
text1.Text = AppResources.AutofillWithBitwarden;
|
||||||
|
text2.Text = AppResources.GoToMyVault;
|
||||||
|
icon.SetImageResource(Resource.Drawable.icon);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Point GetOverlayAnchorPosition(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||||
|
{
|
||||||
|
var rootRect = new Rect();
|
||||||
|
root.GetBoundsInScreen(rootRect);
|
||||||
|
var rootRectHeight = rootRect.Height();
|
||||||
|
|
||||||
|
var eSrcRect = new Rect();
|
||||||
|
e.Source.GetBoundsInScreen(eSrcRect);
|
||||||
|
var eSrcRectLeft = eSrcRect.Left;
|
||||||
|
var eSrcRectTop = eSrcRect.Top;
|
||||||
|
|
||||||
|
var navBarHeight = GetNavigationBarHeight();
|
||||||
|
|
||||||
|
var calculatedTop = rootRectHeight - eSrcRectTop - navBarHeight;
|
||||||
|
|
||||||
|
return new Point(eSrcRectLeft, calculatedTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetStatusBarHeight()
|
||||||
|
{
|
||||||
|
return GetSystemResourceDimenPx("status_bar_height");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetNavigationBarHeight()
|
||||||
|
{
|
||||||
|
return GetSystemResourceDimenPx("navigation_bar_height");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetSystemResourceDimenPx(String resName)
|
||||||
|
{
|
||||||
|
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
|
||||||
|
|
||||||
|
var barHeight = 0;
|
||||||
|
var resourceId = activity.Resources.GetIdentifier(resName, "dimen", "android");
|
||||||
|
if(resourceId > 0)
|
||||||
|
{
|
||||||
|
barHeight = activity.Resources.GetDimensionPixelSize(resourceId);
|
||||||
|
}
|
||||||
|
return barHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
|
using Android.Graphics;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
|
using Android.Provider;
|
||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
using Android.Views.Accessibility;
|
using Android.Views.Accessibility;
|
||||||
|
using Android.Widget;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
@ -20,23 +24,18 @@ namespace Bit.Droid.Accessibility
|
|||||||
[Register("com.x8bit.bitwarden.Accessibility.AccessibilityService")]
|
[Register("com.x8bit.bitwarden.Accessibility.AccessibilityService")]
|
||||||
public class AccessibilityService : Android.AccessibilityServices.AccessibilityService
|
public class AccessibilityService : Android.AccessibilityServices.AccessibilityService
|
||||||
{
|
{
|
||||||
private NotificationChannel _notificationChannel;
|
|
||||||
|
|
||||||
private const int AutoFillNotificationId = 34573;
|
|
||||||
private const string BitwardenPackage = "com.x8bit.bitwarden";
|
private const string BitwardenPackage = "com.x8bit.bitwarden";
|
||||||
private const string BitwardenWebsite = "vault.bitwarden.com";
|
private const string BitwardenWebsite = "vault.bitwarden.com";
|
||||||
|
|
||||||
private IStorageService _storageService;
|
|
||||||
private bool _settingAutofillPasswordField;
|
|
||||||
private bool _settingAutofillPersistNotification;
|
|
||||||
private DateTime? _lastSettingsReload = null;
|
|
||||||
private TimeSpan _settingsReloadSpan = TimeSpan.FromMinutes(1);
|
|
||||||
private long _lastNotificationTime = 0;
|
|
||||||
private string _lastNotificationUri = null;
|
private string _lastNotificationUri = null;
|
||||||
|
|
||||||
private HashSet<string> _launcherPackageNames = null;
|
private HashSet<string> _launcherPackageNames = null;
|
||||||
private DateTime? _lastLauncherSetBuilt = null;
|
private DateTime? _lastLauncherSetBuilt = null;
|
||||||
private TimeSpan _rebuildLauncherSpan = TimeSpan.FromHours(1);
|
private TimeSpan _rebuildLauncherSpan = TimeSpan.FromHours(1);
|
||||||
|
|
||||||
|
private IWindowManager _windowManager = null;
|
||||||
|
private LinearLayout _overlayView = null;
|
||||||
|
|
||||||
public override void OnAccessibilityEvent(AccessibilityEvent e)
|
public override void OnAccessibilityEvent(AccessibilityEvent e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -53,6 +52,7 @@ namespace Bit.Droid.Accessibility
|
|||||||
|
|
||||||
if(SkipPackage(e?.PackageName))
|
if(SkipPackage(e?.PackageName))
|
||||||
{
|
{
|
||||||
|
CancelOverlayPrompt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,107 +62,85 @@ namespace Bit.Droid.Accessibility
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessibilityHelpers.PrintTestData(root, e);
|
var isKnownBroswer = AccessibilityHelpers.SupportedBrowsers.ContainsKey(root.PackageName);
|
||||||
LoadServices();
|
|
||||||
var settingsTask = LoadSettingsAsync();
|
|
||||||
|
|
||||||
var notificationManager = GetSystemService(NotificationService) as NotificationManager;
|
// AccessibilityHelpers.PrintTestData(root, e);
|
||||||
var cancelNotification = true;
|
|
||||||
|
|
||||||
switch(e.EventType)
|
switch(e.EventType)
|
||||||
{
|
{
|
||||||
case EventTypes.ViewFocused:
|
case EventTypes.ViewFocused:
|
||||||
if(e.Source == null || !e.Source.Password || !_settingAutofillPasswordField)
|
case EventTypes.ViewClicked:
|
||||||
|
if (e.EventType == EventTypes.ViewClicked && isKnownBroswer)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (e.Source == null || !e.Source.Password)
|
||||||
|
{
|
||||||
|
CancelOverlayPrompt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(e.PackageName == BitwardenPackage)
|
if(e.PackageName == BitwardenPackage)
|
||||||
{
|
{
|
||||||
CancelNotification(notificationManager);
|
CancelOverlayPrompt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ScanAndAutofill(root, e, notificationManager, cancelNotification))
|
if(ScanAndAutofill(root, e))
|
||||||
{
|
{
|
||||||
CancelNotification(notificationManager);
|
CancelOverlayPrompt();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OverlayPromptToAutofill(root, e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EventTypes.WindowContentChanged:
|
case EventTypes.WindowContentChanged:
|
||||||
case EventTypes.WindowStateChanged:
|
case EventTypes.WindowStateChanged:
|
||||||
if(_settingAutofillPasswordField && e.Source.Password)
|
if (e.Source == null || e.Source.Password)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if(_settingAutofillPasswordField && AccessibilityHelpers.LastCredentials == null)
|
else if(AccessibilityHelpers.LastCredentials == null)
|
||||||
{
|
{
|
||||||
if(string.IsNullOrWhiteSpace(_lastNotificationUri))
|
if(string.IsNullOrWhiteSpace(_lastNotificationUri))
|
||||||
{
|
{
|
||||||
CancelNotification(notificationManager);
|
CancelOverlayPrompt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var uri = AccessibilityHelpers.GetUri(root);
|
var uri = AccessibilityHelpers.GetUri(root);
|
||||||
if(uri != null && uri != _lastNotificationUri)
|
if(uri != null && uri != _lastNotificationUri)
|
||||||
{
|
{
|
||||||
CancelNotification(notificationManager);
|
CancelOverlayPrompt();
|
||||||
}
|
}
|
||||||
else if(uri != null && uri.StartsWith(Constants.AndroidAppProtocol))
|
else if(uri != null && uri.StartsWith(Constants.AndroidAppProtocol))
|
||||||
{
|
{
|
||||||
CancelNotification(notificationManager, 30000);
|
CancelOverlayPrompt();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(e.PackageName == BitwardenPackage)
|
if(e.PackageName == BitwardenPackage)
|
||||||
{
|
{
|
||||||
CancelNotification(notificationManager);
|
CancelOverlayPrompt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_settingAutofillPersistNotification)
|
if(ScanAndAutofill(root, e))
|
||||||
{
|
{
|
||||||
var uri = AccessibilityHelpers.GetUri(root);
|
CancelOverlayPrompt();
|
||||||
if(uri != null && !uri.Contains(BitwardenWebsite))
|
|
||||||
{
|
|
||||||
var needToFill = AccessibilityHelpers.NeedToAutofill(
|
|
||||||
AccessibilityHelpers.LastCredentials, uri);
|
|
||||||
if(needToFill)
|
|
||||||
{
|
|
||||||
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e,
|
|
||||||
n => n.Password, false);
|
|
||||||
needToFill = passwordNodes.Any();
|
|
||||||
if(needToFill)
|
|
||||||
{
|
|
||||||
AccessibilityHelpers.GetNodesAndFill(root, e, passwordNodes);
|
|
||||||
}
|
|
||||||
passwordNodes.Dispose();
|
|
||||||
}
|
|
||||||
if(!needToFill)
|
|
||||||
{
|
|
||||||
NotifyToAutofill(uri, notificationManager);
|
|
||||||
cancelNotification = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AccessibilityHelpers.LastCredentials = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cancelNotification = ScanAndAutofill(root, e, notificationManager, cancelNotification);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cancelNotification)
|
|
||||||
{
|
|
||||||
CancelNotification(notificationManager);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationManager?.Dispose();
|
|
||||||
root.Dispose();
|
root.Dispose();
|
||||||
e.Dispose();
|
e.Dispose();
|
||||||
}
|
}
|
||||||
// Suppress exceptions so that service doesn't crash.
|
// Suppress exceptions so that service doesn't crash.
|
||||||
catch { }
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Exception: " + ex.StackTrace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnInterrupt()
|
public override void OnInterrupt()
|
||||||
@ -170,9 +148,9 @@ namespace Bit.Droid.Accessibility
|
|||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ScanAndAutofill(AccessibilityNodeInfo root, AccessibilityEvent e,
|
public bool ScanAndAutofill(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||||
NotificationManager notificationManager, bool cancelNotification)
|
|
||||||
{
|
{
|
||||||
|
var filled = false;
|
||||||
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e, n => n.Password, false);
|
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e, n => n.Password, false);
|
||||||
if(passwordNodes.Count > 0)
|
if(passwordNodes.Count > 0)
|
||||||
{
|
{
|
||||||
@ -182,12 +160,9 @@ namespace Bit.Droid.Accessibility
|
|||||||
if(AccessibilityHelpers.NeedToAutofill(AccessibilityHelpers.LastCredentials, uri))
|
if(AccessibilityHelpers.NeedToAutofill(AccessibilityHelpers.LastCredentials, uri))
|
||||||
{
|
{
|
||||||
AccessibilityHelpers.GetNodesAndFill(root, e, passwordNodes);
|
AccessibilityHelpers.GetNodesAndFill(root, e, passwordNodes);
|
||||||
|
filled = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
NotifyToAutofill(uri, notificationManager);
|
|
||||||
cancelNotification = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AccessibilityHelpers.LastCredentials = null;
|
AccessibilityHelpers.LastCredentials = null;
|
||||||
}
|
}
|
||||||
@ -200,69 +175,94 @@ namespace Bit.Droid.Accessibility
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
passwordNodes.Dispose();
|
passwordNodes.Dispose();
|
||||||
return cancelNotification;
|
return filled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelNotification(NotificationManager notificationManager, long limit = 250)
|
private void CancelOverlayPrompt()
|
||||||
{
|
{
|
||||||
if(Java.Lang.JavaSystem.CurrentTimeMillis() - _lastNotificationTime < limit)
|
if(_windowManager == null || _overlayView == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_windowManager.RemoveViewImmediate(_overlayView);
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Removed");
|
||||||
|
|
||||||
|
_overlayView = null;
|
||||||
_lastNotificationUri = null;
|
_lastNotificationUri = null;
|
||||||
notificationManager?.Cancel(AutoFillNotificationId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NotifyToAutofill(string uri, NotificationManager notificationManager)
|
private void OverlayPromptToAutofill(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||||
{
|
{
|
||||||
if(notificationManager == null || string.IsNullOrWhiteSpace(uri))
|
if(!AccessibilityHelpers.OverlayPermitted(this))
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Overlay Permission not granted");
|
||||||
|
Toast.MakeText(this, AppResources.AccessibilityOverlayPermissionAlert, ToastLength.Long).Show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var uri = AccessibilityHelpers.GetUri(root);
|
||||||
|
if (string.IsNullOrWhiteSpace(uri))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var now = Java.Lang.JavaSystem.CurrentTimeMillis();
|
WindowManagerTypes windowManagerType;
|
||||||
|
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
|
||||||
|
{
|
||||||
|
windowManagerType = WindowManagerTypes.ApplicationOverlay;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
windowManagerType = WindowManagerTypes.Phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
var layoutParams = new WindowManagerLayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WrapContent,
|
||||||
|
ViewGroup.LayoutParams.WrapContent,
|
||||||
|
windowManagerType,
|
||||||
|
WindowManagerFlags.NotFocusable | WindowManagerFlags.NotTouchModal,
|
||||||
|
Android.Graphics.Format.Transparent);
|
||||||
|
|
||||||
|
var anchorPosition = AccessibilityHelpers.GetOverlayAnchorPosition(root, e);
|
||||||
|
|
||||||
|
layoutParams.Gravity = GravityFlags.Bottom | GravityFlags.Left;
|
||||||
|
layoutParams.X = anchorPosition.X;
|
||||||
|
layoutParams.Y = anchorPosition.Y;
|
||||||
|
|
||||||
var intent = new Intent(this, typeof(AccessibilityActivity));
|
var intent = new Intent(this, typeof(AccessibilityActivity));
|
||||||
intent.PutExtra("uri", uri);
|
intent.PutExtra("uri", uri);
|
||||||
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
||||||
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.UpdateCurrent);
|
|
||||||
|
|
||||||
var notificationContent = Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch ?
|
if (_windowManager == null)
|
||||||
AppResources.BitwardenAutofillServiceNotificationContent :
|
|
||||||
AppResources.BitwardenAutofillServiceNotificationContentOld;
|
|
||||||
|
|
||||||
var builder = new Notification.Builder(this);
|
|
||||||
builder.SetSmallIcon(Resource.Drawable.shield)
|
|
||||||
.SetContentTitle(AppResources.BitwardenAutofillService)
|
|
||||||
.SetContentText(notificationContent)
|
|
||||||
.SetTicker(notificationContent)
|
|
||||||
.SetWhen(now)
|
|
||||||
.SetContentIntent(pendingIntent);
|
|
||||||
|
|
||||||
if(Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch)
|
|
||||||
{
|
{
|
||||||
builder.SetVisibility(NotificationVisibility.Secret)
|
_windowManager = GetSystemService(WindowService).JavaCast<IWindowManager>();
|
||||||
.SetColor(Android.Support.V4.Content.ContextCompat.GetColor(ApplicationContext,
|
|
||||||
Resource.Color.primary));
|
|
||||||
}
|
|
||||||
if(Build.VERSION.SdkInt >= BuildVersionCodes.O)
|
|
||||||
{
|
|
||||||
if(_notificationChannel == null)
|
|
||||||
{
|
|
||||||
_notificationChannel = new NotificationChannel("bitwarden_autofill_service",
|
|
||||||
AppResources.AutofillService, NotificationImportance.Low);
|
|
||||||
notificationManager.CreateNotificationChannel(_notificationChannel);
|
|
||||||
}
|
|
||||||
builder.SetChannelId(_notificationChannel.Id);
|
|
||||||
}
|
|
||||||
if(/*Build.VERSION.SdkInt <= BuildVersionCodes.N && */_settingAutofillPersistNotification)
|
|
||||||
{
|
|
||||||
builder.SetPriority(-2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastNotificationTime = now;
|
var updateView = false;
|
||||||
|
if (_overlayView != null)
|
||||||
|
{
|
||||||
|
updateView = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_overlayView = AccessibilityHelpers.GetOverlayView(this);
|
||||||
|
_overlayView.Click += (sender, eventArgs) => {
|
||||||
|
CancelOverlayPrompt();
|
||||||
|
StartActivity(intent);
|
||||||
|
};
|
||||||
|
|
||||||
_lastNotificationUri = uri;
|
_lastNotificationUri = uri;
|
||||||
notificationManager.Notify(AutoFillNotificationId, builder.Build());
|
|
||||||
builder.Dispose();
|
if (updateView)
|
||||||
|
{
|
||||||
|
_windowManager.UpdateViewLayout(_overlayView, layoutParams);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_windowManager.AddView(_overlayView, layoutParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View " + (updateView ? "Updated to" : "Added at") + " X:{0} Y:{1}", layoutParams.X, layoutParams.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SkipPackage(string eventPackageName)
|
private bool SkipPackage(string eventPackageName)
|
||||||
@ -285,26 +285,5 @@ namespace Bit.Droid.Accessibility
|
|||||||
}
|
}
|
||||||
return _launcherPackageNames.Contains(eventPackageName);
|
return _launcherPackageNames.Contains(eventPackageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadServices()
|
|
||||||
{
|
|
||||||
if(_storageService == null)
|
|
||||||
{
|
|
||||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LoadSettingsAsync()
|
|
||||||
{
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
if(_lastSettingsReload == null || (now - _lastSettingsReload.Value) > _settingsReloadSpan)
|
|
||||||
{
|
|
||||||
_lastSettingsReload = now;
|
|
||||||
_settingAutofillPasswordField = await _storageService.GetAsync<bool>(
|
|
||||||
Constants.AccessibilityAutofillPasswordFieldKey);
|
|
||||||
_settingAutofillPersistNotification = await _storageService.GetAsync<bool>(
|
|
||||||
Constants.AccessibilityAutofillPersistNotificationKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<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="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:summary="@string/AutoFillServiceSummary"
|
android:summary="@string/AutoFillServiceSummary"
|
||||||
android:description="@string/AutoFillServiceDescription"
|
android:description="@string/AutoFillServiceDescription"
|
||||||
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged|typeViewFocused"
|
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged|typeViewFocused|typeViewClicked"
|
||||||
android:accessibilityFeedbackType="feedbackGeneric"
|
android:accessibilityFeedbackType="feedbackGeneric"
|
||||||
android:accessibilityFlags="flagReportViewIds"
|
android:accessibilityFlags="flagReportViewIds"
|
||||||
android:notificationTimeout="100"
|
android:notificationTimeout="100"
|
||||||
|
9
src/App/Resources/AppResources.Designer.cs
generated
9
src/App/Resources/AppResources.Designer.cs
generated
@ -69,6 +69,15 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Bitwarden requires additional accessibility configuration. Open the app for more info..
|
||||||
|
/// </summary>
|
||||||
|
public static string AccessibilityOverlayPermissionAlert {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccessibilityOverlayPermissionAlert", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Account.
|
/// Looks up a localized string similar to Account.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1587,4 +1587,7 @@
|
|||||||
<data name="UseBiometricsToUnlock" xml:space="preserve">
|
<data name="UseBiometricsToUnlock" xml:space="preserve">
|
||||||
<value>Use Biometrics To Unlock</value>
|
<value>Use Biometrics To Unlock</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="AccessibilityOverlayPermissionAlert" xml:space="preserve">
|
||||||
|
<value>Bitwarden requires additional accessibility configuration. Open the app for more info.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
Loading…
Reference in New Issue
Block a user