1 /* 2 * Copyright 2020 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 androidx.core.view; 18 19 import android.annotation.SuppressLint; 20 import android.view.View; 21 import android.view.WindowInsetsAnimationController; 22 23 import androidx.annotation.FloatRange; 24 import androidx.annotation.RequiresApi; 25 import androidx.core.graphics.Insets; 26 import androidx.core.view.WindowInsetsCompat.Type; 27 import androidx.core.view.WindowInsetsCompat.Type.InsetsType; 28 29 import org.jspecify.annotations.NonNull; 30 import org.jspecify.annotations.Nullable; 31 32 /** 33 * Controller for app-driven animation of system windows. 34 * <p> 35 * {@code WindowInsetsAnimationController} lets apps animate system windows such as 36 * the {@link android.inputmethodservice.InputMethodService IME}. The animation is 37 * synchronized, such that changes the system windows and the app's current frame 38 * are rendered at the same time. 39 * <p> 40 * Control is obtained through {@link WindowInsetsControllerCompat#controlWindowInsetsAnimation}. 41 */ 42 public final class WindowInsetsAnimationControllerCompat { 43 44 private final Impl mImpl; 45 46 @RequiresApi(30) WindowInsetsAnimationControllerCompat( @onNull WindowInsetsAnimationController controller)47 WindowInsetsAnimationControllerCompat( 48 @NonNull WindowInsetsAnimationController controller) { 49 mImpl = new Impl30(controller); 50 } 51 52 /** 53 * Retrieves the {@link Insets} when the windows this animation is controlling are fully hidden. 54 * <p> 55 * Note that these insets are always relative to the window, which is the same as being relative 56 * to {@link View#getRootView} 57 * <p> 58 * If there are any animation listeners registered, this value is the same as 59 * {@link WindowInsetsAnimationCompat.BoundsCompat#getLowerBound()} that is being be passed 60 * into the root view of the hierarchy. 61 * 62 * @return Insets when the windows this animation is controlling are fully hidden. 63 * @see WindowInsetsAnimationCompat.BoundsCompat#getLowerBound() 64 */ getHiddenStateInsets()65 public @NonNull Insets getHiddenStateInsets() { 66 return mImpl.getHiddenStateInsets(); 67 } 68 69 /** 70 * Retrieves the {@link Insets} when the windows this animation is 71 * controlling are fully shown. 72 * <p> 73 * Note that these insets are always relative to the window, which is the same as being relative 74 * to {@link View#getRootView} 75 * <p> 76 * If there are any animation listeners registered, this value is the same as 77 * {@link WindowInsetsAnimationCompat.BoundsCompat#getUpperBound()} that is being passed 78 * into the root view of hierarchy. 79 * 80 * @return Insets when the windows this animation is controlling are fully shown. 81 * @see WindowInsetsAnimationCompat.BoundsCompat#getUpperBound() 82 */ getShownStateInsets()83 public @NonNull Insets getShownStateInsets() { 84 return mImpl.getShownStateInsets(); 85 } 86 87 /** 88 * Retrieves the current insets. 89 * <p> 90 * Note that these insets are always relative to the window, which is the same as 91 * being relative 92 * to {@link View#getRootView} 93 * 94 * @return The current insets on the currently showing frame. These insets will change as the 95 * animation progresses to reflect the current insets provided by the controlled window. 96 */ getCurrentInsets()97 public @NonNull Insets getCurrentInsets() { 98 return mImpl.getCurrentInsets(); 99 } 100 101 /** 102 * Returns the progress as previously set by {@code fraction} in {@link #setInsetsAndAlpha} 103 * 104 * @return the progress of the animation, where {@code 0} is fully hidden and {@code 1} is 105 * fully shown. 106 * <p> 107 * Note: this value represents raw overall progress of the animation 108 * i.e. the combined progress of insets and alpha. 109 * <p> 110 */ 111 @FloatRange(from = 0f, to = 1f) getCurrentFraction()112 public float getCurrentFraction() { 113 return mImpl.getCurrentFraction(); 114 } 115 116 /** 117 * Current alpha value of the window. 118 * 119 * @return float value between 0 and 1. 120 */ getCurrentAlpha()121 public float getCurrentAlpha() { 122 return mImpl.getCurrentAlpha(); 123 } 124 125 /** 126 * @return The {@link Type}s this object is currently controlling. 127 */ 128 @InsetsType getTypes()129 public int getTypes() { 130 return mImpl.getTypes(); 131 } 132 133 /** 134 * Modifies the insets for the frame being drawn by indirectly moving the windows around in the 135 * system that are causing window insets. 136 * <p> 137 * Note that these insets are always relative to the window, which is the same as being relative 138 * to {@link View#getRootView} 139 * <p> 140 * Also note that this will <b>not</b> inform the view system of a full inset change via 141 * {@link View#dispatchApplyWindowInsets} in order to avoid a full layout pass during the 142 * animation. If you'd like to animate views during a window inset animation, register a 143 * {@link WindowInsetsAnimationCompat.Callback} by calling 144 * 145 * {@link ViewCompat#setWindowInsetsAnimationCallback(View, 146 * WindowInsetsAnimationCompat.Callback)} 147 * that will be notified about any insets change via 148 * {@link WindowInsetsAnimationCompat.Callback#onProgress} during the animation. 149 * <p> 150 * {@link View#dispatchApplyWindowInsets} will instead be called once the animation has 151 * finished, i.e. once {@link #finish} has been called. 152 * Note: If there are no insets, alpha animation is still applied. 153 * 154 * @param insets The new insets to apply. Based on the requested insets, the system will 155 * calculate the positions of the windows in the system causing insets such that 156 * the resulting insets of that configuration will match the passed in 157 * parameter. 158 * Note that these insets are being clamped to the range from 159 * {@link #getHiddenStateInsets} to {@link #getShownStateInsets}. 160 * If you intend on changing alpha only, pass null or 161 * {@link #getCurrentInsets()}. 162 * @param alpha The new alpha to apply to the inset side. 163 * @param fraction instantaneous animation progress. This value is dispatched to 164 * {@link WindowInsetsAnimationCompat.Callback}. 165 * @see WindowInsetsAnimationCompat.Callback 166 * @see ViewCompat#setWindowInsetsAnimationCallback(View, WindowInsetsAnimationCompat.Callback) 167 */ 168 setInsetsAndAlpha(@ullable Insets insets, @FloatRange(from = 0f, to = 1f) float alpha, @FloatRange(from = 0f, to = 1f) float fraction)169 public void setInsetsAndAlpha(@Nullable Insets insets, 170 @FloatRange(from = 0f, to = 1f) float alpha, 171 @FloatRange(from = 0f, to = 1f) float fraction) { 172 mImpl.setInsetsAndAlpha(insets, alpha, fraction); 173 } 174 175 /** 176 * Finishes the animation, and leaves the windows shown or hidden. 177 * <p> 178 * After invoking {@link #finish}, this instance is no longer {@link #isReady ready}. 179 * <p> 180 * Note: Finishing an animation implicitly {@link #setInsetsAndAlpha sets insets and alpha} 181 * according to the requested end state without any further animation. 182 * 183 * @param shown if {@code true}, the windows will be shown after finishing the 184 * animation. Otherwise they will be hidden. 185 */ finish(boolean shown)186 public void finish(boolean shown) { 187 mImpl.finish(shown); 188 } 189 190 /** 191 * Returns whether this instance is ready to be used to control window insets. 192 * <p> 193 * Instances are ready when passed in {@link WindowInsetsAnimationControlListenerCompat#onReady} 194 * and stop being ready when it is either {@link #isFinished() finished} or 195 * {@link #isCancelled() cancelled}. 196 * 197 * @return {@code true} if the instance is ready, {@code false} otherwise. 198 */ 199 isReady()200 public boolean isReady() { 201 return !isFinished() && !isCancelled(); 202 } 203 204 /** 205 * Returns whether this instance has been finished by a call to {@link #finish}. 206 * 207 * @return {@code true} if the instance is finished, {@code false} otherwise. 208 * @see WindowInsetsAnimationControlListenerCompat#onFinished 209 */ isFinished()210 public boolean isFinished() { 211 return mImpl.isFinished(); 212 } 213 214 /** 215 * Returns whether this instance has been cancelled by the system, or by invoking the 216 * {@link android.os.CancellationSignal} passed into 217 * {@link WindowInsetsControllerCompat#controlWindowInsetsAnimation}. 218 * 219 * @return {@code true} if the instance is cancelled, {@code false} otherwise. 220 * @see WindowInsetsAnimationControlListenerCompat#onCancelled 221 */ isCancelled()222 public boolean isCancelled() { 223 return mImpl.isCancelled(); 224 } 225 226 private static class Impl { Impl()227 Impl() { 228 //privatex 229 } 230 getHiddenStateInsets()231 public @NonNull Insets getHiddenStateInsets() { 232 return Insets.NONE; 233 } 234 getShownStateInsets()235 public @NonNull Insets getShownStateInsets() { 236 return Insets.NONE; 237 } 238 getCurrentInsets()239 public @NonNull Insets getCurrentInsets() { 240 return Insets.NONE; 241 } 242 243 @FloatRange(from = 0f, to = 1f) getCurrentFraction()244 public float getCurrentFraction() { 245 return 0f; 246 } 247 getCurrentAlpha()248 public float getCurrentAlpha() { 249 return 0f; 250 } 251 252 @InsetsType getTypes()253 public int getTypes() { 254 return 0; 255 } 256 setInsetsAndAlpha(@ullable Insets insets, @FloatRange(from = 0f, to = 1f) float alpha, @FloatRange(from = 0f, to = 1f) float fraction)257 public void setInsetsAndAlpha(@Nullable Insets insets, 258 @FloatRange(from = 0f, to = 1f) float alpha, 259 @FloatRange(from = 0f, to = 1f) float fraction) { 260 } 261 finish(boolean shown)262 void finish(boolean shown) { 263 } 264 isFinished()265 boolean isFinished() { 266 return false; 267 } 268 isCancelled()269 boolean isCancelled() { 270 return true; 271 } 272 } 273 274 @RequiresApi(30) 275 private static class Impl30 extends Impl { 276 277 private final WindowInsetsAnimationController mController; 278 Impl30(@onNull WindowInsetsAnimationController controller)279 Impl30(@NonNull WindowInsetsAnimationController controller) { 280 mController = controller; 281 } 282 283 @Override getHiddenStateInsets()284 public @NonNull Insets getHiddenStateInsets() { 285 return Insets.toCompatInsets(mController.getHiddenStateInsets()); 286 } 287 288 @Override getShownStateInsets()289 public @NonNull Insets getShownStateInsets() { 290 return Insets.toCompatInsets(mController.getShownStateInsets()); 291 } 292 293 @Override getCurrentInsets()294 public @NonNull Insets getCurrentInsets() { 295 return Insets.toCompatInsets(mController.getCurrentInsets()); 296 } 297 298 @Override getCurrentFraction()299 public float getCurrentFraction() { 300 return mController.getCurrentFraction(); 301 } 302 303 @Override getCurrentAlpha()304 public float getCurrentAlpha() { 305 return mController.getCurrentAlpha(); 306 } 307 308 @SuppressLint("WrongConstant") 309 @Override getTypes()310 public int getTypes() { 311 return mController.getTypes(); 312 } 313 314 @Override setInsetsAndAlpha(@ullable Insets insets, float alpha, float fraction)315 public void setInsetsAndAlpha(@Nullable Insets insets, float alpha, float fraction) { 316 mController.setInsetsAndAlpha(insets == null ? null : insets.toPlatformInsets(), 317 alpha, 318 fraction 319 ); 320 } 321 322 @Override finish(boolean shown)323 void finish(boolean shown) { 324 mController.finish(shown); 325 } 326 327 @Override isFinished()328 boolean isFinished() { 329 return mController.isFinished(); 330 } 331 332 @Override isCancelled()333 boolean isCancelled() { 334 return mController.isCancelled(); 335 } 336 } 337 } 338 339