ViewUtils.java revision 6f2135232bf216d194b049265f0b92f69e74c241
1/* 2 * Copyright (C) 2014 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.v7.internal.widget; 18 19import android.content.Context; 20import android.content.res.TypedArray; 21import android.graphics.Rect; 22import android.os.Build; 23import android.support.v4.view.ViewCompat; 24import android.support.v7.appcompat.R; 25import android.support.v7.internal.view.ContextThemeWrapper; 26import android.util.AttributeSet; 27import android.util.Log; 28import android.view.View; 29 30import java.lang.reflect.InvocationTargetException; 31import java.lang.reflect.Method; 32 33/** 34 * @hide 35 */ 36public class ViewUtils { 37 private static final String TAG = "ViewUtils"; 38 39 private static Method sComputeFitSystemWindowsMethod; 40 41 static { 42 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { 43 try { 44 sComputeFitSystemWindowsMethod = View.class.getDeclaredMethod( 45 "computeFitSystemWindows", Rect.class, Rect.class); 46 if (!sComputeFitSystemWindowsMethod.isAccessible()) { 47 sComputeFitSystemWindowsMethod.setAccessible(true); 48 } 49 } catch (NoSuchMethodException e) { 50 Log.d(TAG, "Could not find method computeFitSystemWindows. Oh well."); 51 } 52 } 53 } 54 55 private ViewUtils() {} 56 57 public static boolean isLayoutRtl(View view) { 58 return ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_RTL; 59 } 60 61 /** 62 * Merge two states as returned by {@link ViewCompat#getMeasuredState(android.view.View)} ()}. 63 * @param curState The current state as returned from a view or the result 64 * of combining multiple views. 65 * @param newState The new view state to combine. 66 * @return Returns a new integer reflecting the combination of the two 67 * states. 68 */ 69 public static int combineMeasuredStates(int curState, int newState) { 70 return curState | newState; 71 } 72 73 /** 74 * Allow calling the hidden method {@code computeFitSystemWindows(Rect, Rect)} through 75 * reflection on {@code view}. 76 */ 77 public static void computeFitSystemWindows(View view, Rect inoutInsets, Rect outLocalInsets) { 78 if (sComputeFitSystemWindowsMethod != null) { 79 try { 80 sComputeFitSystemWindowsMethod.invoke(view, inoutInsets, outLocalInsets); 81 } catch (Exception e) { 82 Log.d(TAG, "Could not invoke computeFitSystemWindows", e); 83 } 84 } 85 } 86 87 /** 88 * Allow calling the hidden method {@code makeOptionalFitsSystem()} through reflection on 89 * {@code view}. 90 */ 91 public static void makeOptionalFitsSystemWindows(View view) { 92 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 93 try { 94 // We need to use getMethod() for makeOptionalFitsSystemWindows since both View 95 // and ViewGroup implement the method 96 Method method = view.getClass().getMethod("makeOptionalFitsSystemWindows"); 97 if (!method.isAccessible()) { 98 method.setAccessible(true); 99 } 100 method.invoke(view); 101 } catch (NoSuchMethodException e) { 102 Log.d(TAG, "Could not find method makeOptionalFitsSystemWindows. Oh well..."); 103 } catch (InvocationTargetException e) { 104 Log.d(TAG, "Could not invoke makeOptionalFitsSystemWindows", e); 105 } catch (IllegalAccessException e) { 106 Log.d(TAG, "Could not invoke makeOptionalFitsSystemWindows", e); 107 } 108 } 109 } 110 111 /** 112 * Allows us to emulate the {@code android:theme} attribute for devices before L. 113 */ 114 public static Context themifyContext(Context context, AttributeSet attrs, 115 boolean useAndroidTheme, boolean useAppTheme) { 116 final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.View, 0, 0); 117 int themeId = 0; 118 if (useAndroidTheme) { 119 // First try reading android:theme if enabled 120 themeId = a.getResourceId(R.styleable.View_android_theme, 0); 121 } 122 if (useAppTheme && themeId == 0) { 123 // ...if that didn't work, try reading app:theme (for legacy reasons) if enabled 124 themeId = a.getResourceId(R.styleable.View_theme, 0); 125 126 if (themeId != 0) { 127 Log.i(TAG, "app:theme is now deprecated. Please move to using android:theme instead."); 128 } 129 } 130 a.recycle(); 131 132 if (themeId != 0 && (!(context instanceof ContextThemeWrapper) 133 || ((ContextThemeWrapper) context).getThemeResId() != themeId)) { 134 // If the context isn't a ContextThemeWrapperCompat, or it is but does not have 135 // the same theme as we need, wrap it in a new wrapper 136 context = new ContextThemeWrapper(context, themeId); 137 } 138 return context; 139 } 140} 141