c9c7c0c80dd3fbd1dfcd6dd413d18a12041d6e95
[platform/framework/web/crosswalk.git] / src / ui / android / java / src / org / chromium / ui / UiUtils.java
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.ui;
6
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;
16
17 /**
18  * Utility functions for common Android UI tasks.
19  * This class is not supposed to be instantiated.
20  */
21 public class UiUtils {
22     private static final String TAG = "UiUtils";
23
24     /**
25      * Guards this class from being instantiated.
26      */
27     private UiUtils() {
28     }
29
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;
32
33     /**
34      * Shows the software keyboard if necessary.
35      * @param view The currently focused {@link View}, which would receive soft keyboard input.
36      */
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);
43     }
44
45     /**
46      * Hides the keyboard.
47      * @param view The {@link View} that is currently accepting input.
48      * @return Whether the keyboard was visible before.
49      */
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);
55     }
56
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;
66     }
67
68     /**
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.
74      */
75     public static int insertBefore(ViewGroup container, View newView, View existingView) {
76         return insertView(container, newView, existingView, false);
77     }
78
79     /**
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.
85      */
86     public static int insertAfter(ViewGroup container, View newView, View existingView) {
87         return insertView(container, newView, existingView, true);
88     }
89
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;
95
96         // Find the location of the existing view.
97         index = container.indexOfChild(existingView);
98         if (index < 0) return -1;
99
100         // Add the view.
101         if (after) index++;
102         container.addView(newView, index);
103         return index;
104     }
105
106     /**
107      * Generates a scaled screenshot of the given view.  The maximum size of the screenshot is
108      * determined by maximumDimension.
109      *
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.
116      */
117     public static Bitmap generateScaledScreenshot(
118             View currentView, int maximumDimension, Bitmap.Config bitmapConfig) {
119         Bitmap screenshot = null;
120         boolean drawingCacheEnabled = currentView.isDrawingCacheEnabled();
121         try {
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);
136                 }
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;
143                 } else {
144                     screenshot = scaledScreenshot;
145                 }
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);
155                 }
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);
161                 screenshot = bitmap;
162             }
163         } catch (OutOfMemoryError e) {
164             Log.d(TAG, "Unable to capture screenshot and scale it down." + e.getMessage());
165         } finally {
166             if (!drawingCacheEnabled) currentView.setDrawingCacheEnabled(false);
167             prepareViewHierarchyForScreenshot(currentView, false);
168         }
169         return screenshot;
170     }
171
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);
177             }
178         } else if (view instanceof SurfaceView) {
179             view.setWillNotDraw(!takingScreenshot);
180         }
181     }
182 }