aboutsummaryrefslogtreecommitdiff
path: root/input/autofill/AutofillFramework/kotlinApp
diff options
context:
space:
mode:
authorDouglas Sigelbaum <sigelbaum@google.com>2017-05-23 12:08:20 -0700
committerDouglas Sigelbaum <sigelbaum@google.com>2017-05-30 18:01:15 -0700
commit458ac0f88ad2d524fe5644af3855eee6fd27e092 (patch)
treeb63c0cd360587224b1ebae3b443f45fcba7698ce /input/autofill/AutofillFramework/kotlinApp
parent16b2ad6e79136b52236644d438fb954cd6ad08fa (diff)
downloadandroid-458ac0f88ad2d524fe5644af3855eee6fd27e092.tar.gz
Converted Autofill sample service to kotlin.
Also modified some kotlin in Autofill client activities. Bug: 38182790 Test: manual Change-Id: I09938ae3edf83c7a26855c376a96f69a67f542c1
Diffstat (limited to 'input/autofill/AutofillFramework/kotlinApp')
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/build.gradle1
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java54
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.kt52
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.kt5
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CustomVirtualView.kt30
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.kt2
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java160
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.kt134
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java100
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.kt93
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java128
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.kt102
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.java85
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.kt78
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.kt (renamed from input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.java)21
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java127
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/SharedPrefsAutofillRepository.kt101
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java119
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.kt82
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java70
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.kt51
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java184
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.kt99
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/MutableAutofillValue.kt52
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.java135
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.java91
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.kt77
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java176
-rw-r--r--input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.kt139
29 files changed, 1089 insertions, 1459 deletions
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/build.gradle b/input/autofill/AutofillFramework/kotlinApp/Application/build.gradle
index fa91e606..bd0cded2 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/build.gradle
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/build.gradle
@@ -23,6 +23,7 @@ dependencies {
compile "com.android.support:support-v13:25.0.1"
compile "com.android.support:cardview-v7:25.0.1"
compile "com.android.support:appcompat-v7:25.0.1"
+ compile 'com.google.code.gson:gson:2.7'
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java
deleted file mode 100644
index 54049902..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework;
-
-import android.os.Bundle;
-
-import java.util.Arrays;
-import java.util.Set;
-
-public final class CommonUtil {
-
- public static final String TAG = "AutofillSample";
-
- public static final String EXTRA_DATASET_NAME = "dataset_name";
- public static final String EXTRA_FOR_RESPONSE = "for_response";
-
- private static void bundleToString(StringBuilder builder, Bundle data) {
- final Set<String> keySet = data.keySet();
- builder.append("[Bundle with ").append(keySet.size()).append(" keys:");
- for (String key : keySet) {
- builder.append(' ').append(key).append('=');
- Object value = data.get(key);
- if ((value instanceof Bundle)) {
- bundleToString(builder, (Bundle) value);
- } else {
- builder.append((value instanceof Object[])
- ? Arrays.toString((Object[]) value) : value);
- }
- }
- builder.append(']');
- }
-
- public static String bundleToString(Bundle data) {
- if (data == null) {
- return "N/A";
- }
- final StringBuilder builder = new StringBuilder();
- bundleToString(builder, data);
- return builder.toString();
- }
-} \ No newline at end of file
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.kt
new file mode 100644
index 00000000..e2839e92
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/CommonUtil.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework
+
+import android.os.Bundle
+import java.util.Arrays
+
+object CommonUtil {
+
+ val TAG = "AutofillSample"
+
+ val EXTRA_DATASET_NAME = "dataset_name"
+ val EXTRA_FOR_RESPONSE = "for_response"
+
+ private fun bundleToString(builder: StringBuilder, data: Bundle) {
+ val keySet = data.keySet()
+ builder.append("[Bundle with ").append(keySet.size).append(" keys:")
+ for (key in keySet) {
+ builder.append(' ').append(key).append('=')
+ val value = data.get(key)
+ if (value is Bundle) {
+ bundleToString(builder, value)
+ } else {
+ val string = if (value is Array<*>) Arrays.toString(value) else value
+ builder.append(string)
+ }
+ }
+ builder.append(']')
+ }
+
+ fun bundleToString(data: Bundle?): String {
+ if (data == null) {
+ return "N/A"
+ }
+ val builder = StringBuilder()
+ bundleToString(builder, data)
+ return builder.toString()
+ }
+} \ No newline at end of file
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.kt
index 46fdb72a..9c4121aa 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/CreditCardActivity.kt
@@ -27,7 +27,7 @@ class CreditCardActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
-
+ setContentView(R.layout.credit_card_activity)
// Create an ArrayAdapter using the string array and a default spinner layout
val dayAdapter = ArrayAdapter.createFromResource(this, R.array.day_array, android.R.layout.simple_spinner_item)
@@ -57,13 +57,12 @@ class CreditCardActivity : AppCompatActivity() {
* any new data.
*/
private fun submit() {
- val intent = WelcomeActivity.getStartActivityIntent(this@CreditCardActivity)
+ val intent = WelcomeActivity.getStartActivityIntent(this)
startActivity(intent)
finish()
}
companion object {
-
fun getStartActivityIntent(context: Context): Intent {
val intent = Intent(context, CreditCardActivity::class.java)
return intent
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 5f66364c..193008b5 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
@@ -72,21 +72,19 @@ 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.
- Log.d(TAG, "autoFill(): " + values)
+ Log.d(TAG, "autofill(): " + values)
for (i in 0..values.size() - 1) {
val id = values.keyAt(i)
val value = values.valueAt(i)
- val item = mItems.get(id)
- if (item == null) {
- Log.w(TAG, "No item for id " + id)
- return
- }
- if (!item.editable) {
- Log.w(TAG, "Item for id $id is not editable: $item")
- return
+
+ mItems[id]?.let {
+ if (!it.editable) {
+ Log.w(TAG, "Item for autofillId $id is not editable: $it")
+ return@autofill
+ }
+ // Set the item's text to the text wrapped in the AutofillValue.
+ it.text = value.textValue
}
- // Set the item's text to the text wrapped in the AutofillValue.
- item.text = value.textValue
}
postInvalidate()
}
@@ -121,9 +119,8 @@ class CustomVirtualView(context: Context, attrs: AttributeSet) : View(context, a
Log.d(TAG, "onDraw: " + mLines.size + " lines; canvas:" + canvas)
var x: Float
var y = (mTopMargin + mLineLength).toFloat()
- for (i in mLines.indices) {
+ for (line in mLines) {
x = mLeftMargin.toFloat()
- val line = mLines[i]
Log.v(TAG, "Drawing '" + line + "' at " + x + "x" + y)
mTextPaint.color = if (line.fieldTextItem.focused) mFocusedColor else mUnfocusedColor
val readOnlyText = line.labelItem.text.toString() + ": ["
@@ -184,7 +181,9 @@ class CustomVirtualView(context: Context, attrs: AttributeSet) : View(context, a
return line
}
- private class Item internal constructor(val line: Line, val id: Int, val hints: Array<String>?, val type: Int, var text: CharSequence, val editable: Boolean, val sanitized: Boolean) {
+ private class Item internal constructor(val line: Line, val id: Int, val hints: Array<String>?,
+ val type: Int, var text: CharSequence,
+ val editable: Boolean, val sanitized: Boolean) {
var focused = false
override fun toString(): String {
@@ -198,7 +197,8 @@ class CustomVirtualView(context: Context, attrs: AttributeSet) : View(context, a
get() = if (editable) EditText::class.java.name else TextView::class.java.name
}
- private inner class Line constructor(val idEntry: String, label: String, hints: Array<String>, text: String, sanitized: Boolean) {
+ private inner class Line constructor(val idEntry: String, label: String, hints: Array<String>,
+ text: String, sanitized: Boolean) {
// Boundaries of the text field, relative to the CustomView
internal val bounds = Rect()
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.kt
index ca146019..bf3fe874 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.kt
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/app/LoginActivity.kt
@@ -24,8 +24,8 @@ import android.widget.Toast
import com.example.android.autofillframework.R
import kotlinx.android.synthetic.main.login_activity.*
+
class LoginActivity : AppCompatActivity() {
- val TAG = "LoginActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java
deleted file mode 100644
index 768b2ee3..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.app.assist.AssistStructure;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.os.Bundle;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.support.annotation.Nullable;
-import android.text.Editable;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.datasource.LocalAutofillRepository;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-import com.example.android.autofillframework.service.settings.MyPreferences;
-
-import java.util.HashMap;
-
-import static android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE;
-import static android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT;
-import static com.example.android.autofillframework.CommonUtil.EXTRA_DATASET_NAME;
-import static com.example.android.autofillframework.CommonUtil.EXTRA_FOR_RESPONSE;
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * This Activity controls the UI for logging in to the Autofill service.
- * It is launched when an Autofill Response or specific Dataset within the Response requires
- * authentication to access. It bundles the result in an Intent.
- */
-public class AuthActivity extends Activity {
-
- // Unique id for dataset intents.
- private static int sDatasetPendingIntentId = 0;
-
- private EditText mMasterPassword;
- private Button mCancel;
- private Button mLogin;
- private Intent mReplyIntent;
-
- static IntentSender getAuthIntentSenderForResponse(Context context) {
- final Intent intent = new Intent(context, AuthActivity.class);
- return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
- .getIntentSender();
- }
-
- static IntentSender getAuthIntentSenderForDataset(Context context, String datasetName) {
- final Intent intent = new Intent(context, AuthActivity.class);
- intent.putExtra(EXTRA_DATASET_NAME, datasetName);
- intent.putExtra(EXTRA_FOR_RESPONSE, false);
- return PendingIntent.getActivity(context, ++sDatasetPendingIntentId, intent,
- PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
- }
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.auth_activity);
- mCancel = findViewById(R.id.cancel);
- mLogin = findViewById(R.id.login);
- mMasterPassword = findViewById(R.id.master_password);
- mLogin.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- login();
- }
-
- });
-
- mCancel.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- onFailure();
- AuthActivity.this.finish();
- }
- });
- }
-
- private void login() {
- Editable password = mMasterPassword.getText();
- if (password.toString()
- .equals(MyPreferences.getInstance(AuthActivity.this).getMasterPassword())) {
- onSuccess();
- } else {
- Toast.makeText(this, "Password incorrect", Toast.LENGTH_SHORT).show();
- onFailure();
- }
- finish();
- }
-
- @Override
- public void finish() {
- if (mReplyIntent != null) {
- setResult(RESULT_OK, mReplyIntent);
- } else {
- setResult(RESULT_CANCELED);
- }
- super.finish();
- }
-
- private void onFailure() {
- Log.w(TAG, "Failed auth.");
- mReplyIntent = null;
- }
-
- private void onSuccess() {
- Intent intent = getIntent();
- boolean forResponse = intent.getBooleanExtra(EXTRA_FOR_RESPONSE, true);
- AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE);
- StructureParser parser = new StructureParser(structure);
- parser.parse();
- AutofillFieldsCollection autofillFields = parser.getAutofillFields();
- int saveTypes = parser.getSaveTypes();
- mReplyIntent = new Intent();
- HashMap<String, ClientFormData> clientFormDataMap =
- LocalAutofillRepository.getInstance(this).getClientFormData
- (autofillFields.getFocusedHints(), autofillFields.getAllHints());
- if (forResponse) {
- setResponseIntent(AutofillHelper.newResponse
- (this, false, autofillFields, saveTypes, clientFormDataMap));
- } else {
- String datasetName = intent.getStringExtra(EXTRA_DATASET_NAME);
- setDatasetIntent(AutofillHelper.newDataset
- (this, autofillFields, clientFormDataMap.get(datasetName)));
- }
- }
-
- private void setResponseIntent(FillResponse fillResponse) {
- mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse);
- }
-
- private void setDatasetIntent(Dataset dataset) {
- mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, dataset);
- }
-}
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
new file mode 100644
index 00000000..b8c3f8b1
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AuthActivity.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service
+
+import android.app.Activity
+import android.app.PendingIntent
+import android.app.assist.AssistStructure
+import android.content.Context
+import android.content.Intent
+import android.content.IntentSender
+import android.os.Bundle
+import android.service.autofill.Dataset
+import android.service.autofill.FillResponse
+import android.util.Log
+import android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE
+import android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT
+import android.widget.Toast
+import com.example.android.autofillframework.CommonUtil.EXTRA_DATASET_NAME
+import com.example.android.autofillframework.CommonUtil.EXTRA_FOR_RESPONSE
+import com.example.android.autofillframework.CommonUtil.TAG
+import com.example.android.autofillframework.R
+import com.example.android.autofillframework.service.datasource.SharedPrefsAutofillRepository
+import com.example.android.autofillframework.service.settings.MyPreferences
+import kotlinx.android.synthetic.main.auth_activity.cancel
+import kotlinx.android.synthetic.main.auth_activity.login
+import kotlinx.android.synthetic.main.auth_activity.master_password
+
+/**
+ * This Activity controls the UI for logging in to the Autofill service.
+ * It is launched when an Autofill Response or specific Dataset within the Response requires
+ * authentication to access. It bundles the result in an Intent.
+ */
+class AuthActivity : Activity() {
+
+ private var mReplyIntent: Intent? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.auth_activity)
+ login.setOnClickListener { login() }
+ cancel.setOnClickListener {
+ onFailure()
+ this@AuthActivity.finish()
+ }
+ }
+
+ private fun login() {
+ val password = master_password.text
+ if (password.toString() == MyPreferences.getMasterPassword(this@AuthActivity)) {
+ onSuccess()
+ } else {
+ Toast.makeText(this, "Password incorrect", Toast.LENGTH_SHORT).show()
+ onFailure()
+ }
+ finish()
+ }
+
+ override fun finish() {
+ if (mReplyIntent != null) {
+ setResult(Activity.RESULT_OK, mReplyIntent)
+ } else {
+ setResult(Activity.RESULT_CANCELED)
+ }
+ super.finish()
+ }
+
+ private fun onFailure() {
+ Log.w(TAG, "Failed auth.")
+ mReplyIntent = null
+ }
+
+ private fun onSuccess() {
+ val intent = intent
+ val forResponse = intent.getBooleanExtra(EXTRA_FOR_RESPONSE, true)
+ val structure = intent.getParcelableExtra<AssistStructure>(EXTRA_ASSIST_STRUCTURE)
+ val parser = StructureParser(structure)
+ parser.parseForFill()
+ val autofillFields = parser.autofillFields
+ mReplyIntent = Intent()
+ val clientFormDataMap = SharedPrefsAutofillRepository
+ .getClientFormData(this, autofillFields.focusedAutofillHints, autofillFields.allAutofillHints)
+ if (forResponse) {
+ AutofillHelper.newResponse(this, false, autofillFields, clientFormDataMap)?.let(this::setResponseIntent)
+ } else {
+ val datasetName = intent.getStringExtra(EXTRA_DATASET_NAME)
+ clientFormDataMap?.let {
+ it[datasetName]?.let {
+ AutofillHelper.newDataset(this, autofillFields, it)?.let(this::setDatasetIntent)
+ }
+ }
+ }
+ }
+
+ private fun setResponseIntent(fillResponse: FillResponse) {
+ mReplyIntent?.putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse)
+ }
+
+ private fun setDatasetIntent(dataset: Dataset) {
+ mReplyIntent?.putExtra(EXTRA_AUTHENTICATION_RESULT, dataset)
+ }
+
+ companion object {
+
+ // Unique autofillId for dataset intents.
+ private var sDatasetPendingIntentId = 0
+
+ internal fun getAuthIntentSenderForResponse(context: Context): IntentSender {
+ val intent = Intent(context, AuthActivity::class.java)
+ return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
+ .intentSender
+ }
+
+ internal fun getAuthIntentSenderForDataset(context: Context, datasetName: String): IntentSender {
+ 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,
+ PendingIntent.FLAG_CANCEL_CURRENT).intentSender
+ }
+ }
+}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java
deleted file mode 100644
index 460729e6..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service;
-
-import android.content.Context;
-import android.content.IntentSender;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.service.autofill.SaveInfo;
-import android.util.Log;
-import android.view.autofill.AutofillId;
-import android.widget.RemoteViews;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-
-import java.util.HashMap;
-import java.util.Set;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * This is a class containing helper methods for building Autofill Datasets and Responses.
- */
-public final class AutofillHelper {
-
- /**
- * Wraps autofill data in a LoginCredential Dataset object which can then be sent back to the
- * client View.
- */
- public static Dataset newDataset(Context context,
- AutofillFieldsCollection autofillFields, ClientFormData clientFormData) {
- Dataset.Builder datasetBuilder = new Dataset.Builder
- (newRemoteViews(context.getPackageName(), clientFormData.getDatasetName()));
- boolean setValueAtLeastOnce = clientFormData.applyToFields(autofillFields, datasetBuilder);
- if (setValueAtLeastOnce) {
- return datasetBuilder.build();
- } else {
- return null;
- }
- }
-
- public static RemoteViews newRemoteViews(String packageName, String remoteViewsText) {
- RemoteViews presentation = new RemoteViews(packageName, R.layout.list_item);
- presentation.setTextViewText(R.id.text1, remoteViewsText);
- return presentation;
- }
-
- /**
- * Wraps autofill data in a Response object (essentially a series of Datasets) which can then
- * be sent back to the client View.
- */
- public static FillResponse newResponse(Context context,
- boolean datasetAuth, AutofillFieldsCollection autofillFields, int saveType,
- HashMap<String, ClientFormData> clientFormDataMap) {
- FillResponse.Builder responseBuilder = new FillResponse.Builder();
- if (clientFormDataMap != null) {
- Set<String> datasetNames = clientFormDataMap.keySet();
- for (String datasetName : datasetNames) {
- ClientFormData clientFormData = clientFormDataMap.get(datasetName);
- if (datasetAuth) {
- Dataset.Builder datasetBuilder =
- new Dataset.Builder(newRemoteViews
- (context.getPackageName(), clientFormData.getDatasetName()));
- IntentSender sender = AuthActivity
- .getAuthIntentSenderForDataset(context, clientFormData.getDatasetName());
- datasetBuilder.setAuthentication(sender);
- responseBuilder.addDataset(datasetBuilder.build());
- } else {
- Dataset dataset = newDataset(context, autofillFields, clientFormData);
- if (dataset != null) {
- responseBuilder.addDataset(dataset);
- }
- }
- }
- }
- if (saveType != 0) {
- AutofillId[] autofillIds = autofillFields.getAutofillIds();
- responseBuilder.setSaveInfo(new SaveInfo.Builder(saveType, autofillIds).build());
- return responseBuilder.build();
- } else {
- Log.d(TAG, "These fields are not meant to be saved by autofill.");
- return null;
- }
- }
-}
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
new file mode 100644
index 00000000..b7470d7b
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/AutofillHelper.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service
+
+import android.content.Context
+import android.service.autofill.Dataset
+import android.service.autofill.FillResponse
+import android.service.autofill.SaveInfo
+import android.util.Log
+import android.widget.RemoteViews
+import com.example.android.autofillframework.CommonUtil.TAG
+import com.example.android.autofillframework.R
+import com.example.android.autofillframework.service.model.AutofillFieldsCollection
+import com.example.android.autofillframework.service.model.ClientFormData
+import java.util.HashMap
+
+/**
+ * This is a class containing helper methods for building Autofill Datasets and Responses.
+ */
+object AutofillHelper {
+
+ /**
+ * Wraps autofill data in a [Dataset] object which can then be sent back to the
+ * client View.
+ */
+ fun newDataset(context: Context, autofillFields: AutofillFieldsCollection,
+ clientFormData: ClientFormData): Dataset? {
+ clientFormData.datasetName?.let { datasetName ->
+ val datasetBuilder = Dataset.Builder(newRemoteViews(context.packageName, datasetName))
+ val setValueAtLeastOnce = clientFormData.applyToFields(autofillFields, datasetBuilder)
+ if (setValueAtLeastOnce) {
+ return datasetBuilder.build()
+ }
+ }
+ return null
+ }
+
+ fun newRemoteViews(packageName: String, remoteViewsText: String): RemoteViews {
+ val presentation = RemoteViews(packageName, R.layout.list_item)
+ presentation.setTextViewText(R.id.text1, remoteViewsText)
+ return presentation
+ }
+
+ /**
+ * Wraps autofill data in a [FillResponse] object (essentially a series of Datasets) which can
+ * then be sent back to the client View.
+ */
+ fun newResponse(context: Context,
+ datasetAuth: Boolean, autofillFields: AutofillFieldsCollection,
+ clientFormDataMap: HashMap<String, ClientFormData>?): FillResponse? {
+ val responseBuilder = FillResponse.Builder()
+ 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)
+ }
+ }
+ }
+ }
+ if (autofillFields.saveType != 0) {
+ val autofillIds = autofillFields.autofillIds
+ responseBuilder.setSaveInfo(SaveInfo.Builder(autofillFields.saveType,
+ autofillIds.toTypedArray()).build())
+ return responseBuilder.build()
+ } else {
+ Log.d(TAG, "These fields are not meant to be saved by autofill.")
+ return null
+ }
+ }
+} \ No newline at end of file
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java
deleted file mode 100644
index 61e42050..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service;
-
-import android.app.assist.AssistStructure;
-import android.content.IntentSender;
-import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.service.autofill.AutofillService;
-import android.service.autofill.FillCallback;
-import android.service.autofill.FillContext;
-import android.service.autofill.FillRequest;
-import android.service.autofill.FillResponse;
-import android.service.autofill.SaveCallback;
-import android.service.autofill.SaveRequest;
-import android.util.Log;
-import android.widget.RemoteViews;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.datasource.LocalAutofillRepository;
-import com.example.android.autofillframework.service.model.AutofillFieldsCollection;
-import com.example.android.autofillframework.service.model.ClientFormData;
-import com.example.android.autofillframework.service.settings.MyPreferences;
-
-import java.util.HashMap;
-import java.util.List;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-import static com.example.android.autofillframework.CommonUtil.bundleToString;
-
-public class MyAutofillService extends AutofillService {
-
- @Override
- public void onFillRequest(AssistStructure assistStructure, Bundle bundle, int i,
- CancellationSignal cancellationSignal, FillCallback fillCallback) {
- /* Deprecated, ignore */
- }
-
- @Override
- public void onSaveRequest(AssistStructure assistStructure, Bundle bundle,
- SaveCallback saveCallback) {
- /* Deprecated, ignore */
- }
-
- @Override
- public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
- FillCallback callback) {
- AssistStructure structure = request.getStructure();
- final Bundle data = request.getClientState();
- Log.d(TAG, "onFillRequest(): data=" + bundleToString(data));
-
- // Temporary hack for disabling autofill for components in this autofill service.
- // i.e. we don't want to autofill components in AuthActivity.
- if (structure.getActivityComponent().toShortString()
- .contains("com.example.android.autofillframework.service")) {
- callback.onSuccess(null);
- return;
- }
- cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
- @Override
- public void onCancel() {
- Log.w(TAG, "Cancel autofill not implemented in this sample.");
- }
- });
- // Parse AutoFill data in Activity
- StructureParser parser = new StructureParser(structure);
- parser.parse();
- AutofillFieldsCollection autofillFields = parser.getAutofillFields();
- int saveTypes = parser.getSaveTypes();
-
- FillResponse.Builder responseBuilder = new FillResponse.Builder();
- // Check user's settings for authenticating Responses and Datasets.
- boolean responseAuth = MyPreferences.getInstance(this).isResponseAuth();
- if (responseAuth) {
- // If the entire Autofill Response is authenticated, AuthActivity is used
- // to generate Response.
- IntentSender sender = AuthActivity.getAuthIntentSenderForResponse(this);
- RemoteViews presentation = AutofillHelper
- .newRemoteViews(getPackageName(), getString(R.string.autofill_sign_in_prompt));
- responseBuilder
- .setAuthentication(autofillFields.getAutofillIds(), sender, presentation);
- callback.onSuccess(responseBuilder.build());
- } else {
- boolean datasetAuth = MyPreferences.getInstance(this).isDatasetAuth();
- HashMap<String, ClientFormData> clientFormDataMap =
- LocalAutofillRepository.getInstance(this).getClientFormData
- (autofillFields.getFocusedHints(), autofillFields.getAllHints());
- FillResponse response = AutofillHelper.newResponse
- (this, datasetAuth, autofillFields, saveTypes, clientFormDataMap);
- callback.onSuccess(response);
- }
- }
-
- @Override
- public void onSaveRequest(SaveRequest request, SaveCallback callback) {
- List<FillContext> context = request.getFillContexts();
- final AssistStructure structure = context.get(context.size() - 1).getStructure();
- final Bundle data = request.getClientState();
- Log.d(TAG, "onSaveRequest(): data=" + bundleToString(data));
- StructureParser parser = new StructureParser(structure);
- parser.parse();
- ClientFormData clientFormData = parser.getClientFormData();
- LocalAutofillRepository.getInstance(this).saveClientFormData(clientFormData);
- }
-
- @Override
- public void onConnected() {
- Log.d(TAG, "onConnected");
- }
-
- @Override
- public void onDisconnected() {
- Log.d(TAG, "onDisconnected");
- }
-}
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
new file mode 100644
index 00000000..9bc2a8c2
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/MyAutofillService.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service
+
+import android.app.assist.AssistStructure
+import android.os.Bundle
+import android.os.CancellationSignal
+import android.service.autofill.AutofillService
+import android.service.autofill.FillCallback
+import android.service.autofill.FillRequest
+import android.service.autofill.FillResponse
+import android.service.autofill.SaveCallback
+import android.service.autofill.SaveRequest
+import android.util.Log
+import com.example.android.autofillframework.CommonUtil.TAG
+import com.example.android.autofillframework.CommonUtil.bundleToString
+import com.example.android.autofillframework.R
+import com.example.android.autofillframework.service.datasource.SharedPrefsAutofillRepository
+import com.example.android.autofillframework.service.settings.MyPreferences
+
+class MyAutofillService : AutofillService() {
+
+ override fun onFillRequest(assistStructure: AssistStructure, bundle: Bundle, i: Int,
+ cancellationSignal: CancellationSignal, fillCallback: FillCallback) {
+ /* Deprecated, ignore */
+ }
+
+ override fun onSaveRequest(assistStructure: AssistStructure, bundle: Bundle,
+ saveCallback: SaveCallback) {
+ /* Deprecated, ignore */
+ }
+
+ override fun onFillRequest(request: FillRequest, cancellationSignal: CancellationSignal,
+ callback: FillCallback) {
+ val structure = request.structure
+ val data = request.clientState
+ Log.d(TAG, "onFillRequest(): data=" + bundleToString(data))
+
+ // Temporary hack for disabling autofill for components in this autofill service.
+ // i.e. we don't want to autofill components in AuthActivity.
+ if (structure.activityComponent.toShortString()
+ .contains("com.example.android.autofillframework.service")) {
+ callback.onSuccess(null)
+ return
+ }
+ cancellationSignal.setOnCancelListener { Log.w(TAG, "Cancel autofill not implemented in this sample.") }
+ // Parse AutoFill data in Activity
+ val parser = StructureParser(structure)
+ parser.parseForFill()
+ val autofillFields = parser.autofillFields
+
+ val responseBuilder = FillResponse.Builder()
+ // Check user's settings for authenticating Responses and Datasets.
+ val responseAuth = MyPreferences.isResponseAuth(this)
+ if (responseAuth) {
+ // If the entire Autofill Response is authenticated, AuthActivity is used
+ // to generate Response.
+ val sender = AuthActivity.getAuthIntentSenderForResponse(this)
+ val presentation = AutofillHelper
+ .newRemoteViews(packageName, getString(R.string.autofill_sign_in_prompt))
+ responseBuilder
+ .setAuthentication(autofillFields.autofillIds.toTypedArray(), sender, presentation)
+ callback.onSuccess(responseBuilder.build())
+ } else {
+ val datasetAuth = MyPreferences.isDatasetAuth(this)
+ val clientFormDataMap = SharedPrefsAutofillRepository.getClientFormData(this, autofillFields.focusedAutofillHints, autofillFields.allAutofillHints)
+ val response = AutofillHelper.newResponse(this, datasetAuth, autofillFields, clientFormDataMap)
+ callback.onSuccess(response)
+ }
+ }
+
+ override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
+ val context = request.fillContexts
+ val structure = context[context.size - 1].structure
+ val data = request.clientState
+ Log.d(TAG, "onSaveRequest(): data=" + bundleToString(data))
+ val parser = StructureParser(structure)
+ parser.parseForSave()
+ SharedPrefsAutofillRepository.saveClientFormData(this, parser.clientFormData)
+ }
+
+ override fun onConnected() {
+ Log.d(TAG, "onConnected")
+ }
+
+ override fun onDisconnected() {
+ Log.d(TAG, "onDisconnected")
+ }
+}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.java
deleted file mode 100644
index b6294449..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service;
-
-import android.app.assist.AssistStructure;
-import android.app.assist.AssistStructure.ViewNode;
-import android.app.assist.AssistStructure.WindowNode;
-import android.util.Log;
-
-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.SavedAutofillValue;
-
-import static com.example.android.autofillframework.CommonUtil.TAG;
-
-/**
- * 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
- */
-final class StructureParser {
- private final AutofillFieldsCollection mAutofillFields = new AutofillFieldsCollection();
- private final AssistStructure mStructure;
- private ClientFormData mClientFormData;
-
- StructureParser(AssistStructure structure) {
- mStructure = structure;
-
- }
-
- /**
- * Traverse AssistStructure and add ViewNode metadata to a flat list.
- */
- void parse() {
- Log.d(TAG, "Parsing structure for " + mStructure.getActivityComponent());
- int nodes = mStructure.getWindowNodeCount();
- mClientFormData = new ClientFormData();
- for (int i = 0; i < nodes; i++) {
- WindowNode node = mStructure.getWindowNodeAt(i);
- ViewNode view = node.getRootViewNode();
- parseLocked(view);
- }
- }
-
- private void parseLocked(ViewNode viewNode) {
- if (viewNode.getAutofillHints() != null && viewNode.getAutofillHints().length > 0) {
- //TODO check to make sure hints are supported by service.
- mAutofillFields.add(new AutofillField(viewNode));
- mClientFormData
- .set(viewNode.getAutofillHints(), SavedAutofillValue.fromViewNode(viewNode));
- }
- int childrenSize = viewNode.getChildCount();
- if (childrenSize > 0) {
- for (int i = 0; i < childrenSize; i++) {
- parseLocked(viewNode.getChildAt(i));
- }
- }
- }
-
- public AutofillFieldsCollection getAutofillFields() {
- return mAutofillFields;
- }
-
- public int getSaveTypes() {
- return mAutofillFields.getSaveType();
- }
-
- public ClientFormData getClientFormData() {
- return mClientFormData;
- }
-}
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
new file mode 100644
index 00000000..e05a2d51
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/StructureParser.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service
+
+import android.app.assist.AssistStructure
+import android.app.assist.AssistStructure.ViewNode
+import android.util.Log
+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
+
+/**
+ * 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
+ */
+internal class StructureParser(private val mStructure: AssistStructure) {
+ val autofillFields = AutofillFieldsCollection()
+ var clientFormData: ClientFormData = ClientFormData()
+ private set
+
+
+ fun parseForFill() {
+ parse(true)
+ }
+
+ fun parseForSave() {
+ parse(false)
+ }
+
+ /**
+ * Traverse AssistStructure and add ViewNode metadata to a flat list.
+ */
+ private fun parse(forFill: Boolean) {
+ Log.d(TAG, "Parsing structure for " + mStructure.activityComponent)
+ val nodes = mStructure.windowNodeCount
+ clientFormData = ClientFormData()
+ for (i in 0..nodes - 1) {
+ val node = mStructure.getWindowNodeAt(i)
+ val view = node.rootViewNode
+ parseLocked(forFill, view)
+ }
+ }
+
+ private fun parseLocked(forFill: Boolean, viewNode: ViewNode) {
+ viewNode.autofillHints?.let { autofillHints ->
+ if (autofillHints.isNotEmpty()) {
+ if (forFill) {
+ autofillFields.add(AutofillField(viewNode))
+ } else {
+ clientFormData.setAutofillValuesForHints(viewNode.autofillHints,
+ MutableAutofillValue(viewNode))
+ }
+ }
+ }
+ val childrenSize = viewNode.childCount
+ if (childrenSize > 0) {
+ for (i in 0..childrenSize - 1) {
+ parseLocked(forFill, viewNode.getChildAt(i))
+ }
+ }
+ }
+}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.kt
index 8de8b647..f335187e 100644
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.java
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/AutofillRepository.kt
@@ -13,29 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.example.android.autofillframework.service.datasource;
+package com.example.android.autofillframework.service.datasource
-import com.example.android.autofillframework.service.model.ClientFormData;
+import android.content.Context
+import com.example.android.autofillframework.service.model.ClientFormData
+import java.util.HashMap
-import java.util.HashMap;
-import java.util.List;
-
-public interface AutofillRepository {
+interface AutofillRepository {
/**
* Gets saved ClientFormData that contains some objects that can autofill fields with these
- * {@code autofillHints}.
+ * `autofillHints`.
*/
- HashMap<String, ClientFormData> getClientFormData(List<String> focusedAutofillHints,
- List<String> allAutofillHints);
+ fun getClientFormData(context: Context, focusedAutofillHints: List<String>,
+ allAutofillHints: List<String>): HashMap<String, ClientFormData>?
/**
* Saves LoginCredential under this datasetName.
*/
- void saveClientFormData(ClientFormData clientFormData);
+ fun saveClientFormData(context: Context, clientFormData: ClientFormData)
/**
* Clears all data.
*/
- void clear();
+ fun clear(context: Context)
}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java
deleted file mode 100644
index 8336fe1e..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/LocalAutofillRepository.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service.datasource;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.ArraySet;
-
-import com.example.android.autofillframework.service.model.ClientFormData;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Set;
-
-/**
- * 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.
- */
-public class LocalAutofillRepository implements AutofillRepository {
- private static final String SHARED_PREF_KEY = "com.example.android.autofillframework.service";
- private static final String CLIENT_FORM_DATA_KEY = "loginCredentialDatasets";
- private static final String DATASET_NUMBER_KEY = "datasetNumber";
-
- private static LocalAutofillRepository sInstance;
-
- private final SharedPreferences mPrefs;
-
- // TODO prepend with autofill data set in Settings.
- private LocalAutofillRepository(Context context) {
- mPrefs = context.getApplicationContext()
- .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE);
- }
-
- public static LocalAutofillRepository getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new LocalAutofillRepository(context);
- }
- return sInstance;
- }
-
- @Override
- public HashMap<String, ClientFormData> getClientFormData(List<String> focusedAutofillHints,
- List<String> allAutofillHints) {
- try {
- // TODO use sqlite instead.
- boolean hasDataForFocusedAutofillHints = false;
- HashMap<String, ClientFormData> clientFormDataMap = new HashMap<>();
- Set<String> clientFormDataStringSet = getAllAutofillDataStringSet();
- for (String clientFormDataString : clientFormDataStringSet) {
- ClientFormData clientFormData = ClientFormData
- .fromJson(new JSONObject(clientFormDataString));
- if (clientFormData != null) {
- if (clientFormData.helpsWithHints(focusedAutofillHints)) {
- hasDataForFocusedAutofillHints = true;
- }
- if (clientFormData.helpsWithHints(allAutofillHints)) {
- clientFormDataMap.put(clientFormData.getDatasetName(), clientFormData);
- }
- }
- }
- if (hasDataForFocusedAutofillHints) {
- return clientFormDataMap;
- } else {
- return null;
- }
- } catch (JSONException e) {
- return null;
- }
- }
-
- @Override
- public void saveClientFormData(ClientFormData clientFormData) {
- //TODO use sqlite instead.
- String datasetName = "dataset-" + getDatasetNumber();
- clientFormData.setDatasetName(datasetName);
- Set<String> allAutofillData = getAllAutofillDataStringSet();
- allAutofillData.add(clientFormData.toJson().toString());
- saveAllAutofillDataStringSet(allAutofillData);
- incrementDatasetNumber();
- }
-
- @Override
- public void clear() {
- mPrefs.edit().remove(CLIENT_FORM_DATA_KEY).apply();
- }
-
- private Set<String> getAllAutofillDataStringSet() {
- return mPrefs.getStringSet(CLIENT_FORM_DATA_KEY, new ArraySet<String>());
- }
-
- private void saveAllAutofillDataStringSet(Set<String> allAutofillDataStringSet) {
- mPrefs.edit().putStringSet(CLIENT_FORM_DATA_KEY, allAutofillDataStringSet).apply();
- }
-
- /**
- * For simplicity, datasets will be named in the form "dataset-X" where X means
- * this was the Xth dataset saved.
- */
- private int getDatasetNumber() {
- return mPrefs.getInt(DATASET_NUMBER_KEY, 0);
- }
-
- /**
- * Every time a dataset is saved, this should be called to increment the dataset number.
- * (only important for this service's dataset naming scheme).
- */
- private void incrementDatasetNumber() {
- mPrefs.edit().putInt(DATASET_NUMBER_KEY, getDatasetNumber() + 1).apply();
- }
-} \ No newline at end of file
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
new file mode 100644
index 00000000..a7eadc96
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/datasource/SharedPrefsAutofillRepository.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service.datasource
+
+import android.content.Context
+import android.content.SharedPreferences
+import android.util.ArraySet
+import com.example.android.autofillframework.service.model.ClientFormData
+import com.google.gson.Gson
+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.
+ */
+object SharedPrefsAutofillRepository : AutofillRepository {
+ private val SHARED_PREF_KEY = "com.example.android.autofillframework.service"
+ private val CLIENT_FORM_DATA_KEY = "loginCredentialDatasets"
+ private val DATASET_NUMBER_KEY = "datasetNumber"
+
+ private fun getPrefs(context: Context): SharedPreferences {
+ return context.applicationContext.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
+ }
+
+ override fun getClientFormData(context: Context, focusedAutofillHints: List<String>,
+ allAutofillHints: List<String>): HashMap<String, ClientFormData>? {
+ var hasDataForFocusedAutofillHints = false
+ val clientFormDataMap = HashMap<String, ClientFormData>()
+ val clientFormDataStringSet = getAllAutofillDataStringSet(context)
+ for (clientFormDataString in clientFormDataStringSet) {
+ val type = object : TypeToken<ClientFormData>() {}.type
+ Gson().fromJson<ClientFormData>(clientFormDataString, type)?.let { clientFormData ->
+ if (clientFormData.helpsWithHints(focusedAutofillHints)) {
+ hasDataForFocusedAutofillHints = true
+ clientFormData.datasetName?.let { datasetName ->
+ if (clientFormData.helpsWithHints(allAutofillHints)) {
+ clientFormDataMap.put(datasetName, clientFormData)
+ }
+ }
+ }
+ }
+ }
+ if (hasDataForFocusedAutofillHints) {
+ return clientFormDataMap
+ } else {
+ return null
+ }
+ }
+
+ override fun saveClientFormData(context: Context, clientFormData: ClientFormData) {
+ val datasetName = "dataset-" + getDatasetNumber(context)
+ clientFormData.datasetName = datasetName
+ val allAutofillData = getAllAutofillDataStringSet(context)
+ allAutofillData.add(Gson().toJson(clientFormData).toString())
+ saveAllAutofillDataStringSet(context, allAutofillData)
+ incrementDatasetNumber(context)
+ }
+
+ override fun clear(context: Context) {
+ getPrefs(context).edit().remove(CLIENT_FORM_DATA_KEY).remove(DATASET_NUMBER_KEY).apply()
+ }
+
+ private fun getAllAutofillDataStringSet(context: Context): MutableSet<String> {
+ return getPrefs(context).getStringSet(CLIENT_FORM_DATA_KEY, ArraySet<String>())
+ }
+
+ private fun saveAllAutofillDataStringSet(context: Context, allAutofillDataStringSet: Set<String>) {
+ getPrefs(context).edit().putStringSet(CLIENT_FORM_DATA_KEY, allAutofillDataStringSet).apply()
+ }
+
+ /**
+ * For simplicity, datasets will be named in the form "dataset-X" where X means
+ * this was the Xth dataset saved.
+ */
+ private fun getDatasetNumber(context: Context): Int {
+ return getPrefs(context).getInt(DATASET_NUMBER_KEY, 0)
+ }
+
+ /**
+ * Every time a dataset is saved, this should be called to increment the dataset number.
+ * (only important for this service's dataset naming scheme).
+ */
+ private fun incrementDatasetNumber(context: Context) {
+ getPrefs(context).edit().putInt(DATASET_NUMBER_KEY, getDatasetNumber(context) + 1).apply()
+ }
+} \ No newline at end of file
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java
deleted file mode 100644
index 77f0a182..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service.model;
-
-import android.app.assist.AssistStructure;
-import android.service.autofill.SaveInfo;
-import android.view.View;
-import android.view.autofill.AutofillId;
-
-/**
- * Class that represents a field that can be autofilled. It will contain a description
- * (what type data the field holds), an AutoFillId (an ID unique to the rest of the ViewStructure),
- * and a value (what data is currently in the field).
- */
-public class AutofillField {
- private int mSaveType = 0;
- private String[] mHints;
- private AutofillId mId;
- private int mAutofillType;
- private String[] mAutofillOptions;
- private boolean mFocused;
-
- public AutofillField(AssistStructure.ViewNode view) {
- mId = view.getAutofillId();
- setHints(view.getAutofillHints());
- mAutofillType = view.getAutofillType();
- mAutofillOptions = view.getAutofillOptions();
- mFocused = view.isFocused();
- }
-
- public String[] getHints() {
- return mHints;
- }
-
- public void setHints(String[] hints) {
- mHints = hints;
- updateSaveTypeFromHints();
- }
-
- public int getSaveType() {
- return mSaveType;
- }
-
- public AutofillId getId() {
- return mId;
- }
-
- public void setId(AutofillId id) {
- mId = id;
- }
-
- public int getAutofillType() {
- return mAutofillType;
- }
-
- public int getAutofillOptionIndex(String value) {
- for (int i = 0; i < mAutofillOptions.length; i++) {
- if (mAutofillOptions[i].equals(value)) {
- return i;
- }
- }
- return -1;
- }
-
- public boolean isFocused() {
- return mFocused;
- }
-
- private void updateSaveTypeFromHints() {
- mSaveType = 0;
- if (mHints == null) {
- return;
- }
- for (String hint : mHints) {
- switch (hint) {
- case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE:
- case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY:
- case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH:
- case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR:
- case View.AUTOFILL_HINT_CREDIT_CARD_NUMBER:
- case View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE:
- mSaveType |= SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
- break;
- case View.AUTOFILL_HINT_EMAIL_ADDRESS:
- mSaveType |= SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
- break;
- case View.AUTOFILL_HINT_PHONE:
- case View.AUTOFILL_HINT_NAME:
- mSaveType |= SaveInfo.SAVE_DATA_TYPE_GENERIC;
- break;
- case View.AUTOFILL_HINT_PASSWORD:
- mSaveType |= SaveInfo.SAVE_DATA_TYPE_PASSWORD;
- mSaveType &= ~SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
- mSaveType &= ~SaveInfo.SAVE_DATA_TYPE_USERNAME;
- break;
- case View.AUTOFILL_HINT_POSTAL_ADDRESS:
- case View.AUTOFILL_HINT_POSTAL_CODE:
- mSaveType |= SaveInfo.SAVE_DATA_TYPE_ADDRESS;
- break;
- case View.AUTOFILL_HINT_USERNAME:
- mSaveType |= SaveInfo.SAVE_DATA_TYPE_USERNAME;
- break;
- }
- }
- }
-}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.kt
new file mode 100644
index 00000000..315299be
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillField.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service.model
+
+import android.app.assist.AssistStructure.ViewNode;
+import android.service.autofill.SaveInfo
+import android.view.View
+import android.view.autofill.AutofillId
+
+/**
+ * A stripped down version of a [ViewNode] that contains only autofill-relevant metadata. It also
+ * contains a `saveType` flag that is calculated based on the [ViewNode]'s autofill hints.
+ */
+class AutofillField(view: ViewNode) {
+ var saveType = 0
+ private set
+
+ val autofillHints: Array<String> = view.autofillHints
+ val autofillId: AutofillId = view.autofillId
+ val autofillType: Int = view.autofillType
+ val autofillOptions: Array<String>? = view.autofillOptions
+ val isFocused: Boolean = view.isFocused
+
+ init {
+ updateSaveTypeFromHints()
+ }
+
+ /**
+ * When the [ViewNode] is a list that the user needs to choose a string from (i.e. a spinner),
+ * this is called to return the index of a specific item in the list.
+ */
+ fun getAutofillOptionIndex(value: String): Int? {
+ return autofillOptions?.indexOf(value)
+ }
+
+ private fun updateSaveTypeFromHints() {
+ saveType = 0
+ for (hint in autofillHints) {
+ when (hint) {
+ View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE,
+ View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY,
+ View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
+ View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR,
+ View.AUTOFILL_HINT_CREDIT_CARD_NUMBER,
+ View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE -> {
+ saveType = saveType or SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD
+ }
+ View.AUTOFILL_HINT_EMAIL_ADDRESS -> {
+ saveType = saveType or SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS
+ }
+ View.AUTOFILL_HINT_PHONE, View.AUTOFILL_HINT_NAME -> {
+ saveType = saveType or SaveInfo.SAVE_DATA_TYPE_GENERIC
+ }
+ View.AUTOFILL_HINT_PASSWORD -> {
+ saveType = saveType or SaveInfo.SAVE_DATA_TYPE_PASSWORD
+ saveType = saveType and SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS.inv()
+ saveType = saveType and SaveInfo.SAVE_DATA_TYPE_USERNAME.inv()
+ }
+ View.AUTOFILL_HINT_POSTAL_ADDRESS,
+ View.AUTOFILL_HINT_POSTAL_CODE -> {
+ saveType = saveType or SaveInfo.SAVE_DATA_TYPE_ADDRESS
+ }
+ View.AUTOFILL_HINT_USERNAME -> {
+ saveType = saveType or SaveInfo.SAVE_DATA_TYPE_USERNAME
+ }
+ }
+ }
+ }
+}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java
deleted file mode 100644
index 0354b989..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service.model;
-
-import android.view.autofill.AutofillId;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-public final class AutofillFieldsCollection {
-
- private final List<AutofillId> mAutofillIds = new ArrayList<>();
- private final HashMap<String, List<AutofillField>> mAutofillHintsToFieldsMap = new HashMap<>();
- private final List<String> mAllAutofillHints = new ArrayList<>();
- private final List<String> mFocusedAutofillHints = new ArrayList<>();
- private int size = 0;
- private int mSaveType = 0;
-
- public void add(AutofillField autofillField) {
- mSaveType |= autofillField.getSaveType();
- size++;
- mAutofillIds.add(autofillField.getId());
- List<String> hintsList = Arrays.asList(autofillField.getHints());
- mAllAutofillHints.addAll(hintsList);
- if (autofillField.isFocused()) {
- mFocusedAutofillHints.addAll(hintsList);
- }
- for (String hint : autofillField.getHints()) {
- if (mAutofillHintsToFieldsMap.get(hint) == null) {
- mAutofillHintsToFieldsMap.put(hint, new ArrayList<AutofillField>());
- }
- mAutofillHintsToFieldsMap.get(hint).add(autofillField);
- }
- }
-
- public int getSaveType() {
- return mSaveType;
- }
-
- public AutofillId[] getAutofillIds() {
- return mAutofillIds.toArray(new AutofillId[size]);
- }
-
- public List<AutofillField> getFieldsForHint(String hint) {
- return mAutofillHintsToFieldsMap.get(hint);
- }
-
- public List<String> getFocusedHints() {
- return mFocusedAutofillHints;
- }
-
- public List<String> getAllHints() {
- return mAllAutofillHints;
- }
-}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.kt
new file mode 100644
index 00000000..371934da
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/AutofillFieldsCollection.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service.model
+
+import android.view.autofill.AutofillId
+import java.util.ArrayList
+import java.util.HashMap
+
+/**
+ * Data structure that stores a collection of `AutofillField`s. Contains all of the client's `View`
+ * hierarchy autofill-relevant metadata.
+ */
+data class AutofillFieldsCollection(val autofillIds: ArrayList<AutofillId> = ArrayList<AutofillId>(),
+ val allAutofillHints: ArrayList<String> = ArrayList<String>(),
+ val focusedAutofillHints: ArrayList<String> = ArrayList<String>()) {
+
+ private val autofillHintsToFieldsMap = HashMap<String, MutableList<AutofillField>>()
+ var saveType = 0
+ private set
+
+ fun add(autofillField: AutofillField) {
+ saveType = saveType or autofillField.saveType
+ autofillIds.add(autofillField.autofillId)
+ val hintsList = autofillField.autofillHints
+ allAutofillHints.addAll(hintsList)
+ if (autofillField.isFocused) {
+ focusedAutofillHints.addAll(hintsList)
+ }
+ autofillField.autofillHints.forEach { autofillHint ->
+ autofillHintsToFieldsMap[autofillHint] = autofillHintsToFieldsMap[autofillHint] ?: ArrayList<AutofillField>()
+ autofillHintsToFieldsMap[autofillHint]?.add(autofillField)
+ }
+ }
+
+ fun getFieldsForHint(hint: String): MutableList<AutofillField>? {
+ return autofillHintsToFieldsMap[hint]
+ }
+}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java
deleted file mode 100644
index aa57e935..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service.model;
-
-import android.service.autofill.Dataset;
-import android.support.annotation.NonNull;
-import android.util.Log;
-import android.view.View;
-import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillValue;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-/**
- * ClientFormData is the model that holds all of the data on a client app's page, plus the dataset
- * name associated with it.
- */
-public final class ClientFormData {
- private static final String TAG = "ClientFormData";
- private final HashMap<String, SavedAutofillValue> hintMap;
- private String datasetName;
-
- public ClientFormData() {
- this(null, new HashMap<String, SavedAutofillValue>());
- }
-
- public ClientFormData(String datasetName, HashMap<String, SavedAutofillValue> hintMap) {
- this.hintMap = hintMap;
- this.datasetName = datasetName;
- }
-
- public static ClientFormData fromJson(JSONObject jsonObject) {
- HashMap<String, SavedAutofillValue> hintMap = new HashMap<>();
- try {
- String datasetName = jsonObject.has("datasetName") ?
- jsonObject.getString("datasetName") : null;
- JSONObject valuesJson = jsonObject.getJSONObject("values");
- Iterator<String> hints = valuesJson.keys();
- while (hints.hasNext()) {
- String hint = hints.next();
- JSONObject valueAsJson = valuesJson
- .getJSONObject(hint);
- if (valueAsJson != null) {
- SavedAutofillValue savedAutofillValue = SavedAutofillValue.fromJson(valueAsJson);
- hintMap.put(hint, savedAutofillValue);
- }
- }
- return new ClientFormData(datasetName, hintMap);
- } catch (JSONException e) {
- Log.d(TAG, e.getMessage());
- return null;
- }
- }
-
- /**
- * Returns the name of the {@link Dataset}.
- */
- public String getDatasetName() {
- return this.datasetName;
- }
-
- /**
- * Sets the {@link Dataset} name.
- */
- public void setDatasetName(String datasetName) {
- this.datasetName = datasetName;
- }
-
- /**
- * Sets values for a list of hints.
- */
- public void set(@NonNull String[] autofillHints, @NonNull SavedAutofillValue autofillValue) {
- if (autofillHints.length < 1) {
- return;
- }
- for (int i = 0; i < autofillHints.length; i++) {
- hintMap.put(autofillHints[i], autofillValue);
- }
- }
-
- /**
- * Populates a {@link Dataset.Builder} with appropriate values for each {@link AutofillId}
- * in a {@code AutofillFieldsCollection}.
- */
- public boolean applyToFields(AutofillFieldsCollection autofillFieldsCollection,
- Dataset.Builder datasetBuilder) {
- boolean setValueAtLeastOnce = false;
- List<String> allHints = autofillFieldsCollection.getAllHints();
- for (int hintIndex = 0; hintIndex < allHints.size(); hintIndex++) {
- String hint = allHints.get(hintIndex);
- List<AutofillField> autofillFields = autofillFieldsCollection.getFieldsForHint(hint);
- if (autofillFields == null) {
- continue;
- }
- for (int autofillFieldIndex = 0; autofillFieldIndex < autofillFields.size(); autofillFieldIndex++) {
- AutofillField autofillField = autofillFields.get(autofillFieldIndex);
- AutofillId autofillId = autofillField.getId();
- int autofillType = autofillField.getAutofillType();
- SavedAutofillValue savedAutofillValue = hintMap.get(hint);
- switch (autofillType) {
- case View.AUTOFILL_TYPE_LIST:
- int listValue = autofillField.getAutofillOptionIndex(savedAutofillValue.getTextValue());
- if (listValue != -1) {
- datasetBuilder.setValue(autofillId, AutofillValue.forList(listValue));
- setValueAtLeastOnce = true;
- }
- break;
- case View.AUTOFILL_TYPE_DATE:
- long dateValue = savedAutofillValue.getDateValue();
- if (dateValue != -1) {
- datasetBuilder.setValue(autofillId, AutofillValue.forDate(dateValue));
- setValueAtLeastOnce = true;
- }
- break;
- case View.AUTOFILL_TYPE_TEXT:
- String textValue = savedAutofillValue.getTextValue();
- if (textValue != null) {
- datasetBuilder.setValue(autofillId, AutofillValue.forText(textValue));
- setValueAtLeastOnce = true;
- }
- break;
- case View.AUTOFILL_TYPE_TOGGLE:
- if (savedAutofillValue.hasToggleValue()) {
- boolean toggleValue = savedAutofillValue.getToggleValue();
- datasetBuilder.setValue(autofillId, AutofillValue.forToggle(toggleValue));
- setValueAtLeastOnce = true;
- }
- break;
- case View.AUTOFILL_TYPE_NONE:
- default:
- Log.w(TAG, "Invalid autofill type - " + autofillType);
- break;
- }
- }
- }
- return setValueAtLeastOnce;
- }
-
- public JSONObject toJson() {
- JSONObject jsonObject = new JSONObject();
- try {
- jsonObject.put("datasetName", datasetName != null ? datasetName : JSONObject.NULL);
- JSONObject jsonValues = new JSONObject();
- Set<String> hints = hintMap.keySet();
- for (String hint : hints) {
- SavedAutofillValue value = hintMap.get(hint);
- jsonValues.put(hint, value != null ? value.toJson() : JSONObject.NULL);
- }
- jsonObject.put("values", jsonValues);
- } catch (JSONException e) {
- Log.e(TAG, e.getMessage());
- }
- return jsonObject;
- }
-
- public boolean helpsWithHints(List<String> autofillHints) {
- for (int i = 0; i < autofillHints.size(); i++) {
- String autofillHint = autofillHints.get(i);
- if (hintMap.get(autofillHint) != null && !hintMap.get(autofillHint).isNull()) {
- return true;
- }
- }
- return false;
- }
-}
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
new file mode 100644
index 00000000..78980aaa
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/ClientFormData.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service.model
+
+import android.service.autofill.Dataset
+import android.util.Log
+import android.view.View
+import android.view.autofill.AutofillId
+import android.view.autofill.AutofillValue
+import java.util.HashMap
+
+
+/**
+ * ClientFormData is the model that represents all of the form data on a client app's page, plus the
+ * dataset name associated with it.
+ */
+class ClientFormData constructor(var datasetName: String? = null,
+ private val hintMap: HashMap<String, MutableAutofillValue> = HashMap<String, MutableAutofillValue>()) {
+
+ private val TAG = "ClientFormData"
+
+ /**
+ * Sets values for a list of autofillHints.
+ */
+ fun setAutofillValuesForHints(autofillHints: Array<String>, autofillValue: MutableAutofillValue) {
+ autofillHints.forEach { hint ->
+ hintMap[hint] = autofillValue
+ }
+ }
+
+ /**
+ * Populates a [Dataset.Builder] with appropriate values for each [AutofillId]
+ * in a `AutofillFieldsCollection`.
+ */
+ fun applyToFields(autofillFieldsCollection: AutofillFieldsCollection,
+ datasetBuilder: Dataset.Builder): Boolean {
+ var setValueAtLeastOnce = false
+ for (hint in autofillFieldsCollection.allAutofillHints) {
+ val autofillFields = autofillFieldsCollection.getFieldsForHint(hint) ?: continue
+ for (autofillField in autofillFields) {
+ val autofillId = autofillField.autofillId
+ val autofillType = autofillField.autofillType
+ val savedAutofillValue = hintMap[hint]
+ when (autofillType) {
+ View.AUTOFILL_TYPE_LIST -> {
+ savedAutofillValue?.textValue?.let(autofillField::getAutofillOptionIndex)?.let { index ->
+ datasetBuilder.setValue(autofillId, AutofillValue.forList(index))
+ setValueAtLeastOnce = true
+ }
+ }
+ View.AUTOFILL_TYPE_DATE -> {
+ savedAutofillValue?.dateValue?.let { date ->
+ datasetBuilder.setValue(autofillId, AutofillValue.forDate(date))
+ setValueAtLeastOnce = true
+ }
+ }
+ View.AUTOFILL_TYPE_TEXT -> {
+ savedAutofillValue?.textValue?.let { text ->
+ datasetBuilder.setValue(autofillId, AutofillValue.forText(text))
+ setValueAtLeastOnce = true
+ }
+ }
+ View.AUTOFILL_TYPE_TOGGLE -> {
+ savedAutofillValue?.toggleValue?.let { toggle ->
+ datasetBuilder.setValue(autofillId, AutofillValue.forToggle(toggle))
+ setValueAtLeastOnce = true
+ }
+ }
+ else -> Log.w(TAG, "Invalid autofill type - " + autofillType)
+ }
+ }
+ }
+ return setValueAtLeastOnce
+ }
+
+ fun helpsWithHints(autofillHints: List<String>): Boolean {
+ for (autofillHint in autofillHints) {
+ hintMap[autofillHint]?.let { savedAutofillValue ->
+ if (!savedAutofillValue.isNull()) {
+ return true
+ }
+ }
+ }
+ return false
+ }
+}
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/MutableAutofillValue.kt
new file mode 100644
index 00000000..702a1358
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/MutableAutofillValue.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service.model
+
+import android.app.assist.AssistStructure
+import android.view.autofill.AutofillValue
+
+/**
+ * Mutable, JSON serializable data class containing the same data as an [AutofillValue].
+ */
+class MutableAutofillValue(viewNode: AssistStructure.ViewNode) {
+ var textValue: String? = null
+ var dateValue: Long? = null
+ var toggleValue: Boolean? = null
+
+ init {
+ viewNode.autofillValue?.let { autofillValue ->
+ if (autofillValue.isList) {
+ val index = autofillValue.listValue
+ viewNode.autofillOptions?.let { autofillOptions ->
+ if (autofillOptions.size > index) {
+ textValue = autofillOptions[index]
+ }
+ }
+ } else if (autofillValue.isDate) {
+ dateValue = autofillValue.dateValue
+ } else if (autofillValue.isText) {
+ // Using toString of AutofillValue.getTextValue in order to save it to
+ // SharedPreferences.
+ textValue = autofillValue.textValue.toString()
+ } else {
+ }
+ }
+ }
+
+ fun isNull(): Boolean {
+ return textValue == null && dateValue == null && toggleValue == null
+ }
+}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.java
deleted file mode 100644
index 73e0c81e..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/model/SavedAutofillValue.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service.model;
-
-import android.app.assist.AssistStructure;
-import android.util.Log;
-import android.view.autofill.AutofillValue;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-public class SavedAutofillValue {
- private static final String TAG = "SavedAutofillValue";
- private String textValue = null;
- private Long dateValue = -1L;
- private Boolean toggleValue = false;
- private boolean hasToggleValue = false;
-
- public static SavedAutofillValue fromJson(JSONObject jsonObject) {
- if (jsonObject == null) {
- return null;
- }
- try {
- SavedAutofillValue savedAutofillValue = new SavedAutofillValue();
-
- savedAutofillValue.textValue =
- !jsonObject.isNull("textValue") ? jsonObject.getString("textValue") : null;
- savedAutofillValue.dateValue =
- !jsonObject.isNull("dateValue") ? jsonObject.getLong("dateValue") : null;
- savedAutofillValue.setToggleValue
- (!jsonObject.isNull("toggleValue") ? jsonObject.getBoolean("toggleValue") : null);
- return savedAutofillValue;
- } catch (JSONException e) {
- Log.e(TAG, e.getMessage());
- return null;
- }
- }
-
- public static SavedAutofillValue fromViewNode(AssistStructure.ViewNode viewNode) {
- SavedAutofillValue savedAutofillValue = new SavedAutofillValue();
- AutofillValue autofillValue = viewNode.getAutofillValue();
- if (autofillValue != null) {
- if (autofillValue.isList()) {
- String[] autofillOptions = viewNode.getAutofillOptions();
- int index = autofillValue.getListValue();
- if (autofillOptions != null && autofillOptions.length > 0) {
- savedAutofillValue.textValue = autofillOptions[index];
- }
- } else if (autofillValue.isDate()) {
- savedAutofillValue.dateValue = autofillValue.getDateValue();
- } else if (autofillValue.isText()) {
- // Using toString of AutofillValue.getTextValue in order to save it to
- // SharedPreferences.
- savedAutofillValue.textValue = autofillValue.getTextValue().toString();
- }
- }
- return savedAutofillValue;
- }
-
- public JSONObject toJson() {
- JSONObject jsonObject = new JSONObject();
- try {
- jsonObject.put("textValue", textValue != null ? textValue : JSONObject.NULL);
- jsonObject.put("dateValue", dateValue != null ? dateValue : JSONObject.NULL);
- jsonObject.put("toggleValue", toggleValue != null ? toggleValue : JSONObject.NULL);
- return jsonObject;
- } catch (JSONException e) {
- Log.e(TAG, e.getMessage());
- return null;
- }
- }
-
- public String getTextValue() {
- return textValue;
- }
-
- public long getDateValue() {
- return dateValue;
- }
-
-
- public boolean getToggleValue() {
- return toggleValue;
- }
-
- public void setToggleValue(Boolean toggleValue) {
- this.toggleValue = toggleValue;
- hasToggleValue = toggleValue != null;
- }
-
-
- public boolean isNull() {
- return textValue == null && dateValue == -1L && !hasToggleValue;
- }
-
- public boolean hasToggleValue() {
- return hasToggleValue;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- SavedAutofillValue that = (SavedAutofillValue) o;
-
- if (textValue != null ? !textValue.equals(that.textValue) : that.textValue != null)
- return false;
- if (dateValue != null ? !dateValue.equals(that.dateValue) : that.dateValue != null)
- return false;
- return toggleValue != null ? toggleValue.equals(that.toggleValue) : that.toggleValue == null;
-
- }
-
- @Override
- public int hashCode() {
- int result = textValue != null ? textValue.hashCode() : 0;
- result = 31 * result + (dateValue != null ? dateValue.hashCode() : 0);
- result = 31 * result + (toggleValue != null ? toggleValue.hashCode() : 0);
- return result;
- }
-}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.java
deleted file mode 100644
index 3926530e..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service.settings;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.support.annotation.NonNull;
-
-public class MyPreferences {
- private static final String TAG = "MyPreferences";
-
- private static final String RESPONSE_AUTH_KEY = "response_auth";
- private static final String DATASET_AUTH_KEY = "dataset_auth";
- private static final String MASTER_PASSWORD_KEY = "master_password";
-
- private static MyPreferences sInstance;
- private final SharedPreferences mPrefs;
-
- private MyPreferences(Context context) {
- mPrefs = context.getApplicationContext().getSharedPreferences("my-settings",
- Context.MODE_PRIVATE);
- }
-
- public static MyPreferences getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new MyPreferences(context);
- }
- return sInstance;
- }
-
- /**
- * Gets whether {@link FillResponse}s should require authentication.
- */
- public boolean isResponseAuth() {
- return mPrefs.getBoolean(RESPONSE_AUTH_KEY, false);
- }
-
- /**
- * Enables/disables authentication for the entire autofill {@link FillResponse}.
- */
- public void setResponseAuth(boolean responseAuth) {
- mPrefs.edit().putBoolean(RESPONSE_AUTH_KEY, responseAuth).apply();
- }
-
- /**
- * Gets whether {@link Dataset}s should require authentication.
- */
- public boolean isDatasetAuth() {
- return mPrefs.getBoolean(DATASET_AUTH_KEY, false);
- }
-
- /**
- * Enables/disables authentication for individual autofill {@link Dataset}s.
- */
- public void setDatasetAuth(boolean datasetAuth) {
- mPrefs.edit().putBoolean(DATASET_AUTH_KEY, datasetAuth).apply();
- }
-
- /**
- * Gets autofill master username.
- */
- public String getMasterPassword() {
- return mPrefs.getString(MASTER_PASSWORD_KEY, null);
- }
-
- /**
- * Sets autofill master password.
- */
- public void setMasterPassword(@NonNull String masterPassword) {
- mPrefs.edit().putString(MASTER_PASSWORD_KEY, masterPassword).apply();
- }
-
- public void clearCredentials() {
- mPrefs.edit().remove(MASTER_PASSWORD_KEY).apply();
- }
-}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.kt
new file mode 100644
index 00000000..096813f6
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/MyPreferences.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service.settings
+
+import android.content.Context
+import android.content.SharedPreferences
+import android.service.autofill.Dataset
+import android.service.autofill.FillResponse
+
+object MyPreferences {
+ private val TAG = "MyPreferences"
+
+ private val SHARED_PREF_KEY = "com.example.android.autofillframework.service.settings.MyPreferences"
+ private val RESPONSE_AUTH_KEY = "response_auth"
+ private val DATASET_AUTH_KEY = "dataset_auth"
+ private val MASTER_PASSWORD_KEY = "master_password"
+
+ private fun getPrefs(context: Context): SharedPreferences {
+ return context.applicationContext.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
+ }
+
+ /**
+ * Determines whether [FillResponse]s should require authentication.
+ */
+ fun isResponseAuth(context: Context): Boolean {
+ return getPrefs(context).getBoolean(RESPONSE_AUTH_KEY, false)
+ }
+
+ fun setResponseAuth(context: Context, responseAuth: Boolean) {
+ getPrefs(context).edit().putBoolean(RESPONSE_AUTH_KEY, responseAuth).apply()
+ }
+
+ /**
+ * Determines whether [Dataset]s should require authentication.
+ */
+ fun isDatasetAuth(context: Context): Boolean {
+ return getPrefs(context).getBoolean(DATASET_AUTH_KEY, false)
+ }
+
+ fun setDatasetAuth(context: Context, datasetAuth: Boolean) {
+ getPrefs(context).edit().putBoolean(DATASET_AUTH_KEY, datasetAuth).apply()
+ }
+
+ /**
+ * Gets autofill master password.
+ */
+ fun getMasterPassword(context: Context): String? {
+ return getPrefs(context).getString(MASTER_PASSWORD_KEY, null)
+ }
+
+ /**
+ * Sets autofill master password.
+ */
+ fun setMasterPassword(context: Context, masterPassword: String) {
+ getPrefs(context).edit().putString(MASTER_PASSWORD_KEY, masterPassword).apply()
+ }
+
+ /**
+ * Removes master password.
+ */
+ fun clearCredentials(context: Context) {
+ getPrefs(context).edit().remove(MASTER_PASSWORD_KEY).apply()
+ }
+}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java
deleted file mode 100644
index 6387d36b..00000000
--- a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.example.android.autofillframework.service.settings;
-
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CompoundButton;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.example.android.autofillframework.R;
-import com.example.android.autofillframework.service.datasource.LocalAutofillRepository;
-
-public class SettingsActivity extends AppCompatActivity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.settings_activity);
- final MyPreferences preferences = MyPreferences.getInstance(this);
- setupSettingsSwitch(R.id.settings_auth_responses_container,
- R.id.settings_auth_responses_label,
- R.id.settings_auth_responses_switch,
- preferences.isResponseAuth(),
- new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
- preferences.setResponseAuth(b);
- }
- });
- setupSettingsSwitch(R.id.settings_auth_datasets_container,
- R.id.settings_auth_datasets_label,
- R.id.settings_auth_datasets_switch,
- preferences.isDatasetAuth(),
- new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
- preferences.setDatasetAuth(b);
- }
- });
- setupSettingsButton(R.id.settings_clear_data_container,
- R.id.settings_clear_data_label,
- R.id.settings_clear_data_icon,
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- buildClearDataDialog().show();
- }
- });
-
- setupSettingsButton(R.id.settings_auth_credentials_container,
- R.id.settings_auth_credentials_label,
- R.id.settings_auth_credentials_icon,
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (preferences.getMasterPassword() != null) {
- buildCurrentCredentialsDialog().show();
- } else {
- buildNewCredentialsDialog().show();
- }
- }
- });
- }
-
- private AlertDialog buildClearDataDialog() {
- return new AlertDialog.Builder(SettingsActivity.this)
- .setMessage(R.string.settings_clear_data_confirmation)
- .setTitle(R.string.settings_clear_data_confirmation_title)
- .setNegativeButton(R.string.cancel, null)
- .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- LocalAutofillRepository.getInstance
- (SettingsActivity.this).clear();
- MyPreferences.getInstance(SettingsActivity.this)
- .clearCredentials();
- dialog.dismiss();
- }
- })
- .create();
- }
-
- private AlertDialog.Builder prepareCredentialsDialog() {
- return new AlertDialog.Builder(SettingsActivity.this)
- .setTitle(R.string.settings_auth_change_credentials_title)
- .setNegativeButton(R.string.cancel, null);
- }
-
- private AlertDialog buildCurrentCredentialsDialog() {
- final EditText currentPasswordField = LayoutInflater
- .from(SettingsActivity.this)
- .inflate(R.layout.settings_authentication_dialog, null)
- .findViewById(R.id.master_password_field);
- return prepareCredentialsDialog()
- .setMessage(R.string.settings_auth_enter_current_password)
- .setView(currentPasswordField)
- .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String password = currentPasswordField.getText().toString();
- if (MyPreferences.getInstance(SettingsActivity.this).getMasterPassword()
- .equals(password)) {
- buildNewCredentialsDialog().show();
- dialog.dismiss();
- }
- }
- })
- .create();
- }
-
- private AlertDialog buildNewCredentialsDialog() {
- final EditText newPasswordField = LayoutInflater
- .from(SettingsActivity.this)
- .inflate(R.layout.settings_authentication_dialog, null)
- .findViewById(R.id.master_password_field);
- return prepareCredentialsDialog()
- .setMessage(R.string.settings_auth_enter_new_password)
- .setView(newPasswordField)
- .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String password = newPasswordField.getText().toString();
- MyPreferences.getInstance(SettingsActivity.this).setMasterPassword(password);
- dialog.dismiss();
- }
- })
- .create();
- }
-
- private void setupSettingsSwitch(int containerId, int labelId, int switchId, boolean checked,
- CompoundButton.OnCheckedChangeListener checkedChangeListener) {
- ViewGroup container = (ViewGroup) findViewById(containerId);
- String switchLabel = ((TextView) container.findViewById(labelId)).getText().toString();
- final Switch switchView = container.findViewById(switchId);
- switchView.setContentDescription(switchLabel);
- switchView.setChecked(checked);
- container.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- switchView.performClick();
- }
- });
- switchView.setOnCheckedChangeListener(checkedChangeListener);
- }
-
- private void setupSettingsButton(int containerId, int labelId, int imageViewId,
- final View.OnClickListener onClickListener) {
- ViewGroup container = (ViewGroup) findViewById(containerId);
- String buttonLabel = ((TextView) container.findViewById(labelId)).getText().toString();
- final ImageView imageView = container.findViewById(imageViewId);
- imageView.setContentDescription(buttonLabel);
- container.setOnClickListener(onClickListener);
- }
-}
diff --git a/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.kt b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.kt
new file mode 100644
index 00000000..cfa9d82f
--- /dev/null
+++ b/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/service/settings/SettingsActivity.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.example.android.autofillframework.service.settings
+
+import android.os.Bundle
+import android.support.v7.app.AlertDialog
+import android.support.v7.app.AppCompatActivity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CompoundButton
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.Switch
+import android.widget.TextView
+import com.example.android.autofillframework.R
+import com.example.android.autofillframework.service.datasource.SharedPrefsAutofillRepository
+
+class SettingsActivity : AppCompatActivity() {
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(R.layout.settings_activity)
+ setupSettingsSwitch(R.id.settings_auth_responses_container,
+ R.id.settings_auth_responses_label,
+ R.id.settings_auth_responses_switch,
+ MyPreferences.isResponseAuth(this),
+ CompoundButton.OnCheckedChangeListener { compoundButton, b ->
+ MyPreferences.setResponseAuth(this@SettingsActivity, b)
+ })
+ setupSettingsSwitch(R.id.settings_auth_datasets_container,
+ R.id.settings_auth_datasets_label,
+ R.id.settings_auth_datasets_switch,
+ MyPreferences.isDatasetAuth(this),
+ CompoundButton.OnCheckedChangeListener { compoundButton, b ->
+ MyPreferences.setDatasetAuth(this@SettingsActivity, b)
+ })
+ setupSettingsButton(R.id.settings_clear_data_container,
+ R.id.settings_clear_data_label,
+ R.id.settings_clear_data_icon,
+ View.OnClickListener { buildClearDataDialog().show() })
+
+ setupSettingsButton(R.id.settings_auth_credentials_container,
+ R.id.settings_auth_credentials_label,
+ R.id.settings_auth_credentials_icon,
+ View.OnClickListener {
+ MyPreferences.getMasterPassword(this@SettingsActivity)?.let {
+ buildCurrentCredentialsDialog().show()
+ } ?: buildNewCredentialsDialog().show()
+ })
+ }
+
+ private fun buildClearDataDialog(): AlertDialog {
+ return AlertDialog.Builder(this@SettingsActivity)
+ .setMessage(R.string.settings_clear_data_confirmation)
+ .setTitle(R.string.settings_clear_data_confirmation_title)
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(R.string.ok) { dialog, which ->
+ SharedPrefsAutofillRepository.clear(this@SettingsActivity)
+ MyPreferences.clearCredentials(this@SettingsActivity)
+ dialog.dismiss()
+ }
+ .create()
+ }
+
+ private fun prepareCredentialsDialog(): AlertDialog.Builder {
+ return AlertDialog.Builder(this@SettingsActivity)
+ .setTitle(R.string.settings_auth_change_credentials_title)
+ .setNegativeButton(R.string.cancel, null)
+ }
+
+ private fun buildCurrentCredentialsDialog(): AlertDialog {
+ val currentPasswordField = LayoutInflater
+ .from(this@SettingsActivity)
+ .inflate(R.layout.settings_authentication_dialog, null)
+ .findViewById<EditText>(R.id.master_password_field)
+ return prepareCredentialsDialog()
+ .setMessage(R.string.settings_auth_enter_current_password)
+ .setView(currentPasswordField)
+ .setPositiveButton(R.string.ok) { dialog, which ->
+ val password = currentPasswordField.text.toString()
+ if (MyPreferences.getMasterPassword(this@SettingsActivity) == password) {
+ buildNewCredentialsDialog().show()
+ dialog.dismiss()
+ }
+ }
+ .create()
+ }
+
+ private fun buildNewCredentialsDialog(): AlertDialog {
+ val newPasswordField = LayoutInflater
+ .from(this@SettingsActivity)
+ .inflate(R.layout.settings_authentication_dialog, null)
+ .findViewById<EditText>(R.id.master_password_field)
+ return prepareCredentialsDialog()
+ .setMessage(R.string.settings_auth_enter_new_password)
+ .setView(newPasswordField)
+ .setPositiveButton(R.string.ok) { dialog, which ->
+ val password = newPasswordField.text.toString()
+ MyPreferences.setMasterPassword(this@SettingsActivity, password)
+ dialog.dismiss()
+ }
+ .create()
+ }
+
+ private fun setupSettingsSwitch(containerId: Int, labelId: Int, switchId: Int, checked: Boolean,
+ checkedChangeListener: CompoundButton.OnCheckedChangeListener) {
+ val container = findViewById(containerId) as ViewGroup
+ val switchLabel = (container.findViewById<View>(labelId) as TextView).text.toString()
+ val switchView = container.findViewById<Switch>(switchId)
+ switchView.contentDescription = switchLabel
+ switchView.isChecked = checked
+ container.setOnClickListener { switchView.performClick() }
+ switchView.setOnCheckedChangeListener(checkedChangeListener)
+ }
+
+ private fun setupSettingsButton(containerId: Int, labelId: Int, imageViewId: Int,
+ onClickListener: View.OnClickListener) {
+ val container = findViewById(containerId) as ViewGroup
+ val buttonLabel = (container.findViewById<View>(labelId) as TextView).text.toString()
+ val imageView = container.findViewById<ImageView>(imageViewId)
+ imageView.contentDescription = buttonLabel
+ container.setOnClickListener(onClickListener)
+ }
+}