implemented AutoFill service in Java, integrated into main app

This commit is contained in:
Philipp Crocoll 2016-01-27 05:58:33 +01:00
parent c0f2b68963
commit 3d2f6db36d
28 changed files with 813 additions and 285 deletions

View File

@ -84,6 +84,10 @@ namespace keepass2android
AskAddTemplatesMessage,
ReadOnlyReason_PreKitKat,
ReadOnlyReason_ReadOnlyFlag,
ReadOnlyReason_ReadOnlyKitKat
ReadOnlyReason_ReadOnlyKitKat,
ActivateAutoFillService_title,
ActivateAutoFillService_message,
ActivateAutoFillService_btnKeyboard,
ActivateAutoFillService_btnAutoFill
}
}

View File

@ -1 +0,0 @@
#Wed Jan 13 21:02:12 CET 2016

View File

@ -34,23 +34,11 @@
</component>
<component name="FileEditorManager">
<leaf>
<file leaf-file-name="LatinKeyboardBaseView.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/LatinKeyboardBaseView.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="1234" column="25" selection-start-line="1234" selection-start-column="25" selection-end-line="1234" selection-end-column="25" />
<folding>
<element signature="method#LatinKeyboardBaseView#1;class#LatinKeyboardBaseView#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="KP2AKeyboard.java" pinned="false" current-in-tab="true">
<file leaf-file-name="KP2AKeyboard.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/KP2AKeyboard.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="2465" column="13" selection-start-line="2465" selection-start-column="13" selection-end-line="2465" selection-end-column="13" />
<caret line="2618" column="0" selection-start-line="2618" selection-start-column="0" selection-end-line="2618" selection-end-column="0" />
<folding>
<element signature="e#17350#17396#0" expanded="true" />
<element signature="e#17428#17478#0" expanded="true" />
@ -97,70 +85,108 @@
</provider>
</entry>
</file>
<file leaf-file-name="LocaleHelper.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/LocaleHelper.java">
<file leaf-file-name="StringForTyping.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/StringForTyping.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="49" column="53" selection-start-line="49" selection-start-column="53" selection-end-line="49" selection-end-column="53" />
<caret line="2" column="13" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="build.gradle" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-4.76">
<caret line="7" column="24" selection-start-line="7" selection-start-column="24" selection-end-line="7" selection-end-column="24" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="accserviceconfig.xml" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/res/xml/accserviceconfig.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="38" selection-start-line="0" selection-start-column="38" selection-end-line="0" selection-end-column="38" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="strings.xml" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/res/values/strings.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-7.56">
<caret line="378" column="0" selection-start-line="378" selection-start-column="0" selection-end-line="378" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="strings_autofill.xml" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/res/values/strings_autofill.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="8" column="0" selection-start-line="8" selection-start-column="0" selection-end-line="8" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="AutoFillService.java" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/autofill/AutoFillService.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.7568306">
<caret line="104" column="5" selection-start-line="104" selection-start-column="5" selection-end-line="104" selection-end-column="5" />
<folding>
<element signature="imports" expanded="true" />
<element signature="e#1549#1550#0" expanded="true" />
<element signature="e#1585#1586#0" expanded="true" />
<element signature="e#1660#1661#0" expanded="true" />
<element signature="e#1712#1713#0" expanded="true" />
<element signature="e#2880#2881#0" expanded="true" />
<element signature="e#2913#2914#0" expanded="true" />
<element signature="e#9594#9692#0" expanded="true" />
<element signature="e#9727#9793#0" expanded="true" />
<element signature="e#11813#11814#0" expanded="true" />
<element signature="e#11867#11868#0" expanded="true" />
<element signature="e#11925#11926#0" expanded="true" />
<element signature="e#11979#11980#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="kbd_qwerty.xml" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/res/xml/kbd_qwerty.xml">
<file leaf-file-name="prefs.xml" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/res/xml/prefs.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="476" column="38" selection-start-line="476" selection-start-column="38" selection-end-line="476" selection-end-column="38" />
<caret line="60" column="46" selection-start-line="60" selection-start-column="46" selection-end-line="60" selection-end-column="46" />
<folding>
<element signature="e#5702#5728#0" expanded="true" />
<element signature="e#6920#6946#0" expanded="true" />
<element signature="e#8140#8166#0" expanded="true" />
<element signature="e#9357#9383#0" expanded="true" />
<element signature="e#10581#10607#0" expanded="true" />
<element signature="e#12082#12108#0" expanded="true" />
<element signature="e#13602#13628#0" expanded="true" />
<element signature="e#15124#15150#0" expanded="true" />
<element signature="e#16643#16669#0" expanded="true" />
<element signature="e#2450#2474#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="kbd_qwerty_black.xml" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/res/xml/kbd_qwerty_black.xml">
<file leaf-file-name="KeyboardData.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/KeyboardData.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="146" column="46" selection-start-line="146" selection-start-column="35" selection-end-line="146" selection-end-column="46" />
<state vertical-scroll-proportion="-12.24">
<caret line="18" column="30" selection-start-line="18" selection-start-column="30" selection-end-line="18" selection-end-column="30" />
<folding>
<element signature="e#5666#5692#0" expanded="true" />
<element signature="imports" expanded="true" />
<element signature="e#362#363#0" expanded="true" />
<element signature="e#404#405#0" expanded="true" />
<element signature="e#438#439#0" expanded="true" />
<element signature="e#479#480#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="kbd_qwerty.xml" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/res/xml-de/kbd_qwerty.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="147" column="38" selection-start-line="147" selection-start-column="38" selection-end-line="147" selection-end-column="38" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="KeyboardSwitcher.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/KeyboardSwitcher.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="591" column="0" selection-start-line="591" selection-start-column="0" selection-end-line="591" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="LatinIMESettings.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/LatinIMESettings.java">
<provider selected="true" editor-type-id="text-editor">
@ -171,35 +197,14 @@
</provider>
</entry>
</file>
<file leaf-file-name="LatinKeyboardView.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/LatinKeyboardView.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="36" column="23" selection-start-line="36" selection-start-column="23" selection-end-line="36" selection-end-column="23" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="LatinKeyboard.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/LatinKeyboard.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="397" column="24" selection-start-line="397" selection-start-column="24" selection-end-line="397" selection-end-column="24" />
<folding>
<element signature="e#15971#15972#0" expanded="true" />
<element signature="e#16007#16008#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="resourceFile" />
<option value="Class" />
<option value="valueResourceFile" />
</list>
</option>
</component>
@ -1228,7 +1233,7 @@
</option>
<option name="modificationStamps">
<map>
<entry key="$PROJECT_DIR$" value="4358048248205" />
<entry key="$PROJECT_DIR$" value="4359057111489" />
</map>
</option>
<option name="projectBuildClasspath">
@ -1475,7 +1480,6 @@
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/build.gradle" />
<option value="$PROJECT_DIR$/app/build.gradle" />
<option value="$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/LatinKeyboardBaseView.java" />
<option value="$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/LanguageSwitcher.java" />
<option value="$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/Loc.java" />
@ -1483,6 +1487,12 @@
<option value="$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/KeyboardSwitcher.java" />
<option value="$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/LocaleHelper.java" />
<option value="$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/KP2AKeyboard.java" />
<option value="$PROJECT_DIR$/app/build.gradle" />
<option value="$PROJECT_DIR$/app/src/main/res/xml/accserviceconfig.xml" />
<option value="$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/KeyboardData.java" />
<option value="$PROJECT_DIR$/app/src/main/java/keepass2android/autofill/AutoFillService.java" />
<option value="$PROJECT_DIR$/app/src/main/res/values/strings.xml" />
<option value="$PROJECT_DIR$/app/src/main/res/values/strings_autofill.xml" />
</list>
</option>
</component>
@ -1558,96 +1568,6 @@
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="java" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="KP2ASoftkeyboard_AS" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="app" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="src" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="main" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="java" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="KP2ASoftkeyboard_AS" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="app" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="src" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="main" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="java" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="keepass2android" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="softkeyboard" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="java" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="KP2ASoftkeyboard_AS" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="app" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="src" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="main" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="java" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="keepass2android" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="kbbridge" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
</subPane>
</pane>
<pane id="Scope" />
@ -1673,6 +1593,8 @@
<property name="android.project.structure.proportion" value="0.15" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/../KP2ASoftKeyboard2/java" />
<property name="FullScreen" value="false" />
<property name="OverrideImplement.combined" value="true" />
<property name="OverrideImplement.overriding.sorted" value="false" />
</component>
<component name="RunManager">
<configuration default="true" type="AndroidRunConfigurationType" factoryName="Android Application">
@ -1843,34 +1765,43 @@
</task>
<servers />
</component>
<component name="TodoView">
<todo-panel id="selected-file">
<is-autoscroll-to-source value="true" />
</todo-panel>
<todo-panel id="all">
<are-packages-shown value="true" />
<is-autoscroll-to-source value="true" />
</todo-panel>
</component>
<component name="ToolWindowManager">
<frame x="-8" y="-8" width="1382" height="744" extended-state="6" />
<editor active="true" />
<editor active="false" />
<layout>
<window_info id="Palette&#9;" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Designer" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3270869" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Captures" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.32879046" sideWeight="0.5121029" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Gradle Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Build Variants" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.32879046" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Android" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.32879046" sideWeight="0.48789713" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Android" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32879046" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32879046" sideWeight="0.4969743" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Gradle" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.24886535" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.24886535" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.24962178" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
</layout>
@ -2079,25 +2010,17 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="11" column="16" selection-start-line="11" selection-start-column="16" selection-end-line="11" selection-end-column="16" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/InputLanguageSelection.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="92" column="16" selection-start-line="92" selection-start-column="16" selection-end-line="92" selection-end-column="16" />
<folding>
<element signature="e#0#5655#0" expanded="true" />
<element signature="imports" expanded="true" />
<element signature="e#1509#1539#0" expanded="true" />
<element signature="e#2941#2964#0" expanded="true" />
<element signature="e#4545#4546#0" expanded="true" />
<element signature="e#4577#4578#0" expanded="true" />
<element signature="e#0#5655#0" expanded="false" />
<element signature="imports" expanded="false" />
<element signature="e#1509#1539#0" expanded="false" />
<element signature="e#2941#2964#0" expanded="false" />
<element signature="e#4545#4546#0" expanded="false" />
<element signature="e#4577#4578#0" expanded="false" />
</folding>
</state>
</provider>
@ -2118,14 +2041,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/res/values/strings.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-4.88">
<caret line="187" column="34" selection-start-line="187" selection-start-column="18" selection-end-line="187" selection-end-column="34" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/LatinKeyboardView.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
@ -2139,8 +2054,8 @@
<state vertical-scroll-proportion="0.0">
<caret line="397" column="24" selection-start-line="397" selection-start-column="24" selection-end-line="397" selection-end-column="24" />
<folding>
<element signature="e#15971#15972#0" expanded="true" />
<element signature="e#16007#16008#0" expanded="true" />
<element signature="e#15971#15972#0" expanded="false" />
<element signature="e#16007#16008#0" expanded="false" />
</folding>
</state>
</provider>
@ -2160,15 +2075,15 @@
<state vertical-scroll-proportion="0.0">
<caret line="476" column="38" selection-start-line="476" selection-start-column="38" selection-end-line="476" selection-end-column="38" />
<folding>
<element signature="e#5702#5728#0" expanded="true" />
<element signature="e#6920#6946#0" expanded="true" />
<element signature="e#8140#8166#0" expanded="true" />
<element signature="e#9357#9383#0" expanded="true" />
<element signature="e#10581#10607#0" expanded="true" />
<element signature="e#12082#12108#0" expanded="true" />
<element signature="e#13602#13628#0" expanded="true" />
<element signature="e#15124#15150#0" expanded="true" />
<element signature="e#16643#16669#0" expanded="true" />
<element signature="e#5702#5728#0" expanded="false" />
<element signature="e#6920#6946#0" expanded="false" />
<element signature="e#8140#8166#0" expanded="false" />
<element signature="e#9357#9383#0" expanded="false" />
<element signature="e#10581#10607#0" expanded="false" />
<element signature="e#12082#12108#0" expanded="false" />
<element signature="e#13602#13628#0" expanded="false" />
<element signature="e#15124#15150#0" expanded="false" />
<element signature="e#16643#16669#0" expanded="false" />
</folding>
</state>
</provider>
@ -2178,7 +2093,7 @@
<state vertical-scroll-proportion="0.0">
<caret line="146" column="46" selection-start-line="146" selection-start-column="35" selection-end-line="146" selection-end-column="46" />
<folding>
<element signature="e#5666#5692#0" expanded="true" />
<element signature="e#5666#5692#0" expanded="false" />
</folding>
</state>
</provider>
@ -2199,6 +2114,16 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/LocaleHelper.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="49" column="53" selection-start-line="49" selection-start-column="53" selection-end-line="49" selection-end-column="53" />
<folding>
<element signature="imports" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/LatinIMESettings.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
@ -2207,20 +2132,18 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/LocaleHelper.java">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/StringForTyping.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="49" column="53" selection-start-line="49" selection-start-column="53" selection-end-line="49" selection-end-column="53" />
<folding>
<element signature="imports" expanded="true" />
</folding>
<caret line="2" column="13" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/softkeyboard/KP2AKeyboard.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="2465" column="13" selection-start-line="2465" selection-start-column="13" selection-end-line="2465" selection-end-column="13" />
<caret line="2618" column="0" selection-start-line="2618" selection-start-column="0" selection-end-line="2618" selection-end-column="0" />
<folding>
<element signature="e#17350#17396#0" expanded="true" />
<element signature="e#17428#17478#0" expanded="true" />
@ -2266,5 +2189,83 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-4.76">
<caret line="7" column="24" selection-start-line="7" selection-start-column="24" selection-end-line="7" selection-end-column="24" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kbbridge/KeyboardData.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-12.24">
<caret line="18" column="30" selection-start-line="18" selection-start-column="30" selection-end-line="18" selection-end-column="30" />
<folding>
<element signature="imports" expanded="true" />
<element signature="e#362#363#0" expanded="true" />
<element signature="e#404#405#0" expanded="true" />
<element signature="e#438#439#0" expanded="true" />
<element signature="e#479#480#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/res/xml/accserviceconfig.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="38" selection-start-line="0" selection-start-column="38" selection-end-line="0" selection-end-column="38" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/res/xml/prefs.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="60" column="46" selection-start-line="60" selection-start-column="46" selection-end-line="60" selection-end-column="46" />
<folding>
<element signature="e#2450#2474#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/res/values/strings.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-7.56">
<caret line="378" column="0" selection-start-line="378" selection-start-column="0" selection-end-line="378" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/res/values/strings_autofill.xml">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="8" column="0" selection-start-line="8" selection-start-column="0" selection-end-line="8" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/autofill/AutoFillService.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.7568306">
<caret line="104" column="5" selection-start-line="104" selection-start-column="5" selection-end-line="104" selection-end-column="5" />
<folding>
<element signature="imports" expanded="true" />
<element signature="e#1549#1550#0" expanded="true" />
<element signature="e#1585#1586#0" expanded="true" />
<element signature="e#1660#1661#0" expanded="true" />
<element signature="e#1712#1713#0" expanded="true" />
<element signature="e#2880#2881#0" expanded="true" />
<element signature="e#2913#2914#0" expanded="true" />
<element signature="e#9594#9692#0" expanded="true" />
<element signature="e#9727#9793#0" expanded="true" />
<element signature="e#11813#11814#0" expanded="true" />
<element signature="e#11867#11868#0" expanded="true" />
<element signature="e#11925#11926#0" expanded="true" />
<element signature="e#11979#11980#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
</project>

