Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef87755c authored by Tsung-Mao Fang's avatar Tsung-Mao Fang
Browse files

Fix the higlighted settings not work properly from search

Since the Andorid S, we introduce the CollapsingToolbarLayout
, the highlighted funcation might break for unkown reason.
I observed that broken cases with overlapping issue on tool bar.
The possible root cause is the interation bwtween
CoordinatorLayout v.s CollapsingToolbarLayout v.s Recycler
view.

This cl is definetly a workaround to prevent this issue.
I try to collapse the tool bar with an animation before
we start to scroll the list. This makes the overall transition smooth
but always collapse the tool bar.

Fix: 177968297
Test: Click a lot of search results, and screen should highlight
settings correctly.

Change-Id: Id9c32b642433dcc39c179a2cc83a06e77cc47888
parent beefb25b
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@ import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.widget.LayoutPreference;

import com.google.android.material.appbar.AppBarLayout;

import java.util.UUID;

/**
@@ -112,9 +114,8 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF

    @VisibleForTesting
    ViewGroup mPinnedHeaderFrameLayout;

    private AppBarLayout mAppBarLayout;
    private LayoutPreference mHeader;

    private View mEmptyView;
    private LinearLayoutManager mLayoutManager;
    private ArrayMap<String, Preference> mPreferenceCache;
@@ -145,6 +146,7 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
            Bundle savedInstanceState) {
        final View root = super.onCreateView(inflater, container, savedInstanceState);
        mPinnedHeaderFrameLayout = root.findViewById(R.id.pinned_header);
        mAppBarLayout = getActivity().findViewById(R.id.app_bar);
        return root;
    }

@@ -250,7 +252,7 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
            return;
        }
        if (mAdapter != null) {
            mAdapter.requestHighlight(getView(), getListView());
            mAdapter.requestHighlight(getView(), getListView(), mAppBarLayout);
        }
    }

+21 −6
Original line number Diff line number Diff line
@@ -39,10 +39,14 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;

import com.google.android.material.appbar.AppBarLayout;

public class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter {

    private static final String TAG = "HighlightableAdapter";
    @VisibleForTesting
    static final long DELAY_COLLAPSE_DURATION_MILLIS = 300L;
    @VisibleForTesting
    static final long DELAY_HIGHLIGHT_DURATION_MILLIS = 600L;
    private static final long HIGHLIGHT_DURATION = 15000L;
    private static final long HIGHLIGHT_FADE_OUT_DURATION = 500L;
@@ -124,15 +128,26 @@ public class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter
        }
    }

    public void requestHighlight(View root, RecyclerView recyclerView) {
    /**
     * A function can highlight a specific setting in recycler view.
     * note: Before highlighting a setting, screen collapses tool bar with an animation.
     */
    public void requestHighlight(View root, RecyclerView recyclerView, AppBarLayout appBarLayout) {
        if (mHighlightRequested || recyclerView == null || TextUtils.isEmpty(mHighlightKey)) {
            return;
        }
        root.postDelayed(() -> {
        final int position = getPreferenceAdapterPosition(mHighlightKey);
        if (position < 0) {
            return;
        }

        if (appBarLayout != null) {
            root.postDelayed(() -> {
                appBarLayout.setExpanded(false, true);
            }, DELAY_COLLAPSE_DURATION_MILLIS);
        }

        root.postDelayed(() -> {
            mHighlightRequested = true;
            recyclerView.smoothScrollToPosition(position);
            mHighlightPosition = position;
+11 −5
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -43,6 +44,8 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;

import com.google.android.material.appbar.AppBarLayout;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -85,8 +88,11 @@ public class HighlightablePreferenceGroupAdapterTest {

    @Test
    public void requestHighlight_hasKey_notHighlightedBefore_shouldRequest() {
        mAdapter.requestHighlight(mRoot, mock(RecyclerView.class));
        when(mAdapter.getPreferenceAdapterPosition(anyString())).thenReturn(1);
        mAdapter.requestHighlight(mRoot, mock(RecyclerView.class), mock(AppBarLayout.class));

        verify(mRoot).postDelayed(any(),
                eq(HighlightablePreferenceGroupAdapter.DELAY_COLLAPSE_DURATION_MILLIS));
        verify(mRoot).postDelayed(any(),
                eq(HighlightablePreferenceGroupAdapter.DELAY_HIGHLIGHT_DURATION_MILLIS));
    }
@@ -95,21 +101,21 @@ public class HighlightablePreferenceGroupAdapterTest {
    public void requestHighlight_noKey_highlightedBefore_noRecyclerView_shouldNotRequest() {
        ReflectionHelpers.setField(mAdapter, "mHighlightKey", null);
        ReflectionHelpers.setField(mAdapter, "mHighlightRequested", false);
        mAdapter.requestHighlight(mRoot, mock(RecyclerView.class));
        mAdapter.requestHighlight(mRoot, mock(RecyclerView.class),  mock(AppBarLayout.class));

        ReflectionHelpers.setField(mAdapter, "mHighlightKey", TEST_KEY);
        ReflectionHelpers.setField(mAdapter, "mHighlightRequested", true);
        mAdapter.requestHighlight(mRoot, mock(RecyclerView.class));
        mAdapter.requestHighlight(mRoot, mock(RecyclerView.class), mock(AppBarLayout.class));

        ReflectionHelpers.setField(mAdapter, "mHighlightKey", TEST_KEY);
        ReflectionHelpers.setField(mAdapter, "mHighlightRequested", false);
        mAdapter.requestHighlight(mRoot, null /* recyclerView */);
        mAdapter.requestHighlight(mRoot, null /* recyclerView */,  mock(AppBarLayout.class));

        verifyZeroInteractions(mRoot);
    }

    @Test
    public void adjustInitialExpandedChildCount_invalidInput_shouldNotadjust() {
    public void adjustInitialExpandedChildCount_invalidInput_shouldNotAdjust() {
        HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(null /* host */);
        HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(mFragment);
        final Bundle args = new Bundle();