1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package androidx.leanback.transition;
15 
16 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
17 
18 import android.animation.TimeInterpolator;
19 import android.content.Context;
20 import android.graphics.Rect;
21 import android.os.Build;
22 import android.transition.AutoTransition;
23 import android.transition.ChangeTransform;
24 import android.transition.Fade;
25 import android.transition.Scene;
26 import android.transition.Transition;
27 import android.transition.TransitionInflater;
28 import android.transition.TransitionManager;
29 import android.transition.TransitionSet;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.view.Window;
33 import android.view.animation.AnimationUtils;
34 
35 import androidx.annotation.RestrictTo;
36 
37 import java.util.ArrayList;
38 
39 /**
40  * Helper for view transitions.
41  * @hide
42  */
43 @RestrictTo(LIBRARY_GROUP)
44 public final class TransitionHelper {
45 
46     public static final int FADE_IN = 0x1;
47     public static final int FADE_OUT = 0x2;
48 
49     /**
50      * Returns true if system supports entrance Transition animations.
51      */
systemSupportsEntranceTransitions()52     public static boolean systemSupportsEntranceTransitions() {
53         return Build.VERSION.SDK_INT >= 21;
54     }
55 
56     private static class TransitionStub {
57         ArrayList<TransitionListener> mTransitionListeners;
58 
TransitionStub()59         TransitionStub() {
60         }
61     }
62 
getSharedElementEnterTransition(Window window)63     public static Object getSharedElementEnterTransition(Window window) {
64         if (Build.VERSION.SDK_INT >= 21) {
65             return window.getSharedElementEnterTransition();
66         }
67         return null;
68     }
69 
setSharedElementEnterTransition(Window window, Object transition)70     public static void setSharedElementEnterTransition(Window window, Object transition) {
71         if (Build.VERSION.SDK_INT >= 21) {
72             window.setSharedElementEnterTransition((Transition) transition);
73         }
74     }
75 
getSharedElementReturnTransition(Window window)76     public static Object getSharedElementReturnTransition(Window window) {
77         if (Build.VERSION.SDK_INT >= 21) {
78             return window.getSharedElementReturnTransition();
79         }
80         return null;
81     }
82 
setSharedElementReturnTransition(Window window, Object transition)83     public static void setSharedElementReturnTransition(Window window, Object transition) {
84         if (Build.VERSION.SDK_INT >= 21) {
85             window.setSharedElementReturnTransition((Transition) transition);
86         }
87     }
88 
getSharedElementExitTransition(Window window)89     public static Object getSharedElementExitTransition(Window window) {
90         if (Build.VERSION.SDK_INT >= 21) {
91             return window.getSharedElementExitTransition();
92         }
93         return null;
94     }
95 
getSharedElementReenterTransition(Window window)96     public static Object getSharedElementReenterTransition(Window window) {
97         if (Build.VERSION.SDK_INT >= 21) {
98             return window.getSharedElementReenterTransition();
99         }
100         return null;
101     }
102 
getEnterTransition(Window window)103     public static Object getEnterTransition(Window window) {
104         if (Build.VERSION.SDK_INT >= 21) {
105             return window.getEnterTransition();
106         }
107         return null;
108     }
109 
setEnterTransition(Window window, Object transition)110     public static void setEnterTransition(Window window, Object transition) {
111         if (Build.VERSION.SDK_INT >= 21) {
112             window.setEnterTransition((Transition) transition);
113         }
114     }
115 
getReturnTransition(Window window)116     public static Object getReturnTransition(Window window) {
117         if (Build.VERSION.SDK_INT >= 21) {
118             return window.getReturnTransition();
119         }
120         return null;
121     }
122 
setReturnTransition(Window window, Object transition)123     public static void setReturnTransition(Window window, Object transition) {
124         if (Build.VERSION.SDK_INT >= 21) {
125             window.setReturnTransition((Transition) transition);
126         }
127     }
128 
getExitTransition(Window window)129     public static Object getExitTransition(Window window) {
130         if (Build.VERSION.SDK_INT >= 21) {
131             return window.getExitTransition();
132         }
133         return null;
134     }
135 
getReenterTransition(Window window)136     public static Object getReenterTransition(Window window) {
137         if (Build.VERSION.SDK_INT >= 21) {
138             return window.getReenterTransition();
139         }
140         return null;
141     }
142 
createScene(ViewGroup sceneRoot, Runnable r)143     public static Object createScene(ViewGroup sceneRoot, Runnable r) {
144         if (Build.VERSION.SDK_INT >= 19) {
145             Scene scene = new Scene(sceneRoot);
146             scene.setEnterAction(r);
147             return scene;
148         }
149         return r;
150     }
151 
createChangeBounds(boolean reparent)152     public static Object createChangeBounds(boolean reparent) {
153         if (Build.VERSION.SDK_INT >= 19) {
154             CustomChangeBounds changeBounds = new CustomChangeBounds();
155             changeBounds.setReparent(reparent);
156             return changeBounds;
157         }
158         return new TransitionStub();
159     }
160 
createChangeTransform()161     public static Object createChangeTransform() {
162         if (Build.VERSION.SDK_INT >= 21) {
163             return new ChangeTransform();
164         }
165         return new TransitionStub();
166     }
167 
setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay)168     public static void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
169         if (Build.VERSION.SDK_INT >= 19) {
170             ((CustomChangeBounds) changeBounds).setStartDelay(view, startDelay);
171         }
172     }
173 
setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay)174     public static void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
175         if (Build.VERSION.SDK_INT >= 19) {
176             ((CustomChangeBounds) changeBounds).setStartDelay(viewId, startDelay);
177         }
178     }
179 
setChangeBoundsStartDelay(Object changeBounds, String className, int startDelay)180     public static void setChangeBoundsStartDelay(Object changeBounds, String className,
181             int startDelay) {
182         if (Build.VERSION.SDK_INT >= 19) {
183             ((CustomChangeBounds) changeBounds).setStartDelay(className, startDelay);
184         }
185     }
186 
setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay)187     public static void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
188         if (Build.VERSION.SDK_INT >= 19) {
189             ((CustomChangeBounds) changeBounds).setDefaultStartDelay(startDelay);
190         }
191     }
192 
createTransitionSet(boolean sequential)193     public static Object createTransitionSet(boolean sequential) {
194         if (Build.VERSION.SDK_INT >= 19) {
195             TransitionSet set = new TransitionSet();
196             set.setOrdering(sequential ? TransitionSet.ORDERING_SEQUENTIAL
197                     : TransitionSet.ORDERING_TOGETHER);
198             return set;
199         }
200         return new TransitionStub();
201     }
202 
createSlide(int slideEdge)203     public static Object createSlide(int slideEdge) {
204         if (Build.VERSION.SDK_INT >= 19) {
205             SlideKitkat slide = new SlideKitkat();
206             slide.setSlideEdge(slideEdge);
207             return slide;
208         }
209         return new TransitionStub();
210     }
211 
createScale()212     public static Object createScale() {
213         if (Build.VERSION.SDK_INT >= 21) {
214             return new ChangeTransform();
215         }
216         if (Build.VERSION.SDK_INT >= 19) {
217             return new Scale();
218         }
219         return new TransitionStub();
220     }
221 
addTransition(Object transitionSet, Object transition)222     public static void addTransition(Object transitionSet, Object transition) {
223         if (Build.VERSION.SDK_INT >= 19) {
224             ((TransitionSet) transitionSet).addTransition((Transition) transition);
225         }
226     }
227 
exclude(Object transition, int targetId, boolean exclude)228     public static void exclude(Object transition, int targetId, boolean exclude) {
229         if (Build.VERSION.SDK_INT >= 19) {
230             ((Transition) transition).excludeTarget(targetId, exclude);
231         }
232     }
233 
exclude(Object transition, View targetView, boolean exclude)234     public static void exclude(Object transition, View targetView, boolean exclude) {
235         if (Build.VERSION.SDK_INT >= 19) {
236             ((Transition) transition).excludeTarget(targetView, exclude);
237         }
238     }
239 
excludeChildren(Object transition, int targetId, boolean exclude)240     public static void excludeChildren(Object transition, int targetId, boolean exclude) {
241         if (Build.VERSION.SDK_INT >= 19) {
242             ((Transition) transition).excludeChildren(targetId, exclude);
243         }
244     }
245 
excludeChildren(Object transition, View targetView, boolean exclude)246     public static void excludeChildren(Object transition, View targetView, boolean exclude) {
247         if (Build.VERSION.SDK_INT >= 19) {
248             ((Transition) transition).excludeChildren(targetView, exclude);
249         }
250     }
251 
include(Object transition, int targetId)252     public static void include(Object transition, int targetId) {
253         if (Build.VERSION.SDK_INT >= 19) {
254             ((Transition) transition).addTarget(targetId);
255         }
256     }
257 
include(Object transition, View targetView)258     public static void include(Object transition, View targetView) {
259         if (Build.VERSION.SDK_INT >= 19) {
260             ((Transition) transition).addTarget(targetView);
261         }
262     }
263 
setStartDelay(Object transition, long startDelay)264     public static void setStartDelay(Object transition, long startDelay) {
265         if (Build.VERSION.SDK_INT >= 19) {
266             ((Transition) transition).setStartDelay(startDelay);
267         }
268     }
269 
setDuration(Object transition, long duration)270     public static void setDuration(Object transition, long duration) {
271         if (Build.VERSION.SDK_INT >= 19) {
272             ((Transition) transition).setDuration(duration);
273         }
274     }
275 
createAutoTransition()276     public static Object createAutoTransition() {
277         if (Build.VERSION.SDK_INT >= 19) {
278             return new AutoTransition();
279         }
280         return new TransitionStub();
281     }
282 
createFadeTransition(int fadeMode)283     public static Object createFadeTransition(int fadeMode) {
284         if (Build.VERSION.SDK_INT >= 19) {
285             return new Fade(fadeMode);
286         }
287         return new TransitionStub();
288     }
289 
addTransitionListener(Object transition, final TransitionListener listener)290     public static void addTransitionListener(Object transition, final TransitionListener listener) {
291         if (listener == null) {
292             return;
293         }
294         if (Build.VERSION.SDK_INT >= 19) {
295             Transition t = (Transition) transition;
296             listener.mImpl = new Transition.TransitionListener() {
297                 @Override
298                 public void onTransitionStart(Transition transition11) {
299                     listener.onTransitionStart(transition11);
300                 }
301 
302                 @Override
303                 public void onTransitionResume(Transition transition11) {
304                     listener.onTransitionResume(transition11);
305                 }
306 
307                 @Override
308                 public void onTransitionPause(Transition transition11) {
309                     listener.onTransitionPause(transition11);
310                 }
311 
312                 @Override
313                 public void onTransitionEnd(Transition transition11) {
314                     listener.onTransitionEnd(transition11);
315                 }
316 
317                 @Override
318                 public void onTransitionCancel(Transition transition11) {
319                     listener.onTransitionCancel(transition11);
320                 }
321             };
322             t.addListener((Transition.TransitionListener) listener.mImpl);
323         } else {
324             TransitionStub stub = (TransitionStub) transition;
325             if (stub.mTransitionListeners == null) {
326                 stub.mTransitionListeners = new ArrayList<>();
327             }
328             stub.mTransitionListeners.add(listener);
329         }
330     }
331 
removeTransitionListener(Object transition, TransitionListener listener)332     public static void removeTransitionListener(Object transition, TransitionListener listener) {
333         if (Build.VERSION.SDK_INT >= 19) {
334             if (listener == null || listener.mImpl == null) {
335                 return;
336             }
337             Transition t = (Transition) transition;
338             t.removeListener((Transition.TransitionListener) listener.mImpl);
339             listener.mImpl = null;
340         } else {
341             TransitionStub stub = (TransitionStub) transition;
342             if (stub.mTransitionListeners != null) {
343                 stub.mTransitionListeners.remove(listener);
344             }
345         }
346     }
347 
runTransition(Object scene, Object transition)348     public static void runTransition(Object scene, Object transition) {
349         if (Build.VERSION.SDK_INT >= 19) {
350             TransitionManager.go((Scene) scene, (Transition) transition);
351         } else {
352             TransitionStub transitionStub = (TransitionStub) transition;
353             if (transitionStub != null && transitionStub.mTransitionListeners != null) {
354                 for (int i = 0, size = transitionStub.mTransitionListeners.size(); i < size; i++) {
355                     transitionStub.mTransitionListeners.get(i).onTransitionStart(transition);
356                 }
357             }
358             Runnable r = ((Runnable) scene);
359             if (r != null) {
360                 r.run();
361             }
362             if (transitionStub != null && transitionStub.mTransitionListeners != null) {
363                 for (int i = 0, size = transitionStub.mTransitionListeners.size(); i < size; i++) {
364                     transitionStub.mTransitionListeners.get(i).onTransitionEnd(transition);
365                 }
366             }
367         }
368     }
369 
setInterpolator(Object transition, Object timeInterpolator)370     public static void setInterpolator(Object transition, Object timeInterpolator) {
371         if (Build.VERSION.SDK_INT >= 19) {
372             ((Transition) transition).setInterpolator((TimeInterpolator) timeInterpolator);
373         }
374     }
375 
addTarget(Object transition, View view)376     public static void addTarget(Object transition, View view) {
377         if (Build.VERSION.SDK_INT >= 19) {
378             ((Transition) transition).addTarget(view);
379         }
380     }
381 
createDefaultInterpolator(Context context)382     public static Object createDefaultInterpolator(Context context) {
383         if (Build.VERSION.SDK_INT >= 21) {
384             return AnimationUtils.loadInterpolator(context,
385                     android.R.interpolator.fast_out_linear_in);
386         }
387         return null;
388     }
389 
loadTransition(Context context, int resId)390     public static Object loadTransition(Context context, int resId) {
391         if (Build.VERSION.SDK_INT >= 19) {
392             return TransitionInflater.from(context).inflateTransition(resId);
393         }
394         return new TransitionStub();
395     }
396 
setEnterTransition(android.app.Fragment fragment, Object transition)397     public static void setEnterTransition(android.app.Fragment fragment, Object transition) {
398         if (Build.VERSION.SDK_INT >= 21) {
399             fragment.setEnterTransition((Transition) transition);
400         }
401     }
402 
setExitTransition(android.app.Fragment fragment, Object transition)403     public static void setExitTransition(android.app.Fragment fragment, Object transition) {
404         if (Build.VERSION.SDK_INT >= 21) {
405             fragment.setExitTransition((Transition) transition);
406         }
407     }
408 
setSharedElementEnterTransition(android.app.Fragment fragment, Object transition)409     public static void setSharedElementEnterTransition(android.app.Fragment fragment,
410             Object transition) {
411         if (Build.VERSION.SDK_INT >= 21) {
412             fragment.setSharedElementEnterTransition((Transition) transition);
413         }
414     }
415 
addSharedElement(android.app.FragmentTransaction ft, View view, String transitionName)416     public static void addSharedElement(android.app.FragmentTransaction ft,
417             View view, String transitionName) {
418         if (Build.VERSION.SDK_INT >= 21) {
419             ft.addSharedElement(view, transitionName);
420         }
421     }
422 
createFadeAndShortSlide(int edge)423     public static Object createFadeAndShortSlide(int edge) {
424         if (Build.VERSION.SDK_INT >= 21) {
425             return new FadeAndShortSlide(edge);
426         }
427         return new TransitionStub();
428     }
429 
createFadeAndShortSlide(int edge, float distance)430     public static Object createFadeAndShortSlide(int edge, float distance) {
431         if (Build.VERSION.SDK_INT >= 21) {
432             FadeAndShortSlide slide = new FadeAndShortSlide(edge);
433             slide.setDistance(distance);
434             return slide;
435         }
436         return new TransitionStub();
437     }
438 
beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject)439     public static void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject) {
440         if (Build.VERSION.SDK_INT >= 21) {
441             Transition transition = (Transition) transitionObject;
442             TransitionManager.beginDelayedTransition(sceneRoot, transition);
443         }
444     }
445 
setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup)446     public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
447         if (Build.VERSION.SDK_INT >= 21) {
448             viewGroup.setTransitionGroup(transitionGroup);
449         }
450     }
451 
setEpicenterCallback(Object transition, final TransitionEpicenterCallback callback)452     public static void setEpicenterCallback(Object transition,
453             final TransitionEpicenterCallback callback) {
454         if (Build.VERSION.SDK_INT >= 21) {
455             if (callback == null) {
456                 ((Transition) transition).setEpicenterCallback(null);
457             } else {
458                 ((Transition) transition).setEpicenterCallback(new Transition.EpicenterCallback() {
459                     @Override
460                     public Rect onGetEpicenter(Transition transition11) {
461                         return callback.onGetEpicenter(transition11);
462                     }
463                 });
464             }
465         }
466     }
467 
TransitionHelper()468     private TransitionHelper() {
469     }
470 }
471