View File

@ -5,7 +5,7 @@ android {
buildToolsVersion "23.0.0"
defaultConfig {
minSdkVersion 14
minSdkVersion 18
targetSdkVersion 23
}

View File

@ -0,0 +1,380 @@
package keepass2android.autofill;
import android.accessibilityservice.AccessibilityService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
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;
}
}
class SystemUiCondition implements NodeCondition
{
@Override
public boolean check(AccessibilityNodeInfo n) {
return (n.getViewIdResourceName() != null) && (n.getViewIdResourceName().startsWith("com.android.systemui"));
}
}
private class PasswordFieldCondition implements NodeCondition {
@Override
public boolean check(AccessibilityNodeInfo n) {
return n.isPassword() && (
(n.getText() == null)
|| ("".equals(n.getText())));
}
}
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");
try
{
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
|| event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)
{
android.util.Log.d(_logTag, "event: " + event.getEventType() + ", package = " + event.getPackageName());
if ( "com.android.systemui".equals(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, "no com.android.systemui");
}
AccessibilityNodeInfo root = getRootInActiveWindow();
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 ("com.android.browser".equals(root.getPackageName()))
{
List<AccessibilityNodeInfo> urlFields = root.findAccessibilityNodeInfosByViewId("com.android.browser:id/url");
url = urlFromAddressFields(urlFields, 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 );
if (getLastReceivedCredentialsUser() != null)
{
android.util.Log.d (_logTag, getCredentialsField("URL"));
android.util.Log.d (_logTag, 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());
Notification.Builder builder = new Notification.Builder(this);
//TODO remove on release
builder.setSmallIcon(keepass2android.softkeyboard.R.drawable.ic_notify_autofill)
.setContentText(e.toString())
.setContentTitle("error information")
.setWhen(java.lang.System.currentTimeMillis());
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(autoFillNotificationId+1, builder.build());
}
}
private void AskFillPassword(String url)
{
Intent startKp2aIntent = getPackageManager().getLaunchIntentForPackage(getApplicationContext().getPackageName());
if (startKp2aIntent != null)
{
startKp2aIntent.addCategory(Intent.CATEGORY_LAUNCHER);
startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
String taskName = "SearchUrlTask";
startKp2aIntent.putExtra("KP2A_APPTASK", taskName);
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());
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());
}
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;
}
//LookupCredentialsActivity.LastReceivedCredentials = null;
}
private void fillDataInTextField(AccessibilityNodeInfo edit, String value) {
if (value == 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.startsWith("androidapp://"))
return url1.equals(url2);
if (url1 == null)
return (url2 == null);
return getHost(url1).equals(getHost(url2));
}
private String getHost(String url)
{
URI uri = null;
try {
uri = new URI(url);
String domain = uri.getHost();
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);
url = addressField.getText().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);
}
}

