Highlight row (instead of ripple) when come from search.

- Moved HighlightableAdapter to its own class
- Replaced ripple with blue background
- Bluebackground only stays for 5 seconds. After that it's replaced by
  ?attr/selectableBackground

Misc fixes.

- Fix NPE in UserSettings
- Update char limit on a new string

Change-Id: I4687e54e71fd7b9243f520b7630563df58be23d4
Fixes: 71715698
Fixes: 72761974
Test: robotests
This commit is contained in:
Fan Zhang
2018-01-31 14:14:41 -08:00
parent 12fd732b55
commit 3d516e7607
8 changed files with 273 additions and 177 deletions

View File

@@ -30,9 +30,7 @@ import android.support.annotation.VisibleForTesting;
import android.support.annotation.XmlRes;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceGroupAdapter;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
@@ -49,6 +47,7 @@ import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.search.actionbar.SearchMenuController;
import com.android.settings.support.actionbar.HelpMenuController;
import com.android.settings.support.actionbar.HelpResourceProvider;
import com.android.settings.widget.HighlightablePreferenceGroupAdapter;
import com.android.settings.widget.LoadingViewController;
import com.android.settingslib.CustomDialogPreference;
import com.android.settingslib.CustomEditTextPreference;
@@ -65,9 +64,6 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
private static final String TAG = "SettingsPreference";
@VisibleForTesting
static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;
private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
protected final FooterPreferenceMixin mFooterPreferenceMixin =
@@ -75,14 +71,11 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
private static final int ORDER_FIRST = -1;
private static final int ORDER_LAST = Integer.MAX_VALUE -1;
private SettingsDialogFragment mDialogFragment;
// Cache the content resolver for async callbacks
private ContentResolver mContentResolver;
private String mPreferenceKey;
private RecyclerView.Adapter mCurrentRootAdapter;
private boolean mIsDataSetObserverRegistered = false;
private RecyclerView.AdapterDataObserver mDataSetObserver =
@@ -146,8 +139,9 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
// Check if we should keep the preferences expanded.
if (arguments != null) {
mPreferenceKey = arguments.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY);
if (!TextUtils.isEmpty(mPreferenceKey)) {
final String highlightKey =
arguments.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY);
if (!TextUtils.isEmpty(highlightKey)) {
final PreferenceScreen screen = getPreferenceScreen();
if (screen != null) {
screen.setInitialExpandedChildrenCount(Integer.MAX_VALUE);
@@ -205,7 +199,9 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted);
if (mAdapter != null) {
outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mAdapter.isHighlightRequested());
}
}
@Override
@@ -217,10 +213,7 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
@Override
public void onResume() {
super.onResume();
if (mPreferenceKey != null) {
highlightPreferenceIfNeeded();
}
highlightPreferenceIfNeeded();
}
@Override
@@ -263,13 +256,11 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
}
public void highlightPreferenceIfNeeded() {
if (isAdded() && !mPreferenceHighlighted &&!TextUtils.isEmpty(mPreferenceKey)) {
getView().postDelayed(new Runnable() {
@Override
public void run() {
highlightPreference(mPreferenceKey);
}
}, DELAY_HIGHLIGHT_DURATION_MILLIS);
if (!isAdded()) {
return;
}
if (mAdapter != null) {
mAdapter.requestHighlight(getView(), getListView());
}
}
@@ -340,24 +331,6 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
return mEmptyView;
}
/**
* Return a valid ListView position or -1 if none is found
*/
private int canUseListViewForHighLighting(String key) {
if (getListView() == null) {
return -1;
}
RecyclerView listView = getListView();
RecyclerView.Adapter adapter = listView.getAdapter();
if (adapter != null && adapter instanceof PreferenceGroupAdapter) {
return findListPositionFromKey((PreferenceGroupAdapter) adapter, key);
}
return -1;
}
@Override
public RecyclerView.LayoutManager onCreateLayoutManager() {
mLayoutManager = new LinearLayoutManager(getContext());
@@ -366,7 +339,9 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
@Override
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
mAdapter = new HighlightablePreferenceGroupAdapter(preferenceScreen);
mAdapter = new HighlightablePreferenceGroupAdapter(preferenceScreen,
getArguments().getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY),
mPreferenceHighlighted);
return mAdapter;
}
@@ -375,7 +350,7 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
}
protected void cacheRemoveAllPrefs(PreferenceGroup group) {
mPreferenceCache = new ArrayMap<String, Preference>();
mPreferenceCache = new ArrayMap<>();
final int N = group.getPreferenceCount();
for (int i = 0; i < N; i++) {
Preference p = group.getPreference(i);
@@ -401,29 +376,6 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
return mPreferenceCache != null ? mPreferenceCache.size() : 0;
}
private void highlightPreference(String key) {
final int position = canUseListViewForHighLighting(key);
if (position < 0) {
return;
}
mPreferenceHighlighted = true;
mLayoutManager.scrollToPosition(position);
mAdapter.highlight(position);
}
private int findListPositionFromKey(PreferenceGroupAdapter adapter, String key) {
final int count = adapter.getItemCount();
for (int n = 0; n < count; n++) {
final Preference preference = adapter.getItem(n);
final String preferenceKey = preference.getKey();
if (preferenceKey != null && preferenceKey.equals(key)) {
return n;
}
}
return -1;
}
protected boolean removePreference(String key) {
return removePreference(getPreferenceScreen(), key);
}
@@ -692,11 +644,11 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
}
protected boolean hasNextButton() {
return ((ButtonBarHandler)getActivity()).hasNextButton();
return ((ButtonBarHandler) getActivity()).hasNextButton();
}
protected Button getNextButton() {
return ((ButtonBarHandler)getActivity()).getNextButton();
return ((ButtonBarHandler) getActivity()).getNextButton();
}
public void finish() {
@@ -741,45 +693,10 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
} else {
Log.w(TAG,
"Parent isn't SettingsActivity nor PreferenceActivity, thus there's no way to "
+ "launch the given Fragment (name: " + fragmentClass
+ ", requestCode: " + requestCode + ")");
+ "launch the given Fragment (name: " + fragmentClass
+ ", requestCode: " + requestCode + ")");
return false;
}
}
public static class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter {
@VisibleForTesting(otherwise=VisibleForTesting.NONE)
int initialHighlightedPosition = -1;
private int mHighlightPosition = -1;
public HighlightablePreferenceGroupAdapter(PreferenceGroup preferenceGroup) {
super(preferenceGroup);
}
public void highlight(int position) {
mHighlightPosition = position;
initialHighlightedPosition = position;
notifyDataSetChanged();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
if (position == mHighlightPosition) {
View v = holder.itemView;
v.post(() -> {
if (v.getBackground() != null) {
final int centerX = v.getWidth() / 2;
final int centerY = v.getHeight() / 2;
v.getBackground().setHotspot(centerX, centerY);
}
v.setPressed(true);
v.setPressed(false);
mHighlightPosition = -1;
});
}
}
}
}

