Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / public / android / java / src / org / chromium / content / browser / input / PastePopupMenu.java
1 // Copyright 2014 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.content.browser.input;
6
7 import android.content.Context;
8 import android.content.res.TypedArray;
9 import android.util.TypedValue;
10 import android.view.Gravity;
11 import android.view.LayoutInflater;
12 import android.view.View;
13 import android.view.View.OnClickListener;
14 import android.view.ViewGroup;
15 import android.view.ViewGroup.LayoutParams;
16 import android.widget.PopupWindow;
17
18 /**
19  * Paste popup implementation based on TextView.PastePopupMenu.
20  */
21 public class PastePopupMenu implements OnClickListener {
22     private final View mParent;
23     private final PastePopupMenuDelegate mDelegate;
24     private final Context mContext;
25     private final PopupWindow mContainer;
26     private int mRawPositionX;
27     private int mRawPositionY;
28     private int mPositionX;
29     private int mPositionY;
30     private int mStatusBarHeight;
31     private View mPasteView;
32     private final int mPasteViewLayout;
33     private final int mLineOffsetY;
34     private final int mWidthOffsetX;
35
36     /**
37      * Provider of paste functionality for the given popup.
38      */
39     public interface PastePopupMenuDelegate {
40         /**
41          * Called to initiate a paste after the popup has been tapped.
42          */
43         void paste();
44     }
45
46     public PastePopupMenu(View parent, PastePopupMenuDelegate delegate) {
47         mParent = parent;
48         mDelegate = delegate;
49         mContext = parent.getContext();
50         mContainer = new PopupWindow(mContext, null,
51                 android.R.attr.textSelectHandleWindowStyle);
52         mContainer.setSplitTouchEnabled(true);
53         mContainer.setClippingEnabled(false);
54         mContainer.setAnimationStyle(0);
55
56         mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
57         mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
58
59         final int[] popupLayoutAttrs = { android.R.attr.textEditPasteWindowLayout, };
60
61         mPasteView = null;
62         TypedArray attrs = mContext.getTheme().obtainStyledAttributes(popupLayoutAttrs);
63         mPasteViewLayout = attrs.getResourceId(attrs.getIndex(0), 0);
64
65         attrs.recycle();
66
67         // Convert line offset dips to pixels.
68         mLineOffsetY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
69                 5.0f, mContext.getResources().getDisplayMetrics());
70         mWidthOffsetX = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
71                 30.0f, mContext.getResources().getDisplayMetrics());
72
73         final int statusBarHeightResourceId =
74                 mContext.getResources().getIdentifier("status_bar_height", "dimen", "android");
75         if (statusBarHeightResourceId > 0) {
76             mStatusBarHeight =
77                     mContext.getResources().getDimensionPixelSize(statusBarHeightResourceId);
78         }
79     }
80
81     /**
82      * Shows the paste popup at an appropriate location relative to the specified position.
83      */
84     public void showAt(int x, int y) {
85         updateContent();
86         positionAt(x, y);
87     }
88
89     /**
90      * Hides the paste popup.
91      */
92     public void hide() {
93         mContainer.dismiss();
94     }
95
96     /**
97      * @return Whether the popup is active and showing.
98      */
99     public boolean isShowing() {
100         return mContainer.isShowing();
101     }
102
103     @Override
104     public void onClick(View v) {
105         paste();
106         hide();
107     }
108
109     private void positionAt(int x, int y) {
110         if (mRawPositionX == x && mRawPositionY == y && isShowing()) return;
111         mRawPositionX = x;
112         mRawPositionY = y;
113
114         final View contentView = mContainer.getContentView();
115         final int width = contentView.getMeasuredWidth();
116         final int height = contentView.getMeasuredHeight();
117
118         mPositionX = (int) (x - width / 2.0f);
119         mPositionY = y - height - mLineOffsetY;
120
121         final int[] coords = new int[2];
122         mParent.getLocationInWindow(coords);
123         coords[0] += mPositionX;
124         coords[1] += mPositionY;
125
126         int minOffsetY = 0;
127         if (mParent.getSystemUiVisibility() == View.SYSTEM_UI_FLAG_VISIBLE) {
128             minOffsetY = mStatusBarHeight;
129         }
130
131         final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
132         if (coords[1] < minOffsetY) {
133             // Vertical clipping, move under edited line and to the side of insertion cursor
134             // TODO bottom clipping in case there is no system bar
135             coords[1] += height;
136             coords[1] += mLineOffsetY;
137
138             // Move to right hand side of insertion cursor by default. TODO RTL text.
139             final int handleHalfWidth = mWidthOffsetX / 2;
140
141             if (x + width < screenWidth) {
142                 coords[0] += handleHalfWidth + width / 2;
143             } else {
144                 coords[0] -= handleHalfWidth + width / 2;
145             }
146         } else {
147             // Horizontal clipping
148             coords[0] = Math.max(0, coords[0]);
149             coords[0] = Math.min(screenWidth - width, coords[0]);
150         }
151
152         if (!isShowing()) {
153             mContainer.showAtLocation(mParent, Gravity.NO_GRAVITY, coords[0], coords[1]);
154         } else {
155             mContainer.update(coords[0], coords[1], -1, -1);
156         }
157     }
158
159     private void updateContent() {
160         if (mPasteView == null) {
161             final int layout = mPasteViewLayout;
162             LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
163                     Context.LAYOUT_INFLATER_SERVICE);
164             if (inflater != null) {
165                 mPasteView = inflater.inflate(layout, null);
166             }
167
168             if (mPasteView == null) {
169                 throw new IllegalArgumentException("Unable to inflate TextEdit paste window");
170             }
171
172             final int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
173             mPasteView.setLayoutParams(
174                     new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
175                             ViewGroup.LayoutParams.WRAP_CONTENT));
176             mPasteView.measure(size, size);
177
178             mPasteView.setOnClickListener(this);
179         }
180
181         mContainer.setContentView(mPasteView);
182     }
183
184     private void paste() {
185         mDelegate.paste();
186     }
187 }