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