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