blob: daeb1dea6c1a61f74f4d928c3fe629f03f69cc0a [file] [log] [blame]
John Reck0f602f32011-07-07 15:38:43 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.browser;
17
18import android.app.SearchManager;
kaiyizc4ada322013-07-30 09:58:07 +080019import android.content.ActivityNotFoundException;
John Reck0f602f32011-07-07 15:38:43 -070020import android.content.Context;
21import android.content.Intent;
22import android.graphics.Bitmap;
23import android.graphics.drawable.Drawable;
kaiyizc4ada322013-07-30 09:58:07 +080024import android.net.Uri;
John Reck0f602f32011-07-07 15:38:43 -070025import android.os.Bundle;
kaiyizc4ada322013-07-30 09:58:07 +080026import android.os.SystemProperties;
Narayan Kamathf3174a52011-11-17 14:43:32 +000027import android.text.Editable;
28import android.text.TextWatcher;
John Reck0f602f32011-07-07 15:38:43 -070029import android.util.AttributeSet;
kaiyizc4ada322013-07-30 09:58:07 +080030import android.util.Log;
John Reck0f602f32011-07-07 15:38:43 -070031import android.view.KeyEvent;
John Reck0f602f32011-07-07 15:38:43 -070032import android.view.View;
33import android.view.View.OnClickListener;
34import android.view.View.OnFocusChangeListener;
John Reckfa6177a2011-11-15 14:51:11 -080035import android.webkit.WebView;
John Reck0f602f32011-07-07 15:38:43 -070036import android.widget.ImageView;
37import android.widget.LinearLayout;
kaiyizc4ada322013-07-30 09:58:07 +080038import android.widget.Toast;
John Reck0f602f32011-07-07 15:38:43 -070039
John Reck0f602f32011-07-07 15:38:43 -070040import com.android.browser.UrlInputView.UrlInputListener;
John Reck0f602f32011-07-07 15:38:43 -070041
kaiyizc4ada322013-07-30 09:58:07 +080042import java.io.UnsupportedEncodingException;
kaiyiz950eca22013-08-08 11:01:28 +080043import java.net.URISyntaxException;
kaiyizc4ada322013-07-30 09:58:07 +080044
John Reck42229bc2011-08-19 13:26:43 -070045public class NavigationBarBase extends LinearLayout implements
46 OnClickListener, UrlInputListener, OnFocusChangeListener,
Narayan Kamathf3174a52011-11-17 14:43:32 +000047 TextWatcher {
John Reck0f602f32011-07-07 15:38:43 -070048
kaiyizc4ada322013-07-30 09:58:07 +080049 private final static String TAG = "NavigationBarBase";
50
John Reck0f602f32011-07-07 15:38:43 -070051 protected BaseUi mBaseUi;
52 protected TitleBar mTitleBar;
53 protected UiController mUiController;
54 protected UrlInputView mUrlInput;
John Reck0f602f32011-07-07 15:38:43 -070055
56 private ImageView mFavicon;
57 private ImageView mLockIcon;
John Reck0f602f32011-07-07 15:38:43 -070058
59 public NavigationBarBase(Context context) {
60 super(context);
61 }
62
63 public NavigationBarBase(Context context, AttributeSet attrs) {
64 super(context, attrs);
65 }
66
67 public NavigationBarBase(Context context, AttributeSet attrs, int defStyle) {
68 super(context, attrs, defStyle);
69 }
70
71 @Override
72 protected void onFinishInflate() {
73 super.onFinishInflate();
74 mLockIcon = (ImageView) findViewById(R.id.lock);
75 mFavicon = (ImageView) findViewById(R.id.favicon);
76 mUrlInput = (UrlInputView) findViewById(R.id.url);
77 mUrlInput.setUrlInputListener(this);
John Reck0f602f32011-07-07 15:38:43 -070078 mUrlInput.setOnFocusChangeListener(this);
79 mUrlInput.setSelectAllOnFocus(true);
Narayan Kamathf3174a52011-11-17 14:43:32 +000080 mUrlInput.addTextChangedListener(this);
John Reck0f602f32011-07-07 15:38:43 -070081 }
82
83 public void setTitleBar(TitleBar titleBar) {
84 mTitleBar = titleBar;
85 mBaseUi = mTitleBar.getUi();
86 mUiController = mTitleBar.getUiController();
Michael Kolbb2e91fd2011-07-14 13:47:29 -070087 mUrlInput.setController(mUiController);
John Reck0f602f32011-07-07 15:38:43 -070088 }
89
90 public void setLock(Drawable d) {
91 if (mLockIcon == null) return;
92 if (d == null) {
93 mLockIcon.setVisibility(View.GONE);
94 } else {
95 mLockIcon.setImageDrawable(d);
96 mLockIcon.setVisibility(View.VISIBLE);
97 }
98 }
99
100 public void setFavicon(Bitmap icon) {
101 if (mFavicon == null) return;
102 mFavicon.setImageDrawable(mBaseUi.getFaviconDrawable(icon));
103 }
104
John Reck0f602f32011-07-07 15:38:43 -0700105 @Override
106 public void onClick(View v) {
John Reck0f602f32011-07-07 15:38:43 -0700107 }
108
109 @Override
110 public void onFocusChange(View view, boolean hasFocus) {
111 // if losing focus and not in touch mode, leave as is
112 if (hasFocus || view.isInTouchMode() || mUrlInput.needsUpdate()) {
113 setFocusState(hasFocus);
114 }
115 if (hasFocus) {
116 mBaseUi.showTitleBar();
John Reck0f602f32011-07-07 15:38:43 -0700117 } else if (!mUrlInput.needsUpdate()) {
118 mUrlInput.dismissDropDown();
119 mUrlInput.hideIME();
120 if (mUrlInput.getText().length() == 0) {
121 Tab currentTab = mUiController.getTabControl().getCurrentTab();
122 if (currentTab != null) {
John Reck434e9f82011-08-10 18:16:52 -0700123 setDisplayTitle(currentTab.getUrl());
John Reck0f602f32011-07-07 15:38:43 -0700124 }
125 }
126 mBaseUi.suggestHideTitleBar();
127 }
128 mUrlInput.clearNeedsUpdate();
129 }
130
131 protected void setFocusState(boolean focus) {
132 }
133
John Reck0f602f32011-07-07 15:38:43 -0700134 public boolean isEditingUrl() {
135 return mUrlInput.hasFocus();
136 }
137
138 void stopEditingUrl() {
Michael Kolb0b129122012-06-04 16:31:58 -0700139 WebView currentTopWebView = mUiController.getCurrentTopWebView();
140 if (currentTopWebView != null) {
141 currentTopWebView.requestFocus();
142 }
John Reck0f602f32011-07-07 15:38:43 -0700143 }
144
145 void setDisplayTitle(String title) {
146 if (!isEditingUrl()) {
Michael Kolb29aab402012-05-29 17:22:35 -0700147 if (!title.equals(mUrlInput.getText().toString())) {
148 mUrlInput.setText(title, false);
149 }
John Reck0f602f32011-07-07 15:38:43 -0700150 }
151 }
152
John Reck0f602f32011-07-07 15:38:43 -0700153 void setIncognitoMode(boolean incognito) {
154 mUrlInput.setIncognitoMode(incognito);
155 }
156
157 void clearCompletions() {
Narayan Kamathf3174a52011-11-17 14:43:32 +0000158 mUrlInput.dismissDropDown();
John Reck0f602f32011-07-07 15:38:43 -0700159 }
160
161 // UrlInputListener implementation
162
163 /**
164 * callback from suggestion dropdown
165 * user selected a suggestion
166 */
167 @Override
168 public void onAction(String text, String extra, String source) {
Michael Kolb0b129122012-06-04 16:31:58 -0700169 stopEditingUrl();
John Reck0f602f32011-07-07 15:38:43 -0700170 if (UrlInputView.TYPED.equals(source)) {
kaiyizc4ada322013-07-30 09:58:07 +0800171 String url = null;
172 boolean wap2estore = SystemProperties.getBoolean(
173 "persist.env.browser.wap2estore", false);
kaiyiz950eca22013-08-08 11:01:28 +0800174 if ((wap2estore && isEstoreTypeUrl(text))
175 || isRtspTypeUrl(text)) {
kaiyizc4ada322013-07-30 09:58:07 +0800176 url = text;
177 } else {
178 url = UrlUtils.smartUrlFilter(text, false);
179 }
180
John Reck0f602f32011-07-07 15:38:43 -0700181 Tab t = mBaseUi.getActiveTab();
182 // Only shortcut javascript URIs for now, as there is special
183 // logic in UrlHandler for other schemas
184 if (url != null && t != null && url.startsWith("javascript:")) {
185 mUiController.loadUrl(t, url);
186 setDisplayTitle(text);
187 return;
188 }
kaiyizc4ada322013-07-30 09:58:07 +0800189
190 // add for carrier wap2estore feature
191 if (url != null && t != null && wap2estore && isEstoreTypeUrl(url)) {
192 handleEstoreTypeUrl(url);
193 setDisplayTitle(text);
194 return;
195 }
kaiyiz950eca22013-08-08 11:01:28 +0800196 // add for rtsp scheme feature
197 if (url != null && t != null && isRtspTypeUrl(url)) {
198 if (handleRtspTypeUrl(url)) {
199 return;
200 }
201 }
John Reck0f602f32011-07-07 15:38:43 -0700202 }
203 Intent i = new Intent();
Michael Kolb5ff5c8b2012-05-03 11:37:58 -0700204 String action = Intent.ACTION_SEARCH;
John Reck0f602f32011-07-07 15:38:43 -0700205 i.setAction(action);
206 i.putExtra(SearchManager.QUERY, text);
207 if (extra != null) {
208 i.putExtra(SearchManager.EXTRA_DATA_KEY, extra);
209 }
210 if (source != null) {
211 Bundle appData = new Bundle();
212 appData.putString(com.android.common.Search.SOURCE, source);
213 i.putExtra(SearchManager.APP_DATA, appData);
214 }
215 mUiController.handleNewIntent(i);
216 setDisplayTitle(text);
217 }
218
kaiyizc4ada322013-07-30 09:58:07 +0800219 private boolean isEstoreTypeUrl(String url) {
220 String utf8Url = null;
221 try {
222 utf8Url = new String(url.getBytes("UTF-8"), "UTF-8");
223 } catch (UnsupportedEncodingException e) {
224 Log.e(TAG, "err " + e);
225 }
226 if (utf8Url != null && utf8Url.startsWith("estore:")) {
227 return true;
228 }
229 return false;
230 }
231
232 private void handleEstoreTypeUrl(String url) {
233 String utf8Url = null, finalUrl = null;
234 try {
235 utf8Url = new String(url.getBytes("UTF-8"), "UTF-8");
236 } catch (UnsupportedEncodingException e) {
237 Log.e(TAG, "err " + e);
238 }
239 if (utf8Url != null) {
240 finalUrl = utf8Url;
241 } else {
242 finalUrl = url;
243 }
244 if (finalUrl.replaceFirst("estore:", "").length() > 256) {
245 Toast.makeText(mContext, R.string.estore_url_warning, Toast.LENGTH_LONG).show();
246 return;
247 }
248 Intent intent = new Intent(Intent.ACTION_VIEW);
249 intent.setData(Uri.parse(finalUrl));
250 try {
251 mContext.startActivity(intent);
252 } catch (ActivityNotFoundException ex) {
253 String downloadUrl = mContext.getResources().getString(R.string.estore_homepage);
254 mUiController.loadUrl(mBaseUi.getActiveTab(), downloadUrl);
255 Toast.makeText(mContext, R.string.download_estore_app, Toast.LENGTH_LONG).show();
256 }
257 }
258
kaiyiz950eca22013-08-08 11:01:28 +0800259 private boolean isRtspTypeUrl(String url) {
260 String utf8Url = null;
261 try {
262 utf8Url = new String(url.getBytes("UTF-8"), "UTF-8");
263 } catch (UnsupportedEncodingException e) {
264 Log.e(TAG, "err " + e);
265 }
266 if (utf8Url != null && utf8Url.startsWith("rtsp://")) {
267 return true;
268 }
269 return false;
270 }
271
272 private boolean handleRtspTypeUrl(String url) {
273 Intent intent;
274 // perform generic parsing of the URI to turn it into an Intent.
275 try {
276 intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
277 } catch (URISyntaxException ex) {
278 Log.w("Browser", "Bad URI " + url + ": " + ex.getMessage());
279 return false;
280 }
281
282 try {
283 mContext.startActivity(intent);
284 } catch (ActivityNotFoundException ex) {
285 Log.w("Browser", "No resolveActivity " + url);
286 return false;
287 }
288 return true;
289 }
290
John Reck0f602f32011-07-07 15:38:43 -0700291 @Override
292 public void onDismiss() {
293 final Tab currentTab = mBaseUi.getActiveTab();
294 mBaseUi.hideTitleBar();
295 post(new Runnable() {
296 public void run() {
297 clearFocus();
Michael Kolb5ff5c8b2012-05-03 11:37:58 -0700298 if (currentTab != null) {
John Reck0f602f32011-07-07 15:38:43 -0700299 setDisplayTitle(currentTab.getUrl());
300 }
301 }
302 });
303 }
304
305 /**
306 * callback from the suggestion dropdown
307 * copy text to input field and stay in edit mode
308 */
309 @Override
310 public void onCopySuggestion(String text) {
311 mUrlInput.setText(text, true);
312 if (text != null) {
313 mUrlInput.setSelection(text.length());
314 }
315 }
316
317 public void setCurrentUrlIsBookmark(boolean isBookmark) {
318 }
319
320 @Override
321 public boolean dispatchKeyEventPreIme(KeyEvent evt) {
322 if (evt.getKeyCode() == KeyEvent.KEYCODE_BACK) {
323 // catch back key in order to do slightly more cleanup than usual
Michael Kolb0b129122012-06-04 16:31:58 -0700324 stopEditingUrl();
John Reck0f602f32011-07-07 15:38:43 -0700325 return true;
326 }
327 return super.dispatchKeyEventPreIme(evt);
328 }
329
John Reck0f602f32011-07-07 15:38:43 -0700330 /**
331 * called from the Ui when the user wants to edit
332 * @param clearInput clear the input field
333 */
Michael Kolb1f9b3562012-04-24 14:38:34 -0700334 void startEditingUrl(boolean clearInput, boolean forceIME) {
John Reck0f602f32011-07-07 15:38:43 -0700335 // editing takes preference of progress
336 setVisibility(View.VISIBLE);
337 if (mTitleBar.useQuickControls()) {
338 mTitleBar.getProgressView().setVisibility(View.GONE);
339 }
340 if (!mUrlInput.hasFocus()) {
341 mUrlInput.requestFocus();
342 }
343 if (clearInput) {
344 mUrlInput.setText("");
John Reck0f602f32011-07-07 15:38:43 -0700345 }
Michael Kolb1f9b3562012-04-24 14:38:34 -0700346 if (forceIME) {
Michael Kolb4bb6fcb2012-04-13 14:25:27 -0700347 mUrlInput.showIME();
348 }
John Reck0f602f32011-07-07 15:38:43 -0700349 }
350
351 public void onProgressStarted() {
352 }
353
354 public void onProgressStopped() {
355 }
356
John Reck58891902011-08-11 17:48:53 -0700357 public boolean isMenuShowing() {
John Reck42229bc2011-08-19 13:26:43 -0700358 return false;
John Reck58891902011-08-11 17:48:53 -0700359 }
360
John Reck419f6b42011-08-16 16:10:51 -0700361 public void onTabDataChanged(Tab tab) {
362 }
363
Michael Kolb0b129122012-06-04 16:31:58 -0700364 public void onVoiceResult(String s) {
365 startEditingUrl(true, true);
366 onCopySuggestion(s);
367 }
368
Narayan Kamathf3174a52011-11-17 14:43:32 +0000369 @Override
370 public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
371
372 @Override
Michael Kolb5ff5c8b2012-05-03 11:37:58 -0700373 public void onTextChanged(CharSequence s, int start, int before, int count) { }
Narayan Kamathf3174a52011-11-17 14:43:32 +0000374
375 @Override
376 public void afterTextChanged(Editable s) { }
Michael Kolb0b129122012-06-04 16:31:58 -0700377
John Reck0f602f32011-07-07 15:38:43 -0700378}