diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d04b884f426..674ab61eb27 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -136,7 +136,7 @@
android:taskAffinity="com.android.settings.root"
android:launchMode="singleTask"
android:exported="true"
- android:configChanges="keyboard|keyboardHidden|screenSize|screenLayout">
+ android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout">
@@ -228,6 +228,8 @@
+
@@ -257,6 +259,8 @@
+
@@ -314,6 +318,8 @@
+
@@ -479,6 +485,8 @@
+
@@ -489,6 +497,8 @@
android:clearTaskOnLaunch="true">
+
+
+
+
+
+
+
+
@@ -618,6 +642,8 @@
android:targetActivity="Settings$TetherSettingsActivity">
+
+
+
@@ -661,6 +691,8 @@
+
+
@@ -858,6 +892,8 @@
+
@@ -911,6 +947,8 @@
+
@@ -921,6 +959,8 @@
android:exported="true">
+
+
@@ -991,6 +1033,8 @@
android:value="com.android.settings.notification.zen.ZenModeEventRuleSettings" />
+
+
@@ -1028,6 +1074,8 @@
+
+
@@ -1065,6 +1115,8 @@
+
@@ -1088,6 +1140,8 @@
android:value="true" />
+
+
@@ -1353,6 +1409,8 @@
+
+
@@ -1629,6 +1689,8 @@
+
@@ -1644,6 +1706,8 @@
+
@@ -1697,6 +1761,8 @@
+
@@ -1715,6 +1781,8 @@
+
@@ -1729,6 +1797,8 @@
+
@@ -1743,6 +1813,8 @@
+
@@ -1757,6 +1829,8 @@
+
@@ -2429,6 +2503,8 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2821,6 +2919,8 @@
+
@@ -2835,6 +2935,8 @@
+
+
@@ -2893,6 +2997,8 @@
+
@@ -3301,6 +3407,8 @@
android:value="true" />
+
+
@@ -3362,6 +3472,8 @@
android:exported="true">
+
+
@@ -3394,6 +3508,8 @@
+
+
@@ -3577,6 +3695,8 @@
+
@@ -3722,6 +3842,8 @@
+
+
+
+
@@ -3782,7 +3910,7 @@
android:permission="android.permission.BLUETOOTH_CONNECT">
- />
+
= getMinCurrentScreenSplitWidthPx(appContext)
+ && dm.heightPixels >= getMinSmallestScreenSplitWidthPx(appContext);
+ }
}
diff --git a/src/com/android/settings/dashboard/CategoryManager.java b/src/com/android/settings/dashboard/CategoryManager.java
index 2a82abe4859..b6ec4ca3269 100644
--- a/src/com/android/settings/dashboard/CategoryManager.java
+++ b/src/com/android/settings/dashboard/CategoryManager.java
@@ -17,6 +17,7 @@ package com.android.settings.dashboard;
import android.content.ComponentName;
import android.content.Context;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -24,6 +25,7 @@ import android.util.Pair;
import androidx.annotation.VisibleForTesting;
+import com.android.settings.homepage.HighlightableMenu;
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.DashboardCategory;
@@ -153,6 +155,20 @@ public class CategoryManager {
filterDuplicateTiles(mCategoryByKeyMap);
if (firstLoading) {
logTiles(context);
+
+ final DashboardCategory homepageCategory = mCategoryByKeyMap.get(
+ CategoryKey.CATEGORY_HOMEPAGE);
+ if (homepageCategory == null) {
+ return;
+ }
+ for (Tile tile : homepageCategory.getTiles()) {
+ final String key = tile.getKey(context);
+ if (TextUtils.isEmpty(key)) {
+ Log.w(TAG, "Key hint missing for homepage tile: " + tile.getTitle(context));
+ continue;
+ }
+ HighlightableMenu.addMenuKey(key);
+ }
}
}
}
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProvider.java b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
index 8c872f0b8b0..b88ecd4240b 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProvider.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
@@ -47,9 +47,9 @@ public interface DashboardFeatureProvider {
* 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 fragment The fragment that the preference will be bound to
* @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
@@ -58,7 +58,7 @@ public interface DashboardFeatureProvider {
* @return The list of dynamic data observers
*/
List bindPreferenceToTileAndGetObservers(FragmentActivity activity,
- boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile,
+ DashboardFragment fragment, boolean forceRoundedIcon, Preference pref, Tile tile,
String key, int baseOrder);
/**
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index 27b20cf4ef7..f8185db7178 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -36,6 +36,7 @@ import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITL
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface.OnCancelListener;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -60,6 +61,7 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.dashboard.profileselector.ProfileSelectDialog;
+import com.android.settings.homepage.TopLevelSettings;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.PrimarySwitchPreference;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -123,7 +125,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
@Override
public List bindPreferenceToTileAndGetObservers(FragmentActivity activity,
- boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile,
+ DashboardFragment fragment, boolean forceRoundedIcon, Preference pref, Tile tile,
String key, int baseOrder) {
if (pref == null) {
return null;
@@ -149,6 +151,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
bindIcon(pref, tile, forceRoundedIcon);
if (tile instanceof ActivityTile) {
+ final int sourceMetricsCategory = fragment.getMetricsCategory();
final Bundle metadata = tile.getMetaData();
String clsName = null;
String action = null;
@@ -166,7 +169,17 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
intent.setAction(action);
}
pref.setOnPreferenceClickListener(preference -> {
- launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory);
+ OnCancelListener listener = null;
+ if (fragment instanceof TopLevelSettings) {
+ final TopLevelSettings topLevelSettings = (TopLevelSettings) fragment;
+ // Highlight the tile immediately whenever it's clicked
+ topLevelSettings.setHighlightPreferenceKey(key);
+ // If the tile allows users to select profile, the pop-op dialog may be
+ // cancelled and then the previous highlight entry should be restored.
+ listener = dialog -> topLevelSettings.restorePreviousHighlight();
+ }
+ launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory,
+ listener);
return true;
});
}
@@ -198,7 +211,8 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
SettingsEnums.DASHBOARD_SUMMARY)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- launchIntentOrSelectProfile(activity, tile, intent, SettingsEnums.DASHBOARD_SUMMARY);
+ launchIntentOrSelectProfile(activity, tile, intent, SettingsEnums.DASHBOARD_SUMMARY,
+ /* listener= */ null);
}
private DynamicDataObserver createDynamicDataObserver(String method, Uri uri, Preference pref) {
@@ -413,7 +427,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
}
private void launchIntentOrSelectProfile(FragmentActivity activity, Tile tile, Intent intent,
- int sourceMetricCategory) {
+ int sourceMetricCategory, OnCancelListener listener) {
if (!isIntentResolvable(intent)) {
Log.w(TAG, "Cannot resolve intent, skipping. " + intent);
return;
@@ -444,7 +458,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
}
ProfileSelectDialog.show(activity.getSupportFragmentManager(), tile,
- sourceMetricCategory);
+ sourceMetricCategory, listener);
}
}
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index dfd931db7e9..4317fc6ef40 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -496,15 +496,15 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
if (mDashboardTilePrefKeys.containsKey(key)) {
// Have the key already, will rebind.
final Preference preference = screen.findPreference(key);
- mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(),
- forceRoundedIcons, getMetricsCategory(), preference, tile, key,
+ mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(), this,
+ forceRoundedIcons, preference, tile, key,
mPlaceholderPreferenceController.getOrder());
} else {
// Don't have this key, add it.
final Preference pref = createPreference(tile);
final List observers =
mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(),
- forceRoundedIcons, getMetricsCategory(), pref, tile, key,
+ this, forceRoundedIcons, pref, tile, key,
mPlaceholderPreferenceController.getOrder());
screen.addPreference(pref);
registerDynamicDataObservers(observers);
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
index 36cdd422508..b05f23b812b 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
@@ -19,6 +19,7 @@ package com.android.settings.dashboard.profileselector;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
@@ -44,19 +45,23 @@ public class ProfileSelectDialog extends DialogFragment implements OnClickListen
private int mSourceMetricCategory;
private Tile mSelectedTile;
+ private OnCancelListener mOnCancelListener;
/**
* Display the profile select dialog, adding the fragment to the given FragmentManager.
* @param manager The FragmentManager this fragment will be added to.
* @param tile The tile for this fragment.
* @param sourceMetricCategory The source metric category.
+ * @param listener The listener listens to the dialog cancelling event.
*/
- public static void show(FragmentManager manager, Tile tile, int sourceMetricCategory) {
+ public static void show(FragmentManager manager, Tile tile, int sourceMetricCategory,
+ OnCancelListener listener) {
final ProfileSelectDialog dialog = new ProfileSelectDialog();
final Bundle args = new Bundle();
args.putParcelable(ARG_SELECTED_TILE, tile);
args.putInt(ARG_SOURCE_METRIC_CATEGORY, sourceMetricCategory);
dialog.setArguments(args);
+ dialog.mOnCancelListener = listener;
dialog.show(manager, "select_profile");
}
@@ -91,6 +96,13 @@ public class ProfileSelectDialog extends DialogFragment implements OnClickListen
getActivity().startActivityAsUser(intent, user);
}
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ if (mOnCancelListener != null) {
+ mOnCancelListener.onCancel(dialog);
+ }
+ }
+
public static void updateUserHandlesIfNeeded(Context context, Tile tile) {
final List userHandles = tile.userHandle;
if (tile.userHandle == null || tile.userHandle.size() <= 1) {
diff --git a/src/com/android/settings/homepage/HighlightableMenu.java b/src/com/android/settings/homepage/HighlightableMenu.java
new file mode 100644
index 00000000000..6a10e66dd6a
--- /dev/null
+++ b/src/com/android/settings/homepage/HighlightableMenu.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2021 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.homepage;
+
+import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_HIGHLIGHTABLE_MENU_KEY;
+import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
+
+import android.annotation.XmlRes;
+import android.content.Context;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.settings.core.PreferenceXmlParserUtils;
+import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class for mapping highlightable menu keys and preference keys
+ */
+public class HighlightableMenu {
+ private static final String TAG = "HighlightableMenu";
+
+ /**
+ * Map from highlightable menu key to preference key.
+ */
+ private static final Map MENU_TO_PREFERENCE_KEY_MAP;
+
+ /**
+ * Map from old menu key to current key string id.
+ */
+ private static final Map MENU_KEY_COMPAT_MAP;
+
+ private static boolean sXmlParsed;
+
+ static {
+ MENU_TO_PREFERENCE_KEY_MAP = new ArrayMap<>();
+ MENU_KEY_COMPAT_MAP = new ArrayMap<>();
+
+ // Manual mapping for platform compatibility, e.g.
+ // MENU_KEY_COMPAT_MAP.put("top_level_apps_and_notifs", R.string.menu_key_apps);
+ }
+
+ /** Parses the highlightable menu keys from xml */
+ public static synchronized void fromXml(Context context, @XmlRes int xmlResId) {
+ if (sXmlParsed) {
+ return;
+ }
+
+ Log.d(TAG, "parsing highlightable menu from xml");
+ final List preferenceMetadata;
+ try {
+ preferenceMetadata = PreferenceXmlParserUtils.extractMetadata(context, xmlResId,
+ MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_NEED_HIGHLIGHTABLE_MENU_KEY);
+ } catch (IOException | XmlPullParserException e) {
+ Log.e(TAG, "Failed to parse preference xml for getting highlightable menu keys", e);
+ return;
+ }
+
+ for (Bundle metadata : preferenceMetadata) {
+ final String menuKey = metadata.getString(METADATA_HIGHLIGHTABLE_MENU_KEY);
+ if (TextUtils.isEmpty(menuKey)) {
+ continue;
+ }
+ final String prefKey = metadata.getString(METADATA_KEY);
+ if (TextUtils.isEmpty(prefKey)) {
+ Log.w(TAG, "Highlightable menu requires android:key but it's missing in xml: "
+ + menuKey);
+ continue;
+ }
+ MENU_TO_PREFERENCE_KEY_MAP.put(menuKey, prefKey);
+ }
+
+ if (MENU_TO_PREFERENCE_KEY_MAP.isEmpty()) {
+ return;
+ }
+
+ sXmlParsed = true;
+ MENU_KEY_COMPAT_MAP.forEach((compatMenuKey, keyId) -> {
+ final String prefKey = lookupPreferenceKey(context.getString(keyId));
+ if (prefKey != null) {
+ MENU_TO_PREFERENCE_KEY_MAP.put(compatMenuKey, prefKey);
+ }
+ });
+ }
+
+ /** Manually adds a preference as the menu key for Injection */
+ public static synchronized void addMenuKey(String key) {
+ Log.d(TAG, "add menu key: " + key);
+ MENU_TO_PREFERENCE_KEY_MAP.put(key, key);
+ }
+
+ /** Looks up the preference key by a specified menu key */
+ public static String lookupPreferenceKey(String menuKey) {
+ return MENU_TO_PREFERENCE_KEY_MAP.get(menuKey);
+ }
+}
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 3e9b9d059f5..471b1a4d1e2 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -16,13 +16,15 @@
package com.android.settings.homepage;
+import static android.provider.Settings.ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK;
+import static android.provider.Settings.EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI;
+import static android.provider.Settings.EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY;
+
import android.animation.LayoutTransition;
import android.app.ActivityManager;
-import android.app.PendingIntent;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.FeatureFlagUtils;
@@ -36,16 +38,16 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
-import androidx.window.embedding.SplitController;
import com.android.settings.R;
import com.android.settings.Settings;
+import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.accounts.AvatarViewMixin;
-import com.android.settings.core.CategoryMixin;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
+import com.android.settings.core.CategoryMixin;
+import com.android.settings.core.FeatureFlags;
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
@@ -64,6 +66,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
// An alias class name of SettingsHomepageActivity.
public static final String ALIAS_DEEP_LINK = "com.android.settings.DeepLinkHomepageActivity";
+ private static final int DEFAULT_HIGHLIGHT_MENU_KEY = R.string.menu_key_network;
private static final long HOMEPAGE_LOADING_TIMEOUT_MS = 300;
private View mHomepageView;
@@ -120,7 +123,11 @@ public class SettingsHomepageActivity extends FragmentActivity implements
showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
}
}
- showFragment(new TopLevelSettings(), R.id.main_content);
+ final Fragment fragment = new TopLevelSettings();
+ fragment.getArguments().putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
+ getHighlightMenuKey());
+ showFragment(fragment, R.id.main_content);
+
((FrameLayout) findViewById(R.id.main_content))
.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
@@ -132,9 +139,13 @@ public class SettingsHomepageActivity extends FragmentActivity implements
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
- // When it's large screen 2-pane and Settings app is in background. Receiving a Intent
- // in this Activity will not finish nor onCreate. setIntent here for this case.
+ // When it's large screen 2-pane and Settings app is in the background, receiving an Intent
+ // will not recreate this activity. Update the intent for this case.
setIntent(intent);
+ reloadHighlightMenuKey();
+ if (isFinishing()) {
+ return;
+ }
// Launch the intent from deep link for large screen devices.
launchDeepLinkIntentToRight();
}
@@ -180,12 +191,12 @@ public class SettingsHomepageActivity extends FragmentActivity implements
final Intent intent = getIntent();
if (intent == null || !TextUtils.equals(intent.getAction(),
- android.provider.Settings.ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK)) {
+ ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK)) {
return;
}
final String intentUriString = intent.getStringExtra(
- android.provider.Settings.EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI);
+ EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI);
if (TextUtils.isEmpty(intentUriString)) {
Log.e(TAG, "No EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI to deep link");
finish();
@@ -236,6 +247,29 @@ public class SettingsHomepageActivity extends FragmentActivity implements
startActivity(targetIntent);
}
+ private String getHighlightMenuKey() {
+ final Intent intent = getIntent();
+ if (intent != null && TextUtils.equals(intent.getAction(),
+ ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK)) {
+ final String menuKey = intent.getStringExtra(
+ EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY);
+ if (!TextUtils.isEmpty(menuKey)) {
+ return menuKey;
+ }
+ }
+ return getString(DEFAULT_HIGHLIGHT_MENU_KEY);
+ }
+
+ private void reloadHighlightMenuKey() {
+ final TopLevelSettings fragment =
+ (TopLevelSettings) getSupportFragmentManager().findFragmentById(R.id.main_content);
+ if (fragment != null) {
+ fragment.getArguments().putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
+ getHighlightMenuKey());
+ fragment.reloadHighlightMenuKey();
+ }
+ }
+
private void initHomepageContainer() {
final View view = findViewById(R.id.homepage_container);
// Prevent inner RecyclerView gets focus and invokes scrolling.
diff --git a/src/com/android/settings/homepage/TopLevelSettings.java b/src/com/android/settings/homepage/TopLevelSettings.java
index 681ea5111c7..a819b870540 100644
--- a/src/com/android/settings/homepage/TopLevelSettings.java
+++ b/src/com/android/settings/homepage/TopLevelSettings.java
@@ -21,20 +21,27 @@ import static com.android.settingslib.search.SearchIndexable.MOBILE;
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;
+import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
+import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
+import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.support.SupportPreferenceController;
+import com.android.settings.widget.HighlightableTopLevelPreferenceAdapter;
import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.search.SearchIndexable;
@@ -43,6 +50,11 @@ public class TopLevelSettings extends DashboardFragment implements
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
private static final String TAG = "TopLevelSettings";
+ private static final String SAVED_HIGHLIGHTED_PREF = "highlighted_pref";
+
+ private HighlightableTopLevelPreferenceAdapter mTopLevelAdapter;
+
+ private String mHighlightedPreferenceKey;
public TopLevelSettings() {
final Bundle args = new Bundle();
@@ -69,6 +81,7 @@ public class TopLevelSettings extends DashboardFragment implements
@Override
public void onAttach(Context context) {
super.onAttach(context);
+ HighlightableMenu.fromXml(context, getPreferenceScreenResId());
use(SupportPreferenceController.class).setActivity(getActivity());
}
@@ -83,6 +96,12 @@ public class TopLevelSettings extends DashboardFragment implements
return this;
}
+ @Override
+ public boolean onPreferenceTreeClick(Preference preference) {
+ setHighlightPreferenceKey(preference.getKey());
+ return super.onPreferenceTreeClick(preference);
+ }
+
@Override
public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) {
new SubSettingLauncher(getActivity())
@@ -96,6 +115,20 @@ public class TopLevelSettings extends DashboardFragment implements
return true;
}
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ if (icicle != null) {
+ mHighlightedPreferenceKey = icicle.getString(SAVED_HIGHLIGHTED_PREF);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(SAVED_HIGHLIGHTED_PREF, mHighlightedPreferenceKey);
+ }
+
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
super.onCreatePreferences(savedInstanceState, rootKey);
@@ -118,12 +151,78 @@ public class TopLevelSettings extends DashboardFragment implements
}
}
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ highlightPreferenceIfNeeded();
+ }
+
+ @Override
+ public void highlightPreferenceIfNeeded() {
+ if (mTopLevelAdapter != null) {
+ mTopLevelAdapter.requestHighlight();
+ }
+ }
+
+ /** Highlight a preference with specified key */
+ public void setHighlightPreferenceKey(String prefKey) {
+ if (mTopLevelAdapter != null) {
+ mHighlightedPreferenceKey = prefKey;
+ mTopLevelAdapter.highlightPreference(prefKey, /* scrollNeeded= */ false);
+ }
+ }
+
+ /** Highlight the previous preference */
+ public void restorePreviousHighlight() {
+ if (mTopLevelAdapter != null) {
+ mTopLevelAdapter.restorePreviousHighlight();
+ }
+ }
+
@Override
protected boolean shouldForceRoundedIcon() {
return getContext().getResources()
.getBoolean(R.bool.config_force_rounded_icon_TopLevelSettings);
}
+ @Override
+ protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
+ if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(getContext())) {
+ return super.onCreateAdapter(preferenceScreen);
+ }
+
+ if (TextUtils.isEmpty(mHighlightedPreferenceKey)) {
+ mHighlightedPreferenceKey = getHighlightPrefKeyFromArguments();
+ }
+
+ Log.d(TAG, "onCreateAdapter, pref key: " + mHighlightedPreferenceKey);
+ mTopLevelAdapter = new HighlightableTopLevelPreferenceAdapter(preferenceScreen,
+ getListView(), mHighlightedPreferenceKey);
+ return mTopLevelAdapter;
+ }
+
+ void reloadHighlightMenuKey() {
+ if (mTopLevelAdapter == null) {
+ return;
+ }
+
+ mHighlightedPreferenceKey = getHighlightPrefKeyFromArguments();
+ Log.d(TAG, "reloadHighlightMenuKey, pref key: " + mHighlightedPreferenceKey);
+ mTopLevelAdapter.highlightPreference(mHighlightedPreferenceKey, /* scrollNeeded= */ true);
+ }
+
+ private String getHighlightPrefKeyFromArguments() {
+ final Bundle arguments = getArguments();
+ final String menuKey = arguments.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY);
+ final String prefKey = HighlightableMenu.lookupPreferenceKey(menuKey);
+ if (TextUtils.isEmpty(prefKey)) {
+ Log.e(TAG, "Invalid highlight menu key: " + menuKey);
+ } else {
+ Log.d(TAG, "Menu key: " + menuKey);
+ }
+ return prefKey;
+ }
+
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.top_level_settings) {
diff --git a/src/com/android/settings/search/SearchFeatureProviderImpl.java b/src/com/android/settings/search/SearchFeatureProviderImpl.java
index 508d37d7e6a..6f909709058 100644
--- a/src/com/android/settings/search/SearchFeatureProviderImpl.java
+++ b/src/com/android/settings/search/SearchFeatureProviderImpl.java
@@ -50,7 +50,7 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
if (isSettingsPackage || isAllowlistedPackage) {
return;
}
- throw new SecurityException("Search result intents must be called with from a "
+ throw new SecurityException("Search result intents must be called with from an "
+ "allowlisted package.");
}
diff --git a/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java b/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java
new file mode 100644
index 00000000000..eeaad214a21
--- /dev/null
+++ b/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2021 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.widget;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceGroupAdapter;
+import androidx.preference.PreferenceViewHolder;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.settings.Utils;
+import com.android.settings.activityembedding.ActivityEmbeddingUtils;
+
+/**
+ * Adapter for highlighting top level preferences
+ */
+public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapter {
+
+ private static final String TAG = "HighlightableTopLevelAdapter";
+
+ static final long DELAY_HIGHLIGHT_DURATION_MILLIS = 100L;
+
+ @VisibleForTesting
+ final int mHighlightColor;
+ final int mTitleColorNormal;
+ final int mTitleColorHighlight;
+ final int mSummaryColorNormal;
+ final int mSummaryColorHighlight;
+ final int mIconColorNormal;
+ final int mIconColorHighlight;
+
+ private final Context mContext;
+ private final RecyclerView mRecyclerView;
+ private final int mNormalBackgroundRes;
+ private String mHighlightKey;
+ private String mPreviousHighlightKey;
+ private int mHighlightPosition = RecyclerView.NO_POSITION;
+ private boolean mHighlightNeeded;
+ private boolean mScrolled;
+
+ public HighlightableTopLevelPreferenceAdapter(PreferenceGroup preferenceGroup,
+ RecyclerView recyclerView, String key) {
+ super(preferenceGroup);
+ mRecyclerView = recyclerView;
+ mHighlightKey = key;
+ mContext = preferenceGroup.getContext();
+ final TypedValue outValue = new TypedValue();
+ mContext.getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
+ outValue, true /* resolveRefs */);
+ mNormalBackgroundRes = outValue.resourceId;
+ mHighlightColor = Utils.getColorAttrDefaultColor(mContext,
+ com.android.internal.R.attr.colorAccentSecondaryVariant);
+ mTitleColorNormal = Utils.getColorAttrDefaultColor(mContext,
+ android.R.attr.textColorPrimary);
+ mTitleColorHighlight = Utils.getColorAttrDefaultColor(mContext,
+ android.R.attr.textColorPrimaryInverse);
+ mSummaryColorNormal = Utils.getColorAttrDefaultColor(mContext,
+ android.R.attr.textColorSecondary);
+ mSummaryColorHighlight = Utils.getColorAttrDefaultColor(mContext,
+ android.R.attr.textColorSecondaryInverse);
+ mIconColorNormal = Utils.getHomepageIconColor(mContext);
+ mIconColorHighlight = Utils.getHomepageIconColorHighlight(mContext);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder, int position) {
+ super.onBindViewHolder(holder, position);
+ updateBackground(holder, position);
+ }
+
+ @VisibleForTesting
+ void updateBackground(PreferenceViewHolder holder, int position) {
+ if (!isHighlightNeeded()) {
+ removeHighlightBackground(holder);
+ return;
+ }
+
+ if (position == mHighlightPosition
+ && mHighlightKey != null
+ && TextUtils.equals(mHighlightKey, getItem(position).getKey())) {
+ // This position should be highlighted.
+ addHighlightBackground(holder);
+ } else {
+ removeHighlightBackground(holder);
+ }
+ }
+
+ /**
+ * A function can highlight a specific setting in recycler view.
+ */
+ public void requestHighlight() {
+ if (mRecyclerView == null || TextUtils.isEmpty(mHighlightKey)) {
+ return;
+ }
+
+ if (TextUtils.isEmpty(mHighlightKey)) {
+ // De-highlight previous preference.
+ final int previousPosition = mHighlightPosition;
+ mHighlightPosition = RecyclerView.NO_POSITION;
+ mScrolled = true;
+ if (previousPosition >= 0) {
+ notifyItemChanged(previousPosition);
+ }
+ return;
+ }
+
+ final int position = getPreferenceAdapterPosition(mHighlightKey);
+ if (position < 0) {
+ return;
+ }
+
+ final boolean highlightNeeded = isHighlightNeeded();
+ if (highlightNeeded) {
+ scrollToPositionIfNeeded(position);
+ }
+
+ // Turn on/off highlight when screen split mode is changed.
+ if (highlightNeeded != mHighlightNeeded) {
+ Log.d(TAG, "Highlight change needed: " + highlightNeeded);
+ mHighlightNeeded = highlightNeeded;
+ mHighlightPosition = position;
+ notifyItemChanged(position);
+ return;
+ }
+
+ if (position == mHighlightPosition) {
+ return;
+ }
+
+ final int previousPosition = mHighlightPosition;
+ mHighlightPosition = position;
+ Log.d(TAG, "Request highlight position " + position);
+ Log.d(TAG, "Is highlight needed: " + highlightNeeded);
+ if (!highlightNeeded) {
+ return;
+ }
+
+ // Highlight preference.
+ notifyItemChanged(position);
+
+ // De-highlight previous preference.
+ if (previousPosition >= 0) {
+ notifyItemChanged(previousPosition);
+ }
+ }
+
+ /**
+ * A function that highlights a setting by specifying a preference key. Usually used whenever a
+ * preference is clicked.
+ */
+ public void highlightPreference(String key, boolean scrollNeeded) {
+ mPreviousHighlightKey = mHighlightKey;
+ mHighlightKey = key;
+ mScrolled = !scrollNeeded;
+ requestHighlight();
+ }
+
+ /**
+ * A function that restores the previous highlighted setting.
+ */
+ public void restorePreviousHighlight() {
+ mHighlightKey = mPreviousHighlightKey;
+ requestHighlight();
+ }
+
+ private void scrollToPositionIfNeeded(int position) {
+ if (mScrolled || position < 0) {
+ return;
+ }
+
+ // Only when the recyclerView is loaded, it can be scrolled
+ final View view = mRecyclerView.getChildAt(position);
+ if (view == null) {
+ mRecyclerView.postDelayed(() -> scrollToPositionIfNeeded(position),
+ DELAY_HIGHLIGHT_DURATION_MILLIS);
+ return;
+ }
+
+ mScrolled = true;
+ Log.d(TAG, "Scroll to position " + position);
+ // Scroll to the top to reset the position.
+ mRecyclerView.nestedScrollBy(0, -mRecyclerView.getHeight());
+
+ final int scrollY = view.getTop();
+ if (scrollY > 0) {
+ mRecyclerView.nestedScrollBy(0, scrollY);
+ }
+ }
+
+ private void addHighlightBackground(PreferenceViewHolder holder) {
+ final View v = holder.itemView;
+ v.setBackgroundColor(mHighlightColor);
+ ((TextView) v.findViewById(android.R.id.title)).setTextColor(mTitleColorHighlight);
+ ((TextView) v.findViewById(android.R.id.summary)).setTextColor(mSummaryColorHighlight);
+ final Drawable drawable = ((ImageView) v.findViewById(android.R.id.icon)).getDrawable();
+ if (drawable != null) {
+ drawable.setTint(mIconColorHighlight);
+ }
+ }
+
+ private void removeHighlightBackground(PreferenceViewHolder holder) {
+ final View v = holder.itemView;
+ v.setBackgroundResource(mNormalBackgroundRes);
+ ((TextView) v.findViewById(android.R.id.title)).setTextColor(mTitleColorNormal);
+ ((TextView) v.findViewById(android.R.id.summary)).setTextColor(mSummaryColorNormal);
+ final Drawable drawable = ((ImageView) v.findViewById(android.R.id.icon)).getDrawable();
+ if (drawable != null) {
+ drawable.setTint(mIconColorNormal);
+ }
+ }
+
+ private boolean isHighlightNeeded() {
+ return ActivityEmbeddingUtils.isTwoPaneResolution(mContext);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
index a827284a088..cccca9c9ea5 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
@@ -43,7 +43,6 @@ import android.os.UserManager;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
-import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.dashboard.DashboardFeatureProviderImpl;
import com.android.settings.testutils.shadow.ShadowAccountManager;
import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -151,9 +150,9 @@ public class AccountDetailDashboardFragmentTest {
final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class);
final Preference preference = new Preference(mContext);
- dashboardFeatureProvider.bindPreferenceToTileAndGetObservers(activity,
- false /* forceRoundedIcon */, MetricsProto.MetricsEvent.DASHBOARD_SUMMARY,
- preference, tile, null /* key */, Preference.DEFAULT_ORDER);
+ dashboardFeatureProvider.bindPreferenceToTileAndGetObservers(activity, mFragment,
+ false /* forceRoundedIcon */, 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/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
index 5d6fdf98f1b..e7c99c873b1 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
@@ -114,6 +114,7 @@ public class DashboardFeatureProviderImplTest {
private Bundle mSwitchMetaData;
private DashboardFeatureProviderImpl mImpl;
private boolean mForceRoundedIcon;
+ private DashboardFragment mFragment;
@Before
public void setUp() {
@@ -144,6 +145,7 @@ public class DashboardFeatureProviderImplTest {
.thenReturn(new ResolveInfo());
mFeatureFactory = FakeFeatureFactory.setupForTest();
mImpl = new DashboardFeatureProviderImpl(mContext);
+ mFragment = new TestFragment();
}
@Test
@@ -159,8 +161,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.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", Preference.DEFAULT_ORDER);
assertThat(preference.getTitle()).isEqualTo(mContext.getText(R.string.settings_label));
assertThat(preference.getSummary())
@@ -180,8 +182,8 @@ public class DashboardFeatureProviderImplTest {
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);
+ mActivity, mFragment, mForceRoundedIcon, preference, tile, null /* key*/,
+ Preference.DEFAULT_ORDER);
assertThat(preference.getTitle()).isEqualTo(mContext.getText(R.string.settings_label));
assertThat(preference.getSummary())
@@ -198,8 +200,8 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
- mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", Preference.DEFAULT_ORDER);
assertThat(preference.getFragment()).isNull();
assertThat(preference.getOnPreferenceClickListener()).isNotNull();
@@ -214,8 +216,8 @@ public class DashboardFeatureProviderImplTest {
tile.userHandle.add(mock(UserHandle.class));
tile.userHandle.add(mock(UserHandle.class));
- mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", Preference.DEFAULT_ORDER);
preference.getOnPreferenceClickListener().onPreferenceClick(null);
verify(mActivity).getSupportFragmentManager();
@@ -231,8 +233,8 @@ public class DashboardFeatureProviderImplTest {
when(mActivity.getSystemService(Context.USER_SERVICE))
.thenReturn(mUserManager);
- mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", Preference.DEFAULT_ORDER);
preference.getOnPreferenceClickListener().onPreferenceClick(null);
verify(mFeatureFactory.metricsFeatureProvider).logStartedIntent(
@@ -250,8 +252,8 @@ public class DashboardFeatureProviderImplTest {
tile.userHandle = new ArrayList<>();
tile.userHandle.add(mock(UserHandle.class));
- mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", Preference.DEFAULT_ORDER);
preference.getOnPreferenceClickListener().onPreferenceClick(null);
verify(mFeatureFactory.metricsFeatureProvider).logStartedIntent(
any(Intent.class),
@@ -263,8 +265,8 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_nullPreference_shouldIgnore() {
final Tile tile = mock(Tile.class);
- mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.VIEW_UNKNOWN, null, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ null /* keys */, tile, "123", Preference.DEFAULT_ORDER);
verifyZeroInteractions(tile);
}
@@ -273,8 +275,8 @@ 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.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */,
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, null /* key */,
Preference.DEFAULT_ORDER);
assertThat(preference.getKey()).isNotNull();
@@ -288,9 +290,8 @@ public class DashboardFeatureProviderImplTest {
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
- mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */,
- Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, null /* key */, Preference.DEFAULT_ORDER);
assertThat(preference.getSummary()).isNull();
}
@@ -304,8 +305,8 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, uriString);
final List observers = mImpl.bindPreferenceToTileAndGetObservers(
- mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, preference, tile,
- null /*key */, Preference.DEFAULT_ORDER);
+ mActivity, mFragment, mForceRoundedIcon, preference, tile, null /* key */,
+ Preference.DEFAULT_ORDER);
assertThat(preference.getSummary()).isEqualTo(ShadowTileUtils.MOCK_SUMMARY);
assertThat(observers.get(0).getUri().toString()).isEqualTo(uriString);
@@ -320,8 +321,8 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE_URI, uriString);
final List observers = mImpl.bindPreferenceToTileAndGetObservers(
- mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, preference, tile,
- null /*key */, Preference.DEFAULT_ORDER);
+ mActivity, mFragment, mForceRoundedIcon, preference, tile, null /* key */,
+ Preference.DEFAULT_ORDER);
assertThat(preference.getTitle()).isEqualTo(ShadowTileUtils.MOCK_SUMMARY);
assertThat(observers.get(0).getUri().toString()).isEqualTo(uriString);
@@ -336,9 +337,8 @@ public class DashboardFeatureProviderImplTest {
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);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, null /* key */, Preference.DEFAULT_ORDER);
preference.callChangeListener(false);
@@ -358,9 +358,8 @@ public class DashboardFeatureProviderImplTest {
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);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, null /* key */, Preference.DEFAULT_ORDER);
preference.callChangeListener(true);
@@ -378,8 +377,8 @@ public class DashboardFeatureProviderImplTest {
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);
+ mActivity, mFragment, mForceRoundedIcon, preference, tile, null /* key */,
+ Preference.DEFAULT_ORDER);
ShadowTileUtils.setProviderChecked(false);
observers.get(0).onDataChanged();
@@ -397,9 +396,8 @@ 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.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.VIEW_UNKNOWN, preference, tile, null /* key */,
- Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, null /* key */, Preference.DEFAULT_ORDER);
assertThat(preference.getKey()).isEqualTo(tile.getKey(mContext));
}
@@ -483,8 +481,8 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
- mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.VIEW_UNKNOWN, preference, tile, "123", baseOrder);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", baseOrder);
assertThat(preference.getOrder()).isEqualTo(tile.getOrder() + baseOrder);
}
@@ -496,8 +494,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.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.VIEW_UNKNOWN, preference, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", Preference.DEFAULT_ORDER);
assertThat(preference.getOrder()).isEqualTo(testOrder);
}
@@ -508,8 +506,8 @@ public class DashboardFeatureProviderImplTest {
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_KEY_ORDER, "hello");
- mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
- MetricsEvent.VIEW_UNKNOWN, preference, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", Preference.DEFAULT_ORDER);
assertThat(preference.getOrder()).isEqualTo(Preference.DEFAULT_ORDER);
}
@@ -522,8 +520,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.bindPreferenceToTileAndGetObservers(activity, mForceRoundedIcon,
- MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(activity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", Preference.DEFAULT_ORDER);
preference.performClick();
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
@@ -546,8 +544,8 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction");
tile.userHandle = null;
- mImpl.bindPreferenceToTileAndGetObservers(activity, mForceRoundedIcon,
- MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
+ mImpl.bindPreferenceToTileAndGetObservers(activity, mFragment, mForceRoundedIcon,
+ preference, tile, "123", Preference.DEFAULT_ORDER);
preference.performClick();
final ShadowActivity.IntentForResult launchIntent =
@@ -669,4 +667,22 @@ public class DashboardFeatureProviderImplTest {
assertThat(argument.getValue().getIdentifier()).isEqualTo(0);
verify(mActivity, never()).getSupportFragmentManager();
}
+
+ private static class TestFragment extends DashboardFragment {
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.SETTINGS_GESTURES;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.gestures;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return "TestFragment";
+ }
+ }
}