Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.settings.widget;
     18 
     19 import android.app.ActionBar;
     20 import android.app.Activity;
     21 import android.support.annotation.VisibleForTesting;
     22 import android.support.v7.widget.RecyclerView;
     23 import android.view.View;
     24 
     25 import com.android.settingslib.core.lifecycle.Lifecycle;
     26 import com.android.settingslib.core.lifecycle.LifecycleObserver;
     27 import com.android.settingslib.core.lifecycle.events.OnStart;
     28 import com.android.settingslib.core.lifecycle.events.OnStop;
     29 
     30 /**
     31  * A controller that adds shadow to actionbar when content view scrolls.
     32  * <p/>
     33  * It also works on custom views acting as an actionbar.
     34  */
     35 public class ActionBarShadowController implements LifecycleObserver, OnStart, OnStop {
     36 
     37     @VisibleForTesting
     38     static final float ELEVATION_HIGH = 8;
     39     @VisibleForTesting
     40     static final float ELEVATION_LOW = 0;
     41 
     42     @VisibleForTesting
     43     ScrollChangeWatcher mScrollChangeWatcher;
     44     private RecyclerView mRecyclerView;
     45     private boolean isScrollWatcherAttached;
     46 
     47     public static ActionBarShadowController attachToRecyclerView(Activity activity,
     48             Lifecycle lifecycle, RecyclerView recyclerView) {
     49         return new ActionBarShadowController(activity, lifecycle, recyclerView);
     50     }
     51 
     52     public static ActionBarShadowController attachToRecyclerView(View anchorView,
     53             Lifecycle lifecycle, RecyclerView recyclerView) {
     54         return new ActionBarShadowController(anchorView, lifecycle, recyclerView);
     55     }
     56 
     57     private ActionBarShadowController(Activity activity, Lifecycle lifecycle,
     58             RecyclerView recyclerView) {
     59         mScrollChangeWatcher = new ScrollChangeWatcher(activity);
     60         mRecyclerView = recyclerView;
     61         attachScrollWatcher();
     62         lifecycle.addObserver(this);
     63     }
     64 
     65     private ActionBarShadowController(View anchorView, Lifecycle lifecycle,
     66             RecyclerView recyclerView) {
     67         mScrollChangeWatcher = new ScrollChangeWatcher(anchorView);
     68         mRecyclerView = recyclerView;
     69         attachScrollWatcher();
     70         lifecycle.addObserver(this);
     71     }
     72 
     73     @Override
     74     public void onStop() {
     75         detachScrollWatcher();
     76     }
     77 
     78     private void detachScrollWatcher() {
     79         mRecyclerView.removeOnScrollListener(mScrollChangeWatcher);
     80         isScrollWatcherAttached = false;
     81     }
     82 
     83     @Override
     84     public void onStart() {
     85         attachScrollWatcher();
     86     }
     87 
     88     private void attachScrollWatcher() {
     89         if (!isScrollWatcherAttached) {
     90             isScrollWatcherAttached = true;
     91             mRecyclerView.addOnScrollListener(mScrollChangeWatcher);
     92             mScrollChangeWatcher.updateDropShadow(mRecyclerView);
     93         }
     94     }
     95 
     96     /**
     97      * Update the drop shadow as the scrollable entity is scrolled.
     98      */
     99     final class ScrollChangeWatcher extends RecyclerView.OnScrollListener {
    100 
    101         private final Activity mActivity;
    102         private final View mAnchorView;
    103 
    104         public ScrollChangeWatcher(Activity activity) {
    105             mActivity = activity;
    106             mAnchorView = null;
    107         }
    108 
    109         public ScrollChangeWatcher(View anchorView) {
    110             mAnchorView = anchorView;
    111             mActivity = null;
    112         }
    113 
    114         // RecyclerView scrolled.
    115         @Override
    116         public void onScrolled(RecyclerView view, int dx, int dy) {
    117             updateDropShadow(view);
    118         }
    119 
    120         public void updateDropShadow(View view) {
    121             final boolean shouldShowShadow = view.canScrollVertically(-1);
    122             if (mAnchorView != null) {
    123                 mAnchorView.setElevation(shouldShowShadow ? ELEVATION_HIGH : ELEVATION_LOW);
    124             } else if (mActivity != null) { // activity can become null when running monkey
    125                 final ActionBar actionBar = mActivity.getActionBar();
    126                 if (actionBar != null) {
    127                     actionBar.setElevation(shouldShowShadow ? ELEVATION_HIGH : ELEVATION_LOW);
    128                 }
    129             }
    130         }
    131     }
    132 
    133 }
    134