Add shadow to searchbar when user scrolls vertically
Bug: 63528057
Test: robotests
Change-Id: Ib85676d78b43be38aab1eacd0820d0755a601f60
(cherry picked from commit e651ddf9e6)
			
			
This commit is contained in:
		@@ -22,6 +22,7 @@
 | 
			
		||||
    android:orientation="vertical">
 | 
			
		||||
 | 
			
		||||
    <FrameLayout
 | 
			
		||||
        android:id="@+id/search_bar_container"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:background="@color/suggestion_condition_background">
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
    android:layout_height="match_parent"
 | 
			
		||||
    android:orientation="vertical">
 | 
			
		||||
    <FrameLayout
 | 
			
		||||
        android:id="@+id/search_bar_container"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:background="@color/suggestion_condition_background">
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ import com.android.settings.dashboard.suggestions.SuggestionDismissController;
 | 
			
		||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
 | 
			
		||||
import com.android.settings.dashboard.suggestions.SuggestionsChecks;
 | 
			
		||||
import com.android.settings.overlay.FeatureFactory;
 | 
			
		||||
import com.android.settings.widget.ActionBarShadowController;
 | 
			
		||||
import com.android.settingslib.drawer.CategoryKey;
 | 
			
		||||
import com.android.settingslib.drawer.DashboardCategory;
 | 
			
		||||
import com.android.settingslib.drawer.SettingsDrawerActivity;
 | 
			
		||||
