Loading packages/SettingsLib/ActionBarShadow/src/com/android/settingslib/widget/ActionBarShadowController.java +19 −24 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; import androidx.recyclerview.widget.RecyclerView; /** * UI controller that adds a shadow appear/disappear animation to action bar scroll. Loading @@ -41,40 +40,36 @@ public class ActionBarShadowController implements LifecycleObserver { @VisibleForTesting ScrollChangeWatcher mScrollChangeWatcher; private RecyclerView mRecyclerView; private View mScrollView; private boolean mIsScrollWatcherAttached; /** * Wire up the animation to to an {@link Activity}. Shadow will be applied to activity's * action bar. */ public static ActionBarShadowController attachToRecyclerView( Activity activity, Lifecycle lifecycle, RecyclerView recyclerView) { return new ActionBarShadowController(activity, lifecycle, recyclerView); public static ActionBarShadowController attachToView( Activity activity, Lifecycle lifecycle, View scrollView) { return new ActionBarShadowController(activity, lifecycle, scrollView); } /** * Wire up the animation to to a {@link View}. Shadow will be applied to the view. */ public static ActionBarShadowController attachToRecyclerView( View anchorView, Lifecycle lifecycle, RecyclerView recyclerView) { return new ActionBarShadowController(anchorView, lifecycle, recyclerView); public static ActionBarShadowController attachToView( View anchorView, Lifecycle lifecycle, View scrollView) { return new ActionBarShadowController(anchorView, lifecycle, scrollView); } private ActionBarShadowController(Activity activity, Lifecycle lifecycle, RecyclerView recyclerView) { mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(activity); mRecyclerView = recyclerView; private ActionBarShadowController(Activity activity, Lifecycle lifecycle, View scrollView) { mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(activity); mScrollView = scrollView; attachScrollWatcher(); lifecycle.addObserver(this); } private ActionBarShadowController(View anchorView, Lifecycle lifecycle, RecyclerView recyclerView) { mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(anchorView); mRecyclerView = recyclerView; private ActionBarShadowController(View anchorView, Lifecycle lifecycle, View scrollView) { mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(anchorView); mScrollView = scrollView; attachScrollWatcher(); lifecycle.addObserver(this); } Loading @@ -83,21 +78,21 @@ public class ActionBarShadowController implements LifecycleObserver { private void attachScrollWatcher() { if (!mIsScrollWatcherAttached) { mIsScrollWatcherAttached = true; mRecyclerView.addOnScrollListener(mScrollChangeWatcher); mScrollChangeWatcher.updateDropShadow(mRecyclerView); mScrollView.setOnScrollChangeListener(mScrollChangeWatcher); mScrollChangeWatcher.updateDropShadow(mScrollView); } } @OnLifecycleEvent(ON_STOP) private void detachScrollWatcher() { mRecyclerView.removeOnScrollListener(mScrollChangeWatcher); mScrollView.setOnScrollChangeListener(null); mIsScrollWatcherAttached = false; } /** * Update the drop shadow as the scrollable entity is scrolled. */ final class ScrollChangeWatcher extends RecyclerView.OnScrollListener { final class ScrollChangeWatcher implements View.OnScrollChangeListener { private final Activity mActivity; private final View mAnchorView; Loading @@ -112,9 +107,9 @@ public class ActionBarShadowController implements LifecycleObserver { mActivity = null; } // RecyclerView scrolled. @Override public void onScrolled(RecyclerView view, int dx, int dy) { public void onScrollChange(View view, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { updateDropShadow(view); } Loading packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionBarShadowControllerTest.java +24 −12 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static androidx.lifecycle.Lifecycle.Event.ON_STOP; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading Loading @@ -49,6 +50,8 @@ public class ActionBarShadowControllerTest { @Mock private RecyclerView mRecyclerView; @Mock private View mScrollView; @Mock private Activity mActivity; @Mock private ActionBar mActionBar; Loading @@ -66,51 +69,60 @@ public class ActionBarShadowControllerTest { } @Test public void attachToRecyclerView_shouldAddScrollWatcherAndUpdateActionBar() { public void attachToView_shouldAddScrollWatcherAndUpdateActionBar() { when(mRecyclerView.canScrollVertically(-1)).thenReturn(false); ActionBarShadowController.attachToRecyclerView(mActivity, mLifecycle, mRecyclerView); ActionBarShadowController.attachToView(mActivity, mLifecycle, mRecyclerView); verify(mActionBar).setElevation(ActionBarShadowController.ELEVATION_LOW); } @Test public void attachToView_scrollView_shouldAddScrollWatcherAndUpdateActionBar() { when(mScrollView.canScrollVertically(-1)).thenReturn(false); ActionBarShadowController.attachToView(mActivity, mLifecycle, mScrollView); verify(mActionBar).setElevation(ActionBarShadowController.ELEVATION_LOW); } @Test public void attachToRecyclerView_customViewAsActionBar_shouldUpdateElevationOnScroll() { public void attachToView_customViewAsActionBar_shouldUpdateElevationOnScroll() { // Setup mView.setElevation(50); when(mRecyclerView.canScrollVertically(-1)).thenReturn(false); final ActionBarShadowController controller = ActionBarShadowController.attachToRecyclerView(mView, mLifecycle, mRecyclerView); ActionBarShadowController.attachToView(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 */); controller.mScrollChangeWatcher.onScrollChange(mRecyclerView, 10, 10, 0, 0); assertThat(mView.getElevation()).isEqualTo(ActionBarShadowController.ELEVATION_HIGH); } @Test public void attachToRecyclerView_lifecycleChange_shouldAttachDetach() { ActionBarShadowController.attachToRecyclerView(mActivity, mLifecycle, mRecyclerView); public void attachToView_lifecycleChange_shouldAttachDetach() { ActionBarShadowController.attachToView(mActivity, mLifecycle, mRecyclerView); verify(mRecyclerView).addOnScrollListener(any()); verify(mRecyclerView).setOnScrollChangeListener(any()); mLifecycle.handleLifecycleEvent(ON_START); mLifecycle.handleLifecycleEvent(ON_STOP); verify(mRecyclerView).removeOnScrollListener(any()); verify(mRecyclerView).setOnScrollChangeListener(isNull()); mLifecycle.handleLifecycleEvent(ON_START); verify(mRecyclerView, times(2)).addOnScrollListener(any()); verify(mRecyclerView, times(3)).setOnScrollChangeListener(any()); } @Test public void onScrolled_nullAnchorViewAndActivity_shouldNotCrash() { final Activity activity = null; final ActionBarShadowController controller = ActionBarShadowController.attachToRecyclerView(activity, mLifecycle, mRecyclerView); ActionBarShadowController.attachToView(activity, mLifecycle, mRecyclerView); // Scroll controller.mScrollChangeWatcher.onScrolled(mRecyclerView, 10 /* dx */, 10 /* dy */); controller.mScrollChangeWatcher.onScrollChange(mRecyclerView, 10, 10, 0, 0); // no crash } } Loading
packages/SettingsLib/ActionBarShadow/src/com/android/settingslib/widget/ActionBarShadowController.java +19 −24 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; import androidx.recyclerview.widget.RecyclerView; /** * UI controller that adds a shadow appear/disappear animation to action bar scroll. Loading @@ -41,40 +40,36 @@ public class ActionBarShadowController implements LifecycleObserver { @VisibleForTesting ScrollChangeWatcher mScrollChangeWatcher; private RecyclerView mRecyclerView; private View mScrollView; private boolean mIsScrollWatcherAttached; /** * Wire up the animation to to an {@link Activity}. Shadow will be applied to activity's * action bar. */ public static ActionBarShadowController attachToRecyclerView( Activity activity, Lifecycle lifecycle, RecyclerView recyclerView) { return new ActionBarShadowController(activity, lifecycle, recyclerView); public static ActionBarShadowController attachToView( Activity activity, Lifecycle lifecycle, View scrollView) { return new ActionBarShadowController(activity, lifecycle, scrollView); } /** * Wire up the animation to to a {@link View}. Shadow will be applied to the view. */ public static ActionBarShadowController attachToRecyclerView( View anchorView, Lifecycle lifecycle, RecyclerView recyclerView) { return new ActionBarShadowController(anchorView, lifecycle, recyclerView); public static ActionBarShadowController attachToView( View anchorView, Lifecycle lifecycle, View scrollView) { return new ActionBarShadowController(anchorView, lifecycle, scrollView); } private ActionBarShadowController(Activity activity, Lifecycle lifecycle, RecyclerView recyclerView) { mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(activity); mRecyclerView = recyclerView; private ActionBarShadowController(Activity activity, Lifecycle lifecycle, View scrollView) { mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(activity); mScrollView = scrollView; attachScrollWatcher(); lifecycle.addObserver(this); } private ActionBarShadowController(View anchorView, Lifecycle lifecycle, RecyclerView recyclerView) { mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(anchorView); mRecyclerView = recyclerView; private ActionBarShadowController(View anchorView, Lifecycle lifecycle, View scrollView) { mScrollChangeWatcher = new ActionBarShadowController.ScrollChangeWatcher(anchorView); mScrollView = scrollView; attachScrollWatcher(); lifecycle.addObserver(this); } Loading @@ -83,21 +78,21 @@ public class ActionBarShadowController implements LifecycleObserver { private void attachScrollWatcher() { if (!mIsScrollWatcherAttached) { mIsScrollWatcherAttached = true; mRecyclerView.addOnScrollListener(mScrollChangeWatcher); mScrollChangeWatcher.updateDropShadow(mRecyclerView); mScrollView.setOnScrollChangeListener(mScrollChangeWatcher); mScrollChangeWatcher.updateDropShadow(mScrollView); } } @OnLifecycleEvent(ON_STOP) private void detachScrollWatcher() { mRecyclerView.removeOnScrollListener(mScrollChangeWatcher); mScrollView.setOnScrollChangeListener(null); mIsScrollWatcherAttached = false; } /** * Update the drop shadow as the scrollable entity is scrolled. */ final class ScrollChangeWatcher extends RecyclerView.OnScrollListener { final class ScrollChangeWatcher implements View.OnScrollChangeListener { private final Activity mActivity; private final View mAnchorView; Loading @@ -112,9 +107,9 @@ public class ActionBarShadowController implements LifecycleObserver { mActivity = null; } // RecyclerView scrolled. @Override public void onScrolled(RecyclerView view, int dx, int dy) { public void onScrollChange(View view, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { updateDropShadow(view); } Loading
packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionBarShadowControllerTest.java +24 −12 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static androidx.lifecycle.Lifecycle.Event.ON_STOP; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading Loading @@ -49,6 +50,8 @@ public class ActionBarShadowControllerTest { @Mock private RecyclerView mRecyclerView; @Mock private View mScrollView; @Mock private Activity mActivity; @Mock private ActionBar mActionBar; Loading @@ -66,51 +69,60 @@ public class ActionBarShadowControllerTest { } @Test public void attachToRecyclerView_shouldAddScrollWatcherAndUpdateActionBar() { public void attachToView_shouldAddScrollWatcherAndUpdateActionBar() { when(mRecyclerView.canScrollVertically(-1)).thenReturn(false); ActionBarShadowController.attachToRecyclerView(mActivity, mLifecycle, mRecyclerView); ActionBarShadowController.attachToView(mActivity, mLifecycle, mRecyclerView); verify(mActionBar).setElevation(ActionBarShadowController.ELEVATION_LOW); } @Test public void attachToView_scrollView_shouldAddScrollWatcherAndUpdateActionBar() { when(mScrollView.canScrollVertically(-1)).thenReturn(false); ActionBarShadowController.attachToView(mActivity, mLifecycle, mScrollView); verify(mActionBar).setElevation(ActionBarShadowController.ELEVATION_LOW); } @Test public void attachToRecyclerView_customViewAsActionBar_shouldUpdateElevationOnScroll() { public void attachToView_customViewAsActionBar_shouldUpdateElevationOnScroll() { // Setup mView.setElevation(50); when(mRecyclerView.canScrollVertically(-1)).thenReturn(false); final ActionBarShadowController controller = ActionBarShadowController.attachToRecyclerView(mView, mLifecycle, mRecyclerView); ActionBarShadowController.attachToView(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 */); controller.mScrollChangeWatcher.onScrollChange(mRecyclerView, 10, 10, 0, 0); assertThat(mView.getElevation()).isEqualTo(ActionBarShadowController.ELEVATION_HIGH); } @Test public void attachToRecyclerView_lifecycleChange_shouldAttachDetach() { ActionBarShadowController.attachToRecyclerView(mActivity, mLifecycle, mRecyclerView); public void attachToView_lifecycleChange_shouldAttachDetach() { ActionBarShadowController.attachToView(mActivity, mLifecycle, mRecyclerView); verify(mRecyclerView).addOnScrollListener(any()); verify(mRecyclerView).setOnScrollChangeListener(any()); mLifecycle.handleLifecycleEvent(ON_START); mLifecycle.handleLifecycleEvent(ON_STOP); verify(mRecyclerView).removeOnScrollListener(any()); verify(mRecyclerView).setOnScrollChangeListener(isNull()); mLifecycle.handleLifecycleEvent(ON_START); verify(mRecyclerView, times(2)).addOnScrollListener(any()); verify(mRecyclerView, times(3)).setOnScrollChangeListener(any()); } @Test public void onScrolled_nullAnchorViewAndActivity_shouldNotCrash() { final Activity activity = null; final ActionBarShadowController controller = ActionBarShadowController.attachToRecyclerView(activity, mLifecycle, mRecyclerView); ActionBarShadowController.attachToView(activity, mLifecycle, mRecyclerView); // Scroll controller.mScrollChangeWatcher.onScrolled(mRecyclerView, 10 /* dx */, 10 /* dy */); controller.mScrollChangeWatcher.onScrollChange(mRecyclerView, 10, 10, 0, 0); // no crash } }