Skip to content

Commit

Permalink
dispose nodes instead of manual GC
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyle Spearrin committed Feb 20, 2017
1 parent 1d23bcc commit c01d02d
Showing 1 changed file with 46 additions and 32 deletions.
78 changes: 46 additions & 32 deletions src/Android/AutofillService.cs
Expand Up @@ -51,9 +51,6 @@ public class AutofillService : AccessibilityService
new Browser("com.ksmobile.cb", "address_bar_edit_text")
}.ToDictionary(n => n.PackageName);

private long _lastGc = 0;
private int _eventCounter = 0;

public override void OnAccessibilityEvent(AccessibilityEvent e)
{
var root = RootInActiveWindow;
Expand All @@ -64,10 +61,13 @@ public override void OnAccessibilityEvent(AccessibilityEvent e)
}

/*
var testNodes = GetWindowNodes(root, e, n => n.ViewIdResourceName != null && n.Text != null)
.Select(n => new { id = n.ViewIdResourceName, text = n.Text });
var testNodes = GetWindowNodes(root, e, n => n.ViewIdResourceName != null && n.Text != null, false);
var testNodesData = testNodes.Select(n => new { id = n.ViewIdResourceName, text = n.Text });
testNodes.Dispose();
testNodes = null;
*/

var notificationManager = ((NotificationManager)GetSystemService(NotificationService));
switch(e.EventType)
{
case EventTypes.WindowContentChanged:
Expand All @@ -76,69 +76,61 @@ public override void OnAccessibilityEvent(AccessibilityEvent e)

if(e.PackageName == BitwardenPackage)
{
CancelNotification();
notificationManager.Cancel(AutoFillNotificationId);
break;
}

var passwordNodes = GetWindowNodes(root, e, n => n.Password);
var passwordNodes = GetWindowNodes(root, e, n => n.Password, false);
if(passwordNodes.Count > 0)
{
var uri = GetUri(root);
if(uri != null && !uri.Contains(BitwardenWebsite))
{
if(NeedToAutofill(AutofillActivity.LastCredentials, uri))
{
var allEditTexts = GetWindowNodes(root, e, n => EditText(n));
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
var usernameEditText = allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
FillCredentials(usernameEditText, passwordNodes);

allEditTexts.Dispose();
allEditTexts = null;
usernameEditText.Dispose();
usernameEditText = null;
}
else
{
NotifyToAutofill(uri);
NotifyToAutofill(uri, notificationManager);
cancelNotification = false;
}
}

AutofillActivity.LastCredentials = null;
}

passwordNodes.Dispose();
passwordNodes = null;

if(cancelNotification)
{
CancelNotification();
notificationManager.Cancel(AutoFillNotificationId);
}
break;
default:
break;
}

notificationManager.Dispose();
notificationManager = null;
root.Dispose();
root = null;

// Do some manual GCing
_eventCounter++;
var now = Java.Lang.JavaSystem.CurrentTimeMillis();
if((now - _lastGc) > 60000 && _eventCounter >= 20)
{
GC.Collect(0);
_lastGc = now;
_eventCounter = 0;
}
e.Dispose();
}

public override void OnInterrupt()
{

}

private void CancelNotification()
{
var notificationManager = ((NotificationManager)GetSystemService(NotificationService));
notificationManager.Cancel(AutoFillNotificationId);
}

private string GetUri(AccessibilityNodeInfo root)
{
var uri = string.Concat(App.Constants.AndroidAppProtocol, root.PackageName);
Expand All @@ -149,6 +141,8 @@ private string GetUri(AccessibilityNodeInfo root)
if(addressNode != null)
{
uri = ExtractUri(uri, addressNode, SupportedBrowsers[root.PackageName]);
addressNode.Dispose();
addressNode = null;
}
}

Expand Down Expand Up @@ -210,7 +204,7 @@ private static bool EditText(AccessibilityNodeInfo n)
return n.ClassName != null && n.ClassName.Contains("EditText");
}

private void NotifyToAutofill(string uri)
private void NotifyToAutofill(string uri, NotificationManager notificationManager)
{
var intent = new Intent(this, typeof(AutofillActivity));
intent.PutExtra("uri", uri);
Expand All @@ -232,8 +226,10 @@ private void NotifyToAutofill(string uri)
Resource.Color.primary));
}

var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(AutoFillNotificationId, builder.Build());

builder.Dispose();
builder = null;
}

private void FillCredentials(AccessibilityNodeInfo usernameNode, IEnumerable<AccessibilityNodeInfo> passwordNodes)
Expand All @@ -257,24 +253,31 @@ private static void FillEditText(AccessibilityNodeInfo editTextNode, string valu
editTextNode.PerformAction(global::Android.Views.Accessibility.Action.SetText, bundle);
}

private List<AccessibilityNodeInfo> GetWindowNodes(AccessibilityNodeInfo n,
AccessibilityEvent e, Func<AccessibilityNodeInfo, bool> condition, List<AccessibilityNodeInfo> nodes = null)
private NodeList GetWindowNodes(AccessibilityNodeInfo n, AccessibilityEvent e,
Func<AccessibilityNodeInfo, bool> condition, bool disposeIfUnused, NodeList nodes = null)
{
if(nodes == null)
{
nodes = new List<AccessibilityNodeInfo>();
nodes = new NodeList();
}

if(n != null)
{
var dispose = disposeIfUnused;
if(n.WindowId == e.WindowId && !(n.ViewIdResourceName?.StartsWith(SystemUiPackage) ?? false) && condition(n))
{
dispose = false;
nodes.Add(n);
}

for(var i = 0; i < n.ChildCount; i++)
{
GetWindowNodes(n.GetChild(i), e, condition, nodes);
GetWindowNodes(n.GetChild(i), e, condition, true, nodes);
}

if(dispose)
{
n.Dispose();
}
}

Expand All @@ -299,5 +302,16 @@ public Browser(string packageName, string uriViewId, Func<string, string> getUri
public string UriViewId { get; set; }
public Func<string, string> GetUriFunction { get; set; } = (s) => s;
}

public class NodeList : List<AccessibilityNodeInfo>, IDisposable
{
public void Dispose()
{
foreach(var item in this)
{
item.Dispose();
}
}
}
}
}

0 comments on commit c01d02d

Please sign in to comment.