1 /* 2 * Copyright (C) 2016 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.systemui.statusbar.notification; 18 19 import android.util.Pools; 20 import android.view.View; 21 import android.view.animation.Interpolator; 22 import android.widget.ImageView; 23 import android.widget.ProgressBar; 24 import android.widget.TextView; 25 26 import com.android.app.animation.Interpolators; 27 import com.android.internal.widget.MessagingImageMessage; 28 import com.android.internal.widget.MessagingPropertyAnimator; 29 import com.android.internal.widget.ViewClippingUtil; 30 import com.android.systemui.res.R; 31 import com.android.systemui.statusbar.CrossFadeHelper; 32 import com.android.systemui.statusbar.TransformableView; 33 import com.android.systemui.statusbar.ViewTransformationHelper; 34 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; 35 36 /** 37 * A transform state of a view. 38 */ 39 public class TransformState { 40 41 public static final int TRANSFORM_X = 0x1; 42 public static final int TRANSFORM_Y = 0x10; 43 public static final int TRANSFORM_ALL = TRANSFORM_X | TRANSFORM_Y; 44 public static final int ALIGN_END_TAG = R.id.align_transform_end_tag; 45 46 private static final float UNDEFINED = -1f; 47 private static final int TRANSFORMATION_START_X = R.id.transformation_start_x_tag; 48 private static final int TRANSFORMATION_START_Y = R.id.transformation_start_y_tag; 49 private static final int TRANSFORMATION_START_SCLALE_X = R.id.transformation_start_scale_x_tag; 50 private static final int TRANSFORMATION_START_SCLALE_Y = R.id.transformation_start_scale_y_tag; 51 private static Pools.SimplePool<TransformState> sInstancePool = new Pools.SimplePool<>(40); 52 private static ViewClippingUtil.ClippingParameters CLIPPING_PARAMETERS 53 = new ViewClippingUtil.ClippingParameters() { 54 @Override 55 public boolean shouldFinish(View view) { 56 if (view instanceof ExpandableNotificationRow) { 57 ExpandableNotificationRow row = (ExpandableNotificationRow) view; 58 return !row.isChildInGroup(); 59 } 60 return false; 61 } 62 63 @Override 64 public void onClippingStateChanged(View view, boolean isClipping) { 65 if (view instanceof ExpandableNotificationRow) { 66 ExpandableNotificationRow row = (ExpandableNotificationRow) view; 67 if (isClipping) { 68 row.setClipToActualHeight(true); 69 } else if (row.isChildInGroup()) { 70 row.setClipToActualHeight(false); 71 } 72 } 73 } 74 }; 75 76 protected View mTransformedView; 77 protected TransformInfo mTransformInfo; 78 private int[] mOwnPosition = new int[2]; 79 private boolean mSameAsAny; 80 private float mTransformationEndY = UNDEFINED; 81 private float mTransformationEndX = UNDEFINED; 82 private boolean mAlignEnd; 83 protected Interpolator mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN; 84 initFrom(View view, TransformInfo transformInfo)85 public void initFrom(View view, TransformInfo transformInfo) { 86 mTransformedView = view; 87 mTransformInfo = transformInfo; 88 mAlignEnd = Boolean.TRUE.equals(view.getTag(ALIGN_END_TAG)); 89 } 90 91 /** 92 * Transforms the {@link #mTransformedView} from the given transformviewstate 93 * @param otherState the state to transform from 94 * @param transformationAmount how much to transform 95 */ transformViewFrom(TransformState otherState, float transformationAmount)96 public void transformViewFrom(TransformState otherState, float transformationAmount) { 97 mTransformedView.animate().cancel(); 98 if (sameAs(otherState)) { 99 ensureVisible(); 100 } else { 101 CrossFadeHelper.fadeIn(mTransformedView, transformationAmount, true /* remap */); 102 } 103 transformViewFullyFrom(otherState, transformationAmount); 104 } 105 ensureVisible()106 public void ensureVisible() { 107 if (mTransformedView.getVisibility() == View.INVISIBLE 108 || mTransformedView.getAlpha() != 1.0f) { 109 // We have the same content, lets show ourselves 110 mTransformedView.setAlpha(1.0f); 111 mTransformedView.setVisibility(View.VISIBLE); 112 } 113 } 114 transformViewFullyFrom(TransformState otherState, float transformationAmount)115 public void transformViewFullyFrom(TransformState otherState, float transformationAmount) { 116 transformViewFrom(otherState, TRANSFORM_ALL, null, transformationAmount); 117 } 118 transformViewFullyFrom(TransformState otherState, ViewTransformationHelper.CustomTransformation customTransformation, float transformationAmount)119 public void transformViewFullyFrom(TransformState otherState, 120 ViewTransformationHelper.CustomTransformation customTransformation, 121 float transformationAmount) { 122 transformViewFrom(otherState, TRANSFORM_ALL, customTransformation, transformationAmount); 123 } 124 transformViewVerticalFrom(TransformState otherState, ViewTransformationHelper.CustomTransformation customTransformation, float transformationAmount)125 public void transformViewVerticalFrom(TransformState otherState, 126 ViewTransformationHelper.CustomTransformation customTransformation, 127 float transformationAmount) { 128 transformViewFrom(otherState, TRANSFORM_Y, customTransformation, transformationAmount); 129 } 130 transformViewVerticalFrom(TransformState otherState, float transformationAmount)131 public void transformViewVerticalFrom(TransformState otherState, float transformationAmount) { 132 transformViewFrom(otherState, TRANSFORM_Y, null, transformationAmount); 133 } 134 transformViewFrom(TransformState otherState, int transformationFlags, ViewTransformationHelper.CustomTransformation customTransformation, float transformationAmount)135 protected void transformViewFrom(TransformState otherState, int transformationFlags, 136 ViewTransformationHelper.CustomTransformation customTransformation, 137 float transformationAmount) { 138 final View transformedView = mTransformedView; 139 boolean transformX = (transformationFlags & TRANSFORM_X) != 0; 140 boolean transformY = (transformationFlags & TRANSFORM_Y) != 0; 141 int ownContentHeight = getContentHeight(); 142 int otherContentHeight = otherState.getContentHeight(); 143 boolean differentHeight = otherContentHeight != ownContentHeight 144 && otherContentHeight != 0 && ownContentHeight != 0; 145 int ownContentWidth = getContentWidth(); 146 int otherContentWidth = otherState.getContentWidth(); 147 boolean differentWidth = otherContentWidth != ownContentWidth 148 && otherContentWidth != 0 && ownContentWidth != 0; 149 boolean transformScale = (differentHeight || differentWidth) && transformScale(otherState); 150 boolean transformRightEdge = transformRightEdge(otherState); 151 // lets animate the positions correctly 152 if (transformationAmount == 0.0f 153 || transformX && getTransformationStartX() == UNDEFINED 154 || transformY && getTransformationStartY() == UNDEFINED 155 || transformScale && getTransformationStartScaleX() == UNDEFINED && differentWidth 156 || transformScale && getTransformationStartScaleY() == UNDEFINED 157 && differentHeight) { 158 int[] otherPosition; 159 if (transformationAmount != 0.0f) { 160 otherPosition = otherState.getLaidOutLocationOnScreen(); 161 } else { 162 otherPosition = otherState.getLocationOnScreen(); 163 } 164 int[] ownStablePosition = getLaidOutLocationOnScreen(); 165 if (customTransformation == null 166 || !customTransformation.initTransformation(this, otherState)) { 167 if (transformX) { 168 if (transformRightEdge) { 169 int otherViewWidth = otherState.getTransformedView().getWidth(); 170 int ownViewWidth = transformedView.getWidth(); 171 setTransformationStartX((otherPosition[0] + otherViewWidth) 172 - (ownStablePosition[0] + ownViewWidth)); 173 } else { 174 setTransformationStartX(otherPosition[0] - ownStablePosition[0]); 175 } 176 } 177 if (transformY) { 178 setTransformationStartY(otherPosition[1] - ownStablePosition[1]); 179 } 180 // we also want to animate the scale if we're the same 181 View otherView = otherState.getTransformedView(); 182 if (transformScale && differentWidth) { 183 setTransformationStartScaleX(otherContentWidth * otherView.getScaleX() 184 / (float) ownContentWidth); 185 transformedView.setPivotX(transformRightEdge ? transformedView.getWidth() : 0); 186 } else { 187 setTransformationStartScaleX(UNDEFINED); 188 } 189 if (transformScale && differentHeight) { 190 setTransformationStartScaleY(otherContentHeight * otherView.getScaleY() 191 / (float) ownContentHeight); 192 transformedView.setPivotY(0); 193 } else { 194 setTransformationStartScaleY(UNDEFINED); 195 } 196 } 197 if (!transformX) { 198 setTransformationStartX(UNDEFINED); 199 } 200 if (!transformY) { 201 setTransformationStartY(UNDEFINED); 202 } 203 if (!transformScale) { 204 setTransformationStartScaleX(UNDEFINED); 205 setTransformationStartScaleY(UNDEFINED); 206 } 207 setClippingDeactivated(transformedView, true); 208 } 209 float interpolatedValue = mDefaultInterpolator.getInterpolation( 210 transformationAmount); 211 if (transformX) { 212 float interpolation = interpolatedValue; 213 if (customTransformation != null) { 214 Interpolator customInterpolator = 215 customTransformation.getCustomInterpolator(TRANSFORM_X, true /* isFrom */); 216 if (customInterpolator != null) { 217 interpolation = customInterpolator.getInterpolation(transformationAmount); 218 } 219 } 220 transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(), 221 0.0f, 222 interpolation)); 223 } 224 if (transformY) { 225 float interpolation = interpolatedValue; 226 if (customTransformation != null) { 227 Interpolator customInterpolator = 228 customTransformation.getCustomInterpolator(TRANSFORM_Y, true /* isFrom */); 229 if (customInterpolator != null) { 230 interpolation = customInterpolator.getInterpolation(transformationAmount); 231 } 232 } 233 transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(), 234 0.0f, 235 interpolation)); 236 } 237 if (transformScale) { 238 float transformationStartScaleX = getTransformationStartScaleX(); 239 if (transformationStartScaleX != UNDEFINED) { 240 transformedView.setScaleX( 241 NotificationUtils.interpolate(transformationStartScaleX, 242 1.0f, 243 interpolatedValue)); 244 } 245 float transformationStartScaleY = getTransformationStartScaleY(); 246 if (transformationStartScaleY != UNDEFINED) { 247 transformedView.setScaleY( 248 NotificationUtils.interpolate(transformationStartScaleY, 249 1.0f, 250 interpolatedValue)); 251 } 252 } 253 } 254 255 /** 256 * The width of the content of this view. For some views, like TextViews, this will be the 257 * width of content inside the view which is transforming, rather than the view's full width. 258 */ getContentWidth()259 protected int getContentWidth() { 260 return mTransformedView.getWidth(); 261 } 262 263 /** 264 * The height of the content of this view. For some views, like TextViews, this will be the 265 * height of content inside the view which is transforming, rather than the view's full height. 266 */ getContentHeight()267 protected int getContentHeight() { 268 return mTransformedView.getHeight(); 269 } 270 transformScale(TransformState otherState)271 protected boolean transformScale(TransformState otherState) { 272 return sameAs(otherState); 273 } 274 transformRightEdge(TransformState otherState)275 protected boolean transformRightEdge(TransformState otherState) { 276 boolean alignEnd = mAlignEnd && otherState.mAlignEnd; 277 boolean isRtl = mTransformedView.isLayoutRtl() && otherState.mTransformedView.isLayoutRtl(); 278 return alignEnd ^ isRtl; 279 } 280 281 /** 282 * Transforms the {@link #mTransformedView} to the given transformviewstate 283 * @param otherState the state to transform from 284 * @param transformationAmount how much to transform 285 * @return whether an animation was started 286 */ transformViewTo(TransformState otherState, float transformationAmount)287 public boolean transformViewTo(TransformState otherState, float transformationAmount) { 288 mTransformedView.animate().cancel(); 289 if (sameAs(otherState)) { 290 // We have the same text, lets show ourselfs 291 if (mTransformedView.getVisibility() == View.VISIBLE) { 292 mTransformedView.setAlpha(0.0f); 293 mTransformedView.setVisibility(View.INVISIBLE); 294 } 295 return false; 296 } else { 297 CrossFadeHelper.fadeOut(mTransformedView, transformationAmount); 298 } 299 transformViewFullyTo(otherState, transformationAmount); 300 return true; 301 } 302 transformViewFullyTo(TransformState otherState, float transformationAmount)303 public void transformViewFullyTo(TransformState otherState, float transformationAmount) { 304 transformViewTo(otherState, TRANSFORM_ALL, null, transformationAmount); 305 } 306 transformViewFullyTo(TransformState otherState, ViewTransformationHelper.CustomTransformation customTransformation, float transformationAmount)307 public void transformViewFullyTo(TransformState otherState, 308 ViewTransformationHelper.CustomTransformation customTransformation, 309 float transformationAmount) { 310 transformViewTo(otherState, TRANSFORM_ALL, customTransformation, transformationAmount); 311 } 312 transformViewVerticalTo(TransformState otherState, ViewTransformationHelper.CustomTransformation customTransformation, float transformationAmount)313 public void transformViewVerticalTo(TransformState otherState, 314 ViewTransformationHelper.CustomTransformation customTransformation, 315 float transformationAmount) { 316 transformViewTo(otherState, TRANSFORM_Y, customTransformation, transformationAmount); 317 } 318 transformViewVerticalTo(TransformState otherState, float transformationAmount)319 public void transformViewVerticalTo(TransformState otherState, float transformationAmount) { 320 transformViewTo(otherState, TRANSFORM_Y, null, transformationAmount); 321 } 322 transformViewTo(TransformState otherState, int transformationFlags, ViewTransformationHelper.CustomTransformation customTransformation, float transformationAmount)323 private void transformViewTo(TransformState otherState, int transformationFlags, 324 ViewTransformationHelper.CustomTransformation customTransformation, 325 float transformationAmount) { 326 // lets animate the positions correctly 327 328 final View transformedView = mTransformedView; 329 boolean transformX = (transformationFlags & TRANSFORM_X) != 0; 330 boolean transformY = (transformationFlags & TRANSFORM_Y) != 0; 331 boolean transformScale = transformScale(otherState); 332 boolean transformRightEdge = transformRightEdge(otherState); 333 int ownContentWidth = getContentWidth(); 334 int otherContentWidth = otherState.getContentWidth(); 335 // lets animate the positions correctly 336 if (transformationAmount == 0.0f) { 337 if (transformX) { 338 float transformationStartX = getTransformationStartX(); 339 float start = transformationStartX != UNDEFINED ? transformationStartX 340 : transformedView.getTranslationX(); 341 setTransformationStartX(start); 342 } 343 if (transformY) { 344 float transformationStartY = getTransformationStartY(); 345 float start = transformationStartY != UNDEFINED ? transformationStartY 346 : transformedView.getTranslationY(); 347 setTransformationStartY(start); 348 } 349 if (transformScale && otherContentWidth != ownContentWidth) { 350 setTransformationStartScaleX(transformedView.getScaleX()); 351 transformedView.setPivotX(transformRightEdge ? transformedView.getWidth() : 0); 352 } else { 353 setTransformationStartScaleX(UNDEFINED); 354 } 355 if (transformScale && otherState.getContentHeight() != getContentHeight()) { 356 setTransformationStartScaleY(transformedView.getScaleY()); 357 transformedView.setPivotY(0); 358 } else { 359 setTransformationStartScaleY(UNDEFINED); 360 } 361 setClippingDeactivated(transformedView, true); 362 } 363 float interpolatedValue = mDefaultInterpolator.getInterpolation( 364 transformationAmount); 365 int[] otherStablePosition = otherState.getLaidOutLocationOnScreen(); 366 int[] ownPosition = getLaidOutLocationOnScreen(); 367 if (transformX) { 368 int ownViewWidth = transformedView.getWidth(); 369 int otherViewWidth = otherState.getTransformedView().getWidth(); 370 float endX = transformRightEdge 371 ? (otherStablePosition[0] + otherViewWidth) - (ownPosition[0] + ownViewWidth) 372 : otherStablePosition[0] - ownPosition[0]; 373 float interpolation = interpolatedValue; 374 if (customTransformation != null) { 375 if (customTransformation.customTransformTarget(this, otherState)) { 376 endX = mTransformationEndX; 377 } 378 Interpolator customInterpolator = 379 customTransformation.getCustomInterpolator(TRANSFORM_X, false /* isFrom */); 380 if (customInterpolator != null) { 381 interpolation = customInterpolator.getInterpolation(transformationAmount); 382 } 383 } 384 transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(), 385 endX, 386 interpolation)); 387 } 388 if (transformY) { 389 float endY = otherStablePosition[1] - ownPosition[1]; 390 float interpolation = interpolatedValue; 391 if (customTransformation != null) { 392 if (customTransformation.customTransformTarget(this, otherState)) { 393 endY = mTransformationEndY; 394 } 395 Interpolator customInterpolator = 396 customTransformation.getCustomInterpolator(TRANSFORM_Y, false /* isFrom */); 397 if (customInterpolator != null) { 398 interpolation = customInterpolator.getInterpolation(transformationAmount); 399 } 400 } 401 transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(), 402 endY, 403 interpolation)); 404 } 405 if (transformScale) { 406 float transformationStartScaleX = getTransformationStartScaleX(); 407 if (transformationStartScaleX != UNDEFINED) { 408 transformedView.setScaleX( 409 NotificationUtils.interpolate(transformationStartScaleX, 410 (otherContentWidth / (float) ownContentWidth), 411 interpolatedValue)); 412 } 413 float transformationStartScaleY = getTransformationStartScaleY(); 414 if (transformationStartScaleY != UNDEFINED) { 415 transformedView.setScaleY( 416 NotificationUtils.interpolate(transformationStartScaleY, 417 (otherState.getContentHeight() / (float) getContentHeight()), 418 interpolatedValue)); 419 } 420 } 421 } 422 setClippingDeactivated(final View transformedView, boolean deactivated)423 protected void setClippingDeactivated(final View transformedView, boolean deactivated) { 424 ViewClippingUtil.setClippingDeactivated(transformedView, deactivated, CLIPPING_PARAMETERS); 425 } 426 getLaidOutLocationOnScreen()427 public int[] getLaidOutLocationOnScreen() { 428 int[] location = getLocationOnScreen(); 429 // remove translation 430 location[0] -= mTransformedView.getTranslationX(); 431 location[1] -= mTransformedView.getTranslationY(); 432 return location; 433 } 434 getLocationOnScreen()435 public int[] getLocationOnScreen() { 436 mTransformedView.getLocationOnScreen(mOwnPosition); 437 438 // remove scale 439 mOwnPosition[0] -= (1.0f - mTransformedView.getScaleX()) * mTransformedView.getPivotX(); 440 mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY(); 441 442 // Remove local translations 443 mOwnPosition[1] -= MessagingPropertyAnimator.getTop(mTransformedView) 444 - MessagingPropertyAnimator.getLayoutTop(mTransformedView); 445 return mOwnPosition; 446 } 447 sameAs(TransformState otherState)448 protected boolean sameAs(TransformState otherState) { 449 return mSameAsAny; 450 } 451 appear(float transformationAmount, TransformableView otherView)452 public void appear(float transformationAmount, TransformableView otherView) { 453 // There's no other view, lets fade us in 454 // Certain views need to prepare the fade in and make sure its children are 455 // completely visible. An example is the notification header. 456 if (transformationAmount == 0.0f) { 457 prepareFadeIn(); 458 } 459 CrossFadeHelper.fadeIn(mTransformedView, transformationAmount, true /* remap */); 460 } 461 disappear(float transformationAmount, TransformableView otherView)462 public void disappear(float transformationAmount, TransformableView otherView) { 463 CrossFadeHelper.fadeOut(mTransformedView, transformationAmount); 464 } 465 createFrom(View view, TransformInfo transformInfo)466 public static TransformState createFrom(View view, 467 TransformInfo transformInfo) { 468 if (view instanceof TextView) { 469 TextViewTransformState result = TextViewTransformState.obtain(); 470 result.initFrom(view, transformInfo); 471 return result; 472 } 473 if (view.getId() == com.android.internal.R.id.actions_container) { 474 ActionListTransformState result = ActionListTransformState.obtain(); 475 result.initFrom(view, transformInfo); 476 return result; 477 } 478 if (view.getId() == com.android.internal.R.id.notification_messaging) { 479 MessagingLayoutTransformState result = MessagingLayoutTransformState.obtain(); 480 result.initFrom(view, transformInfo); 481 return result; 482 } 483 if (view instanceof MessagingImageMessage) { 484 MessagingImageTransformState result = MessagingImageTransformState.obtain(); 485 result.initFrom(view, transformInfo); 486 return result; 487 } 488 if (view instanceof ImageView) { 489 ImageTransformState result = ImageTransformState.obtain(); 490 result.initFrom(view, transformInfo); 491 return result; 492 } 493 if (view instanceof ProgressBar) { 494 ProgressTransformState result = ProgressTransformState.obtain(); 495 result.initFrom(view, transformInfo); 496 return result; 497 } 498 TransformState result = obtain(); 499 result.initFrom(view, transformInfo); 500 return result; 501 } 502 setIsSameAsAnyView(boolean sameAsAny)503 public void setIsSameAsAnyView(boolean sameAsAny) { 504 mSameAsAny = sameAsAny; 505 } 506 recycle()507 public void recycle() { 508 reset(); 509 if (getClass() == TransformState.class) { 510 sInstancePool.release(this); 511 } 512 } 513 setTransformationEndY(float transformationEndY)514 public void setTransformationEndY(float transformationEndY) { 515 mTransformationEndY = transformationEndY; 516 } 517 setTransformationEndX(float transformationEndX)518 public void setTransformationEndX(float transformationEndX) { 519 mTransformationEndX = transformationEndX; 520 } 521 getTransformationStartX()522 public float getTransformationStartX() { 523 Object tag = mTransformedView.getTag(TRANSFORMATION_START_X); 524 return tag == null ? UNDEFINED : (float) tag; 525 } 526 getTransformationStartY()527 public float getTransformationStartY() { 528 Object tag = mTransformedView.getTag(TRANSFORMATION_START_Y); 529 return tag == null ? UNDEFINED : (float) tag; 530 } 531 getTransformationStartScaleX()532 public float getTransformationStartScaleX() { 533 Object tag = mTransformedView.getTag(TRANSFORMATION_START_SCLALE_X); 534 return tag == null ? UNDEFINED : (float) tag; 535 } 536 getTransformationStartScaleY()537 public float getTransformationStartScaleY() { 538 Object tag = mTransformedView.getTag(TRANSFORMATION_START_SCLALE_Y); 539 return tag == null ? UNDEFINED : (float) tag; 540 } 541 setTransformationStartX(float transformationStartX)542 public void setTransformationStartX(float transformationStartX) { 543 mTransformedView.setTag(TRANSFORMATION_START_X, transformationStartX); 544 } 545 setTransformationStartY(float transformationStartY)546 public void setTransformationStartY(float transformationStartY) { 547 mTransformedView.setTag(TRANSFORMATION_START_Y, transformationStartY); 548 } 549 setTransformationStartScaleX(float startScaleX)550 private void setTransformationStartScaleX(float startScaleX) { 551 mTransformedView.setTag(TRANSFORMATION_START_SCLALE_X, startScaleX); 552 } 553 setTransformationStartScaleY(float startScaleY)554 private void setTransformationStartScaleY(float startScaleY) { 555 mTransformedView.setTag(TRANSFORMATION_START_SCLALE_Y, startScaleY); 556 } 557 reset()558 protected void reset() { 559 mTransformedView = null; 560 mTransformInfo = null; 561 mSameAsAny = false; 562 mTransformationEndX = UNDEFINED; 563 mTransformationEndY = UNDEFINED; 564 mAlignEnd = false; 565 mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN; 566 } 567 setVisible(boolean visible, boolean force)568 public void setVisible(boolean visible, boolean force) { 569 if (!force && mTransformedView.getVisibility() == View.GONE) { 570 return; 571 } 572 if (mTransformedView.getVisibility() != View.GONE) { 573 mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); 574 } 575 mTransformedView.animate().cancel(); 576 mTransformedView.setAlpha(visible ? 1.0f : 0.0f); 577 resetTransformedView(); 578 } 579 prepareFadeIn()580 public void prepareFadeIn() { 581 resetTransformedView(); 582 } 583 resetTransformedView()584 protected void resetTransformedView() { 585 mTransformedView.setTranslationX(0); 586 mTransformedView.setTranslationY(0); 587 mTransformedView.setScaleX(1.0f); 588 mTransformedView.setScaleY(1.0f); 589 setClippingDeactivated(mTransformedView, false); 590 abortTransformation(); 591 } 592 abortTransformation()593 public void abortTransformation() { 594 mTransformedView.setTag(TRANSFORMATION_START_X, UNDEFINED); 595 mTransformedView.setTag(TRANSFORMATION_START_Y, UNDEFINED); 596 mTransformedView.setTag(TRANSFORMATION_START_SCLALE_X, UNDEFINED); 597 mTransformedView.setTag(TRANSFORMATION_START_SCLALE_Y, UNDEFINED); 598 } 599 obtain()600 public static TransformState obtain() { 601 TransformState instance = sInstancePool.acquire(); 602 if (instance != null) { 603 return instance; 604 } 605 return new TransformState(); 606 } 607 getTransformedView()608 public View getTransformedView() { 609 return mTransformedView; 610 } 611 setDefaultInterpolator(Interpolator interpolator)612 public void setDefaultInterpolator(Interpolator interpolator) { 613 mDefaultInterpolator = interpolator; 614 } 615 616 public interface TransformInfo { isAnimating()617 boolean isAnimating(); 618 } 619 } 620