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.animation.AccelerateInterpolator;
27 import android.view.animation.DecelerateInterpolator;
28 import android.view.animation.Interpolator;
29 import android.widget.FrameLayout;
30 import android.widget.LinearLayout;
31 import android.widget.ScrollView;
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 
PreviewPagerAdapter(Context context, boolean isLayoutRtl, int[] previewSampleResIds, Configuration[] configurations)56     public PreviewPagerAdapter(Context context, boolean isLayoutRtl,
57             int[] previewSampleResIds, Configuration[] configurations) {
58         mIsLayoutRtl = isLayoutRtl;
59         mPreviewFrames = new FrameLayout[previewSampleResIds.length];
60 
61         for (int i = 0; i < previewSampleResIds.length; ++i) {
62             int p = mIsLayoutRtl ? previewSampleResIds.length - 1 - i : i;
63             mPreviewFrames[p] = new FrameLayout(context);
64             mPreviewFrames[p].setLayoutParams(new LinearLayout.LayoutParams(
65                     LinearLayout.LayoutParams.MATCH_PARENT,
66                     LinearLayout.LayoutParams.MATCH_PARENT));
67 
68             for (Configuration configuration : configurations) {
69                 // Create a new configuration for the specified value. It won't
70                 // have any theme set, so manually apply the current theme.
71                 final Context configContext = context.createConfigurationContext(configuration);
72                 configContext.setTheme(context.getThemeResId());
73 
74                 final LayoutInflater configInflater = LayoutInflater.from(configContext);
75                 final View sampleView = configInflater.inflate(previewSampleResIds[i],
76                         mPreviewFrames[p], false);
77                 sampleView.setAlpha(0);
78                 sampleView.setVisibility(View.INVISIBLE);
79                 mPreviewFrames[p].addView(sampleView);
80             }
81         }
82     }
83 
84     @Override
destroyItem(ViewGroup container, int position, Object object)85     public void destroyItem (ViewGroup container, int position, Object object) {
86         container.removeView((View) object);
87     }
88 
89     @Override
getCount()90     public int getCount() {
91         return mPreviewFrames.length;
92     }
93 
94     @Override
instantiateItem(ViewGroup container, int position)95     public Object instantiateItem(ViewGroup container, int position) {
96         container.addView(mPreviewFrames[position]);
97         return mPreviewFrames[position];
98     }
99 
100     @Override
isViewFromObject(View view, Object object)101     public boolean isViewFromObject(View view, Object object) {
102         return (view == object);
103     }
104 
isAnimating()105     boolean isAnimating() {
106         return mAnimationCounter > 0;
107     }
108 
setAnimationEndAction(Runnable action)109     void setAnimationEndAction(Runnable action) {
110         mAnimationEndAction = action;
111     }
112 
setPreviewLayer(int newIndex, int currentIndex, int currentItem, boolean animate)113     void setPreviewLayer(int newIndex, int currentIndex, int currentItem, boolean animate) {
114         for (FrameLayout previewFrame : mPreviewFrames) {
115             if (currentIndex >= 0) {
116                 final View lastLayer = previewFrame.getChildAt(currentIndex);
117                 if (animate && previewFrame == mPreviewFrames[currentItem]) {
118                     lastLayer.animate()
119                             .alpha(0)
120                             .setInterpolator(FADE_OUT_INTERPOLATOR)
121                             .setDuration(CROSS_FADE_DURATION_MS)
122                             .setListener(new PreviewFrameAnimatorListener())
123                             .withEndAction(new Runnable() {
124                                 @Override
125                                 public void run() {
126                                     lastLayer.setVisibility(View.INVISIBLE);
127                                 }
128                             });
129                 } else {
130                     lastLayer.setAlpha(0);
131                     lastLayer.setVisibility(View.INVISIBLE);
132                 }
133             }
134 
135             final View nextLayer = previewFrame.getChildAt(newIndex);
136             if (animate && previewFrame == mPreviewFrames[currentItem]) {
137                 nextLayer.animate()
138                         .alpha(1)
139                         .setInterpolator(FADE_IN_INTERPOLATOR)
140                         .setDuration(CROSS_FADE_DURATION_MS)
141                         .setListener(new PreviewFrameAnimatorListener())
142                         .withStartAction(new Runnable() {
143                             @Override
144                             public void run() {
145                                 nextLayer.setVisibility(View.VISIBLE);
146                             }
147                         });
148             } else {
149                 nextLayer.setVisibility(View.VISIBLE);
150                 nextLayer.setAlpha(1);
151             }
152         }
153     }
154 
runAnimationEndAction()155     private void runAnimationEndAction() {
156         if (mAnimationEndAction != null && !isAnimating()) {
157             mAnimationEndAction.run();
158             mAnimationEndAction = null;
159         }
160     }
161 
162     private class PreviewFrameAnimatorListener implements AnimatorListener {
163         @Override
onAnimationStart(Animator animation)164         public void onAnimationStart(Animator animation) {
165             mAnimationCounter++;
166         }
167 
168         @Override
onAnimationEnd(Animator animation)169         public void onAnimationEnd(Animator animation) {
170             mAnimationCounter--;
171             runAnimationEndAction();
172         }
173 
174         @Override
onAnimationCancel(Animator animation)175         public void onAnimationCancel(Animator animation) {
176             // Empty method.
177         }
178 
179         @Override
onAnimationRepeat(Animator animation)180         public void onAnimationRepeat(Animator animation) {
181             // Empty method.
182         }
183     }
184 }
185