diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2018-01-05 00:40:05 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-01-05 00:40:05 +0000 |
commit | 0f601fda034e8c0806781ac55eddc16becbd4473 (patch) | |
tree | aa4489b3e2718834d426089ec177440ed7dce007 /input/autofill | |
parent | 205c4890fd669514d3cf8a6b779a8c47d5a4310a (diff) | |
parent | cec0c701a6c2c00a66bd1c7ec6dd26d13d95d4fd (diff) | |
download | android-0f601fda034e8c0806781ac55eddc16becbd4473.tar.gz |
Merge changes I4ec1d73e,Ib3d740c6,I6d7b029f,I6d6eee18
* changes:
Save ClientViewMetadata between pages.
Autofill sample: Add DAL check req levels to settings.
Autofill sample: use string resources for failure messages.
Autofill sample: Cancel autofill when clear button is pressed.
Diffstat (limited to 'input/autofill')
24 files changed, 428 insertions, 259 deletions
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardCompoundViewActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardCompoundViewActivity.java index c09745e7..b8df27d8 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardCompoundViewActivity.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardCompoundViewActivity.java @@ -51,7 +51,10 @@ public class CreditCardCompoundViewActivity extends AppCompatActivity { findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - getSystemService(AutofillManager.class).cancel(); + AutofillManager afm = getSystemService(AutofillManager.class); + if (afm != null) { + afm.cancel(); + } resetFields(); } }); diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardDatePickerActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardDatePickerActivity.java index f0bcdee8..4a158863 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardDatePickerActivity.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardDatePickerActivity.java @@ -53,7 +53,10 @@ public class CreditCardDatePickerActivity extends AppCompatActivity { findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - getSystemService(AutofillManager.class).cancel(); + AutofillManager afm = getSystemService(AutofillManager.class); + if (afm != null) { + afm.cancel(); + } resetFields(); } }); diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardSpinnersActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardSpinnersActivity.java index 99ec6007..bab53798 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardSpinnersActivity.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/CreditCardSpinnersActivity.java @@ -94,7 +94,10 @@ public class CreditCardSpinnersActivity extends AppCompatActivity { findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - getSystemService(AutofillManager.class).cancel(); + AutofillManager afm = getSystemService(AutofillManager.class); + if (afm != null) { + afm.cancel(); + } resetFields(); } }); diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardAutoCompleteSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardAutoCompleteSignInActivity.java index acdb0f34..089c6b2d 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardAutoCompleteSignInActivity.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardAutoCompleteSignInActivity.java @@ -61,6 +61,10 @@ public class StandardAutoCompleteSignInActivity extends AppCompatActivity { mClearButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + AutofillManager afm = getSystemService(AutofillManager.class); + if (afm != null) { + afm.cancel(); + } resetFields(); } }); diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardSignInActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardSignInActivity.java index 6604ee40..c333bce1 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardSignInActivity.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/StandardSignInActivity.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; +import android.view.autofill.AutofillManager; import android.widget.EditText; import android.widget.Toast; @@ -47,6 +48,10 @@ public class StandardSignInActivity extends AppCompatActivity { findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + AutofillManager afm = getSystemService(AutofillManager.class); + if (afm != null) { + afm.cancel(); + } resetFields(); } }); diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardActivity.java index c23daf7b..3e68a012 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardActivity.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardActivity.java @@ -53,7 +53,10 @@ public class CreditCardActivity extends AppCompatActivity { findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - getSystemService(AutofillManager.class).cancel(); + AutofillManager afm = getSystemService(AutofillManager.class); + if (afm != null) { + afm.cancel(); + } resetFields(); } }); diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardAntiPatternActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardAntiPatternActivity.java index c50994cb..edffcc05 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardAntiPatternActivity.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/CreditCardAntiPatternActivity.java @@ -49,7 +49,10 @@ public class CreditCardAntiPatternActivity extends AppCompatActivity { findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - getSystemService(AutofillManager.class).cancel(); + AutofillManager afm = getSystemService(AutofillManager.class); + if (afm != null) { + afm.cancel(); + } resetFields(); } }); diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultiplePartitionsActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultiplePartitionsActivity.java index 3f4031ce..9e09b45b 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultiplePartitionsActivity.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/edgecases/MultiplePartitionsActivity.java @@ -47,19 +47,14 @@ public class MultiplePartitionsActivity extends AppCompatActivity { private ScrollableCustomVirtualView mCustomVirtualView; private AutofillManager mAutofillManager; - private CustomVirtualView.Partition mCredentialsPartition; private CustomVirtualView.Partition mCcPartition; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.multiple_partitions_activity); - mCustomVirtualView = findViewById(R.id.custom_view); - - mCredentialsPartition = mCustomVirtualView.addPartition(getString(R.string.partition_credentials)); mCredentialsPartition.addLine("username", View.AUTOFILL_TYPE_TEXT, @@ -68,7 +63,6 @@ public class MultiplePartitionsActivity extends AppCompatActivity { mCredentialsPartition.addLine("password", View.AUTOFILL_TYPE_TEXT, getString(R.string.password_label), " ", true, View.AUTOFILL_HINT_PASSWORD); - int ccExpirationType = View.AUTOFILL_TYPE_DATE; // TODO: add a checkbox to switch between text / date instead Intent intent = getIntent(); @@ -82,7 +76,6 @@ public class MultiplePartitionsActivity extends AppCompatActivity { Toast.makeText(getApplicationContext(), typeMessage, Toast.LENGTH_LONG).show(); } } - mCcPartition = mCustomVirtualView.addPartition(getString(R.string.partition_credit_card)); mCcPartition.addLine("ccNumber", View.AUTOFILL_TYPE_TEXT, getString(R.string.credit_card_number_label), @@ -102,13 +95,15 @@ public class MultiplePartitionsActivity extends AppCompatActivity { mCcPartition.addLine("ccSecurityCode", View.AUTOFILL_TYPE_TEXT, getString(R.string.credit_card_security_code_label), " ", true, View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE); - - findViewById(R.id.clear).setOnClickListener((view) -> { - resetFields(); - mCustomVirtualView.resetPositions(); - mAutofillManager.cancel(); - }); mAutofillManager = getSystemService(AutofillManager.class); + findViewById(R.id.clear).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + resetFields(); + mCustomVirtualView.resetPositions(); + mAutofillManager.cancel(); + } + }); } private void resetFields() { diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_edge_cases.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_edge_cases.xml index cca506fa..ab7c32aa 100644 --- a/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_edge_cases.xml +++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_edge_cases.xml @@ -72,7 +72,6 @@ android:id="@+id/multistepSignInButton" android:layout_width="match_parent" android:layout_height="wrap_content" - android:visibility="gone" app:imageColor="@android:color/holo_green_light" app:infoText="@string/multi_step_signin_info" app:itemLogo="@drawable/ic_person_black_24dp" @@ -84,7 +83,6 @@ android:id="@+id/multistepCreditCardButton" android:layout_width="match_parent" android:layout_height="wrap_content" - android:visibility="gone" app:imageColor="@android:color/holo_purple" app:infoText="@string/multi_step_cc_info" app:itemLogo="@drawable/ic_spinners_logo_24dp" diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml index 8b99e6a4..e0fae460 100644 --- a/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml +++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/multiple_partitions_activity.xml @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. --> -<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" +<android.support.constraint.ConstraintLayout + xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/input/autofill/AutofillFramework/afservice/build.gradle b/input/autofill/AutofillFramework/afservice/build.gradle index 65020f48..f341b57b 100644 --- a/input/autofill/AutofillFramework/afservice/build.gradle +++ b/input/autofill/AutofillFramework/afservice/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 27 + compileSdkVersion 26 defaultConfig { minSdkVersion 26 - targetSdkVersion 27 + targetSdkVersion 26 versionCode 1 versionName "1.0" diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java index 595643ff..65ca2e57 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java @@ -32,6 +32,7 @@ import android.widget.EditText; import android.widget.RemoteViews; import android.widget.Toast; +import com.example.android.autofill.service.data.ClientViewMetadataBuilder; import com.example.android.autofill.service.data.DataCallback; import com.example.android.autofill.service.data.adapter.DatasetAdapter; import com.example.android.autofill.service.data.adapter.ResponseAdapter; @@ -140,7 +141,8 @@ public class AuthActivity extends AppCompatActivity { Bundle clientState = intent.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE); AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE); StructureParser structureParser = new StructureParser(structure); - mClientViewMetadata = new ClientViewMetadata(structureParser); + ClientViewMetadataBuilder builder = new ClientViewMetadataBuilder(structureParser); + mClientViewMetadata = builder.buildClientViewMetadata(); mDatasetAdapter = new DatasetAdapter(structureParser); mResponseAdapter = new ResponseAdapter(this, mClientViewMetadata, mPackageName, mDatasetAdapter, clientState); diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java index 96d307f8..4012dbe2 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java @@ -36,6 +36,7 @@ import android.widget.RemoteViews; import com.example.android.autofill.service.data.AutofillDataBuilder; import com.example.android.autofill.service.data.ClientAutofillDataBuilder; import com.example.android.autofill.service.data.ClientViewMetadata; +import com.example.android.autofill.service.data.ClientViewMetadataBuilder; import com.example.android.autofill.service.data.DataCallback; import com.example.android.autofill.service.data.adapter.DatasetAdapter; import com.example.android.autofill.service.data.adapter.ResponseAdapter; @@ -51,7 +52,7 @@ import com.example.android.autofill.service.model.DatasetWithFilledAutofillField import com.example.android.autofill.service.settings.MyPreferences; import com.example.android.autofill.service.util.AppExecutors; import com.example.android.autofill.service.util.Util; - +import static com.example.android.autofill.service.util.Util.DalCheckRequirement; import java.util.List; import static com.example.android.autofill.service.data.adapter.ResponseAdapter.CLIENT_STATE_PARTIAL_ID_TEMPLATE; @@ -61,6 +62,7 @@ import static com.example.android.autofill.service.util.Util.dumpStructure; import static com.example.android.autofill.service.util.Util.findNodeByFilter; import static com.example.android.autofill.service.util.Util.logVerboseEnabled; import static com.example.android.autofill.service.util.Util.logd; +import static com.example.android.autofill.service.util.Util.loge; import static com.example.android.autofill.service.util.Util.logv; import static com.example.android.autofill.service.util.Util.logw; @@ -94,7 +96,8 @@ public class MyAutofillService extends AutofillService { .get(request.getFillContexts().size() - 1).getStructure(); StructureParser parser = new StructureParser(structure); mDatasetAdapter = new DatasetAdapter(parser); - mClientViewMetadata = new ClientViewMetadata(parser); + ClientViewMetadataBuilder clientViewMetadataBuilder = new ClientViewMetadataBuilder(parser); + mClientViewMetadata = clientViewMetadataBuilder.buildClientViewMetadata(); mResponseAdapter = new ResponseAdapter(this, mClientViewMetadata, getPackageName(), mDatasetAdapter, request.getClientState()); String packageName = structure.getActivityComponent().getPackageName(); @@ -149,10 +152,11 @@ public class MyAutofillService extends AutofillService { AssistStructure structure = fillContexts.get(size - 1).getStructure(); StructureParser parser = new StructureParser(structure); mAutofillDataBuilder = new ClientAutofillDataBuilder(parser); - mClientViewMetadata = new ClientViewMetadata(parser); + ClientViewMetadataBuilder clientViewMetadataBuilder = new ClientViewMetadataBuilder(parser); + mClientViewMetadata = clientViewMetadataBuilder.buildClientViewMetadata(); String packageName = structure.getActivityComponent().getPackageName(); if (!mPackageVerificationRepository.putPackageSignatures(packageName)) { - callback.onFailure(getApplicationContext().getString(R.string.invalid_package_signature)); + callback.onFailure(getString(R.string.invalid_package_signature)); return; } Bundle clientState = request.getClientState(); @@ -202,14 +206,15 @@ public class MyAutofillService extends AutofillService { private void checkWebDomainAndBuildAutofillData(String packageName, SaveCallback callback) { String webDomain; try { - webDomain = mClientViewMetadata.buildWebDomain(); - } catch (SecurityException e) { + webDomain = mClientViewMetadata.getWebDomain(); + } catch(SecurityException e) { logw(e.getMessage()); - callback.onFailure(e.getMessage()); + callback.onFailure(getString(R.string.security_exception)); return; } if (webDomain != null && webDomain.length() > 0) { - mDalRepository.checkValid(new DalInfo(webDomain, packageName), + DalCheckRequirement req = MyPreferences.getInstance(this).getDalCheckRequirement(); + mDalRepository.checkValid(req, new DalInfo(webDomain, packageName), new DataCallback<DalCheck>() { @Override public void onLoaded(DalCheck dalCheck) { @@ -217,16 +222,16 @@ public class MyAutofillService extends AutofillService { logd("Domain %s is valid for %s", webDomain, packageName); buildAndSaveAutofillData(); } else { - callback.onFailure(String.format( - "Could not associate web domain %s with app %s", webDomain, - packageName)); + loge("Could not associate web domain %s with app %s", + webDomain, packageName); + callback.onFailure(getString(R.string.dal_exception)); } } @Override public void onDataNotAvailable(String msg, Object... params) { logw(msg, params); - callback.onFailure(String.format(msg, params)); + callback.onFailure(getString(R.string.dal_exception)); } }); } else { diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/StructureParser.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/StructureParser.java index 54296f36..3e6676d8 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/StructureParser.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/StructureParser.java @@ -57,7 +57,6 @@ public final class StructureParser { } } - public interface NodeProcessor { void processNode(ViewNode node); } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadata.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadata.java index abc128f8..24de40c1 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadata.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadata.java @@ -16,143 +16,96 @@ package com.example.android.autofill.service.data; -import android.app.assist.AssistStructure; +import android.os.Parcel; +import android.os.Parcelable; import android.service.autofill.SaveInfo; import android.view.autofill.AutofillId; -import com.example.android.autofill.service.AutofillHints; -import com.example.android.autofill.service.StructureParser; - import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; import java.util.List; -import static com.example.android.autofill.service.util.Util.logd; - /** - * In this simple implementation, the only view data we parse from the client are autofill hints - * of the views in the view hierarchy, the hints of views that are focused, the corresponding - * autofill IDs, and the {@link SaveInfo} based on the hints. - * <p> - * Note: this class is not thread safe. + * In this simple implementation, the only view data we collect from the client are autofill hints + * of the views in the view hierarchy, the corresponding autofill IDs, and the {@link SaveInfo} + * based on the hints. */ -public class ClientViewMetadata { - private final StructureParser mStructureParser; - - private List<String> mCachedAllHints; - private Integer mCachedSaveType; - private SaveInfo mCachedSaveInfo; - private List<AutofillId> mCachedAutofillIds; - - public ClientViewMetadata(StructureParser parser) { - mStructureParser = parser; - } +public class ClientViewMetadata implements Parcelable { - public List<String> getAllHints() { - if (mCachedAllHints == null) { - parseHints(); + public static final Creator<ClientViewMetadata> CREATOR = new Creator<ClientViewMetadata>() { + @Override + public ClientViewMetadata createFromParcel(Parcel parcel) { + return new ClientViewMetadata(parcel); } - return mCachedAllHints; - } - - private List<AutofillId> getAutofillIds() { - if (mCachedAutofillIds == null) { - AutofillSaveType autofillSaveType = new AutofillSaveType(); - List<AutofillId> autofillIds = new ArrayList<>(); - mStructureParser.parse((node) -> parseSaveTypeAndIds(node, autofillSaveType, autofillIds)); - mCachedSaveType = autofillSaveType.saveType; - mCachedAutofillIds = autofillIds; - } - return mCachedAutofillIds; - } - public AutofillId[] getAutofillIdsArray() { - List<AutofillId> autofillIds = getAutofillIds(); - if (autofillIds == null || autofillIds.isEmpty()) { - return null; + @Override + public ClientViewMetadata[] newArray(int size) { + return new ClientViewMetadata[size]; } - return autofillIds.toArray(new AutofillId[autofillIds.size()]); + }; + + private final List<String> mAllHints; + private final int mSaveType; + private final AutofillId[] mAutofillIds; + private final String mWebDomain; + + public ClientViewMetadata(List<String> allHints, int saveType, AutofillId[] autofillIds, + String webDomain) { + mAllHints = allHints; + mSaveType = saveType; + mAutofillIds = autofillIds; + mWebDomain = webDomain; } - public SaveInfo getSaveInfo() { - if (mCachedSaveInfo == null) { - int saveType = getSaveType(); - AutofillId[] autofillIdsArray = getAutofillIdsArray(); - if (autofillIdsArray == null || autofillIdsArray.length == 0) { - return null; - } - // TODO: on MR1, creates a new SaveType without required ids - mCachedSaveInfo = new SaveInfo.Builder(saveType, autofillIdsArray).build(); + private ClientViewMetadata(Parcel parcel) { + mAllHints = new ArrayList<>(); + parcel.readList(mAllHints, String.class.getClassLoader()); + mSaveType = parcel.readInt(); + Parcelable[] ids = parcel.readParcelableArray(AutofillId.class.getClassLoader()); + if (ids != null && ids.length > 0) { + mAutofillIds = Arrays.copyOf(ids, ids.length, AutofillId[].class); + } else { + mAutofillIds = null; } - return mCachedSaveInfo; + mWebDomain = parcel.readString(); } - public int getSaveType() { - if (mCachedSaveType == null) { - AutofillSaveType autofillSaveType = new AutofillSaveType(); - List<AutofillId> autofillIds = new ArrayList<>(); - mStructureParser.parse((node) -> parseSaveTypeAndIds(node, autofillSaveType, autofillIds)); - mCachedSaveType = autofillSaveType.saveType; - mCachedAutofillIds = autofillIds; - } - return mCachedSaveType; + public List<String> getAllHints() { + return mAllHints; } - public String buildWebDomain() { - StringBuilder webDomainBuilder = new StringBuilder(); - mStructureParser.parse((node) -> parseWebDomain(node, webDomainBuilder)); - return webDomainBuilder.toString(); + public AutofillId[] getAutofillIds() { + return mAutofillIds; } - private void parseWebDomain(AssistStructure.ViewNode viewNode, StringBuilder validWebDomain) { - String webDomain = viewNode.getWebDomain(); - if (webDomain != null) { - logd("child web domain: %s", webDomain); - if (validWebDomain.length() > 0) { - if (!webDomain.equals(validWebDomain.toString())) { - throw new SecurityException("Found multiple web domains: valid= " - + validWebDomain + ", child=" + webDomain); - } - } else { - validWebDomain.append(webDomain); - } - } - } - - private void parseSaveTypeAndIds(AssistStructure.ViewNode root, - AutofillSaveType autofillSaveType, List<AutofillId> autofillIds) { - String[] hints = root.getAutofillHints(); - if (hints != null) { - for (String hint : hints) { - if (AutofillHints.isValidHint(hint)) { - autofillSaveType.saveType |= AutofillHints.getSaveTypeForHint(hint); - autofillIds.add(root.getAutofillId()); - } - } - } + public int getSaveType() { + return mSaveType; } - private void parseHints() { - List<String> allHints = new ArrayList<>(); - mStructureParser.parse((node) -> getHints(node, allHints)); - mCachedAllHints = allHints; + public String getWebDomain() { + return mWebDomain; } - private void getHints(AssistStructure.ViewNode node, List<String> allHints) { - if (node.getAutofillHints() != null) { - String[] hints = node.getAutofillHints(); - Collections.addAll(allHints, hints); - } + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeList(mAllHints); + parcel.writeInt(mSaveType); + parcel.writeParcelableArray(mAutofillIds, 0); + parcel.writeString(mWebDomain); } - public void clearCache() { - mCachedAllHints = null; - mCachedSaveType = null; - mCachedSaveInfo = null; - mCachedAutofillIds = null; + @Override + public int describeContents() { + return 0; } - private class AutofillSaveType { - int saveType; + @Override + public String toString() { + return "ClientViewMetadata{" + + "mAllHints=" + mAllHints + + ", mSaveType=" + mSaveType + + ", mAutofillIds=" + Arrays.toString(mAutofillIds) + + ", mWebDomain='" + mWebDomain + '\'' + + '}'; } } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java new file mode 100644 index 00000000..394cd72d --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java @@ -0,0 +1,79 @@ +/* + * 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.autofill.service.data; + + +import android.app.assist.AssistStructure; +import android.util.MutableInt; +import android.view.autofill.AutofillId; + +import com.example.android.autofill.service.AutofillHints; +import com.example.android.autofill.service.StructureParser; + +import java.util.ArrayList; +import java.util.List; + +import static com.example.android.autofill.service.util.Util.logd; + +public class ClientViewMetadataBuilder { + private StructureParser mStructureParser; + + public ClientViewMetadataBuilder(StructureParser parser) { + mStructureParser = parser; + } + + public ClientViewMetadata buildClientViewMetadata() { + List<String> allHints = new ArrayList<>(); + MutableInt saveType = new MutableInt(0); + List<AutofillId> autofillIds = new ArrayList<>(); + StringBuilder webDomainBuilder = new StringBuilder(); + mStructureParser.parse((node) -> parseNode(node, allHints, saveType, autofillIds)); + mStructureParser.parse((node) -> parseWebDomain(node, webDomainBuilder)); + String webDomain = webDomainBuilder.toString(); + AutofillId[] autofillIdsArray = autofillIds.toArray(new AutofillId[autofillIds.size()]); + return new ClientViewMetadata(allHints, saveType.value, autofillIdsArray, webDomain); + } + + private void parseWebDomain(AssistStructure.ViewNode viewNode, StringBuilder validWebDomain) { + String webDomain = viewNode.getWebDomain(); + if (webDomain != null) { + logd("child web domain: %s", webDomain); + if (validWebDomain.length() > 0) { + if (!webDomain.equals(validWebDomain.toString())) { + throw new SecurityException("Found multiple web domains: valid= " + + validWebDomain + ", child=" + webDomain); + } + } else { + validWebDomain.append(webDomain); + } + } + } + + private void parseNode(AssistStructure.ViewNode root, List<String> allHints, + MutableInt autofillSaveType, List<AutofillId> autofillIds) { + String[] hints = root.getAutofillHints(); + if (hints != null) { + for (String hint : hints) { + if (AutofillHints.isValidHint(hint)) { + allHints.add(hint); + autofillSaveType.value |= AutofillHints.getSaveTypeForHint(hint); + autofillIds.add(root.getAutofillId()); + } + } + } + } +} diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java index 39ebf702..974288d2 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java @@ -22,7 +22,6 @@ import android.os.Bundle; import android.service.autofill.Dataset; import android.service.autofill.FillResponse; import android.service.autofill.SaveInfo; -import android.view.View; import android.view.autofill.AutofillId; import android.widget.RemoteViews; @@ -31,24 +30,21 @@ import com.example.android.autofill.service.RemoteViewsHelper; import com.example.android.autofill.service.data.ClientViewMetadata; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; -import static com.example.android.autofill.service.util.Util.bundleToString; -import static com.example.android.autofill.service.util.Util.getSaveTypeAsString; -import static com.example.android.autofill.service.util.Util.logDebugEnabled; import static com.example.android.autofill.service.util.Util.logd; public class ResponseAdapter { public static final String CLIENT_STATE_PARTIAL_ID_TEMPLATE = "partial-%s"; // TODO: move to settings activity and document it private static final boolean SUPPORT_MULTIPLE_STEPS = true; - + static int pageno = 0; private final Context mContext; private final DatasetAdapter mDatasetAdapter; private final String mPackageName; private final ClientViewMetadata mClientViewMetadata; - private final Bundle mPreviousClientState; + private final List<ClientViewMetadata> mPreviousClientViewMetadatas; public ResponseAdapter(Context context, ClientViewMetadata clientViewMetadata, String packageName, DatasetAdapter datasetAdapter, Bundle clientState) { @@ -56,7 +52,15 @@ public class ResponseAdapter { mClientViewMetadata = clientViewMetadata; mDatasetAdapter = datasetAdapter; mPackageName = packageName; - mPreviousClientState = clientState; + mPreviousClientViewMetadatas = new ArrayList<>(); + if (clientState != null) { + clientState.setClassLoader(getClass().getClassLoader()); + for (int i = pageno - 1; i >= 0; i--) { + ClientViewMetadata previousPage = clientState.getParcelable("client-" + (pageno - 1)); + mPreviousClientViewMetadatas.add(previousPage); + } + logd("previous client state == " + mPreviousClientViewMetadatas); + } } /** @@ -91,74 +95,77 @@ public class ResponseAdapter { } } } - + Bundle clientState = new Bundle(); + clientState.putParcelable("client-" + (pageno++), mClientViewMetadata); int saveType = mClientViewMetadata.getSaveType(); - AutofillId[] autofillIds = mClientViewMetadata.getAutofillIdsArray(); - List<String> allHints = mClientViewMetadata.getAllHints(); - if (logDebugEnabled()) { - logd("setPartialSaveInfo() for type %s: allHints=%s, ids=%s, clientState=%s", - getSaveTypeAsString(saveType), allHints, Arrays.toString(autofillIds), - bundleToString(mPreviousClientState)); - } - // TODO: this should be more generic, but for now it's hardcode to support just activities - // that have an username and a password in separate steps (like MultipleStepsSigninActivity) - if ((saveType != SaveInfo.SAVE_DATA_TYPE_USERNAME - && saveType != SaveInfo.SAVE_DATA_TYPE_PASSWORD) - || autofillIds.length != 1 || allHints.size() != 1) { - logd("Unsupported activity for partial info; returning full"); - SaveInfo saveInfo = mClientViewMetadata.getSaveInfo(); - if (saveInfo != null) { - responseBuilder.setSaveInfo(mClientViewMetadata.getSaveInfo()); - return responseBuilder.build(); - } else { - return null; - } - } - int previousSaveType; - String previousHint; - if (saveType == SaveInfo.SAVE_DATA_TYPE_PASSWORD) { - previousHint = View.AUTOFILL_HINT_USERNAME; - previousSaveType = SaveInfo.SAVE_DATA_TYPE_USERNAME; - } else { - previousHint = View.AUTOFILL_HINT_PASSWORD; - previousSaveType = SaveInfo.SAVE_DATA_TYPE_PASSWORD; - } - String previousKey = String.format(CLIENT_STATE_PARTIAL_ID_TEMPLATE, previousHint); - - AutofillId previousValue = mPreviousClientState == null ? null : mPreviousClientState - .getParcelable(previousKey); - logd("previous: %s=%s", previousKey, previousValue); - - Bundle newClientState = new Bundle(); - String key = String.format(CLIENT_STATE_PARTIAL_ID_TEMPLATE, allHints.get(0)); - AutofillId value = autofillIds[0]; - logd("New client state: %s = %s", key, value); - newClientState.putParcelable(key, value); - - if (previousValue != null) { - AutofillId[] newIds = new AutofillId[]{previousValue, value}; - int newSaveType = saveType | previousSaveType; - logd("new values: type=%s, ids=%s", - getSaveTypeAsString(newSaveType), Arrays.toString(newIds)); - newClientState.putAll(mPreviousClientState); - responseBuilder.setSaveInfo(new SaveInfo.Builder(newSaveType, newIds) - .setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) - .build()) - .setClientState(newClientState); - - return responseBuilder.build(); - } - responseBuilder.setClientState(newClientState); - responseBuilder.setSaveInfo(mClientViewMetadata.getSaveInfo()); + AutofillId[] autofillIds = mClientViewMetadata.getAutofillIds(); + SaveInfo saveInfo = new SaveInfo.Builder(saveType, autofillIds).build(); + responseBuilder.setSaveInfo(saveInfo); + responseBuilder.setClientState(clientState); return responseBuilder.build(); +// int saveType = mClientViewMetadata.getSaveType(); +// AutofillId[] autofillIds = mClientViewMetadata.getAutofillIds(); +// List<String> allHints = mClientViewMetadata.getAllHints(); +// if (logDebugEnabled()) { +// logd("setPartialSaveInfo() for type %s: allHints=%s, ids=%s, clientState=%s", +// getSaveTypeAsString(saveType), allHints, Arrays.toString(autofillIds), +// bundleToString(mPreviousClientState)); +// } +// // TODO: this should be more generic, but for now it's hardcode to support just activities +// // that have an username and a password in separate steps (like MultipleStepsSigninActivity) +// if ((saveType != SaveInfo.SAVE_DATA_TYPE_USERNAME +// && saveType != SaveInfo.SAVE_DATA_TYPE_PASSWORD) +// || autofillIds.length != 1 || allHints.size() != 1) { +// logd("Unsupported activity for partial info; returning full"); +// responseBuilder.setSaveInfo(mClientViewMetadata.getSaveInfo()); +// return responseBuilder.build(); +// } +// int previousSaveType; +// String previousHint; +// if (saveType == SaveInfo.SAVE_DATA_TYPE_PASSWORD) { +// previousHint = View.AUTOFILL_HINT_USERNAME; +// previousSaveType = SaveInfo.SAVE_DATA_TYPE_USERNAME; +// } else { +// previousHint = View.AUTOFILL_HINT_PASSWORD; +// previousSaveType = SaveInfo.SAVE_DATA_TYPE_PASSWORD; +// } +// String previousKey = String.format(CLIENT_STATE_PARTIAL_ID_TEMPLATE, previousHint); +// +// AutofillId previousValue = mPreviousClientState == null ? null : mPreviousClientState +// .getParcelable(previousKey); +// logd("previous: %s=%s", previousKey, previousValue); +// +// Bundle newClientState = new Bundle(); +// String key = String.format(CLIENT_STATE_PARTIAL_ID_TEMPLATE, allHints.get(0)); +// AutofillId value = autofillIds[0]; +// logd("New client state: %s = %s", key, value); +// newClientState.putParcelable(key, value); +// +// if (previousValue != null) { +// AutofillId[] newIds = new AutofillId[]{previousValue, value}; +// int newSaveType = saveType | previousSaveType; +// logd("new values: type=%s, ids=%s", +// getSaveTypeAsString(newSaveType), Arrays.toString(newIds)); +// newClientState.putAll(mPreviousClientState); +// responseBuilder.setSaveInfo(new SaveInfo.Builder(newSaveType, newIds) +// .setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) +// .build()) +// .setClientState(newClientState); +// +// return responseBuilder.build(); +// } +// responseBuilder.setClientState(newClientState); +// responseBuilder.setSaveInfo(mClientViewMetadata.getSaveInfo()); +// return responseBuilder.build(); } public FillResponse buildResponse(IntentSender sender, RemoteViews remoteViews) { FillResponse.Builder responseBuilder = new FillResponse.Builder(); - AutofillId[] autofillIds = mClientViewMetadata.getAutofillIdsArray(); - SaveInfo saveInfo = mClientViewMetadata.getSaveInfo(); - responseBuilder.setAuthentication(autofillIds, sender, remoteViews); + int saveType = mClientViewMetadata.getSaveType(); + AutofillId[] autofillIds = mClientViewMetadata.getAutofillIds(); + SaveInfo saveInfo = new SaveInfo.Builder(saveType, autofillIds).build(); responseBuilder.setSaveInfo(saveInfo); + responseBuilder.setAuthentication(autofillIds, sender, remoteViews); return responseBuilder.build(); } } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DigitalAssetLinksDataSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DigitalAssetLinksDataSource.java index c01573b0..00661a7f 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DigitalAssetLinksDataSource.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DigitalAssetLinksDataSource.java @@ -19,6 +19,8 @@ import com.example.android.autofill.service.data.DataCallback; import com.example.android.autofill.service.model.DalCheck; import com.example.android.autofill.service.model.DalInfo; +import static com.example.android.autofill.service.util.Util.DalCheckRequirement; + /** * Data source for * <a href="https://developers.google.com/digital-asset-links/">Digital Asset Links</a>. @@ -28,7 +30,8 @@ public interface DigitalAssetLinksDataSource { /** * Checks if the association between a web domain and a package is valid. */ - void checkValid(DalInfo dalInfo, DataCallback<DalCheck> dalCheckCallback); + void checkValid(DalCheckRequirement dalCheckRequirement, DalInfo dalInfo, + DataCallback<DalCheck> dalCheckCallback); /** * Clears all cached data. diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DigitalAssetLinksRepository.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DigitalAssetLinksRepository.java index dfcecab4..6303a1e7 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DigitalAssetLinksRepository.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DigitalAssetLinksRepository.java @@ -19,12 +19,12 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.support.annotation.NonNull; -import com.example.android.autofill.service.util.SecurityHelper; -import com.example.android.autofill.service.data.source.DalService; import com.example.android.autofill.service.data.DataCallback; +import com.example.android.autofill.service.data.source.DalService; import com.example.android.autofill.service.data.source.DigitalAssetLinksDataSource; import com.example.android.autofill.service.model.DalCheck; import com.example.android.autofill.service.model.DalInfo; +import com.example.android.autofill.service.util.SecurityHelper; import com.google.common.net.InternetDomainName; import java.util.HashMap; @@ -34,6 +34,10 @@ import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; +import static com.example.android.autofill.service.util.Util.DalCheckRequirement; +import static com.example.android.autofill.service.util.Util.DalCheckRequirement.AllUrls; +import static com.example.android.autofill.service.util.Util.DalCheckRequirement.Disabled; +import static com.example.android.autofill.service.util.Util.DalCheckRequirement.LoginOnly; import static com.example.android.autofill.service.util.Util.logd; @@ -41,7 +45,6 @@ import static com.example.android.autofill.service.util.Util.logd; * Singleton repository that caches the result of Digital Asset Links checks. */ public class DigitalAssetLinksRepository implements DigitalAssetLinksDataSource { - private static final String DAL_BASE_URL = "https://digitalassetlinks.googleapis.com"; private static final String PERMISSION_GET_LOGIN_CREDS = "common.get_login_creds"; private static final String PERMISSION_HANDLE_ALL_URLS = "common.handle_all_urls"; @@ -80,7 +83,15 @@ public class DigitalAssetLinksRepository implements DigitalAssetLinksDataSource mCache.clear(); } - public void checkValid(DalInfo dalInfo, DataCallback<DalCheck> dalCheckDataCallback) { + public void checkValid(DalCheckRequirement dalCheckRequirement, DalInfo dalInfo, + DataCallback<DalCheck> dalCheckDataCallback) { + if (dalCheckRequirement.equals(Disabled)) { + DalCheck dalCheck = new DalCheck(); + dalCheck.linked = true; + dalCheckDataCallback.onLoaded(dalCheck); + return; + } + DalCheck dalCheck = mCache.get(dalInfo); if (dalCheck != null) { dalCheckDataCallback.onLoaded(dalCheck); @@ -109,22 +120,27 @@ public class DigitalAssetLinksRepository implements DigitalAssetLinksDataSource DalCheck dalCheck = response.body(); if (dalCheck == null || !dalCheck.linked) { // get_login_creds check failed, so try handle_all_urls check - mDalService.check(webDomain, PERMISSION_HANDLE_ALL_URLS, packageName, - fingerprint).enqueue(new Callback<DalCheck>() { - @Override - public void onResponse(@NonNull Call<DalCheck> call, - @NonNull Response<DalCheck> response) { - DalCheck dalCheck = response.body(); - mCache.put(dalInfo, dalCheck); - dalCheckDataCallback.onLoaded(dalCheck); - } - - @Override - public void onFailure(@NonNull Call<DalCheck> call, - @NonNull Throwable t) { - dalCheckDataCallback.onDataNotAvailable(t.getMessage()); - } - }); + if (dalCheckRequirement.equals(LoginOnly)) { + dalCheckDataCallback.onDataNotAvailable( + "DAL: Login creds check failed."); + } else if (dalCheckRequirement.equals(AllUrls)) { + mDalService.check(webDomain, PERMISSION_HANDLE_ALL_URLS, + packageName, fingerprint).enqueue(new Callback<DalCheck>() { + @Override + public void onResponse(@NonNull Call<DalCheck> call, + @NonNull Response<DalCheck> response) { + DalCheck dalCheck = response.body(); + mCache.put(dalInfo, dalCheck); + dalCheckDataCallback.onLoaded(dalCheck); + } + + @Override + public void onFailure(@NonNull Call<DalCheck> call, + @NonNull Throwable t) { + dalCheckDataCallback.onDataNotAvailable(t.getMessage()); + } + }); + } } else { // get_login_creds check succeeded, so we're finished. mCache.put(dalInfo, dalCheck); diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/MyPreferences.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/MyPreferences.java index 73fa3acf..8770ef83 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/MyPreferences.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/MyPreferences.java @@ -28,6 +28,7 @@ public class MyPreferences { private static final String DATASET_AUTH_KEY = "dataset_auth"; private static final String MASTER_PASSWORD_KEY = "master_password"; private static final String LOGGING_LEVEL = "logging_level"; + private static final String DAL_CHECK_REQUIRED = "dal_check_required"; private static MyPreferences sInstance; private final SharedPreferences mPrefs; @@ -90,11 +91,20 @@ public class MyPreferences { } public Util.LogLevel getLoggingLevel() { - return Util.LogLevel.values()[mPrefs.getInt(LOGGING_LEVEL, Util.LogLevel.OFF.ordinal())]; + return Util.LogLevel.values()[mPrefs.getInt(LOGGING_LEVEL, Util.LogLevel.Off.ordinal())]; } public void setLoggingLevel(Util.LogLevel level) { mPrefs.edit().putInt(LOGGING_LEVEL, level.ordinal()).apply(); Util.setLoggingLevel(level); } + + public Util.DalCheckRequirement getDalCheckRequirement() { + return Util.DalCheckRequirement.values()[mPrefs.getInt(DAL_CHECK_REQUIRED, + Util.DalCheckRequirement.AllUrls.ordinal())]; + } + + public void setDalCheckRequired(Util.DalCheckRequirement level) { + mPrefs.edit().putInt(DAL_CHECK_REQUIRED, level.ordinal()).apply(); + } } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java index 5ccc13ae..82222a80 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java @@ -51,6 +51,9 @@ import com.example.android.autofill.service.util.Util; import java.util.List; +import static com.example.android.autofill.service.util.Util.DalCheckRequirement.AllUrls; +import static com.example.android.autofill.service.util.Util.DalCheckRequirement.Disabled; +import static com.example.android.autofill.service.util.Util.DalCheckRequirement.LoginOnly; import static com.example.android.autofill.service.util.Util.logd; import static com.example.android.autofill.service.util.Util.logw; @@ -60,6 +63,7 @@ public class SettingsActivity extends AppCompatActivity { private AutofillManager mAutofillManager; private LocalAutofillDataSource mLocalAutofillDataSource; private PackageVerificationDataSource mPackageVerificationDataSource; + private MyPreferences mPreferences; @Override public void onCreate(Bundle savedInstanceState) { @@ -72,18 +76,17 @@ public class SettingsActivity extends AppCompatActivity { autofillDao, new AppExecutors()); mAutofillManager = getSystemService(AutofillManager.class); mPackageVerificationDataSource = SharedPrefsPackageVerificationRepository.getInstance(this); - - final MyPreferences preferences = MyPreferences.getInstance(this); + mPreferences = MyPreferences.getInstance(this); setupSettingsSwitch(R.id.settings_auth_responses_container, R.id.settings_auth_responses_label, R.id.settings_auth_responses_switch, - preferences.isResponseAuth(), - (compoundButton, isResponseAuth) -> preferences.setResponseAuth(isResponseAuth)); + mPreferences.isResponseAuth(), + (compoundButton, isResponseAuth) -> mPreferences.setResponseAuth(isResponseAuth)); setupSettingsSwitch(R.id.settings_auth_datasets_container, R.id.settings_auth_datasets_label, R.id.settings_auth_datasets_switch, - preferences.isDatasetAuth(), - (compoundButton, isDatasetAuth) -> preferences.setDatasetAuth(isDatasetAuth)); + mPreferences.isDatasetAuth(), + (compoundButton, isDatasetAuth) -> mPreferences.setDatasetAuth(isDatasetAuth)); setupSettingsButton(R.id.settings_add_data_container, R.id.settings_add_data_label, R.id.settings_add_data_icon, @@ -96,7 +99,7 @@ public class SettingsActivity extends AppCompatActivity { R.id.settings_auth_credentials_label, R.id.settings_auth_credentials_icon, (view) -> { - if (preferences.getMasterPassword() != null) { + if (mPreferences.getMasterPassword() != null) { buildCurrentCredentialsDialog().show(); } else { buildNewCredentialsDialog().show(); @@ -108,29 +111,55 @@ public class SettingsActivity extends AppCompatActivity { mAutofillManager.hasEnabledAutofillServices(), (compoundButton, serviceSet) -> setService(serviceSet)); RadioGroup loggingLevelContainer = findViewById(R.id.loggingLevelContainer); - Util.LogLevel loggingLevel = preferences.getLoggingLevel(); + Util.LogLevel loggingLevel = mPreferences.getLoggingLevel(); Util.setLoggingLevel(loggingLevel); switch (loggingLevel) { - case OFF: + case Off: loggingLevelContainer.check(R.id.loggingOff); break; - case DEBUG: + case Debug: loggingLevelContainer.check(R.id.loggingDebug); break; - case VERBOSE: + case Verbose: loggingLevelContainer.check(R.id.loggingVerbose); break; } loggingLevelContainer.setOnCheckedChangeListener((group, checkedId) -> { switch (checkedId) { case R.id.loggingOff: - preferences.setLoggingLevel(Util.LogLevel.OFF); + mPreferences.setLoggingLevel(Util.LogLevel.Off); break; case R.id.loggingDebug: - preferences.setLoggingLevel(Util.LogLevel.DEBUG); + mPreferences.setLoggingLevel(Util.LogLevel.Debug); break; case R.id.loggingVerbose: - preferences.setLoggingLevel(Util.LogLevel.VERBOSE); + mPreferences.setLoggingLevel(Util.LogLevel.Verbose); + break; + } + }); + RadioGroup dalCheckRequirementContainer = findViewById(R.id.dalCheckRequirementContainer); + Util.DalCheckRequirement dalCheckRequirement = mPreferences.getDalCheckRequirement(); + switch (dalCheckRequirement) { + case Disabled: + dalCheckRequirementContainer.check(R.id.dalDisabled); + break; + case LoginOnly: + dalCheckRequirementContainer.check(R.id.dalLoginOnly); + break; + case AllUrls: + dalCheckRequirementContainer.check(R.id.dalAllUrls); + break; + } + dalCheckRequirementContainer.setOnCheckedChangeListener((group, checkedId) -> { + switch (checkedId) { + case R.id.dalDisabled: + mPreferences.setDalCheckRequired(Disabled); + break; + case R.id.dalLoginOnly: + mPreferences.setDalCheckRequired(LoginOnly); + break; + case R.id.dalAllUrls: + mPreferences.setDalCheckRequired(AllUrls); break; } }); @@ -144,7 +173,7 @@ public class SettingsActivity extends AppCompatActivity { .setPositiveButton(R.string.settings_ok, (dialog, which) -> { mLocalAutofillDataSource.clear(); mPackageVerificationDataSource.clear(); - MyPreferences.getInstance(SettingsActivity.this).clearCredentials(); + mPreferences.clearCredentials(); dialog.dismiss(); }) .create(); @@ -212,7 +241,7 @@ public class SettingsActivity extends AppCompatActivity { @Override public void onClick(DialogInterface dialog, int which) { String password = currentPasswordField.getText().toString(); - if (MyPreferences.getInstance(SettingsActivity.this).getMasterPassword() + if (mPreferences.getMasterPassword() .equals(password)) { buildNewCredentialsDialog().show(); dialog.dismiss(); @@ -232,7 +261,7 @@ public class SettingsActivity extends AppCompatActivity { .setView(newPasswordField) .setPositiveButton(R.string.settings_ok, (dialog, which) -> { String password = newPasswordField.getText().toString(); - MyPreferences.getInstance(SettingsActivity.this).setMasterPassword(password); + mPreferences.setMasterPassword(password); dialog.dismiss(); }) .create(); diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/Util.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/Util.java index d7b5b45b..53943138 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/Util.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/util/Util.java @@ -42,7 +42,7 @@ public final class Util { public static final NodeFilter AUTOFILL_ID_FILTER = (node, id) -> id.equals(node.getAutofillId()); private static final String TAG = "AutofillSample"; - public static LogLevel sLoggingLevel = LogLevel.OFF; + public static LogLevel sLoggingLevel = LogLevel.Off; private static void bundleToString(StringBuilder builder, Bundle data) { final Set<String> keySet = data.keySet(); @@ -252,11 +252,11 @@ public final class Util { } public static boolean logDebugEnabled() { - return sLoggingLevel.ordinal() >= LogLevel.DEBUG.ordinal(); + return sLoggingLevel.ordinal() >= LogLevel.Debug.ordinal(); } public static boolean logVerboseEnabled() { - return sLoggingLevel.ordinal() >= LogLevel.VERBOSE.ordinal(); + return sLoggingLevel.ordinal() >= LogLevel.Verbose.ordinal(); } public static void logw(String message, Object... params) { @@ -279,7 +279,9 @@ public final class Util { sLoggingLevel = level; } - public enum LogLevel {OFF, DEBUG, VERBOSE} + public enum LogLevel {Off, Debug, Verbose} + + public enum DalCheckRequirement {Disabled, LoginOnly, AllUrls} /** * Helper interface used to filter Assist nodes. diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_activity.xml b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_activity.xml index bfbf5f81..ce77e27a 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_activity.xml +++ b/input/autofill/AutofillFramework/afservice/src/main/res/layout/multidataset_service_settings_activity.xml @@ -163,6 +163,44 @@ style="@style/Settings.Header" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:text="@string/settings_dal_header" /> + + <RadioGroup + android:id="@+id/dalCheckRequirementContainer" + style="@style/Settings.Container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <RadioButton + android:id="@+id/dalDisabled" + style="@style/Settings.Label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="@dimen/a11y_min_touch_target_dimen" + android:text="@string/settings_dal_disabled" /> + + <RadioButton + android:id="@+id/dalLoginOnly" + style="@style/Settings.Label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="@dimen/a11y_min_touch_target_dimen" + android:text="@string/settings_dal_login_only" /> + + <RadioButton + android:id="@+id/dalAllUrls" + style="@style/Settings.Label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="@dimen/a11y_min_touch_target_dimen" + android:text="@string/settings_dal_all_urls" /> + </RadioGroup> + + <TextView + style="@style/Settings.Header" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:text="@string/settings_logging_header" /> <RadioGroup diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/values/strings.xml b/input/autofill/AutofillFramework/afservice/src/main/res/values/strings.xml index 9d41f97f..da0e0a8c 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/res/values/strings.xml +++ b/input/autofill/AutofillFramework/afservice/src/main/res/values/strings.xml @@ -1,11 +1,13 @@ <resources> <string name="invalid_package_signature">Invalid package signature</string> + <string name="security_exception">Web domain security exception.</string> + <string name="dal_exception">DAL verification failure.</string> <string name="autofill_sign_in_prompt">Tap to sign in.</string> <string name="authentication_name">Autofill Authentication</string> <string name="settings_name">Autofill Settings</string> <string name="settings_cancel">Cancel</string> <string name="settings_save">Save</string> - <string name="settings_authenticate_responses">Authenticate responses</string> + <string name="settings_authenticate_responses">Authenticate Responses</string> <string name="settings_authenticate_datasets">Authenticate Datasets</string> <string name="settings_add_data_label">Add fake Autofill data</string> <string name="settings_add_data_title">Add Autofill Datasets</string> @@ -25,6 +27,12 @@ <string name="settings_logging_off">Off</string> <string name="settings_logging_debug">Debug</string> <string name="settings_logging_verbose">Verbose</string> + + <string name="settings_dal_header">DAL Check Requirement</string> + <string name="settings_dal_disabled">Disabled</string> + <string name="settings_dal_login_only">Login Credentials Only</string> + <string name="settings_dal_all_urls">Handle All URLs</string> + <string name="settings_enable_header">Enable/Disable</string> <string name="settings_set_service">Set default Autofill service</string> <string name="settings_disable_service">Disable Autofill services</string> |