View File

@ -16,6 +16,11 @@ public class KeyboardData
return !TextUtils.isEmpty(entryId);
}
public static boolean bla2()
{
return !TextUtils.isEmpty(entryId);
}
public static void clear()
{
availableFields.clear();

View File

@ -376,4 +376,6 @@
<!-- Title for Latin keyboard debug settings activity / dialog -->
<string name="english_ime_debug_settings" translatable="false">Android keyboard Debug settings</string>
<string name="prefs_debug_mode" translatable="false">Debug Mode</string>
</resources>

View File

@ -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>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/AutoFillServiceDescription"
android:accessibilityEventTypes="typeAllMask"
@ -7,4 +7,4 @@
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
/>
/>

View File

@ -12,14 +12,14 @@ using Android.Views.Accessibility;
using Android.Widget;
using KeePassLib;
/*
namespace keepass2android.AutoFill
{
//<meta-data android:name="android.accessibilityservice" android:resource="@xml/serviceconfig" />
[Service(Enabled =true, Permission= "android.permission.BIND_ACCESSIBILITY_SERVICE")]
[IntentFilter(new[] { "android.accessibilityservice.AccessibilityService" })]
[MetaData("android.accessibilityservice", Resource = "@xml/accserviceconfig")]
public class Kp2aAccessibilityService : Android.AccessibilityServices.AccessibilityService
public class AccessibilityService : Android.AccessibilityServices.AccessibilityService
{
private static bool _hasUsedData;
const string _logTag = "KP2AAS";
@ -53,13 +53,7 @@ namespace keepass2android.AutoFill
{
bool cancelNotification = true;
var allEditTexts = GetNodeOrChildren(root, IsEditText);
var usernameEdit = allEditTexts.TakeWhile(edit => (edit.Password == false)).LastOrDefault();
string searchString = androidAppPrefix + root.PackageName;
string url = androidAppPrefix + root.PackageName;
string url = androidAppPrefix + root.PackageName;
if (root.PackageName == "com.android.chrome")
{
@ -73,14 +67,24 @@ namespace keepass2android.AutoFill
UrlFromAddressField(ref url, addressField);
}
List<AccessibilityNodeInfo> emptyPasswordFields = GetNodeOrChildren(root, IsPasswordField);
if (emptyPasswordFields.Any())
if (ExistsNodeOrChildren(root, IsPasswordField))
{
if ((LastReceivedCredentialsUser != null) && IsSame(GetCredentialsField(PwDefs.UrlField), url))
{
Android.Util.Log.Debug ("KP2AAS", "Filling credentials for " + url);
List<AccessibilityNodeInfo> emptyPasswordFields = new List<AccessibilityNodeInfo>();
GetNodeOrChildren(root, IsPasswordField, ref emptyPasswordFields);
List<AccessibilityNodeInfo> allEditTexts = new List<AccessibilityNodeInfo>();
GetNodeOrChildren(root, IsEditText, ref allEditTexts);
var usernameEdit = allEditTexts.TakeWhile(edit => (edit.Password == false)).LastOrDefault();
FillPassword(url, usernameEdit, emptyPasswordFields);
allEditTexts.Clear();
emptyPasswordFields.Clear();
}
else
{
@ -91,7 +95,7 @@ namespace keepass2android.AutoFill
Android.Util.Log.Debug ("KP2AAS", url);
}
AskFillPassword(url, usernameEdit, emptyPasswordFields);
AskFillPassword(url);
cancelNotification = false;
}
@ -105,10 +109,11 @@ namespace keepass2android.AutoFill
}
GC.Collect();
Java.Lang.JavaSystem.Gc();
}
private bool IsSystemUi(AccessibilityNodeInfo n)
{
return (n.ViewIdResourceName != null) && (n.ViewIdResourceName.StartsWith("com.android.systemui"));
@ -146,7 +151,12 @@ namespace keepass2android.AutoFill
return (n.ClassName != null) && (n.ClassName.Contains("EditText"));
}
private void AskFillPassword(string url, AccessibilityNodeInfo usernameEdit, List<AccessibilityNodeInfo> passwordFields)
private static bool IsNonPasswordEditText(AccessibilityNodeInfo n)
{
return IsEditText(n) && n.Password == false;
}
private void AskFillPassword(string url)
{
Intent startKp2aIntent = PackageManager.GetLaunchIntentForPackage(ApplicationContext.PackageName);
@ -243,6 +253,7 @@ namespace keepass2android.AutoFill
private bool ExistsNodeOrChildren(AccessibilityNodeInfo n, Func<AccessibilityNodeInfo, bool> p)
{
if (n == null) return false;
if (p(n))
return true;
for (int i = 0; i < n.ChildCount; i++)
@ -253,22 +264,20 @@ namespace keepass2android.AutoFill
return false;
}
private List<AccessibilityNodeInfo> GetNodeOrChildren(AccessibilityNodeInfo n, Func<AccessibilityNodeInfo, bool> p)
private void GetNodeOrChildren(AccessibilityNodeInfo n, Func<AccessibilityNodeInfo, bool> p, ref List<AccessibilityNodeInfo> result)
{
List<AccessibilityNodeInfo> result = new List<AccessibilityNodeInfo>();
if (n != null)
if (n != null)
{
if (p(n))
result.Add(n);
for (int i = 0; i < n.ChildCount; i++)
{
result.AddRange(GetNodeOrChildren(n.GetChild(i), p));
GetNodeOrChildren(n.GetChild(i), p, ref result);
}
}
return result;
}
public override void OnInterrupt()
public override void OnInterrupt()
{
}
@ -283,4 +292,4 @@ namespace keepass2android.AutoFill
_hasUsedData = false;
}
}
}
}*/

View File

@ -0,0 +1,56 @@
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);
}
}
}

