|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko; |
|
6 |
|
7 import org.mozilla.gecko.util.GeckoEventListener; |
|
8 import org.mozilla.gecko.util.ThreadUtils; |
|
9 |
|
10 import org.json.JSONObject; |
|
11 |
|
12 import android.content.Context; |
|
13 import android.text.Editable; |
|
14 import android.text.TextUtils; |
|
15 import android.text.TextWatcher; |
|
16 import android.util.AttributeSet; |
|
17 import android.view.KeyEvent; |
|
18 import android.view.LayoutInflater; |
|
19 import android.view.View; |
|
20 import android.view.inputmethod.InputMethodManager; |
|
21 import android.widget.LinearLayout; |
|
22 |
|
23 public class FindInPageBar extends LinearLayout implements TextWatcher, View.OnClickListener, GeckoEventListener { |
|
24 private static final String REQUEST_ID = "FindInPageBar"; |
|
25 |
|
26 private final Context mContext; |
|
27 private CustomEditText mFindText; |
|
28 private boolean mInflated = false; |
|
29 |
|
30 public FindInPageBar(Context context, AttributeSet attrs) { |
|
31 super(context, attrs); |
|
32 mContext = context; |
|
33 setFocusable(true); |
|
34 } |
|
35 |
|
36 public void inflateContent() { |
|
37 LayoutInflater inflater = LayoutInflater.from(mContext); |
|
38 View content = inflater.inflate(R.layout.find_in_page_content, this); |
|
39 |
|
40 content.findViewById(R.id.find_prev).setOnClickListener(this); |
|
41 content.findViewById(R.id.find_next).setOnClickListener(this); |
|
42 content.findViewById(R.id.find_close).setOnClickListener(this); |
|
43 |
|
44 // Capture clicks on the rest of the view to prevent them from |
|
45 // leaking into other views positioned below. |
|
46 content.setOnClickListener(this); |
|
47 |
|
48 mFindText = (CustomEditText) content.findViewById(R.id.find_text); |
|
49 mFindText.addTextChangedListener(this); |
|
50 mFindText.setOnKeyPreImeListener(new CustomEditText.OnKeyPreImeListener() { |
|
51 @Override |
|
52 public boolean onKeyPreIme(View v, int keyCode, KeyEvent event) { |
|
53 if (keyCode == KeyEvent.KEYCODE_BACK) { |
|
54 hide(); |
|
55 return true; |
|
56 } |
|
57 return false; |
|
58 } |
|
59 }); |
|
60 |
|
61 mInflated = true; |
|
62 GeckoAppShell.getEventDispatcher().registerEventListener("TextSelection:Data", this); |
|
63 } |
|
64 |
|
65 public void show() { |
|
66 if (!mInflated) |
|
67 inflateContent(); |
|
68 |
|
69 setVisibility(VISIBLE); |
|
70 mFindText.requestFocus(); |
|
71 |
|
72 // handleMessage() receives response message and determines initial state of softInput |
|
73 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("TextSelection:Get", REQUEST_ID)); |
|
74 } |
|
75 |
|
76 public void hide() { |
|
77 setVisibility(GONE); |
|
78 getInputMethodManager(mFindText).hideSoftInputFromWindow(mFindText.getWindowToken(), 0); |
|
79 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FindInPage:Closed", null)); |
|
80 } |
|
81 |
|
82 private InputMethodManager getInputMethodManager(View view) { |
|
83 Context context = view.getContext(); |
|
84 return (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); |
|
85 } |
|
86 |
|
87 public void onDestroy() { |
|
88 if (!mInflated) { |
|
89 return; |
|
90 } |
|
91 GeckoAppShell.getEventDispatcher().unregisterEventListener("TextSelection:Data", this); |
|
92 } |
|
93 |
|
94 // TextWatcher implementation |
|
95 |
|
96 @Override |
|
97 public void afterTextChanged(Editable s) { |
|
98 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FindInPage:Find", s.toString())); |
|
99 } |
|
100 |
|
101 @Override |
|
102 public void beforeTextChanged(CharSequence s, int start, int count, int after) { |
|
103 // ignore |
|
104 } |
|
105 |
|
106 @Override |
|
107 public void onTextChanged(CharSequence s, int start, int before, int count) { |
|
108 // ignore |
|
109 } |
|
110 |
|
111 // View.OnClickListener implementation |
|
112 |
|
113 @Override |
|
114 public void onClick(View v) { |
|
115 final int viewId = v.getId(); |
|
116 |
|
117 if (viewId == R.id.find_prev) { |
|
118 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FindInPage:Prev", mFindText.getText().toString())); |
|
119 getInputMethodManager(mFindText).hideSoftInputFromWindow(mFindText.getWindowToken(), 0); |
|
120 return; |
|
121 } |
|
122 |
|
123 if (viewId == R.id.find_next) { |
|
124 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FindInPage:Next", mFindText.getText().toString())); |
|
125 getInputMethodManager(mFindText).hideSoftInputFromWindow(mFindText.getWindowToken(), 0); |
|
126 return; |
|
127 } |
|
128 |
|
129 if (viewId == R.id.find_close) { |
|
130 hide(); |
|
131 } |
|
132 } |
|
133 |
|
134 // GeckoEventListener implementation |
|
135 |
|
136 @Override |
|
137 public void handleMessage(String event, JSONObject message) { |
|
138 if (!event.equals("TextSelection:Data") || !REQUEST_ID.equals(message.optString("requestId"))) { |
|
139 return; |
|
140 } |
|
141 |
|
142 final String text = message.optString("text"); |
|
143 |
|
144 // Populate an initial find string, virtual keyboard not required. |
|
145 if (!TextUtils.isEmpty(text)) { |
|
146 // Populate initial selection |
|
147 ThreadUtils.postToUiThread(new Runnable() { |
|
148 @Override |
|
149 public void run() { |
|
150 mFindText.setText(text); |
|
151 } |
|
152 }); |
|
153 return; |
|
154 } |
|
155 |
|
156 // Show the virtual keyboard. |
|
157 if (mFindText.hasWindowFocus()) { |
|
158 getInputMethodManager(mFindText).showSoftInput(mFindText, 0); |
|
159 } else { |
|
160 // showSoftInput won't work until after the window is focused. |
|
161 mFindText.setOnWindowFocusChangeListener(new CustomEditText.OnWindowFocusChangeListener() { |
|
162 @Override |
|
163 public void onWindowFocusChanged(boolean hasFocus) { |
|
164 if (!hasFocus) |
|
165 return; |
|
166 |
|
167 mFindText.setOnWindowFocusChangeListener(null); |
|
168 getInputMethodManager(mFindText).showSoftInput(mFindText, 0); |
|
169 } |
|
170 }); |
|
171 } |
|
172 } |
|
173 } |