|
|
@@ -1,11 +1,11 @@
|
|
|
package info.knacki.pass.services;
|
|
|
|
|
|
+import android.content.Intent;
|
|
|
import android.graphics.PixelFormat;
|
|
|
import android.os.Build;
|
|
|
import android.os.Bundle;
|
|
|
import android.os.Handler;
|
|
|
import android.view.Gravity;
|
|
|
-import android.view.LayoutInflater;
|
|
|
import android.view.View;
|
|
|
import android.view.WindowManager;
|
|
|
import android.view.accessibility.AccessibilityEvent;
|
|
|
@@ -13,31 +13,62 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
|
|
import android.widget.Toast;
|
|
|
|
|
|
import java.io.File;
|
|
|
+import java.util.Date;
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
import info.knacki.pass.R;
|
|
|
|
|
|
public class AccessibilityService extends android.accessibilityservice.AccessibilityService {
|
|
|
+ private final long CANCEL_DELAY_SEC = 10;
|
|
|
+ private static AccessibilityService fInstance;
|
|
|
private boolean fManagingEvent;
|
|
|
private View fOpenWindow;
|
|
|
|
|
|
+ private class LastCancellation {
|
|
|
+ public long lastCancelledTime;
|
|
|
+ public String lastCancelledPackage;
|
|
|
+
|
|
|
+ private LastCancellation() {
|
|
|
+ Clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Cancel(AccessibilityNodeInfo source) {
|
|
|
+ fLastCancellation.lastCancelledPackage = source.getPackageName().toString();
|
|
|
+ fLastCancellation.lastCancelledTime = new Date().getTime() / 1000;
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean IsCancelling(AccessibilityNodeInfo source, boolean clearCancelling) {
|
|
|
+ boolean cancelling = source.getPackageName().toString().equals(lastCancelledPackage) && (new Date().getTime() / 1000) -lastCancelledTime <= CANCEL_DELAY_SEC;
|
|
|
+ if (cancelling && clearCancelling)
|
|
|
+ this.Clear();
|
|
|
+ return cancelling;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Clear() {
|
|
|
+ this.lastCancelledPackage = null;
|
|
|
+ this.lastCancelledTime = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ protected LastCancellation fLastCancellation = new LastCancellation();
|
|
|
+
|
|
|
@Override
|
|
|
protected void onServiceConnected() {
|
|
|
super.onServiceConnected();
|
|
|
+ fInstance = this;
|
|
|
fManagingEvent = false;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onAccessibilityEvent(AccessibilityEvent event) {
|
|
|
synchronized (AccessibilityService.class) {
|
|
|
- if (fManagingEvent)
|
|
|
+ if (fManagingEvent || fLastCancellation.IsCancelling(event.getSource(), true))
|
|
|
return;
|
|
|
if (event.isPassword())
|
|
|
fManagingEvent = DisplayPasswordList(event.getSource());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private boolean DisplayPasswordList(AccessibilityNodeInfo source) {
|
|
|
+ private boolean DisplayPasswordList(final AccessibilityNodeInfo source) {
|
|
|
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
|
|
WindowManager.LayoutParams.MATCH_PARENT,
|
|
|
WindowManager.LayoutParams.WRAP_CONTENT,
|
|
|
@@ -46,8 +77,8 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi
|
|
|
PixelFormat.TRANSLUCENT);
|
|
|
params.gravity = Gravity.START | Gravity.BOTTOM;
|
|
|
|
|
|
- fOpenWindow = ((AccessibilityView) LayoutInflater.from(this).inflate(R.layout.activity_accessibility, null, false))
|
|
|
- .init(this, new AccessibilityView.AccessibilityViewListener() {
|
|
|
+ fOpenWindow = new AccessibilityView(this)
|
|
|
+ .Init(this, new AccessibilityView.AccessibilityViewListener() {
|
|
|
@Override
|
|
|
public void OnPasswordClicked(File f) {
|
|
|
new Handler(getMainLooper()).post(() -> {
|
|
|
@@ -59,12 +90,14 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi
|
|
|
@Override
|
|
|
public void cancel() {
|
|
|
new Handler(getMainLooper()).post(() -> {
|
|
|
+ fLastCancellation.Cancel(source);
|
|
|
CloseOpenWindow();
|
|
|
fManagingEvent = false;
|
|
|
+ SetFocus(source);
|
|
|
});
|
|
|
}
|
|
|
})
|
|
|
- .AddCancelButton(this);
|
|
|
+ .AddCancelButton();
|
|
|
|
|
|
try {
|
|
|
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
|
|
|
@@ -107,6 +140,12 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi
|
|
|
fManagingEvent = false;
|
|
|
}
|
|
|
|
|
|
+ private void SetFocus(AccessibilityNodeInfo source) {
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
|
|
+ source.performAction(AccessibilityNodeInfo.ACTION_CLICK);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private void LegacySendPassword(String password) {
|
|
|
// FIXME
|
|
|
}
|
|
|
@@ -115,4 +154,14 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi
|
|
|
public void onInterrupt() {
|
|
|
new Handler(getMainLooper()).post(this::CloseOpenWindow);
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean onUnbind(Intent intent) {
|
|
|
+ fInstance = null;
|
|
|
+ return super.onUnbind(intent);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean IsRunning() {
|
|
|
+ return fInstance != null;
|
|
|
+ }
|
|
|
}
|