View File

@ -409,7 +409,7 @@ namespace keepass2android
Intent showNotIntent = new Intent(this, typeof (CopyToClipboardService));
showNotIntent.SetAction(Intents.ShowNotification);
showNotIntent.PutExtra(KeyEntry, Entry.Uuid.ToHexString());
_appTask.PopulatePasswordAccessServiceIntent(showNotIntent);
showNotIntent.PutExtra(KeyCloseAfterCreate, closeAfterCreate);
StartService(showNotIntent);

View File

@ -54,6 +54,13 @@
</intent-filter>
</activity>
<service android:name="keepass2android.autofill.AutoFillService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
<activity android:configChanges="orientation" android:label="@string/app_name" android:theme="@style/MyTheme_Blue" android:name="keepass2android.PasswordActivity" android:windowSoftInputMode="adjustResize">
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
@ -101,4 +108,6 @@
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<!-- Samsung Pass permission -->
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
</manifest>

View File

@ -33,6 +33,13 @@
<category android:name="android.intent.category.OPENABLE" />
</intent-filter>
</activity>
<service android:name="keepass2android.autofill.AutoFillService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
@ -102,6 +109,8 @@
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
<!-- Samsung Pass permission -->
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
</manifest>

View File

@ -16,6 +16,12 @@
<category android:name="android.intent.category.OPENABLE" />
</intent-filter>
</activity>
<service android:name="keepass2android.autofill.AutoFillService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />

