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.ui;
7 import android.content.Context;
8 import android.graphics.Bitmap;
9 import android.graphics.Canvas;
10 import android.graphics.Rect;
11 import android.util.Log;
12 import android.view.SurfaceView;
13 import android.view.View;
14 import android.view.ViewGroup;
15 import android.view.inputmethod.InputMethodManager;
18 * Utility functions for common Android UI tasks.
19 * This class is not supposed to be instantiated.
21 public class UiUtils {
22 private static final String TAG = "UiUtils";
25 * Guards this class from being instantiated.
30 /** The minimum size of the bottom margin below the app to detect a keyboard. */
31 private static final float KEYBOARD_DETECT_BOTTOM_THRESHOLD_DP = 100;
34 * Shows the software keyboard if necessary.
35 * @param view The currently focused {@link View}, which would receive soft keyboard input.
37 public static void showKeyboard(View view) {
38 InputMethodManager imm =
39 (InputMethodManager) view.getContext().getSystemService(
40 Context.INPUT_METHOD_SERVICE);
41 // Only shows soft keyboard if there isn't an open physical keyboard.
42 imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
47 * @param view The {@link View} that is currently accepting input.
48 * @return Whether the keyboard was visible before.
50 public static boolean hideKeyboard(View view) {
51 InputMethodManager imm =
52 (InputMethodManager) view.getContext().getSystemService(
53 Context.INPUT_METHOD_SERVICE);
54 return imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
57 public static boolean isKeyboardShowing(Context context, View view) {
58 View rootView = view.getRootView();
59 if (rootView == null) return false;
60 Rect appRect = new Rect();
61 rootView.getWindowVisibleDisplayFrame(appRect);
62 final float screenHeight = context.getResources().getDisplayMetrics().heightPixels;
63 final float bottomMargin = Math.abs(appRect.bottom - screenHeight);
64 final float density = context.getResources().getDisplayMetrics().density;
65 return bottomMargin > KEYBOARD_DETECT_BOTTOM_THRESHOLD_DP * density;
69 * Inserts a {@link View} into a {@link ViewGroup} after directly before a given {@View}.
70 * @param container The {@link View} to add newView to.
71 * @param newView The new {@link View} to add.
72 * @param existingView The {@link View} to insert the newView before.
73 * @return The index where newView was inserted, or -1 if it was not inserted.
75 public static int insertBefore(ViewGroup container, View newView, View existingView) {
76 return insertView(container, newView, existingView, false);
80 * Inserts a {@link View} into a {@link ViewGroup} after directly after a given {@View}.
81 * @param container The {@link View} to add newView to.
82 * @param newView The new {@link View} to add.
83 * @param existingView The {@link View} to insert the newView after.
84 * @return The index where newView was inserted, or -1 if it was not inserted.
86 public static int insertAfter(ViewGroup container, View newView, View existingView) {
87 return insertView(container, newView, existingView, true);
90 private static int insertView(
91 ViewGroup container, View newView, View existingView, boolean after) {
92 // See if the view has already been added.
93 int index = container.indexOfChild(newView);
94 if (index >= 0) return index;
96 // Find the location of the existing view.
97 index = container.indexOfChild(existingView);
98 if (index < 0) return -1;
102 container.addView(newView, index);
107 * Generates a scaled screenshot of the given view. The maximum size of the screenshot is
108 * determined by maximumDimension.
110 * @param currentView The view to generate a screenshot of.
111 * @param maximumDimension The maximum width or height of the generated screenshot. The bitmap
112 * will be scaled to ensure the maximum width or height is equal to or
113 * less than this. Any value <= 0, will result in no scaling.
114 * @param bitmapConfig Bitmap config for the generated screenshot (ARGB_8888 or RGB_565).
115 * @return The screen bitmap of the view or null if a problem was encountered.
117 public static Bitmap generateScaledScreenshot(
118 View currentView, int maximumDimension, Bitmap.Config bitmapConfig) {
119 Bitmap screenshot = null;
120 boolean drawingCacheEnabled = currentView.isDrawingCacheEnabled();
122 prepareViewHierarchyForScreenshot(currentView, true);
123 if (!drawingCacheEnabled) currentView.setDrawingCacheEnabled(true);
124 // Android has a maximum drawing cache size and if the drawing cache is bigger
125 // than that, getDrawingCache() returns null.
126 Bitmap originalBitmap = currentView.getDrawingCache();
127 if (originalBitmap != null) {
128 double originalHeight = originalBitmap.getHeight();
129 double originalWidth = originalBitmap.getWidth();
130 int newWidth = (int) originalWidth;
131 int newHeight = (int) originalHeight;
132 if (maximumDimension > 0) {
133 double scale = maximumDimension / Math.max(originalWidth, originalHeight);
134 newWidth = (int) Math.round(originalWidth * scale);
135 newHeight = (int) Math.round(originalHeight * scale);
137 Bitmap scaledScreenshot =
138 Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true);
139 if (scaledScreenshot.getConfig() != bitmapConfig) {
140 screenshot = scaledScreenshot.copy(bitmapConfig, false);
141 scaledScreenshot.recycle();
142 scaledScreenshot = null;
144 screenshot = scaledScreenshot;
146 } else if (currentView.getMeasuredHeight() > 0 && currentView.getMeasuredWidth() > 0) {
147 double originalHeight = currentView.getMeasuredHeight();
148 double originalWidth = currentView.getMeasuredWidth();
149 int newWidth = (int) originalWidth;
150 int newHeight = (int) originalHeight;
151 if (maximumDimension > 0) {
152 double scale = maximumDimension / Math.max(originalWidth, originalHeight);
153 newWidth = (int) Math.round(originalWidth * scale);
154 newHeight = (int) Math.round(originalHeight * scale);
156 Bitmap bitmap = Bitmap.createBitmap(newWidth, newHeight, bitmapConfig);
157 Canvas canvas = new Canvas(bitmap);
158 canvas.scale((float) (newWidth / originalWidth),
159 (float) (newHeight / originalHeight));
160 currentView.draw(canvas);
163 } catch (OutOfMemoryError e) {
164 Log.d(TAG, "Unable to capture screenshot and scale it down." + e.getMessage());
166 if (!drawingCacheEnabled) currentView.setDrawingCacheEnabled(false);
167 prepareViewHierarchyForScreenshot(currentView, false);
172 private static void prepareViewHierarchyForScreenshot(View view, boolean takingScreenshot) {
173 if (view instanceof ViewGroup) {
174 ViewGroup viewGroup = (ViewGroup) view;
175 for (int i = 0; i < viewGroup.getChildCount(); i++) {
176 prepareViewHierarchyForScreenshot(viewGroup.getChildAt(i), takingScreenshot);
178 } else if (view instanceof SurfaceView) {
179 view.setWillNotDraw(!takingScreenshot);