Home | History | Annotate | Download | only in settings
      1 /*
      2  * Copyright (C) 2016 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 package com.android.settings;
     17 
     18 import android.animation.Animator;
     19 import android.animation.Animator.AnimatorListener;
     20 import android.content.Context;
     21 import android.content.res.Configuration;
     22 import android.support.v4.view.PagerAdapter;
     23 import android.view.LayoutInflater;
     24 import android.view.View;
     25 import android.view.ViewGroup;
     26 import android.view.ViewStub;
     27 import android.view.ViewStub.OnInflateListener;
     28 import android.view.animation.AccelerateInterpolator;
     29 import android.view.animation.DecelerateInterpolator;
     30 import android.view.animation.Interpolator;
     31 import android.widget.FrameLayout;
     32 import android.widget.LinearLayout;
     33 import android.widget.ScrollView;
     34 
     35 /**
     36  * A PagerAdapter used by PreviewSeekBarPreferenceFragment that for showing multiple preview screen
     37  * regarding a single setting and allowing the user to swipe across them.
     38  */
     39 public class PreviewPagerAdapter extends PagerAdapter {
     40 
     41     /** Duration to use when cross-fading between previews. */
     42     private static final long CROSS_FADE_DURATION_MS = 400;
     43 
     44     /** Interpolator to use when cross-fading between previews. */
     45     private static final Interpolator FADE_IN_INTERPOLATOR = new DecelerateInterpolator();
     46 
     47     /** Interpolator to use when cross-fading between previews. */
     48     private static final Interpolator FADE_OUT_INTERPOLATOR = new AccelerateInterpolator();
     49 
     50     private FrameLayout[] mPreviewFrames;
     51 
     52     private boolean mIsLayoutRtl;
     53 
     54     private Runnable mAnimationEndAction;
     55 
     56     private int mAnimationCounter;
     57 
     58     private boolean[][] mViewStubInflated;
     59 
     60     public PreviewPagerAdapter(Context context, boolean isLayoutRtl,
     61             int[] previewSampleResIds, Configuration[] configurations) {
     62         mIsLayoutRtl = isLayoutRtl;
     63         mPreviewFrames = new FrameLayout[previewSampleResIds.length];
     64         mViewStubInflated = new boolean[previewSampleResIds.length][configurations.length];
     65 
     66         for (int i = 0; i < previewSampleResIds.length; ++i) {
     67             int p = mIsLayoutRtl ? previewSampleResIds.length - 1 - i : i;
     68             mPreviewFrames[p] = new FrameLayout(context);
     69             mPreviewFrames[p].setLayoutParams(new LinearLayout.LayoutParams(
     70                     LinearLayout.LayoutParams.MATCH_PARENT,
     71                     LinearLayout.LayoutParams.MATCH_PARENT));
     72 
     73             for (int j = 0; j < configurations.length; ++j) {
     74                 // Create a new configuration for the specified value. It won't
     75                 // have any theme set, so manually apply the current theme.
     76                 final Context configContext = context.createConfigurationContext(configurations[j]);
     77                 configContext.getTheme().setTo(context.getTheme());
     78 
     79                 final LayoutInflater configInflater = LayoutInflater.from(configContext);
     80                 final ViewStub sampleViewStub = new ViewStub(configContext);
     81                 sampleViewStub.setLayoutResource(previewSampleResIds[i]);
     82                 final int fi = i, fj = j;
     83                 sampleViewStub.setOnInflateListener(new OnInflateListener() {
     84                     @Override
     85                     public void onInflate(ViewStub stub, View inflated) {
     86                         inflated.setVisibility(stub.getVisibility());
     87                         mViewStubInflated[fi][fj] = true;
     88                     }
     89                 });
     90 
     91                 mPreviewFrames[p].addView(sampleViewStub);
     92             }
     93         }
     94     }
     95 
     96     @Override
     97     public void destroyItem (ViewGroup container, int position, Object object) {
     98         container.removeView((View) object);
     99     }
    100 
    101     @Override
    102     public int getCount() {
    103         return mPreviewFrames.length;
    104     }
    105 
    106     @Override
    107     public Object instantiateItem(ViewGroup container, int position) {
    108         container.addView(mPreviewFrames[position]);
    109         return mPreviewFrames[position];
    110     }
    111 
    112     @Override
    113     public boolean isViewFromObject(View view, Object object) {
    114         return (view == object);
    115     }
    116 
    117     boolean isAnimating() {
    118         return mAnimationCounter > 0;
    119     }
    120 
    121     void setAnimationEndAction(Runnable action) {
    122         mAnimationEndAction = action;
    123     }
    124 
    125     void setPreviewLayer(int newLayerIndex, int currentLayerIndex, int currentFrameIndex,
    126             final boolean animate) {
    127         for (FrameLayout previewFrame : mPreviewFrames) {
    128             if (currentLayerIndex >= 0) {
    129                 final View lastLayer = previewFrame.getChildAt(currentLayerIndex);
    130                 if (mViewStubInflated[currentFrameIndex][currentLayerIndex]) {
    131                     // Explicitly set to INVISIBLE only when the stub has
    132                     // already been inflated.
    133                     if (previewFrame == mPreviewFrames[currentFrameIndex]) {
    134                         setVisibility(lastLayer, View.INVISIBLE, animate);
    135                     } else {
    136                         setVisibility(lastLayer, View.INVISIBLE, false);
    137                     }
    138                 }
    139             }
    140 
    141             // Set next layer visible, as well as inflate necessary views.
    142             View nextLayer = previewFrame.getChildAt(newLayerIndex);
    143             if (previewFrame == mPreviewFrames[currentFrameIndex]) {
    144                 // Inflate immediately if the stub has not yet been inflated.
    145                 if (!mViewStubInflated[currentFrameIndex][newLayerIndex]) {
    146                     nextLayer = ((ViewStub) nextLayer).inflate();
    147                     nextLayer.setAlpha(0.0f);
    148                 }
    149                 setVisibility(nextLayer, View.VISIBLE, animate);
    150             } else {
    151                 setVisibility(nextLayer, View.VISIBLE, false);
    152             }
    153         }
    154     }
    155 
    156     private void setVisibility(final View view, final int visibility, boolean animate) {
    157         final float alpha = (visibility == View.VISIBLE ? 1.0f : 0.0f);
    158         if (!animate) {
    159             view.setAlpha(alpha);
    160             view.setVisibility(visibility);
    161         } else {
    162             final Interpolator interpolator = (visibility == View.VISIBLE ? FADE_IN_INTERPOLATOR
    163                     : FADE_OUT_INTERPOLATOR);
    164             if (visibility == View.VISIBLE) {
    165                 // Fade in animation.
    166                 view.animate()
    167                 .alpha(alpha)
    168                 .setInterpolator(FADE_IN_INTERPOLATOR)
    169                 .setDuration(CROSS_FADE_DURATION_MS)
    170                 .setListener(new PreviewFrameAnimatorListener())
    171                 .withStartAction(new Runnable() {
    172                     @Override
    173                     public void run() {
    174                         view.setVisibility(visibility);
    175                     }
    176                 });
    177             } else {
    178                 // Fade out animation.
    179                 view.animate()
    180                 .alpha(alpha)
    181                 .setInterpolator(FADE_OUT_INTERPOLATOR)
    182                 .setDuration(CROSS_FADE_DURATION_MS)
    183                 .setListener(new PreviewFrameAnimatorListener())
    184                 .withEndAction(new Runnable() {
    185                     @Override
    186                     public void run() {
    187                         view.setVisibility(visibility);
    188                     }
    189                 });
    190             }
    191         }
    192     }
    193 
    194     private void runAnimationEndAction() {
    195         if (mAnimationEndAction != null && !isAnimating()) {
    196             mAnimationEndAction.run();
    197             mAnimationEndAction = null;
    198         }
    199     }
    200 
    201     private class PreviewFrameAnimatorListener implements AnimatorListener {
    202         @Override
    203         public void onAnimationStart(Animator animation) {
    204             mAnimationCounter++;
    205         }
    206 
    207         @Override
    208         public void onAnimationEnd(Animator animation) {
    209             mAnimationCounter--;
    210             runAnimationEndAction();
    211         }
    212 
    213         @Override
    214         public void onAnimationCancel(Animator animation) {
    215             // Empty method.
    216         }
    217 
    218         @Override
    219         public void onAnimationRepeat(Animator animation) {
    220             // Empty method.
    221         }
    222     }
    223 }
    224