View File

@ -354,7 +354,7 @@
<string name="ShowSeparateNotifications_summary">Show separate notifications for copying username and password to clipboard and activating the keyboard.</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="ShowKp2aKeyboardNotification_summary">Make full entry accessible through the KP2A keyboard and AutoFill service (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>
@ -647,11 +647,11 @@
<string name="ErrorReportAsk">Ask after error</string>
<string name="ErrorReportPrefTitle">Send error reports</string>
<string name="LookupTitle">Look up credentials</string>
<string name="ApplicationName">KP2A AutoFillPlugin</string>
<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="NotificationTitle">Keepass2Android AutoFill</string>
<string name="NotificationContentText">AutoFill form for %1$s</string>
<string name="ActivateAutoFillService_title">Activate AutoFill?</string>
<string name="ActivateAutoFillService_message">Credentials can be transferred to other apps in several ways: You can copy values to clipboard, but please note that the clipboard is not secure in Android. The built-in keyboard gives full access to the selected entry but must be enabled each time you want to access the credentials. On Android 5 and later, Keepass2Android can enter username and password automatically using the AutoFill service.</string>
<string name="ActivateAutoFillService_btnKeyboard">Use built-in keyboard</string>
<string name="ActivateAutoFillService_btnAutoFill">Use AutoFill service</string>
<string name="ActivateAutoFillService_toast">Please enable the Keepass2Android service.</string>
<string name="ChangeLog_0_9_8c">
Version 0.9.8c\n

View File

@ -347,7 +347,7 @@ namespace keepass2android
#endif
}
class DismissListener: Java.Lang.Object, IDialogInterfaceOnDismissListener
public class DismissListener: Java.Lang.Object, IDialogInterfaceOnDismissListener
{
private readonly Action _onDismiss;

View File

@ -322,11 +322,22 @@ namespace keepass2android
yesHandler, noHandler, cancelHandler, ctx);
}
public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey,
public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey,
UiStringKey yesString, UiStringKey noString,
EventHandler<DialogClickEventArgs> yesHandler,
EventHandler<DialogClickEventArgs> noHandler,
EventHandler<DialogClickEventArgs> cancelHandler,
Context ctx)
{
AskYesNoCancel(titleKey, messageKey, yesString, noString, yesHandler, noHandler, cancelHandler, null, ctx);
}
public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey,
UiStringKey yesString, UiStringKey noString,
EventHandler<DialogClickEventArgs> yesHandler,
EventHandler<DialogClickEventArgs> noHandler,
EventHandler<DialogClickEventArgs> cancelHandler,
EventHandler dismissHandler,
Context ctx)
{
Handler handler = new Handler(Looper.MainLooper);
@ -353,7 +364,11 @@ namespace keepass2android
cancelHandler);
}
AlertDialog dialog = builder.Create();
if (dismissHandler != null)
dialog.SetOnDismissListener(new Util.DismissListener(() => dismissHandler(dialog, EventArgs.Empty)));
dialog.Show();
if (yesText.Length + noText.Length + cancelText.Length >= 20)

