diff options
-rw-r--r-- | FillService/AndroidManifest.xml | 8 | ||||
-rw-r--r-- | FillService/res/xml/autofill_service_config.xml | 20 | ||||
-rw-r--r-- | FillService/src/foo/bar/fill/FillService.java | 120 |
3 files changed, 114 insertions, 34 deletions
diff --git a/FillService/AndroidManifest.xml b/FillService/AndroidManifest.xml index f9128e1..da039b6 100644 --- a/FillService/AndroidManifest.xml +++ b/FillService/AndroidManifest.xml @@ -4,10 +4,16 @@ <application> <service android:name=".FillService" - android:permission="android.permission.BIND_AUTOFILL"> + android:permission="android.permission.BIND_AUTOFILL_SERVICE"> <intent-filter> <action android:name="android.service.autofill.AutofillService" /> </intent-filter> + + <meta-data + android:name="android.autofill" + android:resource="@xml/autofill_service_config"> + </meta-data> + </service> <activity android:name=".AuthActivity"/> diff --git a/FillService/res/xml/autofill_service_config.xml b/FillService/res/xml/autofill_service_config.xml new file mode 100644 index 0000000..dd73a19 --- /dev/null +++ b/FillService/res/xml/autofill_service_config.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<autofill-service xmlns:android="http://schemas.android.com/apk/res/android"> + <compatibility-package android:name="com.android.chrome" android:maxLongVersionCode="1000000000" android:urlBarResourceId="url_bar"/> + <compatibility-package android:name="com.chrome.beta" android:maxLongVersionCode="1000000000" android:urlBarResourceId="url_bar"/> +</autofill-service> diff --git a/FillService/src/foo/bar/fill/FillService.java b/FillService/src/foo/bar/fill/FillService.java index c253e7c..6eebac1 100644 --- a/FillService/src/foo/bar/fill/FillService.java +++ b/FillService/src/foo/bar/fill/FillService.java @@ -24,6 +24,7 @@ import android.app.assist.AssistStructure.WindowNode; import android.app.assist.AssistStructure.ViewNode; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.PackageManager; import android.os.CancellationSignal; import android.service.autofill.AutofillService; import android.service.autofill.Dataset; @@ -33,16 +34,24 @@ import android.service.autofill.FillResponse; import android.service.autofill.SaveCallback; import android.service.autofill.SaveInfo; import android.service.autofill.SaveRequest; +import android.util.Log; import android.view.View; import android.view.autofill.AutofillId; +import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; +import android.widget.EditText; import android.widget.RemoteViews; +import java.util.ArrayList; +import java.util.List; import java.util.function.Predicate; +import android.widget.TextView; import foo.bar.fill.R; public class FillService extends AutofillService { + private static final String LOG_TAG = "FillService"; + static final boolean TEST_RESPONSE_AUTH = false; public static final String RESPONSE_ID = "RESPONSE_ID"; @@ -76,8 +85,20 @@ public class FillService extends AutofillService { @NonNull FillCallback callback) { AssistStructure structure = request.getFillContexts().get(0).getStructure(); - ViewNode username = findUsername(structure); - ViewNode password = findPassword(structure); + dumpNodeTree(structure); + +// ViewNode username = findUsername(structure); +// ViewNode password = findPassword(structure); + + ViewNode username = null; + ViewNode password = null; + final List<ViewNode> inputs = findTextInputs(structure); + if (inputs.size() > 1) { + username = inputs.get(0); + password = inputs.get(1); + } + + Log.i(LOG_TAG, "found username+username:" + (username != null && password != null)); if (username != null && password != null) { final FillResponse response; @@ -134,46 +155,48 @@ public class FillService extends AutofillService { .setValue(password.getAutofillId(), AutofillValue.forText(DATASET1_PASSWORD)) .build()) - .addDataset(new Dataset.Builder(presentation2) - .setValue(username.getAutofillId(), - AutofillValue.forText(DATASET2_USERNAME)) - .setValue(password.getAutofillId(), - AutofillValue.forText(DATASET2_PASSWORD)) -// .setAuthentication(sender) - .build()) - .addDataset(new Dataset.Builder(presentation3) - .setValue(username.getAutofillId(), - AutofillValue.forText(DATASET3_USERNAME)) - .setValue(password.getAutofillId(), - AutofillValue.forText(DATASET3_PASSWORD)) -// .setAuthentication(sender) - .build()) - .addDataset(new Dataset.Builder(presentation4) - .setValue(username.getAutofillId(), - AutofillValue.forText(DATASET4_USERNAME)) - .setValue(password.getAutofillId(), - AutofillValue.forText(DATASET4_PASSWORD)) +// .addDataset(new Dataset.Builder(presentation2) +// .setValue(username.getAutofillId(), +// AutofillValue.forText(DATASET2_USERNAME)) +// .setValue(password.getAutofillId(), +// AutofillValue.forText(DATASET2_PASSWORD)) +//// .setAuthentication(sender) +// .build()) +// .addDataset(new Dataset.Builder(presentation3) +// .setValue(username.getAutofillId(), +// AutofillValue.forText(DATASET3_USERNAME)) +// .setValue(password.getAutofillId(), +// AutofillValue.forText(DATASET3_PASSWORD)) +//// .setAuthentication(sender) +// .build()) +// .addDataset(new Dataset.Builder(presentation4) +// .setValue(username.getAutofillId(), +// AutofillValue.forText(DATASET4_USERNAME)) +// .setValue(password.getAutofillId(), +// AutofillValue.forText(DATASET4_PASSWORD)) +//// .setAuthentication(sender) +// .build()) +// .addDataset(new Dataset.Builder(presentation5) +// .setValue(username.getAutofillId(), +// AutofillValue.forText(DATASET5_USERNAME)) +// .setValue(password.getAutofillId(), +// AutofillValue.forText(DATASET5_PASSWORD)) // .setAuthentication(sender) - .build()) - .addDataset(new Dataset.Builder(presentation5) - .setValue(username.getAutofillId(), - AutofillValue.forText(DATASET5_USERNAME)) - .setValue(password.getAutofillId(), - AutofillValue.forText(DATASET5_PASSWORD)) - .setAuthentication(sender) - .build()) +// .build()) .setSaveInfo(new SaveInfo.Builder( SaveInfo.SAVE_DATA_TYPE_PASSWORD | SaveInfo.SAVE_DATA_TYPE_USERNAME, new AutofillId[] {username.getAutofillId(), password.getAutofillId()}) + .setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) .build()) .build(); } callback.onSuccess(response); } else { - callback.onFailure("Whoops"); + //callback.onFailure("Whoops"); + callback.onSuccess(null); } } @@ -184,20 +207,51 @@ public class FillService extends AutofillService { ViewNode password = findPassword(structure); } + static void dumpNodeTree(AssistStructure structure) { + findByPredicate(structure, (node) -> { + if (node.getAutofillValue() != null) { + Log.e("class:" + LOG_TAG, node.getClassName() + " value:" + node.getAutofillValue()); + } +// Log.e(LOG_TAG, (node.getAutofillValue() != null && node.getAutofillValue().isText()) +// ? node.getAutofillValue().getTextValue().toString() + "-" +node.getAutofillId() : "NOPE"); + return false; + }); + } + + List<ViewNode > findTextInputs(AssistStructure structure) { + final List<ViewNode> inputs = new ArrayList<>(); + findByPredicate(structure, (node) -> { + if (node.getClassName().equals(EditText.class.getName())) { + inputs.add(node); + } + return false; + }); + return inputs; + } + static ViewNode findUsername(AssistStructure structure) { return findByPredicate(structure, (node) -> node.getAutofillType() == View.AUTOFILL_TYPE_TEXT - && "username".equals(node.getIdEntry()) + && (autofillTextValueContains(node, "username") + || "username".equals(node.getIdEntry())) ); } static ViewNode findPassword(AssistStructure structure) { return findByPredicate(structure, (node) -> - node.getAutofillType() == View.AUTOFILL_TYPE_TEXT - && "password".equals(node.getIdEntry()) + node.getAutofillType() == View.AUTOFILL_TYPE_TEXT + && (autofillTextValueContains(node, "password") + || "password".equals(node.getIdEntry())) ); } + private static boolean autofillTextValueContains(ViewNode node, String text) { + return node.getAutofillValue() != null + && node.getAutofillValue().getTextValue() != null + && node.getAutofillValue().getTextValue().toString().toLowerCase() + .contains(text.toLowerCase()); + } + private static ViewNode findByPredicate(AssistStructure structure, Predicate<ViewNode> predicate) { final int windowCount = structure.getWindowNodeCount(); |