@@ -192,12 +193,14 @@ public class DashboardSummary extends InstrumentedFragment
 | 
			
		||||
        mDashboard.setHasFixedSize(true);
 | 
			
		||||
        mDashboard.addItemDecoration(new DashboardDecorator(getContext()));
 | 
			
		||||
        mDashboard.setListener(this);
 | 
			
		||||
        Log.d(TAG, "adapter created");
 | 
			
		||||
        mAdapter = new DashboardAdapter(getContext(), bundle, mConditionManager.getConditions(),
 | 
			
		||||
            mSuggestionParser, this /* SuggestionDismissController.Callback */);
 | 
			
		||||
        mDashboard.setAdapter(mAdapter);
 | 
			
		||||
        mDashboard.setItemAnimator(new DashboardItemAnimator());
 | 
			
		||||
        mSummaryLoader.setSummaryConsumer(mAdapter);
 | 
			
		||||
        ActionBarShadowController.attachToRecyclerView(
 | 
			
		||||
                getActivity().findViewById(R.id.search_bar_container), getLifecycle(), mDashboard);
 | 
			
		||||
 | 
			
		||||
        if (DEBUG_TIMING) {
 | 
			
		||||
            Log.d(TAG, "onViewCreated took "
 | 
			
		||||
                    + (System.currentTimeMillis() - startTime) + " ms");
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ public class CellularDataCondition extends Condition {
 | 
			
		||||
            setActive(false);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        setActive(!telephony.getDataEnabled());
 | 
			
		||||
        setActive(!telephony.isDataEnabled());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,6 @@ import android.provider.Settings;
 | 
			
		||||
import android.support.annotation.NonNull;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
 | 
			
		||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
 | 
			
		||||
import com.android.internal.logging.nano.MetricsProto;
 | 
			
		||||
import com.android.settings.Settings.AmbientDisplayPickupSuggestionActivity;
 | 
			
		||||
import com.android.settings.Settings.AmbientDisplaySuggestionActivity;
 | 
			
		||||
@@ -54,7 +53,6 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider
 | 
			
		||||
 | 
			
		||||
    private final SuggestionRanker mSuggestionRanker;
 | 
			
		||||
    private final MetricsFeatureProvider mMetricsFeatureProvider;
 | 
			
		||||
    private final AmbientDisplayConfiguration mAmbientDisplayConfig;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isSmartSuggestionEnabled(Context context) {
 | 
			
		||||
@@ -96,7 +94,6 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider
 | 
			
		||||
                new SuggestionFeaturizer(new EventStore(appContext)));
 | 
			
		||||
        mMetricsFeatureProvider = FeatureFactory.getFactory(appContext)
 | 
			
		||||
                .getMetricsFeatureProvider();
 | 
			
		||||
        mAmbientDisplayConfig = new AmbientDisplayConfiguration(appContext);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ import com.android.settings.Utils;
 | 
			
		||||
import com.android.settings.core.InstrumentedFragment;
 | 
			
		||||
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
 | 
			
		||||
import com.android.settings.overlay.FeatureFactory;
 | 
			
		||||
import com.android.settings.widget.ActionBarShadowController;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
@@ -202,6 +203,8 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O
 | 
			
		||||
            params.setMarginStart(0);
 | 
			
		||||
            editFrame.setLayoutParams(params);
 | 
			
		||||
        }
 | 
			
		||||
        ActionBarShadowController.attachToRecyclerView(
 | 
			
		||||
                view.findViewById(R.id.search_bar_container), getLifecycle(), mResultsRecyclerView);
 | 
			
		||||
        return view;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ package com.android.settings.widget;
 | 
			
		||||
 | 
			
		||||
import android.app.ActionBar;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.support.annotation.VisibleForTesting;
 | 
			
		||||
import android.support.v7.widget.RecyclerView;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
 | 
			
		||||
@@ -26,9 +27,20 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver;
 | 
			
		||||
import com.android.settingslib.core.lifecycle.events.OnStart;
 | 
			
		||||
import com.android.settingslib.core.lifecycle.events.OnStop;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A controller that adds shadow to actionbar when content view scrolls.
 | 
			
		||||
 * <p/>
 | 
			
		||||
 * It also works on custom views acting as an actionbar.
 | 
			
		||||
 */
 | 
			
		||||
public class ActionBarShadowController implements LifecycleObserver, OnStart, OnStop {
 | 
			
		||||
 | 
			
		||||
    private ScrollChangeWatcher mScrollChangeWatcher;
 | 
			
		||||
    @VisibleForTesting
 | 
			
		||||
    static final float ELEVATION_HIGH = 8;
 | 
			
		||||
    @VisibleForTesting
 | 
			
		||||
    static final float ELEVATION_LOW = 0;
 | 
			
		||||
 | 
			
		||||
    @VisibleForTesting
 | 
			
		||||
    ScrollChangeWatcher mScrollChangeWatcher;
 | 
			
		||||
    private RecyclerView mRecyclerView;
 | 
			
		||||
    private boolean isScrollWatcherAttached;
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +49,11 @@ public class ActionBarShadowController implements LifecycleObserver, OnStart, On
 | 
			
		||||
        return new ActionBarShadowController(activity, lifecycle, recyclerView);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ActionBarShadowController attachToRecyclerView(View anchorView,
 | 
			
		||||
            Lifecycle lifecycle, RecyclerView recyclerView) {
 | 
			
		||||
        return new ActionBarShadowController(anchorView, lifecycle, recyclerView);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ActionBarShadowController(Activity activity, Lifecycle lifecycle,
 | 
			
		||||
            RecyclerView recyclerView) {
 | 
			
		||||
        mScrollChangeWatcher = new ScrollChangeWatcher(activity);
 | 
			
		||||
@@ -45,6 +62,14 @@ public class ActionBarShadowController implements LifecycleObserver, OnStart, On
 | 
			
		||||
        lifecycle.addObserver(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ActionBarShadowController(View anchorView, Lifecycle lifecycle,
 | 
			
		||||
            RecyclerView recyclerView) {
 | 
			
		||||
        mScrollChangeWatcher = new ScrollChangeWatcher(anchorView);
 | 
			
		||||
        mRecyclerView = recyclerView;
 | 
			
		||||
        attachScrollWatcher();
 | 
			
		||||
        lifecycle.addObserver(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onStop() {
 | 
			
		||||
        detachScrollWatcher();
 | 
			
		||||
@@ -71,12 +96,19 @@ public class ActionBarShadowController implements LifecycleObserver, OnStart, On
 | 
			
		||||
    /**
 | 
			
		||||
     * Update the drop shadow as the scrollable entity is scrolled.
 | 
			
		||||
     */
 | 
			
		||||
    private final class ScrollChangeWatcher extends RecyclerView.OnScrollListener {
 | 
			
		||||
    final class ScrollChangeWatcher extends RecyclerView.OnScrollListener {
 | 
			
		||||
 | 
			
		||||
        private Activity mActivity;
 | 
			
		||||
        private final Activity mActivity;
 | 
			
		||||
        private final View mAnchorView;
 | 
			
		||||
 | 
			
		||||
        public ScrollChangeWatcher(Activity activity) {
 | 
			
		||||
            mActivity = activity;
 | 
			
		||||
            mAnchorView = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ScrollChangeWatcher(View anchorView) {
 | 
			
		||||
            mAnchorView = anchorView;
 | 
			
		||||
            mActivity = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // RecyclerView scrolled.
 | 
			
		||||
@@ -87,9 +119,13 @@ public class ActionBarShadowController implements LifecycleObserver, OnStart, On
 | 
			
		||||
 | 
			
		||||
        public void updateDropShadow(View view) {
 | 
			
		||||
            final boolean shouldShowShadow = view.canScrollVertically(-1);
 | 
			
		||||
            final ActionBar actionBar = mActivity.getActionBar();
 | 
			
		||||
            if (actionBar != null) {
 | 
			
		||||
                actionBar.setElevation(shouldShowShadow ? 8 : 0);
 | 
			
		||||
            if (mAnchorView != null) {
 | 
			
		||||
                mAnchorView.setElevation(shouldShowShadow ? ELEVATION_HIGH : ELEVATION_LOW);
 | 
			
		||||
            } else {
 | 
			
		||||
                final ActionBar actionBar = mActivity.getActionBar();
 | 
			
		||||
                if (actionBar != null) {
 | 
			
		||||
                    actionBar.setElevation(shouldShowShadow ? ELEVATION_HIGH : ELEVATION_LOW);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -17,12 +17,19 @@
 | 
			
		||||
package com.android.settings.widget;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import static com.google.common.truth.Truth.assertThat;
 | 
			
		||||
import static org.mockito.Matchers.any;
 | 
			
		||||
import static org.mockito.Mockito.times;
 | 
			
		||||
import static org.mockito.Mockito.verify;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
import android.app.ActionBar;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.support.v7.widget.RecyclerView;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
 | 
			
		||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
 | 
			
		||||
import com.android.settings.TestConfig;
 | 
			
		||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
 | 
			
		||||
import com.android.settingslib.core.lifecycle.Lifecycle;
 | 
			
		||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
 | 
			
		||||
 | 
			
		||||
@@ -31,17 +38,12 @@ import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.MockitoAnnotations;
 | 
			
		||||
import org.robolectric.RuntimeEnvironment;
 | 
			
		||||
import org.robolectric.annotation.Config;
 | 
			
		||||
import org.robolectric.util.ReflectionHelpers;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static com.google.common.truth.Truth.assertThat;
 | 
			
		||||
import static org.mockito.Matchers.any;
 | 
			
		||||
import static org.mockito.Mockito.times;
 | 
			
		||||
import static org.mockito.Mockito.verify;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
@RunWith(SettingsRobolectricTestRunner.class)
 | 
			
		||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 | 
			
		||||
public class ActionBarShadowControllerTest {
 | 
			
		||||
@@ -53,11 +55,13 @@ public class ActionBarShadowControllerTest {
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ActionBar mActionBar;
 | 
			
		||||
    private Lifecycle mLifecycle;
 | 
			
		||||
    private View mView;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() {
 | 
			
		||||
        MockitoAnnotations.initMocks(this);
 | 
			
		||||
        when(mActivity.getActionBar()).thenReturn(mActionBar);
 | 
			
		||||
        mView = new View(RuntimeEnvironment.application);
 | 
			
		||||
        mLifecycle = new Lifecycle();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -67,9 +71,23 @@ public class ActionBarShadowControllerTest {
 | 
			
		||||
 | 
			
		||||
        ActionBarShadowController.attachToRecyclerView(mActivity, mLifecycle, mRecyclerView);
 | 
			
		||||
 | 
			
		||||
        verify(mActionBar).setElevation(0);
 | 
			
		||||
        verify(mActionBar).setElevation(ActionBarShadowController.ELEVATION_LOW);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void attachToRecyclerView_customViewAsActionBar_shouldUpdateElevationOnScroll() {
 | 
			
		||||
        // Setup
 | 
			
		||||
        mView.setElevation(50);
 | 
			
		||||
        when(mRecyclerView.canScrollVertically(-1)).thenReturn(false);
 | 
			
		||||
        final ActionBarShadowController controller =
 | 
			
		||||
                ActionBarShadowController.attachToRecyclerView(mView, mLifecycle, mRecyclerView);
 | 
			
		||||
        assertThat(mView.getElevation()).isEqualTo(ActionBarShadowController.ELEVATION_LOW);
 | 
			
		||||
 | 
			
		||||
        // Scroll
 | 
			
		||||
        when(mRecyclerView.canScrollVertically(-1)).thenReturn(true);
 | 
			
		||||
        controller.mScrollChangeWatcher.onScrolled(mRecyclerView, 10 /* dx */, 10 /* dy */);
 | 
			
		||||
        assertThat(mView.getElevation()).isEqualTo(ActionBarShadowController.ELEVATION_HIGH);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void attachToRecyclerView_lifecycleChange_shouldAttachDetach() {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user