View File

@ -327,6 +327,11 @@ namespace keepass2android
{
activity.StartNotificationsService(false);
}
virtual public void PopulatePasswordAccessServiceIntent(Intent intent)
{
}
}
/// <summary>
@ -393,7 +398,11 @@ namespace keepass2android
//act.AppTask = new NullTask();
}
public override void PopulatePasswordAccessServiceIntent(Intent intent)
{
base.PopulatePasswordAccessServiceIntent(intent);
intent.PutExtra(UrlToSearchKey, UrlToSearchFor);
}
}

View File

@ -116,6 +116,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ActivateAutoFillActivity.cs" />
<Compile Include="addons\OtpKeyProv\EncodingUtil.cs" />
<Compile Include="addons\OtpKeyProv\OathHotpKeyProv.cs" />
<Compile Include="addons\OtpKeyProv\OtpAuxCachingFileStorage.cs" />
@ -155,7 +156,7 @@
<Compile Include="icons\DrawableFactory.cs" />
<Compile Include="KeeChallenge.cs" />
<Compile Include="FixedDrawerLayout.cs" />
<Compile Include="Kp2aAccessibilityService.cs" />
<Compile Include="AccessibilityService.cs" />
<Compile Include="KpEntryTemplatedEdit.cs" />
<Compile Include="MeasuringRelativeLayout.cs" />
<Compile Include="NfcOtpActivity.cs" />
@ -1671,14 +1672,6 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable-mdpi\ic_fp_40px.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_notify_autofill.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\accserviceconfig.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\packages\Xamarin.Insights.1.11.3\build\MonoAndroid10\Xamarin.Insights.targets" Condition="Exists('..\packages\Xamarin.Insights.1.11.3\build\MonoAndroid10\Xamarin.Insights.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

View File

@ -18,6 +18,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
using System;
using System.Collections.Generic;
using System.Linq;
using Android.AccessibilityServices;
using Android.Support.V4.App;
using Java.Util;
@ -27,10 +28,10 @@ using Android.OS;
using Android.Runtime;
using Android.Widget;
using Android.Preferences;
using Android.Views.Accessibility;
using KeePassLib;
using KeePassLib.Utility;
using Android.Views.InputMethods;
using keepass2android.AutoFill;
using KeePass.Util.Spr;
namespace keepass2android
@ -278,6 +279,7 @@ namespace keepass2android
if ((intent.Action == Intents.ShowNotification) || (intent.Action == Intents.UpdateKeyboard))
{
String uuidBytes = intent.GetStringExtra(EntryActivity.KeyEntry);
String searchUrl = intent.GetStringExtra(SearchUrlTask.UrlToSearchKey);
PwUuid entryId = PwUuid.Zero;
if (uuidBytes != null)
@ -308,7 +310,7 @@ namespace keepass2android
{
//first time opening the entry -> bring up the notifications
bool closeAfterCreate = intent.GetBooleanExtra(EntryActivity.KeyCloseAfterCreate, false);
DisplayAccessNotifications(entry, closeAfterCreate);
DisplayAccessNotifications(entry, closeAfterCreate, searchUrl);
}
else //UpdateKeyboard
{
@ -317,7 +319,7 @@ namespace keepass2android
//update the keyboard data.
//Check if keyboard is (still) available
if (Keepass2android.Kbbridge.KeyboardData.EntryId == entry.Uuid.ToHexString())
MakeAccessibleForKeyboard(entry);
MakeAccessibleForKeyboard(entry, searchUrl);
#endif
}
}
@ -386,7 +388,7 @@ namespace keepass2android
private const string ActionNotificationCancelled = "notification_cancelled";
public void DisplayAccessNotifications(PwEntryOutput entry, bool closeAfterCreate)
public void DisplayAccessNotifications(PwEntryOutput entry, bool closeAfterCreate, string searchUrl)
{
var hadKeyboardData = ClearNotifications();
@ -414,28 +416,22 @@ namespace keepass2android
{
//keyboard
hasKeyboardDataNow = MakeAccessibleForKeyboard(entry);
hasKeyboardDataNow = MakeAccessibleForKeyboard(entry, searchUrl);
if (hasKeyboardDataNow)
{
notBuilder.AddKeyboardAccess();
if (prefs.GetBoolean("kp2a_switch_rooted", false))
if (Keepass2android.Autofill.AutoFillService.IsAvailable && (!Keepass2android.Autofill.AutoFillService.IsRunning))
{
//switch rooted
bool onlySwitchOnSearch = prefs.GetBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key), false);
if (closeAfterCreate || (!onlySwitchOnSearch))
if (!prefs.GetBoolean("has_asked_autofillservice", false))
{
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();
var i = new Intent(this, typeof (ActivateAutoFillActivity));
i.AddFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);
StartActivity(i);
prefs.Edit().PutBoolean("has_asked_autofillservice", true).Commit();
}
}
else ActivateKeyboardIfAppropriate(closeAfterCreate, prefs);
}
@ -465,6 +461,31 @@ namespace keepass2android
RegisterReceiver(_notificationDeletedBroadcastReceiver, deletefilter);
}
public void ActivateKeyboardIfAppropriate(bool closeAfterCreate, ISharedPreferences prefs)
{
if (prefs.GetBoolean("kp2a_switch_rooted", false))
{
//switch rooted
bool onlySwitchOnSearch = prefs.GetBoolean(
GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key), false);
if (closeAfterCreate || (!onlySwitchOnSearch))
{
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();
}
}
}
private bool ClearNotifications()
{
// Notification Manager
@ -479,7 +500,7 @@ namespace keepass2android
return hadKeyboardData;
}
bool MakeAccessibleForKeyboard(PwEntryOutput entry)
bool MakeAccessibleForKeyboard(PwEntryOutput entry, string searchUrl)
{
#if EXCLUDE_KEYBOARD
return false;
@ -529,7 +550,7 @@ namespace keepass2android
Keepass2android.Kbbridge.KeyboardData.EntryName = entry.OutputStrings.ReadSafe(PwDefs.TitleField);
Keepass2android.Kbbridge.KeyboardData.EntryId = entry.Uuid.ToHexString();
if (hasData)
Kp2aAccessibilityService.NotifyNewData();
Keepass2android.Autofill.AutoFillService.NotifyNewData(searchUrl);
return hasData;
#endif