import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.util.ArrayMap;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
+import android.util.ArraySet;
import java.util.ArrayList;
import java.util.Collections;
final Rect mOtherRect = new Rect();
final Rect mBestCandidateRect = new Rect();
private final UserSpecifiedFocusComparator mUserSpecifiedFocusComparator =
- new UserSpecifiedFocusComparator((v) -> v.getNextFocusForwardId());
+ new UserSpecifiedFocusComparator((r, v) -> isValidId(v.getNextFocusForwardId())
+ ? v.findUserSetNextFocus(r, View.FOCUS_FORWARD) : null);
private final UserSpecifiedFocusComparator mUserSpecifiedClusterComparator =
- new UserSpecifiedFocusComparator((v) -> v.getNextClusterForwardId());
+ new UserSpecifiedFocusComparator((r, v) -> isValidId(v.getNextClusterForwardId())
+ ? v.findUserSetNextKeyboardNavigationCluster(r, View.FOCUS_FORWARD) : null);
private final FocusComparator mFocusComparator = new FocusComparator();
private final ArrayList<View> mTempList = new ArrayList<View>();
@View.FocusDirection int direction) {
try {
// Note: This sort is stable.
- mUserSpecifiedClusterComparator.setFocusables(clusters);
+ mUserSpecifiedClusterComparator.setFocusables(clusters, root);
Collections.sort(clusters, mUserSpecifiedClusterComparator);
} finally {
mUserSpecifiedClusterComparator.recycle();
View focused, Rect focusedRect, int direction) {
try {
// Note: This sort is stable.
- mUserSpecifiedFocusComparator.setFocusables(focusables);
+ mUserSpecifiedFocusComparator.setFocusables(focusables, root);
Collections.sort(focusables, mUserSpecifiedFocusComparator);
} finally {
mUserSpecifiedFocusComparator.recycle();
* specified focus chains (eg. no nextFocusForward attributes defined), this should be a no-op.
*/
private static final class UserSpecifiedFocusComparator implements Comparator<View> {
- private final SparseArray<View> mFocusables = new SparseArray<View>();
- private final SparseBooleanArray mIsConnectedTo = new SparseBooleanArray();
+ private final ArrayMap<View, View> mNextFoci = new ArrayMap<>();
+ private final ArraySet<View> mIsConnectedTo = new ArraySet<>();
private final ArrayMap<View, View> mHeadsOfChains = new ArrayMap<View, View>();
private final ArrayMap<View, Integer> mOriginalOrdinal = new ArrayMap<>();
- private final NextIdGetter mNextIdGetter;
+ private final NextFocusGetter mNextFocusGetter;
+ private View mRoot;
- public interface NextIdGetter {
- int get(View view);
+ public interface NextFocusGetter {
+ View get(View root, View view);
}
- UserSpecifiedFocusComparator(NextIdGetter nextIdGetter) {
- mNextIdGetter = nextIdGetter;
+ UserSpecifiedFocusComparator(NextFocusGetter nextFocusGetter) {
+ mNextFocusGetter = nextFocusGetter;
}
public void recycle() {
- mFocusables.clear();
+ mRoot = null;
mHeadsOfChains.clear();
mIsConnectedTo.clear();
mOriginalOrdinal.clear();
+ mNextFoci.clear();
}
- public void setFocusables(List<View> focusables) {
+ public void setFocusables(List<View> focusables, View root) {
+ mRoot = root;
+ for (int i = 0; i < focusables.size(); ++i) {
+ mOriginalOrdinal.put(focusables.get(i), i);
+ }
+
for (int i = focusables.size() - 1; i >= 0; i--) {
final View view = focusables.get(i);
- final int id = view.getId();
- if (isValidId(id)) {
- mFocusables.put(id, view);
- }
- final int nextId = mNextIdGetter.get(view);
- if (isValidId(nextId)) {
- mIsConnectedTo.put(nextId, true);
+ final View next = mNextFocusGetter.get(mRoot, view);
+ if (next != null && mOriginalOrdinal.containsKey(next)) {
+ mNextFoci.put(view, next);
+ mIsConnectedTo.add(next);
}
}
for (int i = focusables.size() - 1; i >= 0; i--) {
final View view = focusables.get(i);
- final int nextId = mNextIdGetter.get(view);
- if (isValidId(nextId) && !mIsConnectedTo.get(view.getId())) {
+ final View next = mNextFoci.get(view);
+ if (next != null && !mIsConnectedTo.contains(view)) {
setHeadOfChain(view);
}
}
-
- for (int i = 0; i < focusables.size(); ++i) {
- mOriginalOrdinal.put(focusables.get(i), i);
- }
}
private void setHeadOfChain(View head) {
- for (View view = head; view != null;
- view = mFocusables.get(mNextIdGetter.get(view))) {
+ for (View view = head; view != null; view = mNextFoci.get(view)) {
final View otherHead = mHeadsOfChains.get(view);
if (otherHead != null) {
if (otherHead == head) {
return -1; // first is the head, it should be first
} else if (second == firstHead) {
return 1; // second is the head, it should be first
- } else if (isValidId(mNextIdGetter.get(first))) {
+ } else if (mNextFoci.get(first) != null) {
return -1; // first is not the end of the chain
} else {
return 1; // first is end of chain