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.
5 package org.chromium.base;
7 import android.animation.ValueAnimator;
8 import android.annotation.TargetApi;
9 import android.app.ActivityOptions;
10 import android.app.Notification;
11 import android.app.PendingIntent;
12 import android.content.Context;
13 import android.content.Intent;
14 import android.content.res.Configuration;
15 import android.graphics.drawable.Drawable;
16 import android.os.Build;
17 import android.os.Bundle;
18 import android.provider.Settings;
19 import android.view.View;
20 import android.view.ViewGroup.MarginLayoutParams;
21 import android.view.ViewTreeObserver;
22 import android.widget.ImageView;
23 import android.widget.RemoteViews;
24 import android.widget.TextView;
27 * Utility class to use new APIs that were added after ICS (API level 14).
29 public class ApiCompatibilityUtils {
31 private static final String TAG = "ApiCompatibilityUtils";
33 private ApiCompatibilityUtils() {
37 * Returns true if view's layout direction is right-to-left.
39 * @param view the View whose layout is being considered
41 public static boolean isLayoutRtl(View view) {
42 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
43 return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
45 // All layouts are LTR before JB MR1.
51 * @see Configuration#getLayoutDirection()
53 public static int getLayoutDirection(Configuration configuration) {
54 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
55 return configuration.getLayoutDirection();
57 // All layouts are LTR before JB MR1.
58 return View.LAYOUT_DIRECTION_LTR;
63 * @return True if the running version of the Android supports printing.
65 public static boolean isPrintingSupported() {
66 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
70 * @return True if the running version of the Android supports HTML clipboard.
72 public static boolean isHTMLClipboardSupported() {
73 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
77 * @see android.view.View#setLayoutDirection(int)
79 public static void setLayoutDirection(View view, int layoutDirection) {
80 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
81 view.setLayoutDirection(layoutDirection);
83 // Do nothing. RTL layouts aren't supported before JB MR1.
88 * @see android.view.View#setTextAlignment(int)
90 public static void setTextAlignment(View view, int textAlignment) {
91 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
92 view.setTextAlignment(textAlignment);
94 // Do nothing. RTL text isn't supported before JB MR1.
99 * @see android.view.View#setTextDirection(int)
101 public static void setTextDirection(View view, int textDirection) {
102 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
103 view.setTextDirection(textDirection);
105 // Do nothing. RTL text isn't supported before JB MR1.
110 * @see android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int)
112 public static void setMarginEnd(MarginLayoutParams layoutParams, int end) {
113 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
114 layoutParams.setMarginEnd(end);
116 layoutParams.rightMargin = end;
121 * @see android.view.ViewGroup.MarginLayoutParams#getMarginEnd()
123 public static int getMarginEnd(MarginLayoutParams layoutParams) {
124 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
125 return layoutParams.getMarginEnd();
127 return layoutParams.rightMargin;
132 * @see android.view.ViewGroup.MarginLayoutParams#setMarginStart(int)
134 public static void setMarginStart(MarginLayoutParams layoutParams, int start) {
135 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
136 layoutParams.setMarginStart(start);
138 layoutParams.leftMargin = start;
143 * @see android.view.ViewGroup.MarginLayoutParams#getMarginStart()
145 public static int getMarginStart(MarginLayoutParams layoutParams) {
146 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
147 return layoutParams.getMarginStart();
149 return layoutParams.leftMargin;
154 * @see android.view.View#setPaddingRelative(int, int, int, int)
156 public static void setPaddingRelative(View view, int start, int top, int end, int bottom) {
157 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
158 view.setPaddingRelative(start, top, end, bottom);
160 // Before JB MR1, all layouts are left-to-right, so start == left, etc.
161 view.setPadding(start, top, end, bottom);
166 * @see android.view.View#getPaddingStart()
168 public static int getPaddingStart(View view) {
169 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
170 return view.getPaddingStart();
172 // Before JB MR1, all layouts are left-to-right, so start == left.
173 return view.getPaddingLeft();
178 * @see android.view.View#getPaddingEnd()
180 public static int getPaddingEnd(View view) {
181 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
182 return view.getPaddingEnd();
184 // Before JB MR1, all layouts are left-to-right, so end == right.
185 return view.getPaddingRight();
190 * @see android.widget.TextView#setCompoundDrawablesRelative(Drawable, Drawable, Drawable,
193 public static void setCompoundDrawablesRelative(TextView textView, Drawable start, Drawable top,
194 Drawable end, Drawable bottom) {
195 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
196 // On JB MR1, due to a platform bug, setCompoundDrawablesRelative() is a no-op if the
197 // view has ever been measured. As a workaround, use setCompoundDrawables() directly.
198 // See: http://crbug.com/368196 and http://crbug.com/361709
199 boolean isRtl = isLayoutRtl(textView);
200 textView.setCompoundDrawables(isRtl ? end : start, top, isRtl ? start : end, bottom);
201 } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
202 textView.setCompoundDrawablesRelative(start, top, end, bottom);
204 textView.setCompoundDrawables(start, top, end, bottom);
209 * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable,
210 * Drawable, Drawable, Drawable)
212 public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView,
213 Drawable start, Drawable top, Drawable end, Drawable bottom) {
214 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
215 // Work around the platform bug described in setCompoundDrawablesRelative() above.
216 boolean isRtl = isLayoutRtl(textView);
217 textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top,
218 isRtl ? start : end, bottom);
219 } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
220 textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
222 textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
227 * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int,
230 public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView,
231 int start, int top, int end, int bottom) {
232 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
233 // Work around the platform bug described in setCompoundDrawablesRelative() above.
234 boolean isRtl = isLayoutRtl(textView);
235 textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top,
236 isRtl ? start : end, bottom);
237 } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
238 textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
240 textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
245 * @see android.view.View#postInvalidateOnAnimation()
247 public static void postInvalidateOnAnimation(View view) {
248 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
249 view.postInvalidateOnAnimation();
251 view.postInvalidate();
256 * @see android.view.View#postOnAnimation()
258 public static void postOnAnimation(View view, Runnable action) {
259 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
260 view.postOnAnimation(action);
262 view.postDelayed(action, getFrameTime());
267 * @see android.view.View#postOnAnimationDelayed()
269 public static void postOnAnimationDelayed(View view, Runnable action, long delayMillis) {
270 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
271 view.postOnAnimationDelayed(action, delayMillis);
273 view.postDelayed(action, getFrameTime() + delayMillis);
277 private static long getFrameTime() {
278 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
279 return ValueAnimator.getFrameDelay();
281 // Any reasonable fake frame delay will have to do.
287 * @see android.widget.RemoteViews#setContentDescription(int, CharSequence)
289 public static void setContentDescriptionForRemoteView(RemoteViews remoteViews, int viewId,
290 CharSequence contentDescription) {
291 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
292 remoteViews.setContentDescription(viewId, contentDescription);
294 // setContentDescription() is unavailable in earlier versions.
299 * @see android.app.Activity#startActivity(Intent, Bundle)
301 public static void startActivity(Context context, Intent intent, Bundle options) {
302 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
303 context.startActivity(intent, options);
305 context.startActivity(intent);
310 * @see android.app.ActivityOptions#toBundle()
312 public static Bundle toBundle(ActivityOptions options) {
313 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
314 return options.toBundle();
320 // These methods have a new name, and the old name is deprecated.
323 * @see android.view.View#setBackground(Drawable)
325 @SuppressWarnings("deprecation")
326 public static void setBackgroundForView(View view, Drawable drawable) {
327 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
328 view.setBackground(drawable);
330 view.setBackgroundDrawable(drawable);
335 * @see android.view.ViewTreeObserver#removeOnGlobalLayoutListener()
337 @SuppressWarnings("deprecation")
338 public static void removeOnGlobalLayoutListener(
339 View view, ViewTreeObserver.OnGlobalLayoutListener listener) {
340 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
341 view.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
343 view.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
348 * @see android.widget.ImageView#setImageAlpha(int)
350 @SuppressWarnings("deprecation")
351 public static void setImageAlpha(ImageView iv, int alpha) {
352 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
353 iv.setImageAlpha(alpha);
360 * @see android.app.PendingIntent#getCreatorPackage()
362 @SuppressWarnings("deprecation")
363 public static String getCreatorPackage(PendingIntent intent) {
364 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
365 return intent.getCreatorPackage();
367 return intent.getTargetPackage();
372 * @see android.app.Notification.Builder#setLocalOnly(boolean)
374 @SuppressWarnings("deprecation")
375 public static Notification build(Notification.Builder builder) {
376 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
377 return builder.build();
379 return builder.getNotification();
384 * @see android.provider.Settings.Global#DEVICE_PROVISIONED
386 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
387 public static boolean isDeviceProvisioned(Context context) {
388 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return true;
389 if (context == null) return true;
390 if (context.getContentResolver() == null) return true;
391 return Settings.Global.getInt(
392 context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;