Focusing on item highlighted coming from search result

There are two cases that require different approach:
1. No scrolling or only a bit of scrolling is required to reach desired
   item - then we can focus the item straight away.
2. We're still scrolling when highlighting is started - after
   DELAY_COLLAPSE_DURATION_MILLIS + DELAY_HIGHLIGHT_DURATION_MILLIS.
   Then we need to wait till we reach the element/stop scrolling and focus
   afterwards.

Test: case 1: search for any setting, press enter and see if keyboard is focused
on search result
Test: case 2: search for setting that requires a lot of scrolling, e.g.
"display cutout" and see if it's get the focus after selecting
Fixes: 307902050

Change-Id: Ifa0738748184e78074099e33e09e5d8df198177e
This commit is contained in:
Michal Brzezinski
2023-11-02 14:07:35 +00:00
parent 1926318cdc
commit ef696934b0
2 changed files with 26 additions and 6 deletions

View File

@@ -479,6 +479,7 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
mDialogFragment.dismiss();
mDialogFragment = null;
}
getListView().clearOnScrollListeners();
}
super.onDetach();
}

View File

@@ -29,12 +29,14 @@ import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceGroupAdapter;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
@@ -159,15 +161,32 @@ public class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter
root.postDelayed(() -> {
if (ensureHighlightPosition()) {
recyclerView.smoothScrollToPosition(mHighlightPosition);
highlightAndFocusTargetItem(recyclerView, mHighlightPosition);
}
}, DELAY_HIGHLIGHT_DURATION_MILLIS);
}
// Highlight preference after 900 milliseconds.
root.postDelayed(() -> {
if (ensureHighlightPosition()) {
notifyItemChanged(mHighlightPosition);
}
}, DELAY_COLLAPSE_DURATION_MILLIS + DELAY_HIGHLIGHT_DURATION_MILLIS);
private void highlightAndFocusTargetItem(RecyclerView recyclerView, int highlightPosition) {
ViewHolder target = recyclerView.findViewHolderForAdapterPosition(highlightPosition);
if (target != null) { // view already visible
notifyItemChanged(mHighlightPosition);
target.itemView.requestFocus();
} else { // otherwise we're about to scroll to that view (but we might not be scrolling yet)
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
notifyItemChanged(mHighlightPosition);
ViewHolder target = recyclerView
.findViewHolderForAdapterPosition(highlightPosition);
if (target != null) {
target.itemView.requestFocus();
}
recyclerView.removeOnScrollListener(this);
}
}
});
}
}
/**