Improve Preference highlighting
- use PreferenceFragment.onBindPreferences() to launch highlighting
- improve SettingsPreferenceFragment code for highlighting: now we can
find the View to highlight thru its Tag if there is no ListAdapter available
- add HighlightingFragment for highlighting a View from its tag/key. This
is dealing with cases when the content is custom and not relying on
SettingsPreferenceFragment (like DataUsageSummary)
Also:
- improve DataUsageSummary so that onResume() is not recreating the
Tabs all the time
- add missing "android:keys" on some Security Settings preference files
Change-Id: Ib1dd8238fe2fb57c151d584c0810a0e0a5ad97c4
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index 563a343..b5299ee 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -152,7 +152,7 @@
* Panel showing data usage history across various networks, including options
* to inspect based on usage cycle and control through {@link NetworkPolicy}.
*/
-public class DataUsageSummary extends Fragment implements Indexable {
+public class DataUsageSummary extends HighlightingFragment implements Indexable {
private static final String TAG = "DataUsage";
private static final boolean LOGD = false;
@@ -351,6 +351,7 @@
mDataEnabled = new Switch(inflater.getContext());
mDataEnabledView = inflatePreference(inflater, mNetworkSwitches, mDataEnabled);
+ mDataEnabledView.setTag("data_usage_enable_mobile");
mDataEnabled.setOnCheckedChangeListener(mDataEnabledListener);
mNetworkSwitches.addView(mDataEnabledView);
@@ -358,6 +359,7 @@
mDisableAtLimit.setClickable(false);
mDisableAtLimit.setFocusable(false);
mDisableAtLimitView = inflatePreference(inflater, mNetworkSwitches, mDisableAtLimit);
+ mDisableAtLimitView.setTag("data_usage_disable_mobile_limit");
mDisableAtLimitView.setClickable(true);
mDisableAtLimitView.setFocusable(true);
mDisableAtLimitView.setOnClickListener(mDisableAtLimitListener);
@@ -366,6 +368,7 @@
// bind cycle dropdown
mCycleView = mHeader.findViewById(R.id.cycles);
+ mCycleView.setTag("data_usage_cycle");
mCycleSpinner = (Spinner) mCycleView.findViewById(R.id.cycles_spinner);
mCycleAdapter = new CycleAdapter(context);
mCycleSpinner.setAdapter(mCycleAdapter);
@@ -409,8 +412,8 @@
}
@Override
- public void onResume() {
- super.onResume();
+ public void onViewStateRestored(Bundle savedInstanceState) {
+ super.onViewStateRestored(savedInstanceState);
// pick default tab based on incoming intent
final Intent intent = getActivity().getIntent();
@@ -419,6 +422,18 @@
// this kicks off chain reaction which creates tabs, binds the body to
// selected network, and binds chart, cycles and detail list.
updateTabs();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ getView().post(new Runnable() {
+ @Override
+ public void run() {
+ highlightViewIfNeeded();
+ }
+ });
// kick off background task to update stats
new AsyncTask<Void, Void, Void>() {
@@ -1729,6 +1744,7 @@
final View view = dialogInflater.inflate(R.layout.data_usage_cycle_editor, null, false);
final NumberPicker cycleDayPicker = (NumberPicker) view.findViewById(R.id.cycle_day);
+ cycleDayPicker.setTag("data_usage_cycle");
final NetworkTemplate template = getArguments().getParcelable(EXTRA_TEMPLATE);
final int cycleDay = editor.getPolicyCycleDay(template);
@@ -2403,18 +2419,21 @@
// Mobile data
data = new SearchIndexableRaw(context);
+ data.key = "data_usage_enable_mobile";
data.title = res.getString(R.string.data_usage_enable_mobile);
data.screenTitle = res.getString(R.string.data_usage_summary_title);
result.add(data);
// Set mobile data limit
data = new SearchIndexableRaw(context);
+ data.key = "data_usage_disable_mobile_limit";
data.title = res.getString(R.string.data_usage_disable_mobile_limit);
data.screenTitle = res.getString(R.string.data_usage_summary_title);
result.add(data);
- // Data usage cycke
+ // Data usage cycle
data = new SearchIndexableRaw(context);
+ data.key = "data_usage_cycle";
data.title = res.getString(R.string.data_usage_cycle);
data.screenTitle = res.getString(R.string.data_usage_summary_title);
result.add(data);
diff --git a/src/com/android/settings/HighlightingFragment.java b/src/com/android/settings/HighlightingFragment.java
new file mode 100644
index 0000000..7842044
--- /dev/null
+++ b/src/com/android/settings/HighlightingFragment.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 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;
+
+import android.app.Fragment;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class HighlightingFragment extends Fragment {
+
+ private static final String TAG = "HighlightSettingsFragment";
+
+ private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 300;
+ private static final String SAVE_HIGHLIGHTED_KEY = "android:view_highlighted";
+
+ private String mViewKey;
+ private boolean mViewHighlighted = false;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ if (icicle != null) {
+ mViewHighlighted = icicle.getBoolean(SAVE_HIGHLIGHTED_KEY);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mViewHighlighted);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ final Bundle args = getArguments();
+ if (args != null) {
+ mViewKey = args.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY);
+ highlightViewIfNeeded();
+ }
+ }
+
+ public void highlightViewIfNeeded() {
+ if (!mViewHighlighted &&!TextUtils.isEmpty(mViewKey)) {
+ highlightView(mViewKey);
+ }
+ }
+
+ private Drawable getHighlightDrawable() {
+ return getResources().getDrawable(R.drawable.preference_highlight);
+ }
+
+ private void highlightView(String key) {
+ final Drawable highlight = getHighlightDrawable();
+
+ // Try locating the View thru its Tag / Key
+ final View view = findViewForKey(getView(), key);
+ if (view != null ) {
+ view.setBackground(highlight);
+
+ getView().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ final int centerX = view.getWidth() / 2;
+ final int centerY = view.getHeight() / 2;
+ highlight.setHotspot(0, centerX, centerY);
+ highlight.clearHotspots();
+ }
+ }, DELAY_HIGHLIGHT_DURATION_MILLIS);
+
+ mViewHighlighted = true;
+ }
+ }
+
+ private View findViewForKey(View root, String key) {
+ if (checkTag(root, key)) {
+ return root;
+ }
+ if (root instanceof ViewGroup) {
+ final ViewGroup group = (ViewGroup) root;
+ final int count = group.getChildCount();
+ for (int n = 0; n < count; n++) {
+ final View child = group.getChildAt(n);
+ final View view = findViewForKey(child, key);
+ if (view != null) {
+ return view;
+ }
+ }
+ }
+ return null;
+ }
+
+ private boolean checkTag(View view, String key) {
+ final Object tag = view.getTag();
+ if (tag == null || !(tag instanceof String)) {
+ return false;
+ }
+ final String viewKey = (String) tag;
+ return (!TextUtils.isEmpty(viewKey) && viewKey.equals(key));
+ }
+}
diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index e27c9ed..5e0c06d 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -33,6 +33,8 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
@@ -45,7 +47,7 @@
private static final String TAG = "SettingsPreferenceFragment";
private static final int MENU_HELP = Menu.FIRST + 100;
- private static final int HIGHLIGHT_DURATION_MILLIS = 300;
+ private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 300;
private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
@@ -56,6 +58,7 @@
// Cache the content resolver for async callbacks
private ContentResolver mContentResolver;
+ private String mPreferenceKey;
private boolean mPreferenceHighlighted = false;
@Override
@@ -89,71 +92,128 @@
final Bundle args = getArguments();
if (args != null) {
- final String key = args.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY);
- if (hasListView() && !TextUtils.isEmpty(key)) {
- highlightPreference(key);
- }
+ mPreferenceKey = args.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY);
+ highlightPreferenceIfNeeded();
}
}
- private void highlightPreference(String key) {
- final int position = findPositionFromKey(key);
- if (position >= 0) {
- final ListView listView = getListView();
- final ListAdapter adapter = listView.getAdapter();
+ @Override
+ protected void onBindPreferences() {
+ highlightPreferenceIfNeeded();
+ }
- if (adapter instanceof PreferenceGroupAdapter) {
- final Drawable drawable = getHighlightDrawable();
- ((PreferenceGroupAdapter) adapter).setHighlightedDrawable(drawable);
- ((PreferenceGroupAdapter) adapter).setHighlighted(position);
-
- listView.post(new Runnable() {
- @Override
- public void run() {
- listView.setSelection(position);
- if (!mPreferenceHighlighted) {
- listView.postDelayed(new Runnable() {
- @Override
- public void run() {
- final int centerX = listView.getWidth() / 2;
- final int centerY = listView.getChildAt(0).getHeight() / 2;
- drawable.setHotspot(0, centerX, centerY);
- drawable.clearHotspots();
- ((PreferenceGroupAdapter) adapter).setHighlighted(-1);
- }
- }, HIGHLIGHT_DURATION_MILLIS);
-
- mPreferenceHighlighted = true;
- }
- }
- });
- }
+ public void highlightPreferenceIfNeeded() {
+ if (!mPreferenceHighlighted &&!TextUtils.isEmpty(mPreferenceKey)) {
+ highlightPreference(mPreferenceKey);
}
-
}
private Drawable getHighlightDrawable() {
return getResources().getDrawable(R.drawable.preference_highlight);
}
- private int findPositionFromKey(String key) {
- final ListAdapter adapter = getListView().getAdapter();
- if (adapter != null) {
- final int count = adapter.getCount();
- for (int n = 0; n < count; n++) {
- Object item = adapter.getItem(n);
- if (item instanceof Preference) {
- Preference preference = (Preference) item;
- final String preferenceKey = preference.getKey();
- if (preferenceKey != null && preferenceKey.equals(key)) {
- return n;
- }
+ /**
+ * Return a valid ListView position or -1 if none is found
+ */
+ private int canUseListViewForHighLighting(String key) {
+ if (!hasListView()) {
+ return -1;
+ }
+
+ ListView listView = getListView();
+ ListAdapter adapter = listView.getAdapter();
+
+ if (adapter != null && adapter instanceof PreferenceGroupAdapter) {
+ return findListPositionFromKey(adapter, key);
+ }
+
+ return -1;
+ }
+
+ private void highlightPreference(String key) {
+ final Drawable highlight = getHighlightDrawable();
+
+ final int position = canUseListViewForHighLighting(key);
+ if (position >= 0) {
+ final ListView listView = getListView();
+ final ListAdapter adapter = listView.getAdapter();
+
+ ((PreferenceGroupAdapter) adapter).setHighlightedDrawable(highlight);
+ ((PreferenceGroupAdapter) adapter).setHighlighted(position);
+
+ listView.post(new Runnable() {
+ @Override
+ public void run() {
+ listView.setSelection(position);
+ listView.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ final int centerX = listView.getWidth() / 2;
+ final int centerY = listView.getChildAt(0).getHeight() / 2;
+ highlight.setHotspot(0, centerX, centerY);
+ highlight.clearHotspots();
+ ((PreferenceGroupAdapter) adapter).setHighlighted(-1);
+ }
+ }, DELAY_HIGHLIGHT_DURATION_MILLIS);
+
+ mPreferenceHighlighted = true;
+ }
+ });
+ } else {
+ // Try locating the Preference View thru its tag
+ View preferenceView = findPreferenceViewForKey(getView(), key);
+ if (preferenceView != null ) {
+ preferenceView.setBackground(highlight);
+ final int centerX = preferenceView.getWidth() / 2;
+ final int centerY = preferenceView.getHeight() / 2;
+ highlight.setHotspot(0, centerX, centerY);
+ highlight.clearHotspots();
+ }
+ }
+ }
+
+ private int findListPositionFromKey(ListAdapter adapter, String key) {
+ final int count = adapter.getCount();
+ for (int n = 0; n < count; n++) {
+ final Object item = adapter.getItem(n);
+ if (item instanceof Preference) {
+ Preference preference = (Preference) item;
+ final String preferenceKey = preference.getKey();
+ if (preferenceKey != null && preferenceKey.equals(key)) {
+ return n;
}
}
}
return -1;
}
+ private View findPreferenceViewForKey(View root, String key) {
+ if (checkTag(root, key)) {
+ return root;
+ }
+ if (root instanceof ViewGroup) {
+ final ViewGroup group = (ViewGroup) root;
+ final int count = group.getChildCount();
+ for (int n = 0; n < count; n++) {
+ final View child = group.getChildAt(n);
+ final View view = findPreferenceViewForKey(child, key);
+ if (view != null) {
+ return view;
+ }
+ }
+ }
+ return null;
+ }
+
+ private boolean checkTag(View view, String key) {
+ final Object tag = view.getTag();
+ if (tag == null || !(tag instanceof String)) {
+ return false;
+ }
+ final String prefKey = (String) tag;
+ return (!TextUtils.isEmpty(prefKey) && prefKey.equals(key));
+ }
+
protected void removePreference(String key) {
Preference pref = findPreference(key);
if (pref != null) {
diff --git a/src/com/android/settings/search/IndexDatabaseHelper.java b/src/com/android/settings/search/IndexDatabaseHelper.java
index 4e94cb1..19c4e20 100644
--- a/src/com/android/settings/search/IndexDatabaseHelper.java
+++ b/src/com/android/settings/search/IndexDatabaseHelper.java
@@ -28,7 +28,7 @@
private static final String TAG = "IndexDatabaseHelper";
private static final String DATABASE_NAME = "search_index.db";
- private static final int DATABASE_VERSION = 109;
+ private static final int DATABASE_VERSION = 110;
public interface Tables {
public static final String TABLE_PREFS_INDEX = "prefs_index";