aboutsummaryrefslogtreecommitdiff
path: root/input/autofill/AutofillFramework/kotlinApp
diff options
context:
space:
mode:
authorDouglas Sigelbaum <sigelbaum@google.com>2017-05-31 00:30:47 -0700
committerDouglas Sigelbaum <sigelbaum@google.com>2017-05-31 11:45:41 -0700
commit389ba153ecf015cbff36764e9c07f12ac3a0353d (patch)
tree284aa0a3355b15801ab5a1e171ff541e1ee850ba /input/autofill/AutofillFramework/kotlinApp
parentda2273924314181bb5e7e50fc52effc2f00aff1b (diff)
downloadandroid-389ba153ecf015cbff36764e9c07f12ac3a0353d.tar.gz
Changes to get Kotlin and Java autofill samples in sync.
Also fixed a crash when using datasetAuth. Impacted both samples. Bug: 38182790 Test: manual Change-Id: I1bfb00e3a22708d7bcbaade2aff3b00789499fe7
Diffstat (limited to 'input/autofill/AutofillFramework/kotlinApp')
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml17
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt19
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt1
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.kt8
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.kt20
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.kt3
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.kt8
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/SharedPrefsAutofillRepository.kt10
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.kt10
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavableAutofillData.kt (renamed from input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/MutableAutofillValue.kt)4
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-dimens.xml24
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-styles.xml25
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v11/template-styles.xml22
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-colors.xml21
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml24
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/base-strings.xml29
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/strings.xml1
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/template-dimens.xml32
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/template-styles.xml42
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/README.md192
20 files changed, 159 insertions, 353 deletions
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml
index 28d9c0b5..eb1f43c2 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/AndroidManifest.xml
@@ -32,7 +32,6 @@
android:taskAffinity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
-
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
@@ -40,32 +39,17 @@
android:name=".app.LoginActivity"
android:label="AF StandardLogin"
android:taskAffinity=".LoginActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
</activity>
<activity
android:name=".app.VirtualLoginActivity"
android:label="AF VirtualLogin"
android:taskAffinity=".VirtualLoginActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
</activity>
<activity android:name=".app.WelcomeActivity" />
<activity
android:name=".app.CreditCardActivity"
android:label="AF CreditCard"
android:taskAffinity=".CreditCardActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
</activity>
<!--
Including launcher icon for Autofill Settings to convenience.
@@ -78,7 +62,6 @@
android:taskAffinity=".SettingsActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
-
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt
index 86dc9b25..bef16afe 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt
@@ -70,20 +70,21 @@ class CustomVirtualView(context: Context, attrs: AttributeSet) : View(context, a
}
override fun autofill(values: SparseArray<AutofillValue>) {
- // User has just selected a Dataset from the list of Autofill suggestions and the Dataset's
- // AutofillValue gets passed into this method.
+ // User has just selected a Dataset from the list of autofill suggestions.
+ // The Dataset is comprised of a list of AutofillValues, with each AutofillValue meant
+ // to fill a specific autofillable view. Now we have to update the UI based on the
+ // AutofillValues in the list.
Log.d(TAG, "autofill(): " + values)
for (i in 0..values.size() - 1) {
val id = values.keyAt(i)
val value = values.valueAt(i)
-
- mItems[id]?.let {
- if (!it.editable) {
- Log.w(TAG, "Item for autofillId $id is not editable: $it")
- return@autofill
+ mItems[id]?.let { item ->
+ if (item.editable) {
+ // Set the item's text to the text wrapped in the AutofillValue.
+ item.text = value.textValue
+ } else {
+ Log.w(TAG, "Item for autofillId $id is not editable: $item")
}
- // Set the item's text to the text wrapped in the AutofillValue.
- it.text = value.textValue
}
}
postInvalidate()
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt
index c6eb721f..52081afd 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/VirtualLoginActivity.kt
@@ -51,6 +51,7 @@ class VirtualLoginActivity : AppCompatActivity() {
if (valid) {
val intent = WelcomeActivity.getStartActivityIntent(this@VirtualLoginActivity)
startActivity(intent)
+ finish()
} else {
Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show()
}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.kt
index 12be45bb..d102a7e9 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.kt
@@ -97,8 +97,8 @@ class AuthActivity : Activity() {
} else {
val datasetName = intent.getStringExtra(EXTRA_DATASET_NAME)
clientFormDataMap?.let {
- it[datasetName]?.let {
- AutofillHelper.newDataset(this, autofillFields, it)?.let(this::setDatasetIntent)
+ it[datasetName]?.let { clientFormData ->
+ AutofillHelper.newDataset(this, autofillFields, clientFormData, false)?.let(this::setDatasetIntent)
}
}
}
@@ -115,7 +115,7 @@ class AuthActivity : Activity() {
companion object {
// Unique autofillId for dataset intents.
- private var sDatasetPendingIntentId = 0
+ private var datasetPendingIntentId = 0
internal fun getAuthIntentSenderForResponse(context: Context): IntentSender {
val intent = Intent(context, AuthActivity::class.java)
@@ -127,7 +127,7 @@ class AuthActivity : Activity() {
val intent = Intent(context, AuthActivity::class.java)
intent.putExtra(EXTRA_DATASET_NAME, datasetName)
intent.putExtra(EXTRA_FOR_RESPONSE, false)
- return PendingIntent.getActivity(context, ++sDatasetPendingIntentId, intent,
+ return PendingIntent.getActivity(context, ++datasetPendingIntentId, intent,
PendingIntent.FLAG_CANCEL_CURRENT).intentSender
}
}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.kt
index b7470d7b..58666ef4 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.kt
@@ -37,10 +37,14 @@ object AutofillHelper {
* client View.
*/
fun newDataset(context: Context, autofillFields: AutofillFieldsCollection,
- clientFormData: ClientFormData): Dataset? {
+ clientFormData: ClientFormData, datasetAuth: Boolean): Dataset? {
clientFormData.datasetName?.let { datasetName ->
val datasetBuilder = Dataset.Builder(newRemoteViews(context.packageName, datasetName))
val setValueAtLeastOnce = clientFormData.applyToFields(autofillFields, datasetBuilder)
+ if (datasetAuth) {
+ val sender = AuthActivity.getAuthIntentSenderForDataset(context, datasetName)
+ datasetBuilder.setAuthentication(sender)
+ }
if (setValueAtLeastOnce) {
return datasetBuilder.build()
}
@@ -65,18 +69,8 @@ object AutofillHelper {
clientFormDataMap?.keys?.let { datasetNames ->
for (datasetName in datasetNames) {
clientFormDataMap[datasetName]?.let { clientFormData ->
- if (datasetAuth) {
- clientFormData.datasetName?.let {
- val datasetBuilder = Dataset.Builder(newRemoteViews(context.packageName, it))
- val sender = AuthActivity
- .getAuthIntentSenderForDataset(context, it)
- datasetBuilder.setAuthentication(sender)
- responseBuilder.addDataset(datasetBuilder.build())
- }
- } else {
- val dataset = newDataset(context, autofillFields, clientFormData)
- dataset?.let(responseBuilder::addDataset)
- }
+ val dataset = newDataset(context, autofillFields, clientFormData, datasetAuth)
+ dataset?.let(responseBuilder::addDataset)
}
}
}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.kt
index 9bc2a8c2..41712bd1 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.kt
@@ -76,7 +76,8 @@ class MyAutofillService : AutofillService() {
callback.onSuccess(responseBuilder.build())
} else {
val datasetAuth = MyPreferences.isDatasetAuth(this)
- val clientFormDataMap = SharedPrefsAutofillRepository.getClientFormData(this, autofillFields.focusedAutofillHints, autofillFields.allAutofillHints)
+ val clientFormDataMap = SharedPrefsAutofillRepository.getClientFormData(this,
+ autofillFields.focusedAutofillHints, autofillFields.allAutofillHints)
val response = AutofillHelper.newResponse(this, datasetAuth, autofillFields, clientFormDataMap)
callback.onSuccess(response)
}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.kt
index e05a2d51..2cb37eea 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.kt
@@ -22,12 +22,12 @@ import com.example.android.autofillframework.CommonUtil.TAG
import com.example.android.autofillframework.service.model.AutofillField
import com.example.android.autofillframework.service.model.AutofillFieldsCollection
import com.example.android.autofillframework.service.model.ClientFormData
-import com.example.android.autofillframework.service.model.MutableAutofillValue
+import com.example.android.autofillframework.service.model.SavableAutofillData
/**
* Parser for an AssistStructure object. This is invoked when the Autofill Service receives an
- * AssistStructure from the client Activity, representing its View hierarchy. In this
- * sample, it parses the hierarchy and records
+ * AssistStructure from the client Activity, representing its View hierarchy. In this sample, it
+ * parses the hierarchy and collects autofill metadata from {@link ViewNode}s along the way.
*/
internal class StructureParser(private val mStructure: AssistStructure) {
val autofillFields = AutofillFieldsCollection()
@@ -64,7 +64,7 @@ internal class StructureParser(private val mStructure: AssistStructure) {
autofillFields.add(AutofillField(viewNode))
} else {
clientFormData.setAutofillValuesForHints(viewNode.autofillHints,
- MutableAutofillValue(viewNode))
+ SavableAutofillData(viewNode))
}
}
}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/SharedPrefsAutofillRepository.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/SharedPrefsAutofillRepository.kt
index a7eadc96..e2fb8708 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/SharedPrefsAutofillRepository.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/SharedPrefsAutofillRepository.kt
@@ -24,9 +24,9 @@ import com.google.gson.reflect.TypeToken
/**
- * Singleton autofill data repository, that stores autofill fields to SharedPreferences.
- * DISCLAIMER, you should not store sensitive fields like user data unencrypted. This is only done
- * here for simplicity and learning purposes.
+ * Singleton autofill data repository that stores autofill fields to SharedPreferences.
+ * Disclaimer: you should not store sensitive fields like user data unencrypted. This is done
+ * here only for simplicity and learning purposes.
*/
object SharedPrefsAutofillRepository : AutofillRepository {
private val SHARED_PREF_KEY = "com.example.android.autofillframework.service"
@@ -46,9 +46,13 @@ object SharedPrefsAutofillRepository : AutofillRepository {
val type = object : TypeToken<ClientFormData>() {}.type
Gson().fromJson<ClientFormData>(clientFormDataString, type)?.let { clientFormData ->
if (clientFormData.helpsWithHints(focusedAutofillHints)) {
+ // Saved data has data relevant to at least 1 of the hints associated with the
+ // View in focus.
hasDataForFocusedAutofillHints = true
clientFormData.datasetName?.let { datasetName ->
if (clientFormData.helpsWithHints(allAutofillHints)) {
+ // Saved data has data relevant to at least 1 of these hints associated with any
+ // of the Views in the hierarchy.
clientFormDataMap.put(datasetName, clientFormData)
}
}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.kt
index 78980aaa..2dc844ae 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.kt
@@ -28,16 +28,16 @@ import java.util.HashMap
* dataset name associated with it.
*/
class ClientFormData constructor(var datasetName: String? = null,
- private val hintMap: HashMap<String, MutableAutofillValue> = HashMap<String, MutableAutofillValue>()) {
+ private val hintMap: HashMap<String, SavableAutofillData> = HashMap<String, SavableAutofillData>()) {
private val TAG = "ClientFormData"
/**
* Sets values for a list of autofillHints.
*/
- fun setAutofillValuesForHints(autofillHints: Array<String>, autofillValue: MutableAutofillValue) {
+ fun setAutofillValuesForHints(autofillHints: Array<String>, autofillData: SavableAutofillData) {
autofillHints.forEach { hint ->
- hintMap[hint] = autofillValue
+ hintMap[hint] = autofillData
}
}
@@ -86,6 +86,10 @@ class ClientFormData constructor(var datasetName: String? = null,
return setValueAtLeastOnce
}
+ /**
+ * Returns whether this model contains autofill data that is relevant to any of the
+ * autofillHints that are passed in.
+ */
fun helpsWithHints(autofillHints: List<String>): Boolean {
for (autofillHint in autofillHints) {
hintMap[autofillHint]?.let { savedAutofillValue ->
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/MutableAutofillValue.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavableAutofillData.kt
index 702a1358..44baebfa 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/MutableAutofillValue.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavableAutofillData.kt
@@ -19,9 +19,9 @@ import android.app.assist.AssistStructure
import android.view.autofill.AutofillValue
/**
- * Mutable, JSON serializable data class containing the same data as an [AutofillValue].
+ * JSON serializable data class containing the same data as an [AutofillValue].
*/
-class MutableAutofillValue(viewNode: AssistStructure.ViewNode) {
+class SavableAutofillData(viewNode: AssistStructure.ViewNode) {
var textValue: String? = null
var dateValue: Long? = null
var toggleValue: Boolean? = null
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-dimens.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-dimens.xml
deleted file mode 100644
index 22074a2b..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-dimens.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- Copyright 2013 The Android Open Source Project
-
- 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.
- -->
-
-<resources>
-
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
-</resources>
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-styles.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-styles.xml
deleted file mode 100644
index 03d19741..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-sw600dp/template-styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- Copyright 2013 The Android Open Source Project
-
- 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.
- -->
-
-<resources>
-
- <style name="Widget.SampleMessage">
- <item name="android:textAppearance">?android:textAppearanceLarge</item>
- <item name="android:lineSpacingMultiplier">1.2</item>
- <item name="android:shadowDy">-6.5</item>
- </style>
-
-</resources>
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v11/template-styles.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v11/template-styles.xml
deleted file mode 100644
index 8c1ea66f..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v11/template-styles.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
- Copyright 2013 The Android Open Source Project
-
- 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.
- -->
-
-<resources>
-
- <!-- Activity themes -->
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-</resources>
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-colors.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-colors.xml
deleted file mode 100644
index 8b6ec3f8..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-colors.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright 2013 The Android Open Source Project
-
- 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.
--->
-
-<resources>
-
-
-</resources>
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml
deleted file mode 100644
index c778e4f9..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values-v21/base-template-styles.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright 2013 The Android Open Source Project
-
- 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.
--->
-
-<resources>
-
- <!-- Activity themes -->
- <style name="Theme.Base" parent="android:Theme.Material.Light">
- </style>
-
-</resources>
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/base-strings.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/base-strings.xml
deleted file mode 100644
index ddf8b07d..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/base-strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright 2013 The Android Open Source Project
-
- 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.
--->
-
-<resources>
- <string name="app_name">AutofillFramework</string>
- <string name="intro_message">
- <![CDATA[
-
-
- This sample app demos the Autofill feature introduced in Android O.
-
-
- ]]>
- </string>
-</resources>
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/strings.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/strings.xml
index b5611ae1..f9448a74 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/strings.xml
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/strings.xml
@@ -16,6 +16,7 @@
-->
<resources>
+ <string name="app_name">Autofill Sample</string>
<string name="settings_name">Autofill Settings</string>
<string name="username_label">Username</string>
<string name="password_label">Password</string>
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/template-dimens.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/template-dimens.xml
deleted file mode 100644
index 39e710b5..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/template-dimens.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
- Copyright 2013 The Android Open Source Project
-
- 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.
- -->
-
-<resources>
-
- <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
- <dimen name="margin_tiny">4dp</dimen>
- <dimen name="margin_small">8dp</dimen>
- <dimen name="margin_medium">16dp</dimen>
- <dimen name="margin_large">32dp</dimen>
- <dimen name="margin_huge">64dp</dimen>
-
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
-</resources>
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/template-styles.xml b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/template-styles.xml
deleted file mode 100644
index 6e7d593d..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/res/values/template-styles.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
- Copyright 2013 The Android Open Source Project
-
- 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.
- -->
-
-<resources>
-
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Light" />
-
- <style name="Theme.Sample" parent="Theme.Base" />
-
- <style name="AppTheme" parent="Theme.Sample" />
- <!-- Widget styling -->
-
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
- <item name="android:textAppearance">?android:textAppearanceMedium</item>
- <item name="android:lineSpacingMultiplier">1.1</item>
- </style>
-
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
- </style>
-
-</resources>
diff --git a/input/autofill/AutofillFramework/kotlinApp/README.md b/input/autofill/AutofillFramework/kotlinApp/README.md
index 53e4a7f0..9b060561 100644
--- a/input/autofill/AutofillFramework/kotlinApp/README.md
+++ b/input/autofill/AutofillFramework/kotlinApp/README.md
@@ -1,63 +1,98 @@
-Android AutofillFramework Sample (Kotlin)
+
+Android AutofillFramework Sample
===================================
This sample demonstrates the use of the Autofill Framework. It includes implementations of client
-Activities that want to be autofilled, and a Service that can provide autofill data to client
-Activities. For simplicity, this sample's service uses mock data to autofill what it thinks are
-username and password text fields.
+Activities with views that should be autofilled, and a Service that can provide autofill data to
+client Activities.
Introduction
------------
This sample demonstrates the use of the Autofill framework from the service side and the client
-side. In practice, only a small handful of apps will develop Autofill services because a device will
-only have one service as default at a time. However, all apps targeting O with any autofillable
-fields should follow the necessary steps to ensure their Views can be autofilled. Most of the time,
-there is little to no extra code involved, but the use of custom views and views with virtual child
-views requires more work.
-
-The sample's Autofill service is implemented to parse the client's view hierarchy in search of text
-fields that it has data for. If such text fields exist in the hierarchy, the service sends data
-suggestions to the client to fill in those text fields. In this basic sample, it will only look for
-views whose resource IDs are "usernameField" and "passwordField" and will send mock credential data
-accordingly. A real Autofill service would attempt to autofill more than just login credentials and
-would be able to fill in other view types in addition to text fields (e.g. spinners, checkboxes,
-etc.). It would also use more advanced heuristics to determine what data to send to which views.
-
-To set the device's default Autofill service to the one in the sample, edit
-**Settings** > **Apps &amp; Notifications** > **Default Apps** > **Auto-fill app** and select the
-sample app. To edit the service's settings, open the **Autofill Settings** launcher icon. Here, you
-can set whether you want to enable authentication on the entire Autofill Response or just on
-individual datasets. You can also set the number of mock datasets that are sent to the client app.
-
-The client side of the app has two Activities that each have a username field and a password field.
-One of the Activities uses standard views and the other Activity uses a custom view with virtual
-children. The standard views do not require any extra code to allow autofill. The following code
-example shows the `View` method you have to override in order to provide view hierarchy data to the
-Autofill service. This is triggered when the `View` goes into focus and Android invokes an Autofill
-request.
-
-```java
-/*
-This method is responsible for building the ViewStructure that gets passed to the AutoFillService
-by the framework when it is time to find Autofill suggestions. To do this, it should traverse
-through its view hierarchy and add views to the ViewStructure on the way.
-*/
-@Override
-public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
- structure.setClassName(getClass().getName());
- int childrenSize = mItems.size();
- int index = structure.addChildCount(childrenSize);
- for (int i = 0; i < childrenSize; i++) {
- Item item = mItems.valueAt(i);
- ViewStructure child = structure.newChild(index, item.id, flags);
- child.setSanitized(item.sanitized);
- child.setText(item.text);
- child.setAutoFillValue(AutoFillValue.forText(item.text));
- child.setFocused(item.line.focused);
- child.setId(item.id, getContext().getPackageName(), null, item.line.idEntry);
- index++;
- }
+side. In practice, only a small handful of apps will develop Autofill services because a device
+will only have one service as default at a time, and there is just a small number of 3rd-party apps
+providing these services (typically password managers). However, all apps targeting O with any
+autofillable fields should follow the necessary steps to 1) ensure their views can be autofilled
+and 2) optimize their autofill performance. Most of the time, there is little to no extra code
+involved, but the use of custom views and views with virtual child views requires more work.
+
+The sample's Autofill service is implemented to parse the client's view hierarchy in search of
+autofillable fields that it has data for. If such fields exist in the hierarchy, the service sends
+data suggestions to the client to autofill those fields. The client uses the following attributes
+to specify autofill properties: `importantForAutofill`, `autofillHints`, and `autofillType`.
+`importantForAutofill` specifies whether the view is autofillable. `autofillHints` is a list of
+strings that hint to the service **what** data to fill the view with. This sample service only
+supports the hints listed [here](https://developer.android.com/reference/android/view/View.html#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE)
+with the prefix AUTOFILL_HINT_*. `autofillType` tells the service the type of data it expects to
+receive (i.e. a list index, a date, or a string). Specifying `autofillType` is only necessary
+when implementing a custom view since all of the provided widgets in the UI toolkit do this for you.
+
+To set the device's default Autofill service to the one in the sample, edit **Settings** >
+**System** > **Languages &amp; Input** > **Advanced** > **Auto-fill service** and select the sample
+app. To edit the service's settings, tap the settings icon next to the **Auto-fill service** list
+item or open the **Autofill Settings** launcher icon.. Here, you can set whether you want to enable
+authentication on the entire autofill Response or just on individual autofill datasets. You should
+also set the master password to “unlock” authenticated autofill data with.
+
+**Note:** This sample service stores all autofill data in SharedPreferences and thus is not secure.
+Be careful about what you store when experimenting with the sample because anyone with root access
+to your device will be able to view your autofill data.
+
+The client side of the app has three Activities that each have autofillable fields. The first
+Activity uses standard views to comprise a login form. Very little needs to be done by the client
+app to ensure the views get autofilled properly. The second Activity uses a custom view with
+virtual children, meaning some autofillable child views are not known to the View hierarchy to be
+child views. Supporting autofill on these child views is a little more involved.
+
+The following code snippet shows how to signal to the autofill service that a specific
+autofillable virtual view has come into focus:
+
+```kotlin
+class CustomVirtualView(context: Context, attrs: AttributeSet) : View(context, attrs) {
+...
+ // Cache AutofillManager system service
+ private val autofillManager: AutofillManager = context.getSystemService(AutofillManager::class.java)
+...
+ // Notify service which virtual view has come into focus.
+ autofillManager.notifyViewEntered(this@CustomVirtualView, id, absBounds)
+...
+ // Notify service that a virtual view has left focus.
+ autofillManager.notifyViewExited(this@CustomVirtualView, id)
+}
+```
+
+Now that the autofillable view has signaled to the service that it has been autofilled, it needs
+to provide the virtual view hierarchy to the Autofill service. This is done out of the box for
+views part of the UI toolkit, but you need to implement this yourself if you have the view has
+virtual child views. The following code example shows the `View` method you have to override in
+order to provide this view hierarchy data to the Autofill service.
+
+```kotlin
+override fun onProvideAutofillVirtualStructure(structure: ViewStructure, flags: Int) {
+ // Build a ViewStructure to pack in AutoFillService requests.
+ structure.setClassName(javaClass.name)
+ val childrenSize = mItems.size()
+ Log.d(TAG, "onProvideAutofillVirtualStructure(): flags = " + flags + ", items = "
+ + childrenSize + ", extras: " + bundleToString(structure.extras))
+ var index = structure.addChildCount(childrenSize)
+ // Traverse through the view hierarchy, including virtual child views. For each view, we
+ // need to set the relevant autofill metadata and add it to the ViewStructure.
+ for (i in 0..childrenSize - 1) {
+ val item = mItems.valueAt(i)
+ Log.d(TAG, "Adding new child at index $index: $item")
+ val child = structure.newChild(index)
+ child.setAutofillId(structure, item.id)
+ child.setAutofillHints(item.hints)
+ child.setAutofillType(item.type)
+ child.setDataIsSensitive(!item.sanitized)
+ child.text = item.text
+ child.setAutofillValue(AutofillValue.forText(item.text))
+ child.setFocused(item.focused)
+ child.setId(item.id, context.packageName, null, item.line.idEntry)
+ child.setClassName(item.className)
+ index++
+ }
}
```
@@ -65,30 +100,29 @@ After the service processes the Autofill request and sends back a series of Auto
(wrapped in a `Response` object), the user can pick which `Dataset` they want to autofill their
views with. When a `Dataset` is selected, this method is invoked for all of the views that were
associated with that `Dataset` by the service. For example, the `Dataset` might contain Autofill
-values for username, password, birthday, and address. This method would then be invoked on all four
-of those fields. The following code example shows how the sample app implements the method to
-deliver a UI update to the appropriate child view after the user makes their selection.
-
-```java
-/*
-User has just selected a Dataset from the list of Autofill suggestions and the Dataset's
-AutoFillValue gets passed into this method. This method updates the UI based on the data
-in the AutoFillValue.
-*/
-@Override
-public void autoFillVirtual(int id, AutoFillValue value) {
- Item item = mItems.get(id);
- if (item == null) {
- // ID not recognized so no-op.
- return;
- }
- if (!item.editable) {
- // Component is not editable so no-op.
- return;
- }
- // Set the virtual child view's text to the text wrapped in the AutoFillValue.
- item.text = value.getTextValue();
- postInvalidate();
+values for username, password, birthday, and address. This method would then be invoked on all
+four of those fields. The following code example shows how the sample app implements the method
+to deliver a UI update to the appropriate child view after the user makes their selection.
+
+```kotlin
+override fun autofill(values: SparseArray<AutofillValue>) {
+ // User has just selected a Dataset from the list of autofill suggestions.
+ // The Dataset is comprised of a list of AutofillValues, with each AutofillValue meant
+ // to fill a specific autofillable view. Now we have to update the UI based on the
+ // AutofillValues in the list.
+ for (i in 0..values.size() - 1) {
+ val id = values.keyAt(i)
+ val value = values.valueAt(i)
+ mItems[id]?.let { item ->
+ if (item.editable) {
+ // Set the item's text to the text wrapped in the AutofillValue.
+ item.text = value.textValue
+ } else {
+ // Component not editable, so no-op.
+ }
+ }
+ }
+ postInvalidate()
}
```
@@ -96,8 +130,10 @@ Pre-requisites
--------------
- Android SDK Preview O
-- Android Build Tools v25.0.3
-- Android Support Repository
+- Android Studio 3.0+
+- Android Build Tools v26+
+- Android Support Repository v26+
+- Gradle v3.0+
Screenshots
-------------