OSDN Git Service

Added autofill options on Developer Options screen.
authorFelipe Leme <felipeal@google.com>
Wed, 25 Jul 2018 00:24:40 +0000 (17:24 -0700)
committerFelipe Leme <felipeal@google.com>
Thu, 26 Jul 2018 16:53:11 +0000 (09:53 -0700)
Test: manual verification
Test: atest AutofillResetOptionsPreferenceControllerTest\
            AutofillLoggingLevelPreferenceControllerTest
Test: runtest --path packages/apps/Settings/tests/unit/src/com/android/settings/core/PreferenceControllerContractTest.java
Fixes: 65700540

Change-Id: I6b35fbf549529f4d97df164ce3fb6d641ee37650

15 files changed:
res/values/arrays.xml
res/values/strings.xml
res/xml/development_settings.xml
src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
src/com/android/settings/development/autofill/AbstractGlobalSettingsPreference.java [new file with mode: 0644]
src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java [new file with mode: 0644]
src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceController.java [new file with mode: 0644]
src/com/android/settings/development/autofill/AutofillMaxPartitionsPreference.java [new file with mode: 0644]
src/com/android/settings/development/autofill/AutofillPreferenceCategory.java [new file with mode: 0644]
src/com/android/settings/development/autofill/AutofillResetOptionsPreferenceController.java [new file with mode: 0644]
src/com/android/settings/development/autofill/AutofillVisibleDatasetsPreference.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceControllerTest.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/development/autofill/AutofillResetOptionsPreferenceControllerTest.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/development/autofill/AutofillTestingHelper.java [new file with mode: 0644]
tests/unit/src/com/android/settings/core/PreferenceControllerContractTest.java

index 0a058d5..e57cbfa 100644 (file)
         <item>0</item>
     </string-array>
 
+    <!-- Titles for autofill logging level preference. [CHAR LIMIT=50] -->
+    <string-array name="autofill_logging_level_entries">
+        <item>Off</item>
+        <item>Debug</item>
+        <item>Verbose</item>
+    </string-array>
+
+    <!-- Values for autofill logging level preference. -->
+    <string-array name="autofill_logging_level_values" translatable="false" >
+        <item>0</item> <!-- AutofillManager.NO_LOGGING -->
+        <item>2</item> <!-- AutofillManager.FLAG_ADD_CLIENT_DEBUG -->
+        <item>4</item> <!-- AutofillManager.FLAG_ADD_CLIENT_VERBOSE -->
+    </string-array>
+
 </resources>
index 2bef192..ffeba23 100644 (file)
         ]]>
     </string>
 
+    <!-- Preference category for autofill debugging development settings. [CHAR LIMIT=25] -->
+    <string name="debug_autofill_category">Autofill</string>
+
+    <!-- UI debug setting: logging level for Android Autofill [CHAR LIMIT=25] -->
+    <string name="autofill_logging_level_title">Logging level</string>
+
+    <!-- Title of developer options to set the maximum number of partitions per session [CHAR LIMIT=60]-->
+    <string name="autofill_max_partitions">Max partitions</string>
+
+    <!-- Title of developer options to set the maximum number of visible datasets in the autofill UX [CHAR LIMIT=60]-->
+    <string name="autofill_max_visible_datasets">Max visible datasets</string>
+
+    <!-- Reset all autofill developer options to their default values.[CHAR_LIMIT=60] -->
+    <string name="autofill_reset_developer_options">Reset to default values</string>
+
+    <!-- Toast message shown when autofill_reset_developer_options has been performed. [CHAR_LIMIT=none] -->
+    <string name="autofill_reset_developer_options_complete">Autofill developer options have been reset</string>
+
     <!-- Name of setting for switching device theme [CHAR LIMIT=60] -->
     <string name="device_theme">Device theme</string>
     <!-- Name of default device theme [CHAR LIMIT=60] -->
index 3d5f198..b0c7c9c 100644 (file)
             android:title="@string/reset_shortcut_manager_throttling" />
     </PreferenceCategory>
 
