Home | History | Annotate | Download | only in transition
      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 androidx.transition;
     18 
     19 import android.graphics.Matrix;
     20 import android.graphics.Rect;
     21 import android.os.Build;
     22 import android.util.Log;
     23 import android.util.Property;
     24 import android.view.View;
     25 
     26 import androidx.annotation.NonNull;
     27 import androidx.annotation.Nullable;
     28 import androidx.core.view.ViewCompat;
     29 
     30 import java.lang.reflect.Field;
     31 
     32 /**
     33  * Compatibility utilities for platform features of {@link View}.
     34  */
     35 class ViewUtils {
     36 
     37     private static final ViewUtilsBase IMPL;
     38     private static final String TAG = "ViewUtils";
     39 
     40     private static Field sViewFlagsField;
     41     private static boolean sViewFlagsFieldFetched;
     42     private static final int VISIBILITY_MASK = 0x0000000C;
     43 
     44     static {
     45         if (Build.VERSION.SDK_INT >= 22) {
     46             IMPL = new ViewUtilsApi22();
     47         } else if (Build.VERSION.SDK_INT >= 21) {
     48             IMPL = new ViewUtilsApi21();
     49         } else if (Build.VERSION.SDK_INT >= 19) {
     50             IMPL = new ViewUtilsApi19();
     51         } else {
     52             IMPL = new ViewUtilsBase();
     53         }
     54     }
     55 
     56     /**
     57      * A {@link Property} for animating transitionAlpha value of a View.
     58      */
     59     static final Property<View, Float> TRANSITION_ALPHA =
     60             new Property<View, Float>(Float.class, "translationAlpha") {
     61 
     62                 @Override
     63                 public Float get(View view) {
     64                     return getTransitionAlpha(view);
     65                 }
     66 
     67                 @Override
     68                 public void set(View view, Float alpha) {
     69                     setTransitionAlpha(view, alpha);
     70                 }
     71 
     72             };
     73 
     74     static final Property<View, Rect> CLIP_BOUNDS =
     75             new Property<View, Rect>(Rect.class, "clipBounds") {
     76 
     77                 @Override
     78                 public Rect get(View view) {
     79                     return ViewCompat.getClipBounds(view);
     80                 }
     81 
     82                 @Override
     83                 public void set(View view, Rect clipBounds) {
     84                     ViewCompat.setClipBounds(view, clipBounds);
     85                 }
     86 
     87             };
     88 
     89     /**
     90      * Backward-compatible {@link View#getOverlay()}.
     91      */
     92     static ViewOverlayImpl getOverlay(@NonNull View view) {
     93         if (Build.VERSION.SDK_INT >= 18) {
     94             return new ViewOverlayApi18(view);
     95         }
     96         return ViewOverlayApi14.createFrom(view);
     97     }
     98 
     99     /**
    100      * Backward-compatible {@link View#getWindowId()}.
    101      */
    102     static WindowIdImpl getWindowId(@NonNull View view) {
    103         if (Build.VERSION.SDK_INT >= 18) {
    104             return new WindowIdApi18(view);
    105         }
    106         return new WindowIdApi14(view.getWindowToken());
    107     }
    108 
    109     static void setTransitionAlpha(@NonNull View view, float alpha) {
    110         IMPL.setTransitionAlpha(view, alpha);
    111     }
    112 
    113     static float getTransitionAlpha(@NonNull View view) {
    114         return IMPL.getTransitionAlpha(view);
    115     }
    116 
    117     /**
    118      * This method needs to be called before an animation using {@link #setTransitionAlpha(View,
    119      * float)} in order to make its behavior backward-compatible.
    120      */
    121     static void saveNonTransitionAlpha(@NonNull View view) {
    122         IMPL.saveNonTransitionAlpha(view);
    123     }
    124 
    125     /**
    126      * This method needs to be called after an animation using
    127      * {@link #setTransitionAlpha(View, float)} if {@link #saveNonTransitionAlpha(View)} has been
    128      * called.
    129      */
    130     static void clearNonTransitionAlpha(@NonNull View view) {
    131         IMPL.clearNonTransitionAlpha(view);
    132     }
    133 
    134     /**
    135      * Copy of a hidden platform method, View#setTransitionVisibility.
    136      *
    137      * <p>Change the visibility of the View without triggering any other changes. This is
    138      * important for transitions, where visibility changes should not adjust focus or
    139      * trigger a new layout. This is only used when the visibility has already been changed
    140      * and we need a transient value during an animation. When the animation completes,
    141      * the original visibility value is always restored.</p>
    142      *
    143      * @param view       The target view.
    144      * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or
    145      *                   {@link View#GONE}.
    146      */
    147     static void setTransitionVisibility(@NonNull View view, int visibility) {
    148         fetchViewFlagsField();
    149         if (sViewFlagsField != null) {
    150             try {
    151                 int viewFlags = sViewFlagsField.getInt(view);
    152                 sViewFlagsField.setInt(view, (viewFlags & ~VISIBILITY_MASK) | visibility);
    153             } catch (IllegalAccessException e) {
    154                 // Do nothing
    155             }
    156         }
    157     }
    158 
    159     /**
    160      * Modifies the input matrix such that it maps view-local coordinates to
    161      * on-screen coordinates.
    162      *
    163      * <p>On API Level 21 and above, this includes transformation matrix applied to {@code
    164      * ViewRootImpl}, but not on older platforms. This difference is balanced out by the
    165      * implementation difference in other related platform APIs and their backport, such as
    166      * GhostView.</p>
    167      *
    168      * @param view   target view
    169      * @param matrix input matrix to modify
    170      */
    171     static void transformMatrixToGlobal(@NonNull View view, @NonNull Matrix matrix) {
    172         IMPL.transformMatrixToGlobal(view, matrix);
    173     }
    174 
    175     /**
    176      * Modifies the input matrix such that it maps on-screen coordinates to
    177      * view-local coordinates.
    178      *
    179      * <p>On API Level 21 and above, this includes transformation matrix applied to {@code
    180      * ViewRootImpl}, but not on older platforms. This difference is balanced out by the
    181      * implementation difference in other related platform APIs and their backport, such as
    182      * GhostView.</p>
    183      *
    184      * @param view   target view
    185      * @param matrix input matrix to modify
    186      */
    187     static void transformMatrixToLocal(@NonNull View view, @NonNull Matrix matrix) {
    188         IMPL.transformMatrixToLocal(view, matrix);
    189     }
    190 
    191     /**
    192      * Sets the transformation matrix for animation.
    193      *
    194      * @param v The view
    195      * @param m The matrix
    196      */
    197     static void setAnimationMatrix(@NonNull View v, @Nullable Matrix m) {
    198         IMPL.setAnimationMatrix(v, m);
    199     }
    200 
    201     /**
    202      * Assign a size and position to this view.
    203      *
    204      * @param left   Left position, relative to parent
    205      * @param top    Top position, relative to parent
    206      * @param right  Right position, relative to parent
    207      * @param bottom Bottom position, relative to parent
    208      */
    209     static void setLeftTopRightBottom(@NonNull View v, int left, int top, int right, int bottom) {
    210         IMPL.setLeftTopRightBottom(v, left, top, right, bottom);
    211     }
    212 
    213     private static void fetchViewFlagsField() {
    214         if (!sViewFlagsFieldFetched) {
    215             try {
    216                 sViewFlagsField = View.class.getDeclaredField("mViewFlags");
    217                 sViewFlagsField.setAccessible(true);
    218             } catch (NoSuchFieldException e) {
    219                 Log.i(TAG, "fetchViewFlagsField: ");
    220             }
    221             sViewFlagsFieldFetched = true;
    222         }
    223     }
    224 
    225     private ViewUtils() {
    226     }
    227 }
    228