diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index e459ab8a81c..70536c03a6e 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -583,12 +583,7 @@ public class SettingsActivity extends SettingsBaseActivity // Generally the items that are will be changing from these updates will // not be in the top list of tiles, so run it in the background and the // SettingsBaseActivity will pick up on the updates automatically. - AsyncTask.execute(new Runnable() { - @Override - public void run() { - doUpdateTilesList(); - } - }); + AsyncTask.execute(() -> doUpdateTilesList()); } private void doUpdateTilesList() { @@ -648,7 +643,6 @@ public class SettingsActivity extends SettingsBaseActivity || somethingChanged; if (UserHandle.MU_ENABLED && !isAdmin) { - // When on restricted users, disable all extra categories (but only the settings ones). final List categories = mDashboardFeatureProvider.getAllCategories(); synchronized (categories) { diff --git a/src/com/android/settings/dashboard/CategoryManager.java b/src/com/android/settings/dashboard/CategoryManager.java index 5cc75c88f91..525b6f83aa3 100644 --- a/src/com/android/settings/dashboard/CategoryManager.java +++ b/src/com/android/settings/dashboard/CategoryManager.java @@ -27,6 +27,7 @@ import androidx.annotation.VisibleForTesting; import com.android.settingslib.applications.InterestingConfigChanges; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; +import com.android.settingslib.drawer.ProviderTile; import com.android.settingslib.drawer.Tile; import com.android.settingslib.drawer.TileUtils; @@ -189,21 +190,31 @@ public class CategoryManager { /** * Filter out duplicate tiles from category. Duplicate tiles are the ones pointing to the - * same intent. + * same intent for ActivityTile, and also the ones having the same description for ProviderTile. */ @VisibleForTesting synchronized void filterDuplicateTiles(Map categoryByKeyMap) { for (Entry categoryEntry : categoryByKeyMap.entrySet()) { final DashboardCategory category = categoryEntry.getValue(); final int count = category.getTilesCount(); + final Set descriptions = new ArraySet<>(); final Set components = new ArraySet<>(); for (int i = count - 1; i >= 0; i--) { final Tile tile = category.getTile(i); - final ComponentName tileComponent = tile.getIntent().getComponent(); - if (components.contains(tileComponent)) { - category.removeTile(i); + if (tile instanceof ProviderTile) { + final String desc = tile.getDescription(); + if (descriptions.contains(desc)) { + category.removeTile(i); + } else { + descriptions.add(desc); + } } else { - components.add(tileComponent); + final ComponentName tileComponent = tile.getIntent().getComponent(); + if (components.contains(tileComponent)) { + category.removeTile(i); + } else { + components.add(tileComponent); + } } } } diff --git a/src/com/android/settings/dashboard/DashboardFeatureProvider.java b/src/com/android/settings/dashboard/DashboardFeatureProvider.java index 9f562a08467..8c872f0b8b0 100644 --- a/src/com/android/settings/dashboard/DashboardFeatureProvider.java +++ b/src/com/android/settings/dashboard/DashboardFeatureProvider.java @@ -44,19 +44,22 @@ public interface DashboardFeatureProvider { String getDashboardKeyForTile(Tile tile); /** - * Binds preference to data provided by tile. + * Binds preference to data provided by tile and gets dynamic data observers. * * @param activity If tile contains intent to launch, it will be launched from this activity - * @param forceRoundedIcon Whether or not injected tiles from other packages should be forced to rounded icon. + * @param forceRoundedIcon Whether or not injected tiles from other packages should be forced to + * rounded icon. * @param sourceMetricsCategory The context (source) from which an action is performed * @param pref The preference to bind data * @param tile The binding data * @param key They key for preference. If null, we will generate one from tile data * @param baseOrder The order offset value. When binding, pref's order is determined by * both this value and tile's own priority. + * @return The list of dynamic data observers */ - void bindPreferenceToTile(FragmentActivity activity, boolean forceRoundedIcon, - int sourceMetricsCategory, Preference pref, Tile tile, String key, int baseOrder); + List bindPreferenceToTileAndGetObservers(FragmentActivity activity, + boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile, + String key, int baseOrder); /** * Opens a tile to its destination intent. diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java index 2cfcbe68e6d..4e541cb1c7f 100644 --- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java @@ -18,9 +18,18 @@ package com.android.settings.dashboard; import static android.content.Intent.EXTRA_USER; +import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_CHECKED_STATE; +import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR; +import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE; +import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_SUMMARY; +import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_TITLE; +import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_PROVIDER_ICON; +import static com.android.settingslib.drawer.SwitchesProvider.METHOD_IS_CHECKED; +import static com.android.settingslib.drawer.SwitchesProvider.METHOD_ON_CHECKED_CHANGED; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI; +import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE_URI; @@ -40,22 +49,26 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; +import android.widget.Toast; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.FragmentActivity; import androidx.preference.Preference; +import androidx.preference.SwitchPreference; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.dashboard.profileselector.ProfileSelectDialog; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; import com.android.settingslib.drawer.TileUtils; import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.widget.AdaptiveIcon; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -106,40 +119,54 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { } @Override - public void bindPreferenceToTile(FragmentActivity activity, boolean forceRoundedIcon, - int sourceMetricsCategory, Preference pref, Tile tile, String key, int baseOrder) { + public List bindPreferenceToTileAndGetObservers(FragmentActivity activity, + boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile, + String key, int baseOrder) { if (pref == null) { - return; + return null; } if (!TextUtils.isEmpty(key)) { pref.setKey(key); } else { pref.setKey(getDashboardKeyForTile(tile)); } - bindTitle(pref, tile); - bindSummary(pref, tile); + final List outObservers = new ArrayList<>(); + DynamicDataObserver observer = bindTitleAndGetObserver(pref, tile); + if (observer != null) { + outObservers.add(observer); + } + observer = bindSummaryAndGetObserver(pref, tile); + if (observer != null) { + outObservers.add(observer); + } + observer = bindSwitchAndGetObserver(pref, tile); + if (observer != null) { + outObservers.add(observer); + } bindIcon(pref, tile, forceRoundedIcon); - final Bundle metadata = tile.getMetaData(); - String clsName = null; - String action = null; - if (metadata != null) { - clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS); - action = metadata.getString(META_DATA_KEY_INTENT_ACTION); - } - if (!TextUtils.isEmpty(clsName)) { - pref.setFragment(clsName); - } else { - final Intent intent = new Intent(tile.getIntent()); - intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, - sourceMetricsCategory); - if (action != null) { - intent.setAction(action); + if (tile instanceof ActivityTile) { + final Bundle metadata = tile.getMetaData(); + String clsName = null; + String action = null; + if (metadata != null) { + clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS); + action = metadata.getString(META_DATA_KEY_INTENT_ACTION); + } + if (!TextUtils.isEmpty(clsName)) { + pref.setFragment(clsName); + } else { + final Intent intent = new Intent(tile.getIntent()); + intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, + sourceMetricsCategory); + if (action != null) { + intent.setAction(action); + } + pref.setOnPreferenceClickListener(preference -> { + launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory); + return true; + }); } - pref.setOnPreferenceClickListener(preference -> { - launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory); - return true; - }); } if (tile.hasOrder()) { @@ -153,6 +180,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { pref.setOrder(order + baseOrder); } } + return outObservers.isEmpty() ? null : outObservers; } @Override @@ -170,11 +198,35 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { launchIntentOrSelectProfile(activity, tile, intent, SettingsEnums.DASHBOARD_SUMMARY); } - private void bindTitle(Preference preference, Tile tile) { + private DynamicDataObserver createDynamicDataObserver(String method, Uri uri, Preference pref) { + return new DynamicDataObserver() { + @Override + public Uri getUri() { + return uri; + } + + @Override + public void onDataChanged() { + switch (method) { + case METHOD_GET_DYNAMIC_TITLE: + refreshTitle(uri, pref); + break; + case METHOD_GET_DYNAMIC_SUMMARY: + refreshSummary(uri, pref); + break; + case METHOD_IS_CHECKED: + refreshSwitch(uri, pref); + break; + } + } + }; + } + + private DynamicDataObserver bindTitleAndGetObserver(Preference preference, Tile tile) { final CharSequence title = tile.getTitle(mContext.getApplicationContext()); if (title != null) { preference.setTitle(title); - return; + return null; } if (tile.getMetaData() != null && tile.getMetaData().containsKey( META_DATA_PREFERENCE_TITLE_URI)) { @@ -182,9 +234,12 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { // to avoid preference height change. preference.setTitle(R.string.summary_placeholder); - final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_TITLE_URI); + final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_TITLE_URI, + METHOD_GET_DYNAMIC_TITLE); refreshTitle(uri, preference); + return createDynamicDataObserver(METHOD_GET_DYNAMIC_TITLE, uri, preference); } + return null; } private void refreshTitle(Uri uri, Preference preference) { @@ -196,7 +251,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { }); } - private void bindSummary(Preference preference, Tile tile) { + private DynamicDataObserver bindSummaryAndGetObserver(Preference preference, Tile tile) { final CharSequence summary = tile.getSummary(mContext); if (summary != null) { preference.setSummary(summary); @@ -206,11 +261,14 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { // to avoid preference height change. preference.setSummary(R.string.summary_placeholder); - final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_SUMMARY_URI); + final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_SUMMARY_URI, + METHOD_GET_DYNAMIC_SUMMARY); refreshSummary(uri, preference); + return createDynamicDataObserver(METHOD_GET_DYNAMIC_SUMMARY, uri, preference); } else { preference.setSummary(R.string.summary_placeholder); } + return null; } private void refreshSummary(Uri uri, Preference preference) { @@ -222,6 +280,70 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { }); } + private DynamicDataObserver bindSwitchAndGetObserver(Preference preference, Tile tile) { + if (!tile.hasSwitch()) { + return null; + } + + final Uri onCheckedChangedUri = TileUtils.getCompleteUri(tile, + META_DATA_PREFERENCE_SWITCH_URI, METHOD_ON_CHECKED_CHANGED); + preference.setOnPreferenceChangeListener((pref, newValue) -> { + onCheckedChanged(onCheckedChangedUri, pref, (boolean) newValue); + return true; + }); + + final Uri isCheckedUri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_SWITCH_URI, + METHOD_IS_CHECKED); + setSwitchEnabled(preference, false); + refreshSwitch(isCheckedUri, preference); + return createDynamicDataObserver(METHOD_IS_CHECKED, isCheckedUri, preference); + } + + private void onCheckedChanged(Uri uri, Preference pref, boolean checked) { + setSwitchEnabled(pref, false); + ThreadUtils.postOnBackgroundThread(() -> { + final Map providerMap = new ArrayMap<>(); + final Bundle result = TileUtils.putBooleanToUri(mContext, uri, providerMap, + EXTRA_SWITCH_CHECKED_STATE, checked); + + ThreadUtils.postOnMainThread(() -> { + setSwitchEnabled(pref, true); + final boolean error = result.getBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR); + if (!error) { + return; + } + + setSwitchChecked(pref, !checked); + final String errorMsg = result.getString(EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE); + if (!TextUtils.isEmpty(errorMsg)) { + Toast.makeText(mContext, errorMsg, Toast.LENGTH_SHORT).show(); + } + }); + }); + } + + private void refreshSwitch(Uri uri, Preference preference) { + ThreadUtils.postOnBackgroundThread(() -> { + final Map providerMap = new ArrayMap<>(); + final boolean checked = TileUtils.getBooleanFromUri(mContext, uri, providerMap, + EXTRA_SWITCH_CHECKED_STATE); + ThreadUtils.postOnMainThread(() -> { + setSwitchChecked(preference, checked); + setSwitchEnabled(preference, true); + }); + }); + } + + private void setSwitchChecked(Preference pref, boolean checked) { + if (pref instanceof SwitchPreference) { + ((SwitchPreference) pref).setChecked(checked); + } + } + + private void setSwitchEnabled(Preference pref, boolean enabled) { + pref.setEnabled(enabled); + } + @VisibleForTesting void bindIcon(Preference preference, Tile tile, boolean forceRoundedIcon) { // Use preference context instead here when get icon from Tile, as we are using the context @@ -246,7 +368,8 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { packageName = intent.getComponent().getPackageName(); } final Map providerMap = new ArrayMap<>(); - final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_ICON_URI); + final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_ICON_URI, + METHOD_GET_PROVIDER_ICON); final Pair iconInfo = TileUtils.getIconFromUri( mContext, packageName, uri, providerMap); if (iconInfo == null) { diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java index 3575b7293db..30d6df38aa2 100644 --- a/src/com/android/settings/dashboard/DashboardFragment.java +++ b/src/com/android/settings/dashboard/DashboardFragment.java @@ -17,11 +17,11 @@ package com.android.settings.dashboard; import android.app.Activity; import android.app.settings.SettingsEnums; +import android.content.ContentResolver; import android.content.Context; import android.os.Bundle; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.Log; import androidx.annotation.CallSuper; @@ -30,6 +30,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; @@ -41,6 +42,7 @@ import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.drawer.DashboardCategory; +import com.android.settingslib.drawer.ProviderTile; import com.android.settingslib.drawer.Tile; import com.android.settingslib.search.Indexable; @@ -49,7 +51,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.Objects; /** * Base fragment for dashboard style UI containing a list of static and dynamic setting items. @@ -60,9 +62,11 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment BasePreferenceController.UiBlockListener { private static final String TAG = "DashboardFragment"; + @VisibleForTesting + final ArrayMap> mDashboardTilePrefKeys = new ArrayMap<>(); private final Map> mPreferenceControllers = new ArrayMap<>(); - private final Set mDashboardTilePrefKeys = new ArraySet<>(); + private final List mRegisteredObservers = new ArrayList<>(); private final List mControllers = new ArrayList<>(); private DashboardFeatureProvider mDashboardFeatureProvider; @@ -171,6 +175,15 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment mListeningToCategoryChange = true; ((SettingsBaseActivity) activity).addCategoryListener(this); } + final ContentResolver resolver = getContentResolver(); + mDashboardTilePrefKeys.values().stream() + .filter(Objects::nonNull) + .flatMap(List::stream) + .forEach(observer -> { + if (!mRegisteredObservers.contains(observer)) { + registerDynamicDataObserver(resolver, observer); + } + }); } @Override @@ -200,6 +213,7 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment @Override public void onStop() { super.onStop(); + unregisterDynamicDataObservers(new ArrayList<>(mRegisteredObservers)); if (mListeningToCategoryChange) { final Activity activity = getActivity(); if (activity instanceof SettingsBaseActivity) { @@ -325,7 +339,7 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment * Refresh all preference items, including both static prefs from xml, and dynamic items from * DashboardCategory. */ - private void refreshAllPreferences(final String TAG) { + private void refreshAllPreferences(final String tag) { final PreferenceScreen screen = getPreferenceScreen(); // First remove old preferences. if (screen != null) { @@ -336,11 +350,11 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment // Add resource based tiles. displayResourceTiles(); - refreshDashboardTiles(TAG); + refreshDashboardTiles(tag); final Activity activity = getActivity(); if (activity != null) { - Log.d(TAG, "All preferences added, reporting fully drawn"); + Log.d(tag, "All preferences added, reporting fully drawn"); activity.reportFullyDrawn(); } @@ -371,59 +385,62 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment /** * Refresh preference items backed by DashboardCategory. */ - @VisibleForTesting - void refreshDashboardTiles(final String TAG) { + private void refreshDashboardTiles(final String tag) { final PreferenceScreen screen = getPreferenceScreen(); final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory(getCategoryKey()); if (category == null) { - Log.d(TAG, "NO dashboard tiles for " + TAG); + Log.d(tag, "NO dashboard tiles for " + tag); return; } final List tiles = category.getTiles(); if (tiles == null) { - Log.d(TAG, "tile list is empty, skipping category " + category.key); + Log.d(tag, "tile list is empty, skipping category " + category.key); return; } // Create a list to track which tiles are to be removed. - final List remove = new ArrayList<>(mDashboardTilePrefKeys); + final Map> remove = new ArrayMap(mDashboardTilePrefKeys); // Install dashboard tiles. final boolean forceRoundedIcons = shouldForceRoundedIcon(); for (Tile tile : tiles) { final String key = mDashboardFeatureProvider.getDashboardKeyForTile(tile); if (TextUtils.isEmpty(key)) { - Log.d(TAG, "tile does not contain a key, skipping " + tile); + Log.d(tag, "tile does not contain a key, skipping " + tile); continue; } if (!displayTile(tile)) { continue; } - if (mDashboardTilePrefKeys.contains(key)) { + if (mDashboardTilePrefKeys.containsKey(key)) { // Have the key already, will rebind. final Preference preference = screen.findPreference(key); - mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), forceRoundedIcons, - getMetricsCategory(), preference, tile, key, + mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(), + forceRoundedIcons, getMetricsCategory(), preference, tile, key, mPlaceholderPreferenceController.getOrder()); } else { // Don't have this key, add it. - final Preference pref = new Preference(getPrefContext()); - mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), forceRoundedIcons, - getMetricsCategory(), pref, tile, key, - mPlaceholderPreferenceController.getOrder()); + final Preference pref = createPreference(tile); + final List observers = + mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(), + forceRoundedIcons, getMetricsCategory(), pref, tile, key, + mPlaceholderPreferenceController.getOrder()); screen.addPreference(pref); - mDashboardTilePrefKeys.add(key); + registerDynamicDataObservers(observers); + mDashboardTilePrefKeys.put(key, observers); } remove.remove(key); } // Finally remove tiles that are gone. - for (String key : remove) { + for (Map.Entry> entry : remove.entrySet()) { + final String key = entry.getKey(); mDashboardTilePrefKeys.remove(key); final Preference preference = screen.findPreference(key); if (preference != null) { screen.removePreference(preference); } + unregisterDynamicDataObservers(entry.getValue()); } } @@ -431,4 +448,41 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment public void onBlockerWorkFinished(BasePreferenceController controller) { mBlockerController.countDown(controller.getPreferenceKey()); } + + @VisibleForTesting + Preference createPreference(Tile tile) { + return tile instanceof ProviderTile + ? new SwitchPreference(getPrefContext()) + : new Preference(getPrefContext()); + } + + @VisibleForTesting + void registerDynamicDataObservers(List observers) { + if (observers == null || observers.isEmpty()) { + return; + } + final ContentResolver resolver = getContentResolver(); + observers.forEach(observer -> registerDynamicDataObserver(resolver, observer)); + } + + private void registerDynamicDataObserver(ContentResolver resolver, + DynamicDataObserver observer) { + Log.d(TAG, "register observer: @" + Integer.toHexString(observer.hashCode()) + + ", uri: " + observer.getUri()); + resolver.registerContentObserver(observer.getUri(), false, observer); + mRegisteredObservers.add(observer); + } + + private void unregisterDynamicDataObservers(List observers) { + if (observers == null || observers.isEmpty()) { + return; + } + final ContentResolver resolver = getContentResolver(); + observers.forEach(observer -> { + Log.d(TAG, "unregister observer: @" + Integer.toHexString(observer.hashCode()) + + ", uri: " + observer.getUri()); + mRegisteredObservers.remove(observer); + resolver.unregisterContentObserver(observer); + }); + } } diff --git a/src/com/android/settings/dashboard/DynamicDataObserver.java b/src/com/android/settings/dashboard/DynamicDataObserver.java new file mode 100644 index 00000000000..f5299be4168 --- /dev/null +++ b/src/com/android/settings/dashboard/DynamicDataObserver.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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.dashboard; + +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; + +/** + * Observer for updating injected dynamic data. + */ +public abstract class DynamicDataObserver extends ContentObserver { + + protected DynamicDataObserver() { + super(new Handler(Looper.getMainLooper())); + } + + /** Returns the uri of the callback. */ + public abstract Uri getUri(); + + /** Called when data changes. */ + public abstract void onDataChanged(); + + @Override + public void onChange(boolean selfChange) { + onDataChanged(); + } +} diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml index 0dec65f2090..679062beb8e 100644 --- a/tests/robotests/res/values-mcc999/config.xml +++ b/tests/robotests/res/values-mcc999/config.xml @@ -92,5 +92,6 @@ injected_tile_key + injected_tile_key2 diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java index 03c5de30f23..a827284a088 100644 --- a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java @@ -151,9 +151,9 @@ public class AccountDetailDashboardFragmentTest { final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class); final Preference preference = new Preference(mContext); - dashboardFeatureProvider.bindPreferenceToTile(activity, false /* forceRoundedIcon */, - MetricsProto.MetricsEvent.DASHBOARD_SUMMARY, preference, tile, null /* key */, - Preference.DEFAULT_ORDER); + dashboardFeatureProvider.bindPreferenceToTileAndGetObservers(activity, + false /* forceRoundedIcon */, MetricsProto.MetricsEvent.DASHBOARD_SUMMARY, + preference, tile, null /* key */, Preference.DEFAULT_ORDER); assertThat(preference.getKey()).isEqualTo(tile.getKey(mContext)); preference.performClick(); diff --git a/tests/robotests/src/com/android/settings/dashboard/CategoryManagerTest.java b/tests/robotests/src/com/android/settings/dashboard/CategoryManagerTest.java index 1efaed9a367..64eaad50b66 100644 --- a/tests/robotests/src/com/android/settings/dashboard/CategoryManagerTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/CategoryManagerTest.java @@ -18,18 +18,21 @@ package com.android.settings.dashboard; import static com.android.settingslib.drawer.CategoryKey.CATEGORY_HOMEPAGE; import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER; +import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT; import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.ProviderInfo; import android.os.Bundle; import android.util.Pair; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; +import com.android.settingslib.drawer.ProviderTile; import com.android.settingslib.drawer.Tile; import org.junit.Before; @@ -132,25 +135,9 @@ public class CategoryManagerTest { // Create some fake tiles that are not sorted. final String testPackage = "com.android.test"; final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE); - final ActivityInfo activityInfo1 = new ActivityInfo(); - activityInfo1.metaData = new Bundle(); - activityInfo1.metaData.putInt(META_DATA_KEY_ORDER, 100); - activityInfo1.packageName = testPackage; - activityInfo1.name = "class1"; - final ActivityInfo activityInfo2 = new ActivityInfo(); - activityInfo2.metaData = new Bundle(); - activityInfo2.metaData.putInt(META_DATA_KEY_ORDER, 50); - activityInfo2.packageName = testPackage; - activityInfo2.name = "class2"; - final ActivityInfo activityInfo3 = new ActivityInfo(); - activityInfo3.metaData = new Bundle(); - activityInfo3.metaData.putInt(META_DATA_KEY_ORDER, 200); - activityInfo3.packageName = testPackage; - activityInfo3.name = "class3"; - final Tile tile1 = new ActivityTile(activityInfo1, category.key); - final Tile tile2 = new ActivityTile(activityInfo2, category.key); - final Tile tile3 = new ActivityTile(activityInfo3, category.key); - + final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 100); + final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 50); + final Tile tile3 = createActivityTile(category.key, testPackage, "class3", 200); category.addTile(tile1); category.addTile(tile2); category.addTile(tile3); @@ -171,25 +158,9 @@ public class CategoryManagerTest { final String testPackage1 = "com.android.test1"; final String testPackage2 = "com.android.test2"; final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE); - final ActivityInfo activityInfo1 = new ActivityInfo(); - activityInfo1.metaData = new Bundle(); - activityInfo1.metaData.putInt(META_DATA_KEY_ORDER, 100); - activityInfo1.packageName = testPackage2; - activityInfo1.name = "class1"; - final ActivityInfo activityInfo2 = new ActivityInfo(); - activityInfo2.metaData = new Bundle(); - activityInfo2.metaData.putInt(META_DATA_KEY_ORDER, 100); - activityInfo2.packageName = testPackage1; - activityInfo2.name = "class2"; - final ActivityInfo activityInfo3 = new ActivityInfo(); - activityInfo3.metaData = new Bundle(); - activityInfo3.metaData.putInt(META_DATA_KEY_ORDER, 50); - activityInfo3.packageName = testPackage1; - activityInfo3.name = "class3"; - - final Tile tile1 = new ActivityTile(activityInfo1, category.key); - final Tile tile2 = new ActivityTile(activityInfo2, category.key); - final Tile tile3 = new ActivityTile(activityInfo3, category.key); + final Tile tile1 = createActivityTile(category.key, testPackage2, "class1", 100); + final Tile tile2 = createActivityTile(category.key, testPackage1, "class2", 100); + final Tile tile3 = createActivityTile(category.key, testPackage1, "class3", 50); category.addTile(tile1); category.addTile(tile2); category.addTile(tile3); @@ -209,24 +180,9 @@ public class CategoryManagerTest { // Create some fake tiles that are not sorted. final String testPackage = mContext.getPackageName(); final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE); - final ActivityInfo activityInfo1 = new ActivityInfo(); - activityInfo1.packageName = testPackage; - activityInfo1.name = "class1"; - activityInfo1.metaData = new Bundle(); - activityInfo1.metaData.putInt(META_DATA_KEY_ORDER, 100); - final ActivityInfo activityInfo2 = new ActivityInfo(); - activityInfo2.packageName = testPackage; - activityInfo2.name = "class2"; - activityInfo2.metaData = new Bundle(); - activityInfo2.metaData.putInt(META_DATA_KEY_ORDER, 100); - final ActivityInfo activityInfo3 = new ActivityInfo(); - activityInfo3.packageName = testPackage; - activityInfo3.name = "class3"; - activityInfo3.metaData = new Bundle(); - activityInfo3.metaData.putInt(META_DATA_KEY_ORDER, 50); - final Tile tile1 = new ActivityTile(activityInfo1, category.key); - final Tile tile2 = new ActivityTile(activityInfo2, category.key); - final Tile tile3 = new ActivityTile(activityInfo3, category.key); + final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 100); + final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 100); + final Tile tile3 = createActivityTile(category.key, testPackage, "class3", 50); category.addTile(tile1); category.addTile(tile2); category.addTile(tile3); @@ -247,32 +203,10 @@ public class CategoryManagerTest { final String testPackage = mContext.getPackageName(); final String testPackage2 = "com.google.test2"; final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE); - - final ActivityInfo activityInfo1 = new ActivityInfo(); - activityInfo1.packageName = testPackage; - activityInfo1.name = "class1"; - activityInfo1.metaData = new Bundle(); - activityInfo1.metaData.putInt(META_DATA_KEY_ORDER, 2); - final ActivityInfo activityInfo2 = new ActivityInfo(); - activityInfo2.packageName = testPackage; - activityInfo2.name = "class2"; - activityInfo2.metaData = new Bundle(); - activityInfo2.metaData.putInt(META_DATA_KEY_ORDER, 1); - final ActivityInfo activityInfo3 = new ActivityInfo(); - activityInfo3.packageName = testPackage2; - activityInfo3.name = "class0"; - activityInfo3.metaData = new Bundle(); - activityInfo3.metaData.putInt(META_DATA_KEY_ORDER, 0); - final ActivityInfo activityInfo4 = new ActivityInfo(); - activityInfo4.packageName = testPackage; - activityInfo4.name = "class3"; - activityInfo4.metaData = new Bundle(); - activityInfo4.metaData.putInt(META_DATA_KEY_ORDER, -1); - - final Tile tile1 = new ActivityTile(activityInfo1, category.key); - final Tile tile2 = new ActivityTile(activityInfo2, category.key); - final Tile tile4 = new ActivityTile(activityInfo4, category.key); - final Tile tile3 = new ActivityTile(activityInfo3, category.key); + final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 2); + final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 1); + final Tile tile3 = createActivityTile(category.key, testPackage2, "class0", 0); + final Tile tile4 = createActivityTile(category.key, testPackage, "class3", -1); category.addTile(tile1); category.addTile(tile2); category.addTile(tile3); @@ -296,24 +230,9 @@ public class CategoryManagerTest { final String testPackage2 = "com.google.test2"; final String testPackage3 = "com.abcde.test3"; final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE); - final ActivityInfo activityInfo1 = new ActivityInfo(); - activityInfo1.packageName = testPackage2; - activityInfo1.name = "class1"; - activityInfo1.metaData = new Bundle(); - activityInfo1.metaData.putInt(META_DATA_KEY_ORDER, 1); - final ActivityInfo activityInfo2 = new ActivityInfo(); - activityInfo2.packageName = testPackage; - activityInfo2.name = "class2"; - activityInfo2.metaData = new Bundle(); - activityInfo2.metaData.putInt(META_DATA_KEY_ORDER, 1); - final ActivityInfo activityInfo3 = new ActivityInfo(); - activityInfo3.packageName = testPackage3; - activityInfo3.name = "class3"; - activityInfo3.metaData = new Bundle(); - activityInfo3.metaData.putInt(META_DATA_KEY_ORDER, 1); - final Tile tile1 = new ActivityTile(activityInfo1, category.key); - final Tile tile2 = new ActivityTile(activityInfo2, category.key); - final Tile tile3 = new ActivityTile(activityInfo3, category.key); + final Tile tile1 = createActivityTile(category.key, testPackage2, "class1", 1); + final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 1); + final Tile tile3 = createActivityTile(category.key, testPackage3, "class3", 1); category.addTile(tile1); category.addTile(tile2); category.addTile(tile3); @@ -333,58 +252,36 @@ public class CategoryManagerTest { // Create some unique tiles final String testPackage = mContext.getPackageName(); final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE); - final ActivityInfo activityInfo1 = new ActivityInfo(); - activityInfo1.packageName = testPackage; - activityInfo1.name = "class1"; - activityInfo1.metaData = new Bundle(); - activityInfo1.metaData.putInt(META_DATA_KEY_ORDER, 100); - final ActivityInfo activityInfo2 = new ActivityInfo(); - activityInfo2.packageName = testPackage; - activityInfo2.name = "class2"; - activityInfo2.metaData = new Bundle(); - activityInfo2.metaData.putInt(META_DATA_KEY_ORDER, 100); - final ActivityInfo activityInfo3 = new ActivityInfo(); - activityInfo3.packageName = testPackage; - activityInfo3.name = "class3"; - activityInfo3.metaData = new Bundle(); - activityInfo3.metaData.putInt(META_DATA_KEY_ORDER, 50); - final Tile tile1 = new ActivityTile(activityInfo1, category.key); - final Tile tile2 = new ActivityTile(activityInfo2, category.key); - final Tile tile3 = new ActivityTile(activityInfo3, category.key); + final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 100); + final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 100); + final Tile tile3 = createActivityTile(category.key, testPackage, "class3", 50); + final Tile tile4 = createProviderTile(category.key, testPackage, "class1", "authority1", + "key1", 100); + final Tile tile5 = createProviderTile(category.key, testPackage, "class1", "authority2", + "key2", 100); + final Tile tile6 = createProviderTile(category.key, testPackage, "class1", "authority1", + "key2", 50); category.addTile(tile1); category.addTile(tile2); category.addTile(tile3); + category.addTile(tile4); + category.addTile(tile5); + category.addTile(tile6); mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category); mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap); - assertThat(category.getTilesCount()).isEqualTo(3); + assertThat(category.getTilesCount()).isEqualTo(6); } @Test - public void filterTiles_hasDuplicate_shouldOnlyKeepUniqueTiles() { + public void filterTiles_hasDuplicateActivityTiles_shouldOnlyKeepUniqueTiles() { // Create tiles pointing to same intent. final String testPackage = mContext.getPackageName(); final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE); - final ActivityInfo activityInfo1 = new ActivityInfo(); - activityInfo1.packageName = testPackage; - activityInfo1.name = "class1"; - activityInfo1.metaData = new Bundle(); - activityInfo1.metaData.putInt(META_DATA_KEY_ORDER, 100); - final ActivityInfo activityInfo2 = new ActivityInfo(); - activityInfo2.packageName = testPackage; - activityInfo2.name = "class1"; - activityInfo2.metaData = new Bundle(); - activityInfo2.metaData.putInt(META_DATA_KEY_ORDER, 100); - final ActivityInfo activityInfo3 = new ActivityInfo(); - activityInfo3.packageName = testPackage; - activityInfo3.name = "class1"; - activityInfo3.metaData = new Bundle(); - activityInfo3.metaData.putInt(META_DATA_KEY_ORDER, 50); - - final Tile tile1 = new ActivityTile(activityInfo1, category.key); - final Tile tile2 = new ActivityTile(activityInfo2, category.key); - final Tile tile3 = new ActivityTile(activityInfo3, category.key); + final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 100); + final Tile tile2 = createActivityTile(category.key, testPackage, "class1", 100); + final Tile tile3 = createActivityTile(category.key, testPackage, "class1", 50); category.addTile(tile1); category.addTile(tile2); category.addTile(tile3); @@ -394,4 +291,47 @@ public class CategoryManagerTest { assertThat(category.getTilesCount()).isEqualTo(1); } + + @Test + public void filterTiles_hasDuplicateProviderTiles_shouldOnlyKeepUniqueTiles() { + // Create tiles pointing to same authority and key. + final String testPackage = mContext.getPackageName(); + final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE); + final Tile tile1 = createProviderTile(category.key, testPackage, "class1", "authority1", + "key1", 100); + final Tile tile2 = createProviderTile(category.key, testPackage, "class2", "authority1", + "key1", 100); + final Tile tile3 = createProviderTile(category.key, testPackage, "class3", "authority1", + "key1", 50); + category.addTile(tile1); + category.addTile(tile2); + category.addTile(tile3); + mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category); + + mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap); + + assertThat(category.getTilesCount()).isEqualTo(1); + } + + private Tile createActivityTile(String categoryKey, String packageName, String className, + int order) { + final ActivityInfo activityInfo = new ActivityInfo(); + activityInfo.packageName = packageName; + activityInfo.name = className; + activityInfo.metaData = new Bundle(); + activityInfo.metaData.putInt(META_DATA_KEY_ORDER, order); + return new ActivityTile(activityInfo, categoryKey); + } + + private Tile createProviderTile(String categoryKey, String packageName, String className, + String authority, String key, int order) { + final ProviderInfo providerInfo = new ProviderInfo(); + final Bundle metaData = new Bundle(); + providerInfo.packageName = packageName; + providerInfo.name = className; + providerInfo.authority = authority; + metaData.putString(META_DATA_PREFERENCE_KEYHINT, key); + metaData.putInt(META_DATA_KEY_ORDER, order); + return new ProviderTile(providerInfo, categoryKey, metaData); + } } diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java index 7dafd0738e6..14fd2840e88 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java @@ -18,10 +18,12 @@ package com.android.settings.dashboard; import static android.content.Intent.EXTRA_USER; +import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR; import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER; import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY; +import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE; import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL; import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY; @@ -43,6 +45,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.drawable.Icon; @@ -52,6 +55,7 @@ import android.os.UserManager; import androidx.fragment.app.FragmentActivity; import androidx.preference.Preference; +import androidx.preference.SwitchPreference; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; @@ -62,6 +66,7 @@ import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.CategoryKey; +import com.android.settingslib.drawer.ProviderTile; import com.android.settingslib.drawer.Tile; import com.android.settingslib.drawer.TileUtils; @@ -81,11 +86,15 @@ import org.robolectric.shadows.ShadowActivity; import org.robolectric.util.ReflectionHelpers; import java.util.ArrayList; +import java.util.List; @RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowUserManager.class) public class DashboardFeatureProviderImplTest { + private static final String KEY = "key"; + private static final String SWITCH_URI = "content://com.android.settings/tile_switch"; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private FragmentActivity mActivity; @Mock(answer = Answers.RETURNS_DEEP_STUBS) @@ -96,6 +105,8 @@ public class DashboardFeatureProviderImplTest { private Context mContext; private ActivityInfo mActivityInfo; + private ProviderInfo mProviderInfo; + private Bundle mSwitchMetaData; private DashboardFeatureProviderImpl mImpl; private boolean mForceRoundedIcon; @@ -112,6 +123,17 @@ public class DashboardFeatureProviderImplTest { mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label); mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.about_settings_summary); + + mProviderInfo = new ProviderInfo(); + mProviderInfo.packageName = mContext.getPackageName(); + mProviderInfo.name = "provider"; + mProviderInfo.authority = "com.android.settings"; + mSwitchMetaData = new Bundle(); + mSwitchMetaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label); + mSwitchMetaData.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.about_settings_summary); + mSwitchMetaData.putString(META_DATA_PREFERENCE_KEYHINT, KEY); + mSwitchMetaData.putString(META_DATA_PREFERENCE_SWITCH_URI, SWITCH_URI); + doReturn(mPackageManager).when(mContext).getPackageManager(); when(mPackageManager.resolveActivity(any(Intent.class), anyInt())) .thenReturn(new ResolveInfo()); @@ -132,8 +154,8 @@ public class DashboardFeatureProviderImplTest { doReturn(Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565))) .when(tile).getIcon(any(Context.class)); mActivityInfo.metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, "HI"); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES, - preference, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER); assertThat(preference.getTitle()).isEqualTo(mContext.getText(R.string.settings_label)); assertThat(preference.getSummary()) @@ -144,14 +166,35 @@ public class DashboardFeatureProviderImplTest { assertThat(preference.getOrder()).isEqualTo(tile.getOrder()); } + @Test + public void bindPreference_shouldBindAllSwitchData() { + final Preference preference = new SwitchPreference(RuntimeEnvironment.application); + final Tile tile = spy(new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, + mSwitchMetaData)); + mSwitchMetaData.putInt(META_DATA_KEY_ORDER, 10); + doReturn(Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565))) + .when(tile).getIcon(any(Context.class)); + final List observers = mImpl.bindPreferenceToTileAndGetObservers( + mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES, preference, tile, + null /* key*/, Preference.DEFAULT_ORDER); + + assertThat(preference.getTitle()).isEqualTo(mContext.getText(R.string.settings_label)); + assertThat(preference.getSummary()) + .isEqualTo(mContext.getText(R.string.about_settings_summary)); + assertThat(preference.getKey()).isEqualTo(KEY); + assertThat(preference.getIcon()).isNotNull(); + assertThat(preference.getOrder()).isEqualTo(tile.getOrder()); + assertThat(observers.get(0).getUri().toString()).isEqualTo(SWITCH_URI); + } + @Test public void bindPreference_noFragmentMetadata_shouldBindIntent() { final Preference preference = new Preference(RuntimeEnvironment.application); mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10); final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES, - preference, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER); assertThat(preference.getFragment()).isNull(); assertThat(preference.getOnPreferenceClickListener()).isNotNull(); @@ -166,8 +209,8 @@ public class DashboardFeatureProviderImplTest { tile.userHandle.add(mock(UserHandle.class)); tile.userHandle.add(mock(UserHandle.class)); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES, - preference, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER); preference.getOnPreferenceClickListener().onPreferenceClick(null); verify(mActivity).getSupportFragmentManager(); @@ -183,8 +226,8 @@ public class DashboardFeatureProviderImplTest { when(mActivity.getSystemService(Context.USER_SERVICE)) .thenReturn(mUserManager); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES, - preference, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER); preference.getOnPreferenceClickListener().onPreferenceClick(null); verify(mFeatureFactory.metricsFeatureProvider).logDashboardStartIntent( @@ -203,8 +246,8 @@ public class DashboardFeatureProviderImplTest { tile.userHandle = new ArrayList<>(); tile.userHandle.add(mock(UserHandle.class)); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES, - preference, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER); preference.getOnPreferenceClickListener().onPreferenceClick(null); verify(mFeatureFactory.metricsFeatureProvider).logDashboardStartIntent( any(Context.class), @@ -217,8 +260,8 @@ public class DashboardFeatureProviderImplTest { @Test public void bindPreference_nullPreference_shouldIgnore() { final Tile tile = mock(Tile.class); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, - null, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.VIEW_UNKNOWN, null, tile, "123", Preference.DEFAULT_ORDER); verifyZeroInteractions(tile); } @@ -227,8 +270,9 @@ public class DashboardFeatureProviderImplTest { public void bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority() { final Preference preference = new Preference(RuntimeEnvironment.application); final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, - preference, tile, null /*key */, Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */, + Preference.DEFAULT_ORDER); assertThat(preference.getKey()).isNotNull(); assertThat(preference.getOrder()).isEqualTo(Preference.DEFAULT_ORDER); @@ -241,8 +285,9 @@ public class DashboardFeatureProviderImplTest { final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, - preference, tile, null /*key */, Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */, + Preference.DEFAULT_ORDER); assertThat(preference.getSummary()) .isEqualTo(RuntimeEnvironment.application.getString(R.string.summary_placeholder)); @@ -250,30 +295,99 @@ public class DashboardFeatureProviderImplTest { @Test @Config(shadows = {ShadowTileUtils.class}) - public void bindPreference_hasSummaryUri_shouldLoadSummaryFromContentProvider() { + public void bindPreference_hasSummaryUri_shouldLoadSummaryFromContentProviderAndHaveObserver() { final Preference preference = new Preference(RuntimeEnvironment.application); final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); - mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, - "content://com.android.settings/tile_summary"); + final String uriString = "content://com.android.settings/tile_summary"; + mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, uriString); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, - preference, tile, null /*key */, Preference.DEFAULT_ORDER); + final List observers = mImpl.bindPreferenceToTileAndGetObservers( + mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, preference, tile, + null /*key */, Preference.DEFAULT_ORDER); assertThat(preference.getSummary()).isEqualTo(ShadowTileUtils.MOCK_SUMMARY); + assertThat(observers.get(0).getUri().toString()).isEqualTo(uriString); } @Test @Config(shadows = {ShadowTileUtils.class}) - public void bindPreference_hasTitleUri_shouldLoadFromContentProvider() { + public void bindPreference_hasTitleUri_shouldLoadFromContentProviderAndHaveObserver() { final Preference preference = new Preference(RuntimeEnvironment.application); final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); - mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE_URI, - "content://com.android.settings/tile_title"); + final String uriString = "content://com.android.settings/tile_title"; + mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE_URI, uriString); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, - preference, tile, null /*key */, Preference.DEFAULT_ORDER); + final List observers = mImpl.bindPreferenceToTileAndGetObservers( + mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, preference, tile, + null /*key */, Preference.DEFAULT_ORDER); assertThat(preference.getTitle()).isEqualTo(ShadowTileUtils.MOCK_SUMMARY); + assertThat(observers.get(0).getUri().toString()).isEqualTo(uriString); + } + + @Test + @Config(shadows = {ShadowTileUtils.class}) + public void bindPreference_onCheckedChanged_shouldPutStateToContentProvider() { + final SwitchPreference preference = new SwitchPreference(RuntimeEnvironment.application); + final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, + mSwitchMetaData); + final Bundle bundle = new Bundle(); + bundle.putBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR, false); + ShadowTileUtils.setResultBundle(bundle); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */, + Preference.DEFAULT_ORDER); + + preference.callChangeListener(false); + + assertThat(ShadowTileUtils.getProviderChecked()).isFalse(); + + preference.callChangeListener(true); + + assertThat(ShadowTileUtils.getProviderChecked()).isTrue(); + } + + @Test + @Config(shadows = {ShadowTileUtils.class}) + public void bindPreference_onCheckedChangedError_shouldRevertCheckedState() { + final SwitchPreference preference = new SwitchPreference(RuntimeEnvironment.application); + final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, + mSwitchMetaData); + final Bundle bundle = new Bundle(); + bundle.putBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR, true); + ShadowTileUtils.setResultBundle(bundle); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */, + Preference.DEFAULT_ORDER); + + preference.callChangeListener(true); + + assertThat(preference.isChecked()).isFalse(); + + preference.callChangeListener(false); + + assertThat(preference.isChecked()).isTrue(); + } + + @Test + @Config(shadows = {ShadowTileUtils.class}) + public void bindPreference_callbackOnChanged_shouldLoadFromContentProvider() { + final SwitchPreference preference = new SwitchPreference(RuntimeEnvironment.application); + final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, + mSwitchMetaData); + final List observers = mImpl.bindPreferenceToTileAndGetObservers( + mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, preference, tile, + null /*key */, Preference.DEFAULT_ORDER); + + ShadowTileUtils.setProviderChecked(false); + observers.get(0).onDataChanged(); + + assertThat(preference.isChecked()).isFalse(); + + ShadowTileUtils.setProviderChecked(true); + observers.get(0).onDataChanged(); + + assertThat(preference.isChecked()).isTrue(); } @Test @@ -281,8 +395,9 @@ public class DashboardFeatureProviderImplTest { final Preference preference = new Preference(RuntimeEnvironment.application); mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key"); final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, - preference, tile, null /* key */, Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.VIEW_UNKNOWN, preference, tile, null /* key */, + Preference.DEFAULT_ORDER); assertThat(preference.getKey()).isEqualTo(tile.getKey(mContext)); } @@ -308,8 +423,8 @@ public class DashboardFeatureProviderImplTest { mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10); final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, - preference, tile, "123", baseOrder); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.VIEW_UNKNOWN, preference, tile, "123", baseOrder); assertThat(preference.getOrder()).isEqualTo(tile.getOrder() + baseOrder); } @@ -321,8 +436,8 @@ public class DashboardFeatureProviderImplTest { mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10); final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, testOrder); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, - preference, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.VIEW_UNKNOWN, preference, tile, "123", Preference.DEFAULT_ORDER); assertThat(preference.getOrder()).isEqualTo(testOrder); } @@ -333,8 +448,8 @@ public class DashboardFeatureProviderImplTest { final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); mActivityInfo.metaData.putString(META_DATA_KEY_ORDER, "hello"); - mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, - preference, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, + MetricsEvent.VIEW_UNKNOWN, preference, tile, "123", Preference.DEFAULT_ORDER); assertThat(preference.getOrder()).isEqualTo(Preference.DEFAULT_ORDER); } @@ -347,8 +462,8 @@ public class DashboardFeatureProviderImplTest { mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key"); mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction"); tile.userHandle = null; - mImpl.bindPreferenceToTile(activity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES, - preference, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(activity, mForceRoundedIcon, + MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER); preference.performClick(); ShadowActivity shadowActivity = Shadows.shadowOf(activity); @@ -371,8 +486,8 @@ public class DashboardFeatureProviderImplTest { mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction"); tile.userHandle = null; - mImpl.bindPreferenceToTile(activity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES, - preference, tile, "123", Preference.DEFAULT_ORDER); + mImpl.bindPreferenceToTileAndGetObservers(activity, mForceRoundedIcon, + MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER); preference.performClick(); final ShadowActivity.IntentForResult launchIntent = diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java index 954a872e614..146b37aa058 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java @@ -17,9 +17,11 @@ package com.android.settings.dashboard; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.DASHBOARD_CONTAINER; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT; +import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -29,14 +31,18 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.settings.SettingsEnums; +import android.content.ContentResolver; import android.content.Context; import android.content.pm.ActivityInfo; +import android.content.pm.ProviderInfo; import android.net.Uri; import android.os.Bundle; import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.core.PreferenceControllerMixin; @@ -47,7 +53,7 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.DashboardCategory; -import com.android.settingslib.drawer.Tile; +import com.android.settingslib.drawer.ProviderTile; import org.junit.Before; import org.junit.Test; @@ -57,6 +63,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; import org.robolectric.util.ReflectionHelpers; import java.util.ArrayList; @@ -70,24 +78,37 @@ public class DashboardFragmentTest { @Mock private FakeFeatureFactory mFakeFeatureFactory; - private ActivityInfo mActivityInfo; private DashboardCategory mDashboardCategory; private Context mContext; private TestFragment mTestFragment; private List mControllers; + private ActivityTile mActivityTile; + private ProviderTile mProviderTile; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - mActivityInfo = new ActivityInfo(); - mActivityInfo.packageName = "pkg"; - mActivityInfo.name = "class"; - mActivityInfo.metaData = new Bundle(); - mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "injected_tile_key"); + final ActivityInfo activityInfo = new ActivityInfo(); + activityInfo.packageName = "pkg"; + activityInfo.name = "class"; + activityInfo.metaData = new Bundle(); + activityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "injected_tile_key"); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mDashboardCategory = new DashboardCategory("key"); - mDashboardCategory.addTile(new ActivityTile(mActivityInfo, mDashboardCategory.key)); + mActivityTile = new ActivityTile(activityInfo, mDashboardCategory.key); + mDashboardCategory.addTile(mActivityTile); + + final ProviderInfo providerInfo = new ProviderInfo(); + providerInfo.packageName = "pkg"; + providerInfo.name = "provider"; + providerInfo.authority = "authority"; + final Bundle metaData = new Bundle(); + metaData.putString(META_DATA_PREFERENCE_KEYHINT, "injected_tile_key2"); + metaData.putString(META_DATA_PREFERENCE_SWITCH_URI, "uri"); + mProviderTile = new ProviderTile(providerInfo, mDashboardCategory.key, metaData); + mDashboardCategory.addTile(mProviderTile); + mTestFragment = new TestFragment(RuntimeEnvironment.application); when(mFakeFeatureFactory.dashboardFeatureProvider .getTilesForCategory(nullable(String.class))) @@ -127,11 +148,14 @@ public class DashboardFragmentTest { .getTilesForCategory(nullable(String.class))) .thenReturn(mDashboardCategory); when(mFakeFeatureFactory.dashboardFeatureProvider - .getDashboardKeyForTile(nullable(Tile.class))) + .getDashboardKeyForTile(any(ActivityTile.class))) .thenReturn("test_key"); + when(mFakeFeatureFactory.dashboardFeatureProvider + .getDashboardKeyForTile(any(ProviderTile.class))) + .thenReturn("test_key2"); mTestFragment.onCreatePreferences(new Bundle(), "rootKey"); - verify(mTestFragment.mScreen).addPreference(nullable(Preference.class)); + verify(mTestFragment.mScreen, times(2)).addPreference(nullable(Preference.class)); } @Test @@ -156,8 +180,11 @@ public class DashboardFragmentTest { .getTilesForCategory(nullable(String.class))) .thenReturn(mDashboardCategory); when(mFakeFeatureFactory.dashboardFeatureProvider - .getDashboardKeyForTile(nullable(Tile.class))) + .getDashboardKeyForTile(any(ActivityTile.class))) .thenReturn("test_key"); + when(mFakeFeatureFactory.dashboardFeatureProvider + .getDashboardKeyForTile(any(ProviderTile.class))) + .thenReturn("test_key2"); mTestFragment.onCreatePreferences(new Bundle(), "rootKey"); verify(mTestFragment.mScreen, never()).addPreference(nullable(Preference.class)); @@ -171,6 +198,29 @@ public class DashboardFragmentTest { assertThat(controller).isNotNull(); } + @Test + @Config(shadows = ShadowPreferenceFragmentCompat.class) + public void onStart_shouldRegisterDynamicDataObservers() { + final DynamicDataObserver observer = new TestDynamicDataObserver(); + mTestFragment.mDashboardTilePrefKeys.put("key", Arrays.asList(observer)); + + mTestFragment.onStart(); + + verify(mTestFragment.getContentResolver()).registerContentObserver(observer.getUri(), false, + observer); + } + + @Test + @Config(shadows = ShadowPreferenceFragmentCompat.class) + public void onStop_shouldUnregisterDynamicDataObservers() { + final DynamicDataObserver observer = new TestDynamicDataObserver(); + mTestFragment.registerDynamicDataObservers(Arrays.asList(observer)); + + mTestFragment.onStop(); + + verify(mTestFragment.getContentResolver()).unregisterContentObserver(observer); + } + @Test public void updateState_skipUnavailablePrefs() { final List preferenceControllers = mTestFragment.mControllers; @@ -266,7 +316,14 @@ public class DashboardFragmentTest { assertThat(mTestFragment.mBlockerController).isNull(); } - public static class TestPreferenceController extends AbstractPreferenceController + @Test + public void createPreference_isProviderTile_returnSwitchPreference() { + final Preference pref = mTestFragment.createPreference(mProviderTile); + + assertThat(pref).isInstanceOf(SwitchPreference.class); + } + + private static class TestPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin { private TestPreferenceController(Context context) { @@ -293,18 +350,20 @@ public class DashboardFragmentTest { } } - public static class TestFragment extends DashboardFragment { + private static class TestFragment extends DashboardFragment { + + public final PreferenceScreen mScreen; private final PreferenceManager mPreferenceManager; private final Context mContext; private final List mControllers; - - public final PreferenceScreen mScreen; + private final ContentResolver mContentResolver; public TestFragment(Context context) { mContext = context; mPreferenceManager = mock(PreferenceManager.class); mScreen = mock(PreferenceScreen.class); + mContentResolver = mock(ContentResolver.class); mControllers = new ArrayList<>(); when(mPreferenceManager.getContext()).thenReturn(mContext); @@ -346,5 +405,36 @@ public class DashboardFragmentTest { public PreferenceManager getPreferenceManager() { return mPreferenceManager; } + + @Override + protected ContentResolver getContentResolver() { + return mContentResolver; + } + } + + private static class TestDynamicDataObserver extends DynamicDataObserver { + + @Override + public Uri getUri() { + return Uri.parse("content://abc"); + } + + @Override + public void onDataChanged() { + } + } + + @Implements(PreferenceFragmentCompat.class) + public static class ShadowPreferenceFragmentCompat { + + @Implementation + public void onStart() { + // do nothing + } + + @Implementation + public void onStop() { + // do nothing + } } } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileUtils.java index e46d72fba83..e1b815ec880 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileUtils.java @@ -19,6 +19,7 @@ package com.android.settings.testutils.shadow; import android.content.Context; import android.content.IContentProvider; import android.net.Uri; +import android.os.Bundle; import android.util.Pair; import com.android.settings.R; @@ -35,6 +36,9 @@ public class ShadowTileUtils { public static final String MOCK_SUMMARY = "summary"; + private static boolean sChecked; + private static Bundle sResult; + @Implementation protected static String getTextFromUri(Context context, Uri uri, Map providerMap, String key) { @@ -46,4 +50,29 @@ public class ShadowTileUtils { Uri uri, Map providerMap) { return Pair.create(RuntimeEnvironment.application.getPackageName(), R.drawable.ic_settings_accent); } + + @Implementation + public static boolean getBooleanFromUri(Context context, Uri uri, + Map providerMap, String key) { + return sChecked; + } + + @Implementation + public static Bundle putBooleanToUri(Context context, Uri uri, + Map providerMap, String key, boolean value) { + sChecked = value; + return sResult; + } + + public static boolean getProviderChecked() { + return sChecked; + } + + public static void setProviderChecked(boolean value) { + sChecked = value; + } + + public static void setResultBundle(Bundle result) { + sResult = result; + } }