+    <com.android.settings.development.autofill.AutofillPreferenceCategory
+        android:key="debug_autofill_category"
+        android:title="@string/debug_autofill_category"
+        android:order="1100">
+
+        <ListPreference
+            android:key="autofill_logging_level"
+            android:title="@string/autofill_logging_level_title"
+            android:entries="@array/autofill_logging_level_entries"
+            android:entryValues="@array/autofill_logging_level_values" />
+
+        <com.android.settings.development.autofill.AutofillMaxPartitionsPreference
+            android:key="autofill_max_partitions"
+            android:title="@string/autofill_max_partitions" />
+
+        <com.android.settings.development.autofill.AutofillVisibleDatasetsPreference
+            android:key="autofill_visible_datasets"
+            android:title="@string/autofill_max_visible_datasets" />
+
+        <Preference
+            android:key="autofill_reset_developer_options"
+            android:title="@string/autofill_reset_developer_options" />
+
+    </com.android.settings.development.autofill.AutofillPreferenceCategory>
+
 </PreferenceScreen>
index 82ca54b..5be381a 100644 (file)
@@ -39,6 +39,8 @@ import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.Utils;
 import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.development.autofill.AutofillLoggingLevelPreferenceController;
+import com.android.settings.development.autofill.AutofillResetOptionsPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settings.widget.SwitchBar;
@@ -466,6 +468,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
         controllers.add(new DefaultLaunchPreferenceController(context, "density"));
         controllers.add(new DefaultLaunchPreferenceController(context, "background_check"));
         controllers.add(new DefaultLaunchPreferenceController(context, "inactive_apps"));
+        controllers.add(new AutofillLoggingLevelPreferenceController(context));
+        controllers.add(new AutofillResetOptionsPreferenceController(context));
         return controllers;
     }
 