View File

@@ -309,7 +309,7 @@ public class UserSettings extends SettingsPreferenceFragment
public void onDestroy() {
super.onDestroy();
if (!mUserCaps.mEnabled) {
if (mUserCaps == null || !mUserCaps.mEnabled) {
return;
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.widget;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceGroupAdapter;
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.View;
import com.android.settings.R;
public class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter {
@VisibleForTesting
static final long DELAY_HIGHLIGHT_DURATION_MILLIS = 600L;
private static final long HIGHLIGHT_DURATION = 5000L;
private final int mHighlightColor;
private final int mNormalBackgroundRes;
private final String mHighlightKey;
private boolean mHighlightRequested;
private int mHighlightPosition = RecyclerView.NO_POSITION;
public HighlightablePreferenceGroupAdapter(PreferenceGroup preferenceGroup, String key,
boolean highlightRequested) {
super(preferenceGroup);
mHighlightKey = key;
mHighlightRequested = highlightRequested;
final Context context = preferenceGroup.getContext();
final TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
outValue, true /* resolveRefs */);
mNormalBackgroundRes = outValue.resourceId;
mHighlightColor = context.getColor(R.color.preference_highligh_color);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
updateBackground(holder, position);
}
@VisibleForTesting
void updateBackground(PreferenceViewHolder holder, int position) {
View v = holder.itemView;
if (position == mHighlightPosition) {
v.setBackgroundColor(mHighlightColor);
v.setTag(R.id.preference_highlighted, true);
v.postDelayed(() -> {
mHighlightPosition = RecyclerView.NO_POSITION;
removeHighlightBackground(v);
}, HIGHLIGHT_DURATION);
} else if (Boolean.TRUE.equals(v.getTag(R.id.preference_highlighted))) {
removeHighlightBackground(v);
}
}
public void requestHighlight(View root, RecyclerView recyclerView) {
if (mHighlightRequested || recyclerView == null || TextUtils.isEmpty(mHighlightKey)) {
return;
}
root.postDelayed(() -> {
final int position = getPreferenceAdapterPosition(mHighlightKey);
if (position < 0) {
return;
}
mHighlightRequested = true;
recyclerView.getLayoutManager().scrollToPosition(position);
mHighlightPosition = position;
notifyItemChanged(position);
}, DELAY_HIGHLIGHT_DURATION_MILLIS);
}
public boolean isHighlightRequested() {
return mHighlightRequested;
}
private void removeHighlightBackground(View v) {
v.setBackgroundResource(mNormalBackgroundRes);
v.setTag(R.id.preference_highlighted, false);
}
}