1 /* 2 * Copyright (C) 2021 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 android.view; 18 19 import static android.view.InsetsAnimationControlImplProto.CURRENT_ALPHA; 20 import static android.view.InsetsAnimationControlImplProto.IS_CANCELLED; 21 import static android.view.InsetsAnimationControlImplProto.IS_FINISHED; 22 import static android.view.InsetsAnimationControlImplProto.PENDING_ALPHA; 23 import static android.view.InsetsAnimationControlImplProto.PENDING_FRACTION; 24 import static android.view.InsetsAnimationControlImplProto.PENDING_INSETS; 25 import static android.view.InsetsAnimationControlImplProto.SHOWN_ON_FINISH; 26 import static android.view.InsetsAnimationControlImplProto.TMP_MATRIX; 27 import static android.view.InsetsController.ANIMATION_TYPE_RESIZE; 28 29 import android.animation.Animator; 30 import android.animation.AnimatorListenerAdapter; 31 import android.animation.ValueAnimator; 32 import android.annotation.Nullable; 33 import android.graphics.Insets; 34 import android.graphics.Rect; 35 import android.util.SparseArray; 36 import android.util.proto.ProtoOutputStream; 37 import android.view.InsetsController.LayoutInsetsDuringAnimation; 38 import android.view.WindowInsets.Type.InsetsType; 39 import android.view.WindowInsetsAnimation.Bounds; 40 import android.view.animation.Interpolator; 41 import android.view.inputmethod.ImeTracker; 42 43 /** 44 * Runs a fake animation of resizing insets to produce insets animation callbacks. 45 * @hide 46 */ 47 public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner, 48 InternalInsetsAnimationController, WindowInsetsAnimationControlListener { 49 50 private final InsetsState mFromState; 51 private final InsetsState mToState; 52 private final @InsetsType int mTypes; 53 private final WindowInsetsAnimation mAnimation; 54 private final InsetsAnimationControlCallbacks mController; 55 private ValueAnimator mAnimator; 56 private boolean mCancelled; 57 private boolean mFinished; 58 InsetsResizeAnimationRunner(Rect frame, InsetsState fromState, InsetsState toState, Interpolator interpolator, long duration, @InsetsType int types, InsetsAnimationControlCallbacks controller)59 public InsetsResizeAnimationRunner(Rect frame, InsetsState fromState, InsetsState toState, 60 Interpolator interpolator, long duration, @InsetsType int types, 61 InsetsAnimationControlCallbacks controller) { 62 mFromState = fromState; 63 mToState = toState; 64 mTypes = types; 65 mController = controller; 66 mAnimation = new WindowInsetsAnimation(types, interpolator, duration); 67 mAnimation.setAlpha(1f); 68 final Insets fromInsets = fromState.calculateInsets( 69 frame, types, false /* ignoreVisibility */); 70 final Insets toInsets = toState.calculateInsets( 71 frame, types, false /* ignoreVisibility */); 72 controller.startAnimation(this, this, types, mAnimation, 73 new Bounds(Insets.min(fromInsets, toInsets), Insets.max(fromInsets, toInsets))); 74 } 75 76 @Override getTypes()77 public int getTypes() { 78 return mTypes; 79 } 80 81 @Override getControllingTypes()82 public int getControllingTypes() { 83 return mTypes; 84 } 85 86 @Override getAnimation()87 public WindowInsetsAnimation getAnimation() { 88 return mAnimation; 89 } 90 91 @Override getAnimationType()92 public int getAnimationType() { 93 return ANIMATION_TYPE_RESIZE; 94 } 95 96 @Override getSurfaceParamsApplier()97 public SurfaceParamsApplier getSurfaceParamsApplier() { 98 return SurfaceParamsApplier.DEFAULT; 99 } 100 101 @Override 102 @Nullable getStatsToken()103 public ImeTracker.Token getStatsToken() { 104 // Return null as resizing the IME view is not explicitly tracked. 105 return null; 106 } 107 108 @Override cancel()109 public void cancel() { 110 if (mCancelled || mFinished) { 111 return; 112 } 113 mCancelled = true; 114 if (mAnimator != null) { 115 mAnimator.cancel(); 116 } 117 } 118 119 @Override isCancelled()120 public boolean isCancelled() { 121 return mCancelled; 122 } 123 124 @Override onReady(WindowInsetsAnimationController controller, int types)125 public void onReady(WindowInsetsAnimationController controller, int types) { 126 if (mCancelled) { 127 return; 128 } 129 mAnimator = ValueAnimator.ofFloat(0f, 1f); 130 mAnimator.setDuration(mAnimation.getDurationMillis()); 131 mAnimator.addUpdateListener(animation -> { 132 mAnimation.setFraction(animation.getAnimatedFraction()); 133 mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this); 134 }); 135 mAnimator.addListener(new AnimatorListenerAdapter() { 136 137 @Override 138 public void onAnimationEnd(Animator animation) { 139 mFinished = true; 140 mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this); 141 } 142 }); 143 mAnimator.start(); 144 } 145 146 @Override applyChangeInsets(InsetsState outState)147 public boolean applyChangeInsets(InsetsState outState) { 148 if (mCancelled) { 149 return false; 150 } 151 final float fraction = mAnimation.getInterpolatedFraction(); 152 InsetsState.traverse(mFromState, mToState, new InsetsState.OnTraverseCallbacks() { 153 @Override 154 public void onIdMatch(InsetsSource fromSource, InsetsSource toSource) { 155 final Rect fromFrame = fromSource.getFrame(); 156 final Rect toFrame = toSource.getFrame(); 157 final Rect frame = new Rect( 158 (int) (fromFrame.left + fraction * (toFrame.left - fromFrame.left)), 159 (int) (fromFrame.top + fraction * (toFrame.top - fromFrame.top)), 160 (int) (fromFrame.right + fraction * (toFrame.right - fromFrame.right)), 161 (int) (fromFrame.bottom + fraction * (toFrame.bottom - fromFrame.bottom))); 162 final InsetsSource source = 163 new InsetsSource(fromSource.getId(), fromSource.getType()); 164 source.setFrame(frame); 165 source.setVisible(toSource.isVisible()); 166 outState.addSource(source); 167 } 168 }); 169 if (mFinished) { 170 mController.notifyFinished(this, true /* shown */); 171 } 172 return mFinished; 173 } 174 175 @Override dumpDebug(ProtoOutputStream proto, long fieldId)176 public void dumpDebug(ProtoOutputStream proto, long fieldId) { 177 final long token = proto.start(fieldId); 178 proto.write(IS_CANCELLED, mCancelled); 179 proto.write(IS_FINISHED, mFinished); 180 proto.write(TMP_MATRIX, "null"); 181 proto.write(PENDING_INSETS, "null"); 182 proto.write(PENDING_FRACTION, mAnimation.getInterpolatedFraction()); 183 proto.write(SHOWN_ON_FINISH, true); 184 proto.write(CURRENT_ALPHA, 1f); 185 proto.write(PENDING_ALPHA, 1f); 186 proto.end(token); 187 } 188 189 @Override getHiddenStateInsets()190 public Insets getHiddenStateInsets() { 191 return Insets.NONE; 192 } 193 194 @Override getShownStateInsets()195 public Insets getShownStateInsets() { 196 return Insets.NONE; 197 } 198 199 @Override getCurrentInsets()200 public Insets getCurrentInsets() { 201 return Insets.NONE; 202 } 203 204 @Override getCurrentFraction()205 public float getCurrentFraction() { 206 return 0; 207 } 208 209 @Override getCurrentAlpha()210 public float getCurrentAlpha() { 211 return 0; 212 } 213 214 @Override setInsetsAndAlpha(Insets insets, float alpha, float fraction)215 public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) { 216 } 217 218 @Override finish(boolean shown)219 public void finish(boolean shown) { 220 } 221 222 @Override isFinished()223 public boolean isFinished() { 224 return false; 225 } 226 227 @Override notifyControlRevoked(int types)228 public void notifyControlRevoked(int types) { 229 } 230 231 @Override updateSurfacePosition(SparseArray<InsetsSourceControl> controls)232 public void updateSurfacePosition(SparseArray<InsetsSourceControl> controls) { 233 } 234 235 @Override willUpdateSurface()236 public boolean willUpdateSurface() { 237 return false; 238 } 239 240 @Override hasZeroInsetsIme()241 public boolean hasZeroInsetsIme() { 242 return false; 243 } 244 245 @Override getDurationMs()246 public long getDurationMs() { 247 return 0; 248 } 249 250 @Override getInsetsInterpolator()251 public Interpolator getInsetsInterpolator() { 252 return null; 253 } 254 255 @Override setReadyDispatched(boolean dispatched)256 public void setReadyDispatched(boolean dispatched) { 257 } 258 259 @Override onFinished(WindowInsetsAnimationController controller)260 public void onFinished(WindowInsetsAnimationController controller) { 261 } 262 263 @Override onCancelled(WindowInsetsAnimationController controller)264 public void onCancelled(WindowInsetsAnimationController controller) { 265 } 266 267 @Override updateLayoutInsetsDuringAnimation( @ayoutInsetsDuringAnimation int layoutInsetsDuringAnimation)268 public void updateLayoutInsetsDuringAnimation( 269 @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { 270 } 271 } 272