diff --git a/src/com/android/settings/development/autofill/AbstractGlobalSettingsPreference.java b/src/com/android/settings/development/autofill/AbstractGlobalSettingsPreference.java
new file mode 100644 (file)
index 0000000..080c387
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.text.BidiFormatter;
+import android.text.InputType;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Slog;
+import android.view.Display;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.widget.EditText;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settingslib.CustomEditTextPreferenceCompat;
+
+import java.text.NumberFormat;
+
+/**
+ * Base class for Autofill integer properties that are backed by
+ * {@link android.provider.Settings.Global}.
+ */
+abstract class AbstractGlobalSettingsPreference extends CustomEditTextPreferenceCompat {
+
+    private static final String TAG = "AbstractGlobalSettingsPreference";
+
+    private final String mKey;
+    private final int mDefaultValue;
+
+    private final AutofillDeveloperSettingsObserver mObserver;
+
+    protected AbstractGlobalSettingsPreference(Context context, AttributeSet attrs,
+            String key, int defaultValue) {
+        super(context, attrs);
+
+        mKey = key;
+        mDefaultValue = defaultValue;
+        mObserver = new AutofillDeveloperSettingsObserver(context, () -> updateSummary());
+    }
+
+    @Override
+    public void onAttached() {
+        super.onAttached();
+
+        mObserver.register();
+        updateSummary();
+    }
+
+    @Override
+    public void onDetached() {
+        mObserver.unregister();
+
+        super.onDetached();
+    }
+
+    private String getCurrentValue() {
+        final int value = Settings.Global.getInt(getContext().getContentResolver(),
+                mKey, mDefaultValue);
+
+        return Integer.toString(value);
+    }
+
+    private void updateSummary() {
+        setSummary(getCurrentValue());
+
+    }
+
+    @Override
+    protected void onBindDialogView(View view) {
+        super.onBindDialogView(view);
+
+        EditText editText = view.findViewById(android.R.id.edit);
+        if (editText != null) {
+            editText.setInputType(InputType.TYPE_CLASS_NUMBER);
+            editText.setText(getCurrentValue());
+            Utils.setEditTextCursorPosition(editText);
+        }
+    }
+
+    @Override
+    protected void onDialogClosed(boolean positiveResult) {
+        if (positiveResult) {
+            final String stringValue = getText();
+            int newValue = mDefaultValue;
+            try {
+                newValue = Integer.parseInt(stringValue);
+            } catch (Exception e) {
+                Log.e(TAG, "Error converting '" + stringValue + "' to integer. Using "
+                        + mDefaultValue + " instead");
+            }
+            Settings.Global.putInt(getContext().getContentResolver(), mKey, newValue);
+        }
+    }
+}
diff --git a/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java b/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java
new file mode 100644 (file)
index 0000000..ae8e246
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+final class AutofillDeveloperSettingsObserver extends ContentObserver {
+
+    private final Runnable mChangeCallback;
+    private final ContentResolver mResolver;
+
+    public AutofillDeveloperSettingsObserver(Context context, Runnable changeCallback) {
+        super(new Handler());
+
+        mResolver = context.getContentResolver();
+        mChangeCallback = changeCallback;
+    }
+
+    public void register() {
+        mResolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.AUTOFILL_LOGGING_LEVEL), false, this,
+                UserHandle.USER_ALL);
+        mResolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE), false, this,
+                UserHandle.USER_ALL);
+        mResolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, this,
+                UserHandle.USER_ALL);
+    }
+
+    public void unregister() {
+        mResolver.unregisterContentObserver(this);
+    }
+
+    @Override
+    public void onChange(boolean selfChange, Uri uri, int userId) {
+        mChangeCallback.run(); // Run Forrest, Run!
+    }
+}
diff --git a/src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceController.java b/src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceController.java
new file mode 100644 (file)
index 0000000..a22295c
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.view.autofill.AutofillManager;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+
+public final class AutofillLoggingLevelPreferenceController
+        extends DeveloperOptionsPreferenceController
+        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
+
+    private static final String AUTOFILL_LOGGING_LEVEL_KEY = "autofill_logging_level";
+
+    private final String[] mListValues;
+    private final String[] mListSummaries;
+    private final AutofillDeveloperSettingsObserver mObserver;
+
+    public AutofillLoggingLevelPreferenceController(Context context) {
+        super(context);
+
+        Resources resources = context.getResources();
+        mListValues = resources.getStringArray(R.array.autofill_logging_level_values);
+        mListSummaries = resources.getStringArray(R.array.autofill_logging_level_entries);
+        mObserver = new AutofillDeveloperSettingsObserver(mContext, () -> updateOptions());
+        mObserver.register();
+        // TODO: there should be a hook on AbstractPreferenceController where we could unregister it
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return AUTOFILL_LOGGING_LEVEL_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        writeLevel(newValue);
+        updateOptions();
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        updateOptions();
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        writeLevel(null);
+    }
+
+    private void updateOptions() {
+        final int level = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AUTOFILL_LOGGING_LEVEL, AutofillManager.DEFAULT_LOGGING_LEVEL);
+
+        final int index;
+        if (level == AutofillManager.FLAG_ADD_CLIENT_DEBUG) {
+            index = 1;
+        } else if (level == AutofillManager.FLAG_ADD_CLIENT_VERBOSE) {
+            index = 2;
+        } else {
+            index = 0;
+        }
+        final ListPreference listPreference = (ListPreference) mPreference;
+        listPreference.setValue(mListValues[index]);
+        listPreference.setSummary(mListSummaries[index]);
+    }
+
+    private void writeLevel(Object newValue) {
+        int level = AutofillManager.NO_LOGGING;
+        if (newValue instanceof String) {
+            level = Integer.parseInt((String) newValue);
+        }
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.AUTOFILL_LOGGING_LEVEL, level);
+    }
+}
diff --git a/src/com/android/settings/development/autofill/AutofillMaxPartitionsPreference.java b/src/com/android/settings/development/autofill/AutofillMaxPartitionsPreference.java
new file mode 100644 (file)
index 0000000..ab0cec9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.view.autofill.AutofillManager;
+
+import java.text.NumberFormat;
+
+public final class AutofillMaxPartitionsPreference extends AbstractGlobalSettingsPreference {
+
+    public AutofillMaxPartitionsPreference(Context context, AttributeSet attrs) {
+        super(context, attrs, Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
+                AutofillManager.DEFAULT_MAX_PARTITIONS_SIZE);
+    }
+}
diff --git a/src/com/android/settings/development/autofill/AutofillPreferenceCategory.java b/src/com/android/settings/development/autofill/AutofillPreferenceCategory.java
new file mode 100644 (file)
index 0000000..ed07f62
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.autofill.AutofillManager;
+
+import androidx.preference.PreferenceCategory;
+
+public final class AutofillPreferenceCategory extends PreferenceCategory {
+
+    private static final String TAG = "AutofillPreferenceCategory";
+
+    private final ContentResolver mContentResolver;
+    private final ContentObserver mSettingsObserver;
+
+    public AutofillPreferenceCategory(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mSettingsObserver = new ContentObserver(new Handler()) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri, int userId) {
+                Log.w(TAG, "Autofill Service changed, but UI cannot be refreshed");
+                // TODO(b/111838239): we cannot update the UI because AFM.isEnabled() will return
+                // the previous value. Once that's fixed, we'll need to call one of the 2 callbacks
+                // below:
+                // notifyChanged();
+                // notifyDependencyChange(shouldDisableDependents());
+            }
+        };
+        mContentResolver = context.getContentResolver();
+    }
+
+    @Override
+    public void onAttached() {
+        super.onAttached();
+
+        mContentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.AUTOFILL_SERVICE), false,
+                mSettingsObserver);
+    }
+
+    @Override
+    public void onDetached() {
+        mContentResolver.unregisterContentObserver(mSettingsObserver);
+
+        super.onDetached();
+    }
+
+    // PreferenceCategory.isEnabled() always return false, so we rather not change that logic
+    // decide whether the children should be shown using isAutofillEnabled() instead.
+    private boolean isAutofillEnabled() {
+        final AutofillManager afm = getContext().getSystemService(AutofillManager.class);
+        final boolean enabled = afm != null && afm.isEnabled();
+        Log.v(TAG, "isAutofillEnabled(): " + enabled);
+        return enabled;
+    }
+
+    @Override
+    public boolean shouldDisableDependents() {
+        final boolean shouldIt = !isAutofillEnabled();
+        Log.v(TAG, "shouldDisableDependents(): " + shouldIt);
+        return shouldIt;
+    }
+}
diff --git a/src/com/android/settings/development/autofill/AutofillResetOptionsPreferenceController.java b/src/com/android/settings/development/autofill/AutofillResetOptionsPreferenceController.java
new file mode 100644 (file)
index 0000000..42f7a48
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.autofill.AutofillManager;
+import android.widget.Toast;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+
+public final class AutofillResetOptionsPreferenceController
+        extends DeveloperOptionsPreferenceController
+        implements PreferenceControllerMixin {
+
+    private static final String AUTOFILL_RESET_OPTIONS_KEY = "autofill_reset_developer_options";
+
+    public AutofillResetOptionsPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return AUTOFILL_RESET_OPTIONS_KEY;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(AUTOFILL_RESET_OPTIONS_KEY, preference.getKey())) {
+            return false;
+        }
+        final ContentResolver contentResolver = mContext.getContentResolver();
+        Settings.Global.putInt(contentResolver, Settings.Global.AUTOFILL_LOGGING_LEVEL,
+                AutofillManager.DEFAULT_LOGGING_LEVEL);
+        Settings.Global.putInt(contentResolver, Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
+                AutofillManager.DEFAULT_MAX_PARTITIONS_SIZE);
+        Settings.Global.putInt(contentResolver, Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, 0);
+        Toast.makeText(mContext, R.string.autofill_reset_developer_options_complete,
+                Toast.LENGTH_SHORT).show();
+        return true;
+    }
+}
diff --git a/src/com/android/settings/development/autofill/AutofillVisibleDatasetsPreference.java b/src/com/android/settings/development/autofill/AutofillVisibleDatasetsPreference.java
new file mode 100644 (file)
index 0000000..2f0d15f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.util.AttributeSet;
+
+public final class AutofillVisibleDatasetsPreference extends AbstractGlobalSettingsPreference {
+
+    public AutofillVisibleDatasetsPreference(Context context, AttributeSet attrs) {
+        super(context, attrs, Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, 0);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceControllerTest.java
new file mode 100644 (file)
index 0000000..b9da71d
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.RemoteException;
+import android.view.autofill.AutofillManager;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.ListPreference;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class AutofillLoggingLevelPreferenceControllerTest {
+
+    private static final int IDX_OFF = 0;
+    private static final int IDX_DEBUG = 1;
+    private static final int IDX_VERBOSE = 2;
+
+    @Mock
+    private ListPreference mPreference;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+
+    private Context mContext;
+    private AutofillLoggingLevelPreferenceController mController;
+    private AutofillTestingHelper mHelper;
+
+    private String[] mListValues;
+    private String[] mListSummaries;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this); // TODO: use @Rule
+        mContext = RuntimeEnvironment.application;
+        mHelper = new AutofillTestingHelper(mContext);
+        final Resources resources = mContext.getResources();
+        mListValues = resources.getStringArray(R.array.autofill_logging_level_values);
+        mListSummaries = resources.getStringArray(R.array.autofill_logging_level_entries);
+        mController = new AutofillLoggingLevelPreferenceController(mContext);
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+            .thenReturn(mPreference);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void handlePreferenceTreeClick_differentPreferenceKey_shouldNotTrigger()
+            throws Exception {
+        when(mPreference.getKey()).thenReturn("SomeRandomKey");
+
+        mHelper.setLoggingLevel(108);
+
+        assertThat(mController.handlePreferenceTreeClick(mPreference)).isFalse();
+
+        assertThat(mHelper.getLoggingLevel()).isEqualTo(108);
+    }
+
+    @Test
+    public void onPreferenceChange_off() throws Exception {
+        mHelper.setLoggingLevel(108);
+
+        mController.onPreferenceChange(mPreference, mListValues[IDX_OFF]);
+
+        assertThat(mHelper.getLoggingLevel()).isEqualTo(AutofillManager.NO_LOGGING);
+    }
+
+    @Test
+    public void onPreferenceChange_debug() throws Exception {
+        mHelper.setLoggingLevel(108);
+
+        mController.onPreferenceChange(mPreference, mListValues[IDX_DEBUG]);
+
+        assertThat(mHelper.getLoggingLevel())
+                .isEqualTo(AutofillManager.FLAG_ADD_CLIENT_DEBUG);
+    }
+
+    @Test
+    public void onPreferenceChange_verbose() throws Exception {
+        mHelper.setLoggingLevel(108);
+
+        mController.onPreferenceChange(mPreference, mListValues[IDX_VERBOSE]);
+
+        assertThat(mHelper.getLoggingLevel())
+                .isEqualTo(AutofillManager.FLAG_ADD_CLIENT_VERBOSE);
+    }
+
+    @Test
+    public void onSettingsChange_off() throws Exception {
+        mHelper.setLoggingLevel(AutofillManager.NO_LOGGING);
+
+        mController.updateState(mPreference);
+
+        verify(mPreference).setValue(mListValues[IDX_OFF]);
+        verify(mPreference).setSummary(mListSummaries[IDX_OFF]);
+    }
+
+    @Test
+    public void onSettingsChange_debug() throws Exception {
+        mHelper.setLoggingLevel(AutofillManager.FLAG_ADD_CLIENT_DEBUG);
+
+        mController.updateState(mPreference);
+
+        verify(mPreference).setValue(mListValues[IDX_DEBUG]);
+        verify(mPreference).setSummary(mListSummaries[IDX_DEBUG]);
+    }
+
+    @Test
+    public void onSettingsChange_verbose() throws Exception {
+        mHelper.setLoggingLevel(AutofillManager.FLAG_ADD_CLIENT_VERBOSE);
+
+        mController.updateState(mPreference);
+
+        verify(mPreference).setValue(mListValues[IDX_VERBOSE]);
+        verify(mPreference).setSummary(mListSummaries[IDX_VERBOSE]);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/autofill/AutofillResetOptionsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/autofill/AutofillResetOptionsPreferenceControllerTest.java
new file mode 100644 (file)
index 0000000..e560a83
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.view.autofill.AutofillManager;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class AutofillResetOptionsPreferenceControllerTest {
+
+    @Mock
+    private SwitchPreference mPreference;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+
+    private Context mContext;
+    private AutofillResetOptionsPreferenceController mController;
+    private AutofillTestingHelper mHelper;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this); // TODO: use @Rule
+        mContext = RuntimeEnvironment.application;
+        mHelper = new AutofillTestingHelper(mContext);
+        mController = new AutofillResetOptionsPreferenceController(mContext);
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+            .thenReturn(mPreference);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void handlePreferenceTreeClick_differentPreferenceKey_shouldNotReset() throws Exception {
+        when(mPreference.getKey()).thenReturn("SomeRandomKey");
+
+        mHelper.setLoggingLevel(4);
+        mHelper.setMaxPartitionsSize(8);
+        mHelper.setMaxVisibleDatasets(15);
+
+        assertThat(mController.handlePreferenceTreeClick(mPreference)).isFalse();
+
+        assertThat(mHelper.getLoggingLevel()).isEqualTo(4);
+        assertThat(mHelper.getMaxPartitionsSize()).isEqualTo(8);
+        assertThat(mHelper.getMaxVisibleDatasets()).isEqualTo(15);
+    }
+
+    @Test
+    public void handlePreferenceTreeClick_correctPreferenceKey_shouldReset() throws Exception {
+        when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
+
+        mHelper.setMaxPartitionsSize(16);
+        mHelper.setMaxVisibleDatasets(23);
+        mHelper.setLoggingLevel(42);
+
+        assertThat(mController.handlePreferenceTreeClick(mPreference)).isTrue();
+
+        assertThat(mHelper.getLoggingLevel())
+                .isEqualTo(AutofillManager.DEFAULT_LOGGING_LEVEL);
+        assertThat(mHelper.getMaxPartitionsSize())
+                .isEqualTo(AutofillManager.DEFAULT_MAX_PARTITIONS_SIZE);
+        assertThat(mHelper.getMaxVisibleDatasets())
+                .isEqualTo(0);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/autofill/AutofillTestingHelper.java b/tests/robotests/src/com/android/settings/development/autofill/AutofillTestingHelper.java
new file mode 100644 (file)
index 0000000..59090bc
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 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.android.settings.development.autofill;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+
+final class AutofillTestingHelper {
+    private final ContentResolver mResolver;
+
+    public AutofillTestingHelper(Context context) {
+        mResolver = context.getContentResolver();
+    }
+
+    public void setLoggingLevel(int max) {
+        setGlobal(Settings.Global.AUTOFILL_LOGGING_LEVEL, max);
+    }
+
+    public void setMaxPartitionsSize(int max) {
+        setGlobal(Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, max);
+    }
+
+    public void setMaxVisibleDatasets(int level) {
+        setGlobal(Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, level);
+    }
+
+    public int getLoggingLevel() throws SettingNotFoundException {
+        return getGlobal(Settings.Global.AUTOFILL_LOGGING_LEVEL);
+    }
+
+    public int getMaxPartitionsSize() throws SettingNotFoundException {
+        return getGlobal(Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE);
+    }
+
+    public int getMaxVisibleDatasets() throws SettingNotFoundException {
+        return getGlobal(Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS);
+    }
+
+    private void setGlobal(String key, int value) {
+        Settings.Global.putInt(mResolver, key, value);
+    }
+
+    private int getGlobal(String key) throws SettingNotFoundException {
+        return Settings.Global.getInt(mResolver, key);
+    }
+}
index 176d3c4..59f22db 100644 (file)
@@ -19,6 +19,7 @@ package com.android.settings.core;
 import static junit.framework.Assert.fail;
 
 import android.content.Context;
+import android.os.Looper;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
@@ -52,6 +53,7 @@ public class PreferenceControllerContractTest {
     @Test
     @Presubmit
     public void controllersInSearchShouldImplementPreferenceControllerMixin() {
+        Looper.prepare(); // Required by AutofillLoggingLevelPreferenceController
         final Set<String> errorClasses = new ArraySet<>();
 
         final SearchIndexableResources resources =