move accservice based auto fill plugin into own apk to distribte outside Google Play, closes #111
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -149,3 +149,6 @@ intermediates | ||||
| *.iml | ||||
| /build | ||||
| /src/Kp2aKeyboardBinding/Jars | ||||
| /src/java/Kp2aAccServiceLib/app/build | ||||
| /src/java/Kp2aAccServiceLib/app/app.iml | ||||
| /src/java/Kp2aAccServiceLib/gradle | ||||
|   | ||||
							
								
								
									
										5
									
								
								docs/AccServiceAutoFill.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								docs/AccServiceAutoFill.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| As of December 2017, Google does not accept the use of Accessibility services for anything except helping people with disabilities. This means that Keepass2Android can no longer provide the accessibility service based AutoFill feature. Otherwise, Google would remove Keepass2Android from Play Store. | ||||
|  | ||||
| If you want to continue using this feature, please [install the Accessibility service based AutoFill plugin] (https://github.com/PhilippC/kp2a_accservice_autofill/releases/). | ||||
|  | ||||
| After installation, please enable the accessibility service "KP2A AutoFillPlugin" in the Android system settings. When trying to use the plugin for the first time, KP2A will ask you if the plugin may access the Keepass database. Please accept this to use the plugin. | ||||
| @@ -6,6 +6,10 @@ Displays password entries as QR code; can be used to scan QR codes which can the | ||||
| Allows to switch input method automatically on non-rooted devices. | ||||
| [https://play.google.com/store/apps/details?id=keepass2android.plugin.keyboardswap2](https://play.google.com/store/apps/details?id=keepass2android.plugin.keyboardswap2) | ||||
|  | ||||
| # AutoFill Plug-in | ||||
| Uses Android Accessibility Service to provide an option to AutoFill forms (e.g. on Chrome) or any Android app. | ||||
| [https://philippc.github.io/keepass2android/AccServiceAutoFill.md] | ||||
|  | ||||
| # InputStick Plug-in | ||||
| Allows to send text from KP2A via InputStick to your PC. | ||||
| [https://play.google.com/store/apps/details?id=com.inputstick.apps.kp2aplugin](https://play.google.com/store/apps/details?id=com.inputstick.apps.kp2aplugin) | ||||
|   | ||||
| @@ -44,6 +44,7 @@ | ||||
|     <WarningLevel>4</WarningLevel> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <Reference Include="Java.Interop" /> | ||||
|     <Reference Include="Mono.Android" /> | ||||
|     <Reference Include="System" /> | ||||
|     <Reference Include="System.Core" /> | ||||
|   | ||||
| @@ -1,101 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Keepass2AndroidPluginSDK2" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> | ||||
|   <component name="FacetManager"> | ||||
|     <facet type="android-gradle" name="Android-Gradle"> | ||||
|       <configuration> | ||||
|         <option name="GRADLE_PROJECT_PATH" value=":app" /> | ||||
|       </configuration> | ||||
|     </facet> | ||||
|     <facet type="android" name="Android"> | ||||
|       <configuration> | ||||
|         <option name="SELECTED_BUILD_VARIANT" value="debug" /> | ||||
|         <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> | ||||
|         <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" /> | ||||
|         <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" /> | ||||
|         <afterSyncTasks> | ||||
|           <task>generateDebugSources</task> | ||||
|         </afterSyncTasks> | ||||
|         <option name="ALLOW_USER_CONFIGURATION" value="false" /> | ||||
|         <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> | ||||
|         <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" /> | ||||
|         <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" /> | ||||
|         <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" /> | ||||
|         <option name="LIBRARY_PROJECT" value="true" /> | ||||
|       </configuration> | ||||
|     </facet> | ||||
|   </component> | ||||
|   <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false"> | ||||
|     <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" /> | ||||
|     <output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" /> | ||||
|     <exclude-output /> | ||||
|     <content url="file://$MODULE_DIR$"> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/mockable-Google-Inc.-Google-APIs-23.jar" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/outputs" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/build/tmp" /> | ||||
|     </content> | ||||
|     <orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" /> | ||||
|     <orderEntry type="sourceFolder" forTests="false" /> | ||||
|     <orderEntry type="library" exported="" scope="TEST" name="mockable-Google-Inc.-Google-APIs-23" level="project" /> | ||||
|     <orderEntry type="library" exported="" name="effects-android-23" level="project" /> | ||||
|     <orderEntry type="library" exported="" name="usb-android-23" level="project" /> | ||||
|     <orderEntry type="library" exported="" name="maps-android-23" level="project" /> | ||||
|   </component> | ||||
| </module> | ||||
							
								
								
									
										20
									
								
								src/java/Kp2aAccServiceLib/app/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/java/Kp2aAccServiceLib/app/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| apply plugin: 'com.android.library' | ||||
| android { | ||||
|     compileSdkVersion 23 | ||||
|     buildToolsVersion '23.0.2' | ||||
|  | ||||
|     defaultConfig { | ||||
|         minSdkVersion 18 | ||||
|         targetSdkVersion 23 | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
| } | ||||
							
								
								
									
										22
									
								
								src/java/Kp2aAccServiceLib/app/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/java/Kp2aAccServiceLib/app/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         package="keepass2android.softkeyboard"> | ||||
|  | ||||
|     <uses-permission android:name="android.permission.VIBRATE"/> | ||||
|     <uses-sdk android:targetSdkVersion="14" android:minSdkVersion="14"/> | ||||
|  | ||||
|     <application | ||||
|             android:killAfterRestore="false"> | ||||
|  | ||||
|  | ||||
|         <!--service android:name="keepass2android.autofill.AutoFillService" | ||||
|             android:enabled="true" | ||||
|             android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.accessibilityservice.AccessibilityService" /> | ||||
|             </intent-filter> | ||||
|             <meta-data | ||||
|                 android:name="android.accessibilityservice" | ||||
|                 android:resource="@xml/accserviceconfig" /> | ||||
|         </service--> | ||||
|     </application> | ||||
| </manifest> | ||||
| @@ -0,0 +1,439 @@ | ||||
| package keepass2android.autofill; | ||||
|  | ||||
| import android.accessibilityservice.AccessibilityService; | ||||
| import android.annotation.TargetApi; | ||||
| import android.app.Notification; | ||||
| import android.app.NotificationManager; | ||||
| import android.app.PendingIntent; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.view.accessibility.AccessibilityEvent; | ||||
| import android.view.accessibility.AccessibilityNodeInfo; | ||||
|  | ||||
| import java.net.URI; | ||||
| import java.net.URISyntaxException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
|  | ||||
| import keepass2android.kbbridge.KeyboardData; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Created by Philipp on 25.01.2016. | ||||
|  */ | ||||
| public class AutoFillService extends AccessibilityService { | ||||
|  | ||||
|  | ||||
|     private static boolean _hasUsedData = false; | ||||
|     private static String _lastSearchUrl; | ||||
|     private static final String _logTag = "KP2AAF"; | ||||
|     private static boolean _isRunning; | ||||
|  | ||||
|     private final int autoFillNotificationId = 798810; | ||||
|     private final String androidAppPrefix = "androidapp://"; | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         _isRunning = true; | ||||
|         android.util.Log.d(_logTag, "OnCreate"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         _isRunning = false; | ||||
|     } | ||||
|  | ||||
|     interface NodeCondition | ||||
|     { | ||||
|         boolean check(AccessibilityNodeInfo n); | ||||
|     } | ||||
|  | ||||
|     class WindowIdCondition implements NodeCondition | ||||
|     { | ||||
|         private int id; | ||||
|  | ||||
|         public WindowIdCondition(int id) | ||||
|         { | ||||
|             this.id = id; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean check(AccessibilityNodeInfo n) { | ||||
|             return n.getWindowId() == id; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     boolean isLauncherPackage(CharSequence packageName) | ||||
|     { | ||||
|         return "com.android.systemui".equals(packageName) | ||||
|                 || "com.android.launcher3".equals(packageName); | ||||
|     } | ||||
|  | ||||
|     @TargetApi(21) | ||||
|     class SystemUiCondition implements NodeCondition | ||||
|     { | ||||
|         @Override | ||||
|         public boolean check(AccessibilityNodeInfo n) { | ||||
|             return (n.getViewIdResourceName() != null) && ( | ||||
|                     (n.getViewIdResourceName().startsWith("com.android.systemui")) || (n.getViewIdResourceName().startsWith("com.android.launcher3"))); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private class PasswordFieldCondition implements NodeCondition { | ||||
|         @Override | ||||
|         public boolean check(AccessibilityNodeInfo n) { | ||||
|             return n.isPassword(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private class EditTextCondition implements NodeCondition { | ||||
|         @Override | ||||
|         public boolean check(AccessibilityNodeInfo n) { | ||||
|             //it seems like n.Editable is not a good check as this is false for some fields which are actually editable, at least in tests with Chrome. | ||||
|             return (n.getClassName() != null) && (n.getClassName().toString().toLowerCase().contains("edittext")); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static boolean isAvailable() | ||||
|     { | ||||
|         return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP); | ||||
|     } | ||||
|  | ||||
|     public static boolean isRunning() | ||||
|     { | ||||
|         return _isRunning; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onAccessibilityEvent(AccessibilityEvent event) { | ||||
|         android.util.Log.d(_logTag, "OnAccEvent"); | ||||
|  | ||||
|         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) | ||||
|         { | ||||
|             android.util.Log.d(_logTag, "AndroidVersion not supported"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         handleAccessibilityEvent(event); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @TargetApi(21) | ||||
|     private void handleAccessibilityEvent(AccessibilityEvent event) { | ||||
|         try | ||||
|         { | ||||
|             if (event.getEventType() ==  AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED | ||||
|                     || event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) | ||||
|             { | ||||
|                 CharSequence packageName = event.getPackageName(); | ||||
|                 android.util.Log.d(_logTag, "event: " + event.getEventType() + ", package = " + packageName); | ||||
|                 if ( isLauncherPackage(event.getPackageName()) ) | ||||
|                 { | ||||
|                     android.util.Log.d(_logTag, "return."); | ||||
|                     return; //avoid that the notification is cancelled when pulling down notif drawer | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     android.util.Log.d(_logTag, "event package is no launcher"); | ||||
|                 } | ||||
|  | ||||
|                 if ((packageName != null) | ||||
|                     && (packageName.toString().startsWith("keepass2android."))) | ||||
|                 { | ||||
|                     android.util.Log.d(_logTag, "don't autofill kp2a."); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 AccessibilityNodeInfo root = getRootInActiveWindow(); | ||||
|  | ||||
|                 if ( isLauncherPackage(root.getPackageName()) ) | ||||
|                 { | ||||
|                     android.util.Log.d(_logTag, "return, root is from launcher."); | ||||
|                     return; //avoid that the notification is cancelled when pulling down notif drawer | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     android.util.Log.d(_logTag, "root package is no launcher"); | ||||
|                 } | ||||
|  | ||||
|                 int eventWindowId = event.getWindowId(); | ||||
|                 if ((ExistsNodeOrChildren(root, new WindowIdCondition(eventWindowId)) && !ExistsNodeOrChildren(root, new SystemUiCondition()))) | ||||
|                 { | ||||
|                     boolean cancelNotification = true; | ||||
|  | ||||
|                     String url = androidAppPrefix + root.getPackageName(); | ||||
|  | ||||
|                     if ( "com.android.chrome".equals(root.getPackageName()) ) | ||||
|                     { | ||||
|                         List<AccessibilityNodeInfo> urlFields = root.findAccessibilityNodeInfosByViewId("com.android.chrome:id/url_bar"); | ||||
|                         url = urlFromAddressFields(urlFields, url); | ||||
|  | ||||
|                     } | ||||
|                     else if (packageName == "com.sec.android.app.sbrowser") | ||||
|                     { | ||||
|                         List<AccessibilityNodeInfo> urlFields = root.findAccessibilityNodeInfosByViewId("com.sec.android.app.sbrowser:id/location_bar_edit_text"); | ||||
|                         url = urlFromAddressFields(urlFields, url); | ||||
|                     } | ||||
|                     else if ("com.android.browser".equals(root.getPackageName())) | ||||
|                     { | ||||
|                         List<AccessibilityNodeInfo> urlFields =  root.findAccessibilityNodeInfosByViewId("com.android.browser:id/url"); | ||||
|                         url = urlFromAddressFields(urlFields, url); | ||||
|                     } | ||||
|  | ||||
|                     android.util.Log.d(_logTag, "URL=" + url); | ||||
|  | ||||
|                     if (ExistsNodeOrChildren(root, new PasswordFieldCondition())) | ||||
|                     { | ||||
|                         if ((getLastReceivedCredentialsUser() != null) && | ||||
|                                 (Objects.equals(url, _lastSearchUrl) | ||||
|                                 || isSame(getCredentialsField("URL"), url))) | ||||
|                         { | ||||
|                             android.util.Log.d(_logTag, "Filling credentials for " + url); | ||||
|  | ||||
|                             List<AccessibilityNodeInfo> emptyPasswordFields = new ArrayList<>(); | ||||
|                             GetNodeOrChildren(root, new PasswordFieldCondition(), emptyPasswordFields); | ||||
|  | ||||
|                             List<AccessibilityNodeInfo> allEditTexts = new ArrayList<>(); | ||||
|                             GetNodeOrChildren(root, new EditTextCondition(), allEditTexts); | ||||
|  | ||||
|                             AccessibilityNodeInfo usernameEdit = null; | ||||
|                             for (int i=0;i<allEditTexts.size();i++) | ||||
|                             { | ||||
|                                 if (allEditTexts.get(i).isPassword() == false) | ||||
|                                 { | ||||
|                                     usernameEdit = allEditTexts.get(i); | ||||
|                                     android.util.Log.d(_logTag, "setting usernameEdit = " + usernameEdit.getText() + " "); | ||||
|                                 } | ||||
|                                 else break; | ||||
|                             } | ||||
|  | ||||
|                             FillPassword(url, usernameEdit, emptyPasswordFields); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             android.util.Log.d (_logTag, "Notif for " + url ); | ||||
|                             AskFillPassword(url); | ||||
|                             cancelNotification = false; | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                     if (cancelNotification) | ||||
|                     { | ||||
|                         ((NotificationManager)getSystemService(NOTIFICATION_SERVICE)).cancel(autoFillNotificationId); | ||||
|                         android.util.Log.d (_logTag,"Cancel notif"); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             android.util.Log.e(_logTag, (e.toString() == null) ? "(null)" : e.toString() ); | ||||
|  | ||||
|             /*Intent intent = new Intent(Intent.ACTION_SEND); | ||||
|             intent.setType("message/rfc822"); | ||||
|             String to =  "crocoapps@gmail.com"; | ||||
|             intent.putExtra(Intent.EXTRA_EMAIL, new String[]{to}); | ||||
|             intent.putExtra(Intent.EXTRA_SUBJECT, "Error report 7d+"); | ||||
|             intent.putExtra(Intent.EXTRA_TEXT, | ||||
|                     "Please send the following text as an error report to crocoapps@gmail.com. You may also add additional information about the workflow you tried to perform. This will help me improve the app. Thanks! \n"+e.toString() ); | ||||
|  | ||||
|  | ||||
|             Notification.Builder builder = new Notification.Builder(this); | ||||
|             builder.setSmallIcon(keepass2android.softkeyboard.R.drawable.ic_notify_autofill) | ||||
|                     .setContentText(e.toString()) | ||||
|                     .setContentTitle("error information") | ||||
|                     .setWhen(java.lang.System.currentTimeMillis()) | ||||
|             .setContentIntent(PendingIntent.getActivity(this, 0, Intent.createChooser(intent, "Send error report"), PendingIntent.FLAG_CANCEL_CURRENT)); | ||||
|  | ||||
|             NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); | ||||
|             notificationManager.notify(autoFillNotificationId+1, builder.build());*/ | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @TargetApi(21) | ||||
|     private void AskFillPassword(String url) | ||||
|     { | ||||
|         android.util.Log.d("KP2AAF", "asking for password for " + url); | ||||
|  | ||||
|         Intent startKp2aIntent = new Intent(); | ||||
|         startKp2aIntent.setComponent(new ComponentName(this, "md58dca69cf5ce118dfdacac1ed5b2bbacf.LookupCredentialsActivity")); | ||||
|         if (startKp2aIntent != null) | ||||
|         { | ||||
|             startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); | ||||
|             startKp2aIntent.putExtra("UrlToSearch", url); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         PendingIntent pending = PendingIntent.getActivity(this, 0, startKp2aIntent, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
|         String targetName = url; | ||||
|  | ||||
|         if (url.startsWith(androidAppPrefix)) | ||||
|         { | ||||
|             String packageName = url.substring(androidAppPrefix.length()); | ||||
|             try | ||||
|             { | ||||
|                 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(packageName, 0); | ||||
|                 targetName = (String) (appInfo != null ? getPackageManager().getApplicationLabel(appInfo) : packageName); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 android.util.Log.d(_logTag, (e.toString() == null) ? "(null)" : e.toString()); | ||||
|                 targetName = packageName; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             targetName = getHost(url); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         Notification.Builder builder = new Notification.Builder(this); | ||||
|         //TODO icon | ||||
|         //TODO plugin icon | ||||
|         builder.setSmallIcon(keepass2android.softkeyboard.R.drawable.ic_notify_autofill) | ||||
|                 .setContentText(getString(keepass2android.softkeyboard.R.string.NotificationContentText, new Object[]{targetName})) | ||||
|                 .setContentTitle(getString(keepass2android.softkeyboard.R.string.NotificationTitle)) | ||||
|                 .setWhen(java.lang.System.currentTimeMillis()) | ||||
|                 .setVisibility(Notification.VISIBILITY_SECRET) | ||||
|                 .setContentIntent(pending); | ||||
|         NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); | ||||
|         notificationManager.notify(autoFillNotificationId, builder.build()); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @TargetApi(21) | ||||
|     private void FillPassword(String url, AccessibilityNodeInfo usernameEdit, List<AccessibilityNodeInfo> passwordFields) | ||||
|     { | ||||
|         if ((keepass2android.kbbridge.KeyboardData.hasData()) && (_hasUsedData == false)) | ||||
|         { | ||||
|             fillDataInTextField(usernameEdit, getLastReceivedCredentialsUser()); | ||||
|             for (int i=0;i<passwordFields.size();i++) | ||||
|             { | ||||
|                 fillDataInTextField(passwordFields.get(i), getLastReceivedCredentialsPassword()); | ||||
|             } | ||||
|             _hasUsedData = true; | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @TargetApi(21) | ||||
|     private void fillDataInTextField(AccessibilityNodeInfo edit, String value) { | ||||
|         if ((value == null) || (edit == null)) | ||||
|             return; | ||||
|         Bundle b = new Bundle(); | ||||
|         b.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, value); | ||||
|         edit.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, b); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private boolean isSame(String url1, String url2) { | ||||
|         if (url1 == null) | ||||
|             return (url2 == null); | ||||
|         if (url2 == null) | ||||
|             return (url1 == null); | ||||
|  | ||||
|         if (url1.startsWith("androidapp://")) | ||||
|             return url1.equals(url2); | ||||
|  | ||||
|         return getHost(url1).equals(getHost(url2)); | ||||
|     } | ||||
|  | ||||
|     private String getHost(String url) | ||||
|     { | ||||
|         URI uri = null; | ||||
|         try { | ||||
|             uri = new URI(url); | ||||
|             String domain = uri.getHost(); | ||||
|             if (domain == null) | ||||
|                 return url; | ||||
|             return domain.startsWith("www.") ? domain.substring(4) : domain; | ||||
|         } catch (URISyntaxException e) { | ||||
|             android.util.Log.d(_logTag, "error parsing url: "+ url + e.toString()); | ||||
|             return url; | ||||
|         } | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private String getLastReceivedCredentialsUser() { | ||||
|         return getCredentialsField("UserName"); | ||||
|     } | ||||
|     private String getLastReceivedCredentialsPassword() { | ||||
|         return getCredentialsField("Password"); | ||||
|     } | ||||
|  | ||||
|     private String getCredentialsField(String key) { | ||||
|         for (int i=0;i<KeyboardData.availableFields.size();i++) | ||||
|         { | ||||
|             if (key.equals(KeyboardData.availableFields.get(i).key)) | ||||
|             { | ||||
|                 if (KeyboardData.availableFields.get(i).value != null) | ||||
|                     return KeyboardData.availableFields.get(i).value; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     private void GetNodeOrChildren(AccessibilityNodeInfo n, NodeCondition condition, List<AccessibilityNodeInfo> result) { | ||||
|         if (n != null) | ||||
|         { | ||||
|             if (condition.check(n)) | ||||
|                 result.add(n); | ||||
|             for (int i = 0; i < n.getChildCount(); i++) | ||||
|             { | ||||
|                 GetNodeOrChildren(n.getChild(i), condition, result); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private boolean ExistsNodeOrChildren(AccessibilityNodeInfo n, NodeCondition condition) { | ||||
|         if (n == null) return false; | ||||
|         if (condition.check(n)) | ||||
|             return true; | ||||
|         for (int i = 0; i < n.getChildCount(); i++) | ||||
|         { | ||||
|             if (ExistsNodeOrChildren(n.getChild(i), condition)) | ||||
|                 return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     private String urlFromAddressFields(List<AccessibilityNodeInfo> urlFields, String url) { | ||||
|         if (!urlFields.isEmpty()) | ||||
|         { | ||||
|             AccessibilityNodeInfo addressField = urlFields.get(0); | ||||
|             CharSequence text = addressField.getText(); | ||||
|             if (text != null) | ||||
|             { | ||||
|                 url = text.toString(); | ||||
|                 if (!url.contains("://")) | ||||
|                     url = "http://" + url; | ||||
|             } | ||||
|         } | ||||
|         return url; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onInterrupt() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public static void NotifyNewData(String searchUrl) | ||||
|     { | ||||
|         _hasUsedData = false; | ||||
|         _lastSearchUrl = searchUrl; | ||||
|         android.util.Log.d(_logTag, "Notify new data: " + searchUrl); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,24 @@ | ||||
|  | ||||
| package keepass2android.kbbridge; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
|  | ||||
| import android.text.TextUtils; | ||||
| public class KeyboardData  | ||||
| { | ||||
| 	public static List<StringForTyping> availableFields = new ArrayList<StringForTyping>(); | ||||
| 	public static String entryName; | ||||
| 	public static String entryId; | ||||
| 	 | ||||
| 	public static boolean hasData() | ||||
| 	{ | ||||
| 		return !TextUtils.isEmpty(entryId);  | ||||
| 	} | ||||
|  | ||||
| 	public static void clear() | ||||
| 	{ | ||||
| 		 availableFields.clear(); | ||||
| 		 entryName = entryId = ""; | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,20 @@ | ||||
| package keepass2android.kbbridge; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| public class KeyboardDataBuilder { | ||||
| 	 private ArrayList<StringForTyping> availableFields = new ArrayList<StringForTyping>(); | ||||
| 	  | ||||
| 	 public void addString(String key, String displayName, String valueToType) | ||||
| 	 { | ||||
| 		 StringForTyping stringToType = new StringForTyping(); | ||||
| 		 stringToType.key = key; | ||||
| 		 stringToType.displayName = displayName; | ||||
| 		 stringToType.value = valueToType; | ||||
| 		 availableFields.add(stringToType); | ||||
| 	 } | ||||
| 	  | ||||
| 	 public void commit() | ||||
| 	 { | ||||
| 	 	KeyboardData.availableFields = this.availableFields; | ||||
| 	 } | ||||
| } | ||||
| @@ -0,0 +1,20 @@ | ||||
| package keepass2android.kbbridge; | ||||
|  | ||||
| public class StringForTyping { | ||||
| 	public String key; //internal identifier (PwEntry string field key) | ||||
| 	public String displayName; //display name for displaying the key (might be translated) | ||||
| 	public String value; | ||||
| 	 | ||||
| 	@Override | ||||
| 	public StringForTyping clone(){ | ||||
|  | ||||
| 		StringForTyping theClone = new StringForTyping(); | ||||
| 		theClone.key = key; | ||||
| 		theClone.displayName = displayName; | ||||
| 		theClone.value = value; | ||||
| 		 | ||||
| 		return theClone; | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.3 KiB | 
| @@ -0,0 +1,10 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <string name="AutoFillServiceDescription">Monitors apps and websites for password fields. Offers to look up credentials from Keepass2Android and auto-fill them into the forms.</string> | ||||
|  | ||||
|     <string name="LookupTitle">Look up credentials</string> | ||||
|     <string name="ApplicationName">KP2A AutoFillPlugin</string> | ||||
|     <string name="NotificationTitle">Keepass2Android AutoFill</string> | ||||
|     <string name="NotificationContentText">AutoFill form for %1$s</string> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										15
									
								
								src/java/Kp2aAccServiceLib/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/java/Kp2aAccServiceLib/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| // Top-level build file where you can add configuration options common to all sub-projects/modules. | ||||
| buildscript { | ||||
|     repositories { | ||||
|         jcenter() | ||||
|     } | ||||
|     dependencies { | ||||
|         classpath 'com.android.tools.build:gradle:1.2.3' | ||||
|     } | ||||
| } | ||||
|  | ||||
| allprojects { | ||||
|     repositories { | ||||
|         jcenter() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								src/java/Kp2aAccServiceLib/gradle.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/java/Kp2aAccServiceLib/gradle.properties
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| org.gradle.jvmargs=-Xmx1024m | ||||
							
								
								
									
										164
									
								
								src/java/Kp2aAccServiceLib/gradlew
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/java/Kp2aAccServiceLib/gradlew
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| ############################################################################## | ||||
| ## | ||||
| ##  Gradle start up script for UN*X | ||||
| ## | ||||
| ############################################################################## | ||||
|  | ||||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| DEFAULT_JVM_OPTS="" | ||||
|  | ||||
| APP_NAME="Gradle" | ||||
| APP_BASE_NAME=`basename "$0"` | ||||
|  | ||||
| # Use the maximum available, or set MAX_FD != -1 to use that value. | ||||
| MAX_FD="maximum" | ||||
|  | ||||
| warn ( ) { | ||||
|     echo "$*" | ||||
| } | ||||
|  | ||||
| die ( ) { | ||||
|     echo | ||||
|     echo "$*" | ||||
|     echo | ||||
|     exit 1 | ||||
| } | ||||
|  | ||||
| # OS specific support (must be 'true' or 'false'). | ||||
| cygwin=false | ||||
| msys=false | ||||
| darwin=false | ||||
| case "`uname`" in | ||||
|   CYGWIN* ) | ||||
|     cygwin=true | ||||
|     ;; | ||||
|   Darwin* ) | ||||
|     darwin=true | ||||
|     ;; | ||||
|   MINGW* ) | ||||
|     msys=true | ||||
|     ;; | ||||
| esac | ||||
|  | ||||
| # For Cygwin, ensure paths are in UNIX format before anything is touched. | ||||
| if $cygwin ; then | ||||
|     [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` | ||||
| fi | ||||
|  | ||||
| # Attempt to set APP_HOME | ||||
| # Resolve links: $0 may be a link | ||||
| PRG="$0" | ||||
| # Need this for relative symlinks. | ||||
| while [ -h "$PRG" ] ; do | ||||
|     ls=`ls -ld "$PRG"` | ||||
|     link=`expr "$ls" : '.*-> \(.*\)$'` | ||||
|     if expr "$link" : '/.*' > /dev/null; then | ||||
|         PRG="$link" | ||||
|     else | ||||
|         PRG=`dirname "$PRG"`"/$link" | ||||
|     fi | ||||
| done | ||||
| SAVED="`pwd`" | ||||
| cd "`dirname \"$PRG\"`/" >&- | ||||
| APP_HOME="`pwd -P`" | ||||
| cd "$SAVED" >&- | ||||
|  | ||||
| CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | ||||
|  | ||||
| # Determine the Java command to use to start the JVM. | ||||
| if [ -n "$JAVA_HOME" ] ; then | ||||
|     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | ||||
|         # IBM's JDK on AIX uses strange locations for the executables | ||||
|         JAVACMD="$JAVA_HOME/jre/sh/java" | ||||
|     else | ||||
|         JAVACMD="$JAVA_HOME/bin/java" | ||||
|     fi | ||||
|     if [ ! -x "$JAVACMD" ] ; then | ||||
|         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | ||||
|  | ||||
| Please set the JAVA_HOME variable in your environment to match the | ||||
| location of your Java installation." | ||||
|     fi | ||||
| else | ||||
|     JAVACMD="java" | ||||
|     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
|  | ||||
| Please set the JAVA_HOME variable in your environment to match the | ||||
| location of your Java installation." | ||||
| fi | ||||
|  | ||||
| # Increase the maximum file descriptors if we can. | ||||
| if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then | ||||
|     MAX_FD_LIMIT=`ulimit -H -n` | ||||
|     if [ $? -eq 0 ] ; then | ||||
|         if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | ||||
|             MAX_FD="$MAX_FD_LIMIT" | ||||
|         fi | ||||
|         ulimit -n $MAX_FD | ||||
|         if [ $? -ne 0 ] ; then | ||||
|             warn "Could not set maximum file descriptor limit: $MAX_FD" | ||||
|         fi | ||||
|     else | ||||
|         warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | ||||
|     fi | ||||
| fi | ||||
|  | ||||
| # For Darwin, add options to specify how the application appears in the dock | ||||
| if $darwin; then | ||||
|     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | ||||
| fi | ||||
|  | ||||
| # For Cygwin, switch paths to Windows format before running java | ||||
| if $cygwin ; then | ||||
|     APP_HOME=`cygpath --path --mixed "$APP_HOME"` | ||||
|     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | ||||
|  | ||||
|     # We build the pattern for arguments to be converted via cygpath | ||||
|     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | ||||
|     SEP="" | ||||
|     for dir in $ROOTDIRSRAW ; do | ||||
|         ROOTDIRS="$ROOTDIRS$SEP$dir" | ||||
|         SEP="|" | ||||
|     done | ||||
|     OURCYGPATTERN="(^($ROOTDIRS))" | ||||
|     # Add a user-defined pattern to the cygpath arguments | ||||
|     if [ "$GRADLE_CYGPATTERN" != "" ] ; then | ||||
|         OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | ||||
|     fi | ||||
|     # Now convert the arguments - kludge to limit ourselves to /bin/sh | ||||
|     i=0 | ||||
|     for arg in "$@" ; do | ||||
|         CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | ||||
|         CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option | ||||
|  | ||||
|         if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition | ||||
|             eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | ||||
|         else | ||||
|             eval `echo args$i`="\"$arg\"" | ||||
|         fi | ||||
|         i=$((i+1)) | ||||
|     done | ||||
|     case $i in | ||||
|         (0) set -- ;; | ||||
|         (1) set -- "$args0" ;; | ||||
|         (2) set -- "$args0" "$args1" ;; | ||||
|         (3) set -- "$args0" "$args1" "$args2" ;; | ||||
|         (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | ||||
|         (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | ||||
|         (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | ||||
|         (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | ||||
|         (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | ||||
|         (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | ||||
|     esac | ||||
| fi | ||||
|  | ||||
| # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules | ||||
| function splitJvmOpts() { | ||||
|     JVM_OPTS=("$@") | ||||
| } | ||||
| eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS | ||||
| JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" | ||||
|  | ||||
| exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" | ||||
							
								
								
									
										90
									
								
								src/java/Kp2aAccServiceLib/gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/java/Kp2aAccServiceLib/gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| @if "%DEBUG%" == "" @echo off | ||||
| @rem ########################################################################## | ||||
| @rem | ||||
| @rem  Gradle startup script for Windows | ||||
| @rem | ||||
| @rem ########################################################################## | ||||
|  | ||||
| @rem Set local scope for the variables with windows NT shell | ||||
| if "%OS%"=="Windows_NT" setlocal | ||||
|  | ||||
| @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| set DEFAULT_JVM_OPTS= | ||||
|  | ||||
| set DIRNAME=%~dp0 | ||||
| if "%DIRNAME%" == "" set DIRNAME=. | ||||
| set APP_BASE_NAME=%~n0 | ||||
| set APP_HOME=%DIRNAME% | ||||
|  | ||||
| @rem Find java.exe | ||||
| if defined JAVA_HOME goto findJavaFromJavaHome | ||||
|  | ||||
| set JAVA_EXE=java.exe | ||||
| %JAVA_EXE% -version >NUL 2>&1 | ||||
| if "%ERRORLEVEL%" == "0" goto init | ||||
|  | ||||
| echo. | ||||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
| echo. | ||||
| echo Please set the JAVA_HOME variable in your environment to match the | ||||
| echo location of your Java installation. | ||||
|  | ||||
| goto fail | ||||
|  | ||||
| :findJavaFromJavaHome | ||||
| set JAVA_HOME=%JAVA_HOME:"=% | ||||
| set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||||
|  | ||||
| if exist "%JAVA_EXE%" goto init | ||||
|  | ||||
| echo. | ||||
| echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||||
| echo. | ||||
| echo Please set the JAVA_HOME variable in your environment to match the | ||||
| echo location of your Java installation. | ||||
|  | ||||
| goto fail | ||||
|  | ||||
| :init | ||||
| @rem Get command-line arguments, handling Windowz variants | ||||
|  | ||||
| if not "%OS%" == "Windows_NT" goto win9xME_args | ||||
| if "%@eval[2+2]" == "4" goto 4NT_args | ||||
|  | ||||
| :win9xME_args | ||||
| @rem Slurp the command line arguments. | ||||
| set CMD_LINE_ARGS= | ||||
| set _SKIP=2 | ||||
|  | ||||
| :win9xME_args_slurp | ||||
| if "x%~1" == "x" goto execute | ||||
|  | ||||
| set CMD_LINE_ARGS=%* | ||||
| goto execute | ||||
|  | ||||
| :4NT_args | ||||
| @rem Get arguments from the 4NT Shell from JP Software | ||||
| set CMD_LINE_ARGS=%$ | ||||
|  | ||||
| :execute | ||||
| @rem Setup the command line | ||||
|  | ||||
| set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||||
|  | ||||
| @rem Execute Gradle | ||||
| "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | ||||
|  | ||||
| :end | ||||
| @rem End local scope for the variables with windows NT shell | ||||
| if "%ERRORLEVEL%"=="0" goto mainEnd | ||||
|  | ||||
| :fail | ||||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||||
| rem the _cmd.exe /c_ return code! | ||||
| if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||||
| exit /b 1 | ||||
|  | ||||
| :mainEnd | ||||
| if "%OS%"=="Windows_NT" endlocal | ||||
|  | ||||
| :omega | ||||
							
								
								
									
										2
									
								
								src/java/Kp2aAccServiceLib/settings.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/java/Kp2aAccServiceLib/settings.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| include ':app' | ||||
|  | ||||
| @@ -1,56 +0,0 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
|  | ||||
| using Android.App; | ||||
| using Android.Content; | ||||
| using Android.OS; | ||||
| using Android.Preferences; | ||||
| using Android.Runtime; | ||||
| using Android.Views; | ||||
| using Android.Widget; | ||||
|  | ||||
| namespace keepass2android | ||||
| { | ||||
| 	[Activity(Label = AppNames.AppName, Theme = "@style/MyTheme_ActionBar")] | ||||
| 	public class ActivateAutoFillActivity : LifecycleDebugActivity | ||||
| 	{ | ||||
| 		 | ||||
| 		protected override void OnCreate(Bundle savedInstanceState) | ||||
| 		{ | ||||
| 			new ActivityDesign(this).ApplyTheme(); | ||||
|  | ||||
| 			base.OnCreate(savedInstanceState); | ||||
|  | ||||
| 			ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this); | ||||
| 			App.Kp2a.AskYesNoCancel(UiStringKey.ActivateAutoFillService_title, | ||||
| 								UiStringKey.ActivateAutoFillService_message, | ||||
| 								UiStringKey.ActivateAutoFillService_btnKeyboard, | ||||
| 								UiStringKey.ActivateAutoFillService_btnAutoFill,  | ||||
| 								delegate | ||||
| 								{ | ||||
| 									//yes | ||||
| 									CopyToClipboardService.ActivateKeyboard(this); | ||||
| 									Finish(); | ||||
| 								}, | ||||
| 								delegate | ||||
| 								{ | ||||
| 									//no  | ||||
| 									Intent intent = new Intent(Android.Provider.Settings.ActionAccessibilitySettings); | ||||
| 									StartActivity(intent); | ||||
| 									prefs.Edit().PutBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomatically_key), false).Commit(); | ||||
| 									Toast.MakeText(this, Resource.String.ActivateAutoFillService_toast, ToastLength.Long).Show(); | ||||
| 									Finish();  | ||||
| 								}, | ||||
| 								delegate | ||||
| 								{ | ||||
| 									//cancel | ||||
| 									Finish(); | ||||
| 								}, | ||||
| 								(sender, args) => Finish() //dismiss | ||||
| 								,this); | ||||
| 			 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,21 +0,0 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
|  | ||||
| using Android.App; | ||||
| using Android.Content; | ||||
| using Android.OS; | ||||
| using Android.Runtime; | ||||
| using Android.Views; | ||||
| using Android.Widget; | ||||
|  | ||||
| namespace keepass2android.AutoFillPlugin | ||||
| { | ||||
|     public class Credentials | ||||
|     { | ||||
|         public string User; | ||||
|         public string Password; | ||||
|         public string Url; | ||||
|     } | ||||
| } | ||||
| @@ -31,16 +31,6 @@ | ||||
| 				<category android:name="android.intent.category.OPENABLE" /> | ||||
| 			</intent-filter> | ||||
| 		</activity> | ||||
| 		<service android:name="keepass2android.autofill.AutoFillService" | ||||
|              android:enabled="true" | ||||
| 			android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> | ||||
| 		  <intent-filter> | ||||
| 			<action android:name="android.accessibilityservice.AccessibilityService" /> | ||||
| 		  </intent-filter> | ||||
| 		  <meta-data | ||||
| 		 android:name="android.accessibilityservice" | ||||
| 		 android:resource="@xml/accserviceconfig" /> | ||||
| 		</service> | ||||
| 		<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD"> | ||||
| 			<intent-filter> | ||||
| 				<action android:name="android.view.InputMethod" /> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"  | ||||
| 			android:versionCode="99"  | ||||
| 			android:versionName="1.03-pre1"  | ||||
| 			android:versionCode="101"  | ||||
| 			android:versionName="1.03-pre3"  | ||||
| 			package="keepass2android.keepass2android"  | ||||
| 			android:installLocation="auto"> | ||||
| 	<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> | ||||
| @@ -35,16 +35,6 @@ | ||||
| 				<category android:name="android.intent.category.OPENABLE" /> | ||||
| 			</intent-filter> | ||||
| 		</activity> | ||||
| 		<service android:name="keepass2android.autofill.AutoFillService" | ||||
|              android:enabled="true" | ||||
| 			android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> | ||||
| 		  <intent-filter> | ||||
| 			<action android:name="android.accessibilityservice.AccessibilityService" /> | ||||
| 		  </intent-filter> | ||||
| 		  <meta-data | ||||
| 		 android:name="android.accessibilityservice" | ||||
| 		 android:resource="@xml/accserviceconfig" /> | ||||
| 		</service> | ||||
|  | ||||
| 		<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD"> | ||||
| 			<intent-filter> | ||||
|   | ||||
| @@ -17,16 +17,6 @@ | ||||
| 				<category android:name="android.intent.category.OPENABLE" /> | ||||
| 			</intent-filter> | ||||
| 		</activity> | ||||
| 		<service android:name="keepass2android.autofill.AutoFillService" | ||||
| 			android:enabled="true" | ||||
| 			android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> | ||||
| 		  <intent-filter> | ||||
| 			<action android:name="android.accessibilityservice.AccessibilityService" /> | ||||
| 		  </intent-filter> | ||||
| 		<meta-data | ||||
| 			 android:name="android.accessibilityservice" | ||||
| 		 	android:resource="@xml/accserviceconfig" />		 | ||||
| 		</service> | ||||
|  | ||||
| 		<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD"> | ||||
| 			<intent-filter> | ||||
|   | ||||
| @@ -32,6 +32,16 @@ namespace keepass2android | ||||
| 		private string _requestedUrl; | ||||
| 		private string _pluginPackage; | ||||
|  | ||||
| 		public QueryCredentialsActivity (IntPtr javaReference, JniHandleOwnership transfer) | ||||
| 			: base(javaReference, transfer) | ||||
| 		{ | ||||
| 			 | ||||
| 		} | ||||
|  | ||||
| 		public QueryCredentialsActivity() | ||||
| 		{ | ||||
| 		} | ||||
|  | ||||
| 		protected override void OnCreate(Bundle savedInstanceState) | ||||
| 		{ | ||||
| 			base.OnCreate(savedInstanceState); | ||||
| @@ -164,6 +174,7 @@ namespace keepass2android | ||||
| 					//return credentials to caller: | ||||
| 					Intent credentialData = new Intent(); | ||||
| 					PluginHost.AddEntryToIntent(credentialData, App.Kp2a.GetDb().LastOpenedEntry); | ||||
| 					credentialData.PutExtra(Strings.ExtraQueryString,_requestedUrl); | ||||
| 					SetResult(Result.Ok, credentialData); | ||||
| 					Finish(); | ||||
| 				} | ||||
|   | ||||
| @@ -366,9 +366,11 @@ | ||||
|  | ||||
| 	<string name="ShowSeparateNotifications_title">Separate notifications</string> | ||||
| 	<string name="ShowSeparateNotifications_summary">Show separate notifications for copying username and password to clipboard and activating the keyboard.</string> | ||||
|  | ||||
|   <string name="AccServiceAutoFill_prefs">AutoFill Accessibility-Service</string> | ||||
| 	 | ||||
| 	<string name="ShowKp2aKeyboardNotification_title">Keyboard/AutoFill notification</string> | ||||
|   <string name="ShowKp2aKeyboardNotification_summary">Make full entry accessible through the KP2A keyboard and AutoFill service (recommended).</string> | ||||
| 	<string name="ShowKp2aKeyboardNotification_title">KP2A keyboard notification</string> | ||||
|   <string name="ShowKp2aKeyboardNotification_summary">Make full entry accessible through the KP2A keyboard (recommended).</string> | ||||
|   <string name="OpenKp2aKeyboardAutomatically_title">Switch keyboard</string> | ||||
|   <string name="OpenKp2aKeyboardAutomatically_summary">Open keyboard selection dialog when entry is available through KP2A keyboard after search from the browser.</string> | ||||
|  | ||||
|   | ||||
| @@ -374,7 +374,13 @@ | ||||
|             /> | ||||
|  | ||||
| 			</PreferenceScreen> | ||||
| 		</PreferenceScreen> | ||||
|  | ||||
|       <Preference android:title="@string/AccServiceAutoFill_prefs" > | ||||
|         <intent android:action="android.intent.action.VIEW" | ||||
|                 android:data="https://philippc.github.io/keepass2android/AccServiceAutoFill.md" /> | ||||
|       </Preference> | ||||
|  | ||||
|       </PreferenceScreen> | ||||
| 		<PreferenceScreen | ||||
| 			  android:key="@string/QuickUnlock_prefs_key" | ||||
| 			  android:title="@string/QuickUnlock_prefs" | ||||
|   | ||||
| @@ -127,7 +127,6 @@ | ||||
|     </Reference> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <Compile Include="ActivateAutoFillActivity.cs" /> | ||||
|     <Compile Include="EntryActivityClasses\ViewImagePopupItem.cs" /> | ||||
|     <Compile Include="ImageViewActivity.cs" /> | ||||
|     <Compile Include="addons\OtpKeyProv\EncodingUtil.cs" /> | ||||
| @@ -142,7 +141,6 @@ | ||||
|     <Compile Include="ChallengeInfo.cs" /> | ||||
|     <Compile Include="CreateDatabaseActivity.cs" /> | ||||
|     <Compile Include="CreateNewFilename.cs" /> | ||||
|     <Compile Include="Credentials.cs" /> | ||||
|     <Compile Include="EntryActivityClasses\CopyToClipboardPopupMenuIcon.cs" /> | ||||
|     <Compile Include="EntryActivityClasses\ExtraStringView.cs" /> | ||||
|     <Compile Include="EntryActivityClasses\GotoUrlMenuItem.cs" /> | ||||
|   | ||||
| @@ -420,25 +420,24 @@ namespace keepass2android | ||||
| 				if (hasKeyboardDataNow) | ||||
| 				{ | ||||
| 					notBuilder.AddKeyboardAccess(); | ||||
|  | ||||
| 					if (closeAfterCreate && Keepass2android.Autofill.AutoFillService.IsAvailable) | ||||
| 					if (prefs.GetBoolean("kp2a_switch_rooted", false)) | ||||
| 					{ | ||||
| 						if (IsKp2aInputMethodEnabled) | ||||
| 						//switch rooted | ||||
| 						bool onlySwitchOnSearch = prefs.GetBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key), false); | ||||
| 						if (closeAfterCreate || (!onlySwitchOnSearch)) | ||||
| 						{ | ||||
| 							ActivateKeyboardIfAppropriate(closeAfterCreate, prefs); | ||||
| 						} else if (Keepass2android.Autofill.AutoFillService.IsRunning) | ||||
| 						{ | ||||
| 							//don't do anything, service is notified | ||||
| 						} | ||||
| 						else //neither keyboard nor activity service are running/enabled. Ask the user what to do. | ||||
| 						{ | ||||
| 							var i = new Intent(this, typeof(ActivateAutoFillActivity)); | ||||
| 							i.AddFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask); | ||||
| 							StartActivity(i); | ||||
| 							prefs.Edit().PutBoolean("has_asked_autofillservice", true).Commit(); | ||||
| 							ActivateKp2aKeyboard(); | ||||
| 						} | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						//if the app is about to be closed again (e.g. after searching for a URL and returning to the browser: | ||||
| 						// automatically bring up the Keyboard selection dialog | ||||
| 						if ((closeAfterCreate) && prefs.GetBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomatically_key), Resources.GetBoolean(Resource.Boolean.OpenKp2aKeyboardAutomatically_default))) | ||||
| 						{ | ||||
| 							ActivateKp2aKeyboard(); | ||||
| 						} | ||||
| 					} | ||||
| 					else ActivateKeyboardIfAppropriate(closeAfterCreate, prefs); | ||||
|  | ||||
| 				} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Philipp Crocoll
					Philipp Crocoll