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