1 /* 2 * Copyright (C) 2024 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 17 package com.android.car.scalableui.model; 18 19 import android.animation.Animator; 20 import android.view.animation.AccelerateDecelerateInterpolator; 21 import android.view.animation.Interpolator; 22 23 import androidx.annotation.NonNull; 24 import androidx.annotation.Nullable; 25 26 import com.android.car.scalableui.panel.Panel; 27 28 /** 29 * Represents a transition between two {@link Variant}s in the Scalable UI system. 30 * 31 * <p>A Transition defines the animation that should be used to transition from one variant to 32 * another in response to an event. It can optionally specify a specific "from" variant, a "to" 33 * variant, an event trigger, and a custom animator. 34 */ 35 public class Transition { 36 public static final long DEFAULT_DURATION = 300; 37 38 @Nullable private final Variant mFromVariant; 39 @NonNull private final Variant mToVariant; 40 @Nullable private final Event mOnEvent; 41 @Nullable private final Animator mAnimator; 42 @NonNull private final Interpolator mDefaultInterpolator; 43 private final long mDefaultDuration; 44 45 /** 46 * Constructor for Transition. Package-private; use the Builder. 47 * 48 * @param fromVariant The variant to transition from (can be null). 49 * @param toVariant The variant to transition to. 50 * @param onEvent The event that triggers the transition. 51 * @param animator A custom animator to use for the transition (can be null). 52 * @param defaultDuration The default duration of the transition. 53 * @param defaultInterpolator The default interpolator to use for the transition. 54 */ Transition( @ullable Variant fromVariant, @NonNull Variant toVariant, @Nullable Event onEvent, @Nullable Animator animator, long defaultDuration, @Nullable Interpolator defaultInterpolator)55 Transition( 56 @Nullable Variant fromVariant, 57 @NonNull Variant toVariant, 58 @Nullable Event onEvent, 59 @Nullable Animator animator, 60 long defaultDuration, 61 @Nullable Interpolator defaultInterpolator) { 62 mFromVariant = fromVariant; 63 mToVariant = toVariant; 64 mAnimator = animator; 65 mOnEvent = onEvent; 66 mDefaultDuration = defaultDuration >= 0 ? defaultDuration : DEFAULT_DURATION; 67 mDefaultInterpolator = 68 defaultInterpolator != null 69 ? defaultInterpolator 70 : new AccelerateDecelerateInterpolator(); 71 } 72 73 /** 74 * Returns the "from" variant of the transition. 75 * 76 * @return The "from" variant, or null if not specified. 77 */ 78 @Nullable getFromVariant()79 public Variant getFromVariant() { 80 return mFromVariant; 81 } 82 83 /** 84 * Returns the "to" variant of the transition. 85 * 86 * @return The "to" variant. 87 */ 88 @NonNull getToVariant()89 public Variant getToVariant() { 90 return mToVariant; 91 } 92 93 /** 94 * Returns the animator for the transition. 95 * 96 * <p>If a custom animator was provided, it is cloned and returned. Otherwise, a default 97 * animator will be created to transition from "from" variant to "to" variant with the default 98 * duration and interpolator. 99 * 100 * @param panel The panel to apply the animation to. 101 * @param fromVariant The actual "from" variant of the transition. 102 * @return The animator for the transition. 103 */ 104 @Nullable getAnimator(@onNull Panel panel, @NonNull Variant fromVariant)105 public Animator getAnimator(@NonNull Panel panel, @NonNull Variant fromVariant) { 106 if (fromVariant.getId().equals(mToVariant.getId())) { 107 return null; 108 } 109 110 if (mAnimator != null) { 111 Animator animator = this.mAnimator.clone(); 112 animator.setTarget(panel); 113 return animator; 114 } 115 return fromVariant.getAnimator( 116 panel, mToVariant, mDefaultDuration, mDefaultInterpolator); 117 } 118 119 /** 120 * Returns the event that triggers the transition. 121 * 122 * @return The event that triggers the transition. 123 */ 124 @Nullable getOnEvent()125 public Event getOnEvent() { 126 return mOnEvent; 127 } 128 129 @Override 130 @NonNull toString()131 public String toString() { 132 return "Transition{" 133 + "mFromVariant=" + (mFromVariant != null ? mFromVariant : "null") 134 + ", mToVariant=" + (mToVariant != null ? mToVariant : "null") 135 + ", mOnEvent=" + mOnEvent 136 + ", mAnimator=" + mAnimator 137 + ", mDefaultInterpolator=" + mDefaultInterpolator 138 + ", mDefaultDuration=" + mDefaultDuration 139 + '}'; 140 } 141 142 /** Builder for {@link Transition} objects. */ 143 public static class Builder { 144 @Nullable private Variant mFromVariant; // Now nullable 145 @NonNull private Variant mToVariant; 146 @Nullable private Event mOnEvent; 147 @Nullable private Animator mAnimator; 148 @Nullable private Interpolator mDefaultInterpolator; 149 @Nullable private Long mDefaultDuration; // Use boxed type Long 150 Builder(@ullable Variant fromVariant, @NonNull Variant toVariant)151 public Builder(@Nullable Variant fromVariant, @NonNull Variant toVariant) { 152 mFromVariant = fromVariant; 153 mToVariant = toVariant; 154 } 155 156 /** Sets from variant */ setFromVariant(@ullable Variant fromVariant)157 public Builder setFromVariant(@Nullable Variant fromVariant) { 158 mFromVariant = fromVariant; // Accept null 159 return this; 160 } 161 162 /** Sets to variant */ setToVariant(@onNull Variant toVariant)163 public Builder setToVariant(@NonNull Variant toVariant) { 164 mToVariant = toVariant; 165 return this; 166 } 167 168 /** Sets onEvent */ setOnEvent(@ullable String eventId, @Nullable String eventTokens)169 public Builder setOnEvent(@Nullable String eventId, @Nullable String eventTokens) { 170 if (eventId == null) { 171 mOnEvent = null; 172 } else { 173 mOnEvent = new Event.Builder(eventId) 174 .addTokensFromString(eventTokens) 175 .build(); 176 } 177 return this; 178 } 179 180 /** Sets animator */ setAnimator(@ullable Animator animator)181 public Builder setAnimator(@Nullable Animator animator) { 182 mAnimator = animator; 183 return this; 184 } 185 186 /** Sets default duration */ setDefaultDuration(long duration)187 public Builder setDefaultDuration(long duration) { 188 mDefaultDuration = duration; 189 return this; 190 } 191 192 /** Sets default interpolator */ setDefaultInterpolator(@ullable Interpolator interpolator)193 public Builder setDefaultInterpolator(@Nullable Interpolator interpolator) { 194 mDefaultInterpolator = interpolator; 195 return this; 196 } 197 198 /** Returns the {@link Transition} instance */ 199 @NonNull build()200 public Transition build() { 201 return new Transition( 202 mFromVariant, 203 mToVariant, 204 mOnEvent, 205 mAnimator, 206 mDefaultDuration != null ? mDefaultDuration : DEFAULT_DURATION, 207 mDefaultInterpolator); 208 } 209 } 210 } 211