1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base; 6 7 import android.app.PendingIntent; 8 import android.content.res.Configuration; 9 import android.graphics.drawable.Drawable; 10 import android.os.Build; 11 import android.view.View; 12 import android.view.ViewGroup.MarginLayoutParams; 13 import android.view.ViewTreeObserver; 14 import android.widget.ImageView; 15 import android.widget.RemoteViews; 16 import android.widget.TextView; 17 18 /** 19 * Utility class to use new APIs that were added after ICS (API level 14). 20 */ 21 public class ApiCompatibilityUtils { 22 23 private static final String TAG = "ApiCompatibilityUtils"; 24 ApiCompatibilityUtils()25 private ApiCompatibilityUtils() { 26 } 27 28 /** 29 * Returns true if view's layout direction is right-to-left. 30 * 31 * @param view the View whose layout is being considered 32 */ isLayoutRtl(View view)33 public static boolean isLayoutRtl(View view) { 34 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 35 return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; 36 } else { 37 // All layouts are LTR before JB MR1. 38 return false; 39 } 40 } 41 42 /** 43 * @see Configuration#getLayoutDirection() 44 */ getLayoutDirection(Configuration configuration)45 public static int getLayoutDirection(Configuration configuration) { 46 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 47 return configuration.getLayoutDirection(); 48 } else { 49 // All layouts are LTR before JB MR1. 50 return View.LAYOUT_DIRECTION_LTR; 51 } 52 } 53 54 /** 55 * @return True if the running version of the Android supports printing. 56 */ isPrintingSupported()57 public static boolean isPrintingSupported() { 58 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; 59 } 60 61 /** 62 * @return True if the running version of the Android supports HTML clipboard. 63 */ isHTMLClipboardSupported()64 public static boolean isHTMLClipboardSupported() { 65 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; 66 } 67 68 /** 69 * @see android.view.View#setLayoutDirection(int) 70 */ setLayoutDirection(View view, int layoutDirection)71 public static void setLayoutDirection(View view, int layoutDirection) { 72 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 73 view.setLayoutDirection(layoutDirection); 74 } else { 75 // Do nothing. RTL layouts aren't supported before JB MR1. 76 } 77 } 78 79 /** 80 * @see android.view.View#setTextDirection(int) 81 */ setTextAlignment(View view, int textAlignment)82 public static void setTextAlignment(View view, int textAlignment) { 83 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 84 view.setTextAlignment(textAlignment); 85 } else { 86 // Do nothing. RTL text isn't supported before JB MR1. 87 } 88 } 89 90 /** 91 * @see android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int) 92 */ setMarginEnd(MarginLayoutParams layoutParams, int end)93 public static void setMarginEnd(MarginLayoutParams layoutParams, int end) { 94 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 95 layoutParams.setMarginEnd(end); 96 } else { 97 layoutParams.rightMargin = end; 98 } 99 } 100 101 /** 102 * @see android.view.ViewGroup.MarginLayoutParams#getMarginEnd() 103 */ getMarginEnd(MarginLayoutParams layoutParams)104 public static int getMarginEnd(MarginLayoutParams layoutParams) { 105 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 106 return layoutParams.getMarginEnd(); 107 } else { 108 return layoutParams.rightMargin; 109 } 110 } 111 112 /** 113 * @see android.view.ViewGroup.MarginLayoutParams#setMarginStart(int) 114 */ setMarginStart(MarginLayoutParams layoutParams, int start)115 public static void setMarginStart(MarginLayoutParams layoutParams, int start) { 116 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 117 layoutParams.setMarginStart(start); 118 } else { 119 layoutParams.leftMargin = start; 120 } 121 } 122 123 /** 124 * @see android.view.ViewGroup.MarginLayoutParams#getMarginStart() 125 */ getMarginStart(MarginLayoutParams layoutParams)126 public static int getMarginStart(MarginLayoutParams layoutParams) { 127 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 128 return layoutParams.getMarginStart(); 129 } else { 130 return layoutParams.leftMargin; 131 } 132 } 133 134 /** 135 * @see android.view.View#setPaddingRelative(int, int, int, int) 136 */ setPaddingRelative(View view, int start, int top, int end, int bottom)137 public static void setPaddingRelative(View view, int start, int top, int end, int bottom) { 138 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 139 view.setPaddingRelative(start, top, end, bottom); 140 } else { 141 // Before JB MR1, all layouts are left-to-right, so start == left, etc. 142 view.setPadding(start, top, end, bottom); 143 } 144 } 145 146 /** 147 * @see android.view.View#getPaddingStart() 148 */ getPaddingStart(View view)149 public static int getPaddingStart(View view) { 150 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 151 return view.getPaddingStart(); 152 } else { 153 // Before JB MR1, all layouts are left-to-right, so start == left. 154 return view.getPaddingLeft(); 155 } 156 } 157 158 /** 159 * @see android.view.View#getPaddingEnd() 160 */ getPaddingEnd(View view)161 public static int getPaddingEnd(View view) { 162 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 163 return view.getPaddingEnd(); 164 } else { 165 // Before JB MR1, all layouts are left-to-right, so end == right. 166 return view.getPaddingRight(); 167 } 168 } 169 170 /** 171 * @see android.widget.TextView#setCompoundDrawablesRelative(Drawable, Drawable, Drawable, 172 * Drawable) 173 */ setCompoundDrawablesRelative(TextView textView, Drawable start, Drawable top, Drawable end, Drawable bottom)174 public static void setCompoundDrawablesRelative(TextView textView, Drawable start, Drawable top, 175 Drawable end, Drawable bottom) { 176 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) { 177 // On JB MR1, due to a platform bug, setCompoundDrawablesRelative() is a no-op if the 178 // view has ever been measured. As a workaround, use setCompoundDrawables() directly. 179 // See: http://crbug.com/368196 and http://crbug.com/361709 180 boolean isRtl = isLayoutRtl(textView); 181 textView.setCompoundDrawables(isRtl ? end : start, top, isRtl ? start : end, bottom); 182 } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) { 183 textView.setCompoundDrawablesRelative(start, top, end, bottom); 184 } else { 185 textView.setCompoundDrawables(start, top, end, bottom); 186 } 187 } 188 189 /** 190 * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable, 191 * Drawable, Drawable, Drawable) 192 */ setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView, Drawable start, Drawable top, Drawable end, Drawable bottom)193 public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView, 194 Drawable start, Drawable top, Drawable end, Drawable bottom) { 195 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) { 196 // Work around the platform bug described in setCompoundDrawablesRelative() above. 197 boolean isRtl = isLayoutRtl(textView); 198 textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top, 199 isRtl ? start : end, bottom); 200 } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) { 201 textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom); 202 } else { 203 textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom); 204 } 205 } 206 207 /** 208 * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, 209 * int) 210 */ setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView, int start, int top, int end, int bottom)211 public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView, 212 int start, int top, int end, int bottom) { 213 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) { 214 // Work around the platform bug described in setCompoundDrawablesRelative() above. 215 boolean isRtl = isLayoutRtl(textView); 216 textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top, 217 isRtl ? start : end, bottom); 218 } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) { 219 textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom); 220 } else { 221 textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom); 222 } 223 } 224 225 /** 226 * @see android.view.View#postInvalidateOnAnimation() 227 */ postInvalidateOnAnimation(View view)228 public static void postInvalidateOnAnimation(View view) { 229 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 230 view.postInvalidateOnAnimation(); 231 } else { 232 view.postInvalidate(); 233 } 234 } 235 236 /** 237 * @see android.widget.RemoteViews#setContentDescription(int, CharSequence) 238 */ setContentDescriptionForRemoteView(RemoteViews remoteViews, int viewId, CharSequence contentDescription)239 public static void setContentDescriptionForRemoteView(RemoteViews remoteViews, int viewId, 240 CharSequence contentDescription) { 241 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { 242 remoteViews.setContentDescription(viewId, contentDescription); 243 } else { 244 // setContentDescription() is unavailable in earlier versions. 245 } 246 } 247 248 // These methods have a new name, and the old name is deprecated. 249 250 /** 251 * @see android.view.View#setBackground(Drawable) 252 */ 253 @SuppressWarnings("deprecation") setBackgroundForView(View view, Drawable drawable)254 public static void setBackgroundForView(View view, Drawable drawable) { 255 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 256 view.setBackground(drawable); 257 } else { 258 view.setBackgroundDrawable(drawable); 259 } 260 } 261 262 /** 263 * @see android.view.ViewTreeObserver#removeOnGlobalLayoutListener() 264 */ 265 @SuppressWarnings("deprecation") removeOnGlobalLayoutListener( View view, ViewTreeObserver.OnGlobalLayoutListener listener)266 public static void removeOnGlobalLayoutListener( 267 View view, ViewTreeObserver.OnGlobalLayoutListener listener) { 268 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 269 view.getViewTreeObserver().removeOnGlobalLayoutListener(listener); 270 } else { 271 view.getViewTreeObserver().removeGlobalOnLayoutListener(listener); 272 } 273 } 274 275 /** 276 * @see android.widget.ImageView#setImageAlpha(int) 277 */ 278 @SuppressWarnings("deprecation") setImageAlpha(ImageView iv, int alpha)279 public static void setImageAlpha(ImageView iv, int alpha) { 280 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 281 iv.setImageAlpha(alpha); 282 } else { 283 iv.setAlpha(alpha); 284 } 285 } 286 287 /** 288 * @see android.app.PendingIntent#getCreatorPackage() 289 */ 290 @SuppressWarnings("deprecation") getCreatorPackage(PendingIntent intent)291 public static String getCreatorPackage(PendingIntent intent) { 292 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 293 return intent.getCreatorPackage(); 294 } else { 295 return intent.getTargetPackage(); 296 } 297 } 298 datePickerRequiresAccept()299 public static boolean datePickerRequiresAccept() { 300 // TODO(miguelg) use the final code for the L 301 // https://crbug.com/399198 302 return Build.VERSION.SDK_INT < 20; /* CUR_DEVELOPMENT */ 303 } 304 } 305