blob: 96a98964972143a6347c37295c86c2a6fe317439 [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 */
Bijan Amirzada41242f22014-03-21 12:12:18 -070016package com.android.browser;
John Reck0f602f32011-07-07 15:38:43 -070017
Enrico Ros1f5a0952014-11-18 20:15:48 -080018import android.app.Activity;
John Reck0f602f32011-07-07 15:38:43 -070019import android.app.SearchManager;
kaiyizc4ada322013-07-30 09:58:07 +080020import android.content.ActivityNotFoundException;
John Reck0f602f32011-07-07 15:38:43 -070021import android.content.Context;
22import android.content.Intent;
23import android.graphics.Bitmap;
24import android.graphics.drawable.Drawable;
kaiyizc4ada322013-07-30 09:58:07 +080025import android.net.Uri;
John Reck0f602f32011-07-07 15:38:43 -070026import android.os.Bundle;
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;
Enrico Ros1f5a0952014-11-18 20:15:48 -080032import android.view.Menu;
33import android.view.MenuItem;
John Reck0f602f32011-07-07 15:38:43 -070034import android.view.View;
35import android.view.View.OnClickListener;
36import android.view.View.OnFocusChangeListener;
Enrico Ros1f5a0952014-11-18 20:15:48 -080037import android.view.ViewConfiguration;
John Reck0f602f32011-07-07 15:38:43 -070038import android.widget.ImageView;
39import android.widget.LinearLayout;
Enrico Ros1f5a0952014-11-18 20:15:48 -080040import android.widget.PopupMenu;
kaiyizc4ada322013-07-30 09:58:07 +080041import android.widget.Toast;
John Reck0f602f32011-07-07 15:38:43 -070042
Bijan Amirzada41242f22014-03-21 12:12:18 -070043import com.android.browser.R;
44import com.android.browser.UrlInputView.UrlInputListener;
John Reck0f602f32011-07-07 15:38:43 -070045
kaiyizc4ada322013-07-30 09:58:07 +080046import java.io.UnsupportedEncodingException;
kaiyiz950eca22013-08-08 11:01:28 +080047import java.net.URISyntaxException;
kaiyizc4ada322013-07-30 09:58:07 +080048
Kevin Hart055e6d82014-12-19 15:53:19 -080049import org.codeaurora.swe.Engine;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080050import org.codeaurora.swe.WebView;
51
John Reck42229bc2011-08-19 13:26:43 -070052public class NavigationBarBase extends LinearLayout implements
53 OnClickListener, UrlInputListener, OnFocusChangeListener,
Enrico Ros1f5a0952014-11-18 20:15:48 -080054 TextWatcher, UrlInputView.StateListener,
55 PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener {
John Reck0f602f32011-07-07 15:38:43 -070056
kaiyizc4ada322013-07-30 09:58:07 +080057 private final static String TAG = "NavigationBarBase";
58
John Reck0f602f32011-07-07 15:38:43 -070059 protected BaseUi mBaseUi;
60 protected TitleBar mTitleBar;
61 protected UiController mUiController;
62 protected UrlInputView mUrlInput;
Axesh R. Ajmera2e241242014-05-19 15:53:38 -070063 protected LocationButton mLocationButton;
John Reck0f602f32011-07-07 15:38:43 -070064
65 private ImageView mFavicon;
66 private ImageView mLockIcon;
John Reck0f602f32011-07-07 15:38:43 -070067
Enrico Ros1f5a0952014-11-18 20:15:48 -080068 private View mMore;
69 private PopupMenu mPopupMenu;
70 private boolean mOverflowMenuShowing;
71 private boolean mNeedsMenu;
Axesh R. Ajmera2e241242014-05-19 15:53:38 -070072
John Reck0f602f32011-07-07 15:38:43 -070073 public NavigationBarBase(Context context) {
74 super(context);
75 }
76
77 public NavigationBarBase(Context context, AttributeSet attrs) {
78 super(context, attrs);
79 }
80
81 public NavigationBarBase(Context context, AttributeSet attrs, int defStyle) {
82 super(context, attrs, defStyle);
83 }
84
85 @Override
86 protected void onFinishInflate() {
87 super.onFinishInflate();
88 mLockIcon = (ImageView) findViewById(R.id.lock);
Tarun Nainani8eb00912014-07-17 12:28:32 -070089 mLocationButton = (LocationButton) findViewById(R.id.location_button);
John Reck0f602f32011-07-07 15:38:43 -070090 mFavicon = (ImageView) findViewById(R.id.favicon);
91 mUrlInput = (UrlInputView) findViewById(R.id.url);
92 mUrlInput.setUrlInputListener(this);
John Reck0f602f32011-07-07 15:38:43 -070093 mUrlInput.setOnFocusChangeListener(this);
94 mUrlInput.setSelectAllOnFocus(true);
Narayan Kamathf3174a52011-11-17 14:43:32 +000095 mUrlInput.addTextChangedListener(this);
Enrico Ros1f5a0952014-11-18 20:15:48 -080096 mMore = findViewById(R.id.more_browser_settings);
97 mMore.setOnClickListener(this);
98 mNeedsMenu = !ViewConfiguration.get(getContext()).hasPermanentMenuKey();
John Reck0f602f32011-07-07 15:38:43 -070099 }
100
101 public void setTitleBar(TitleBar titleBar) {
102 mTitleBar = titleBar;
103 mBaseUi = mTitleBar.getUi();
104 mUiController = mTitleBar.getUiController();
Michael Kolbb2e91fd2011-07-14 13:47:29 -0700105 mUrlInput.setController(mUiController);
John Reck0f602f32011-07-07 15:38:43 -0700106 }
107
108 public void setLock(Drawable d) {
109 if (mLockIcon == null) return;
110 if (d == null) {
111 mLockIcon.setVisibility(View.GONE);
112 } else {
113 mLockIcon.setImageDrawable(d);
114 mLockIcon.setVisibility(View.VISIBLE);
115 }
116 }
117
118 public void setFavicon(Bitmap icon) {
119 if (mFavicon == null) return;
120 mFavicon.setImageDrawable(mBaseUi.getFaviconDrawable(icon));
121 }
122
John Reck0f602f32011-07-07 15:38:43 -0700123 @Override
124 public void onClick(View v) {
Enrico Ros1f5a0952014-11-18 20:15:48 -0800125 if (mMore == v) {
126 showMenu(mMore);
127 }
128 }
129
130 void showMenu(View anchor) {
131 Activity activity = mUiController.getActivity();
132 if (mPopupMenu == null) {
133 mPopupMenu = new PopupMenu(getContext(), anchor);
134 mPopupMenu.setOnMenuItemClickListener(this);
135 mPopupMenu.setOnDismissListener(this);
136 if (!activity.onCreateOptionsMenu(mPopupMenu.getMenu())) {
137 mPopupMenu = null;
138 return;
139 }
140 }
141 Menu menu = mPopupMenu.getMenu();
142
143 if (mUiController instanceof Controller) {
144 Controller controller = (Controller) mUiController;
145 if (controller.onPrepareOptionsMenu(menu)) {
146 mOverflowMenuShowing = true;
147 }
148 }
John Reck0f602f32011-07-07 15:38:43 -0700149 }
150
151 @Override
152 public void onFocusChange(View view, boolean hasFocus) {
153 // if losing focus and not in touch mode, leave as is
154 if (hasFocus || view.isInTouchMode() || mUrlInput.needsUpdate()) {
155 setFocusState(hasFocus);
156 }
157 if (hasFocus) {
Kevin Hart055e6d82014-12-19 15:53:19 -0800158 Engine.warmUpChildProcessAsync(mUiController.getActivity().getApplicationContext());
John Reck0f602f32011-07-07 15:38:43 -0700159 mBaseUi.showTitleBar();
John Reck0f602f32011-07-07 15:38:43 -0700160 } else if (!mUrlInput.needsUpdate()) {
161 mUrlInput.dismissDropDown();
162 mUrlInput.hideIME();
163 if (mUrlInput.getText().length() == 0) {
164 Tab currentTab = mUiController.getTabControl().getCurrentTab();
165 if (currentTab != null) {
John Reck434e9f82011-08-10 18:16:52 -0700166 setDisplayTitle(currentTab.getUrl());
John Reck0f602f32011-07-07 15:38:43 -0700167 }
168 }
169 mBaseUi.suggestHideTitleBar();
170 }
171 mUrlInput.clearNeedsUpdate();
172 }
173
174 protected void setFocusState(boolean focus) {
175 }
176
John Reck0f602f32011-07-07 15:38:43 -0700177 public boolean isEditingUrl() {
178 return mUrlInput.hasFocus();
179 }
180
181 void stopEditingUrl() {
Michael Kolb0b129122012-06-04 16:31:58 -0700182 WebView currentTopWebView = mUiController.getCurrentTopWebView();
183 if (currentTopWebView != null) {
184 currentTopWebView.requestFocus();
185 }
John Reck0f602f32011-07-07 15:38:43 -0700186 }
187
188 void setDisplayTitle(String title) {
189 if (!isEditingUrl()) {
Michael Kolb29aab402012-05-29 17:22:35 -0700190 if (!title.equals(mUrlInput.getText().toString())) {
191 mUrlInput.setText(title, false);
192 }
John Reck0f602f32011-07-07 15:38:43 -0700193 }
194 }
195
John Reck0f602f32011-07-07 15:38:43 -0700196 void setIncognitoMode(boolean incognito) {
197 mUrlInput.setIncognitoMode(incognito);
198 }
199
200 void clearCompletions() {
Narayan Kamathf3174a52011-11-17 14:43:32 +0000201 mUrlInput.dismissDropDown();
John Reck0f602f32011-07-07 15:38:43 -0700202 }
203
204 // UrlInputListener implementation
205
206 /**
207 * callback from suggestion dropdown
208 * user selected a suggestion
209 */
210 @Override
211 public void onAction(String text, String extra, String source) {
Michael Kolb0b129122012-06-04 16:31:58 -0700212 stopEditingUrl();
John Reck0f602f32011-07-07 15:38:43 -0700213 if (UrlInputView.TYPED.equals(source)) {
kaiyizc4ada322013-07-30 09:58:07 +0800214 String url = null;
Panos Thomas4bdb5252014-11-13 16:20:11 -0800215 boolean wap2estore = BrowserConfig.getInstance(getContext())
216 .hasFeature(BrowserConfig.Feature.WAP2ESTORE);
Vivek Sekhar5e631472014-03-31 23:59:10 -0700217 if ((wap2estore && isEstoreTypeUrl(text)) || isRtspTypeUrl(text)
218 || isMakeCallTypeUrl(text)) {
kaiyizc4ada322013-07-30 09:58:07 +0800219 url = text;
220 } else {
221 url = UrlUtils.smartUrlFilter(text, false);
222 }
223
John Reck0f602f32011-07-07 15:38:43 -0700224 Tab t = mBaseUi.getActiveTab();
225 // Only shortcut javascript URIs for now, as there is special
226 // logic in UrlHandler for other schemas
227 if (url != null && t != null && url.startsWith("javascript:")) {
228 mUiController.loadUrl(t, url);
229 setDisplayTitle(text);
230 return;
231 }
kaiyizc4ada322013-07-30 09:58:07 +0800232
233 // add for carrier wap2estore feature
234 if (url != null && t != null && wap2estore && isEstoreTypeUrl(url)) {
Vivek Sekharb54614f2014-05-01 19:03:37 -0700235 if (handleEstoreTypeUrl(url)) {
236 setDisplayTitle(text);
237 return;
238 }
kaiyizc4ada322013-07-30 09:58:07 +0800239 }
kaiyiz950eca22013-08-08 11:01:28 +0800240 // add for rtsp scheme feature
241 if (url != null && t != null && isRtspTypeUrl(url)) {
242 if (handleRtspTypeUrl(url)) {
Vivek Sekharb54614f2014-05-01 19:03:37 -0700243 setDisplayTitle(text);
kaiyiz950eca22013-08-08 11:01:28 +0800244 return;
245 }
246 }
Vivek Sekhar5e631472014-03-31 23:59:10 -0700247 // add for "wtai://wp/mc;" scheme feature
248 if (url != null && t != null && isMakeCallTypeUrl(url)) {
249 if (handleMakeCallTypeUrl(url)) {
250 return;
251 }
252 }
John Reck0f602f32011-07-07 15:38:43 -0700253 }
254 Intent i = new Intent();
Michael Kolb5ff5c8b2012-05-03 11:37:58 -0700255 String action = Intent.ACTION_SEARCH;
John Reck0f602f32011-07-07 15:38:43 -0700256 i.setAction(action);
257 i.putExtra(SearchManager.QUERY, text);
258 if (extra != null) {
259 i.putExtra(SearchManager.EXTRA_DATA_KEY, extra);
260 }
261 if (source != null) {
262 Bundle appData = new Bundle();
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800263 appData.putString("source", source);
264 i.putExtra("source", appData);
John Reck0f602f32011-07-07 15:38:43 -0700265 }
266 mUiController.handleNewIntent(i);
267 setDisplayTitle(text);
268 }
269
Vivek Sekhar5e631472014-03-31 23:59:10 -0700270 private boolean isMakeCallTypeUrl(String url) {
271 String utf8Url = null;
272 try {
273 utf8Url = new String(url.getBytes("UTF-8"), "UTF-8");
274 } catch (UnsupportedEncodingException e) {
275 Log.e(TAG, "err " + e);
276 }
277 if (utf8Url != null && utf8Url.startsWith(UrlHandler.SCHEME_WTAI_MC)) {
278 return true;
279 }
280 return false;
281 }
282
283 private boolean handleMakeCallTypeUrl(String url) {
284 // wtai://wp/mc;number
285 // number=string(phone-number)
286 if (url.startsWith(UrlHandler.SCHEME_WTAI_MC)) {
287 Intent intent = new Intent(Intent.ACTION_VIEW,
288 Uri.parse(WebView.SCHEME_TEL +
289 url.substring(UrlHandler.SCHEME_WTAI_MC.length())));
290 getContext().startActivity(intent);
291 // before leaving BrowserActivity, close the empty child tab.
292 // If a new tab is created through JavaScript open to load this
293 // url, we would like to close it as we will load this url in a
294 // different Activity.
295 Tab current = mUiController.getCurrentTab();
296 if (current != null
297 && current.getWebView().copyBackForwardList().getSize() == 0) {
298 mUiController.closeCurrentTab();
299 }
300 return true;
301 }
302 return false;
303 }
304
kaiyizc4ada322013-07-30 09:58:07 +0800305 private boolean isEstoreTypeUrl(String url) {
Vivek Sekharb54614f2014-05-01 19:03:37 -0700306 if (url != null && url.startsWith("estore:")) {
kaiyizc4ada322013-07-30 09:58:07 +0800307 return true;
308 }
309 return false;
310 }
311
Vivek Sekharb54614f2014-05-01 19:03:37 -0700312 private boolean handleEstoreTypeUrl(String url) {
313 if (url.getBytes().length > 256) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800314 Toast.makeText(getContext(), R.string.estore_url_warning, Toast.LENGTH_LONG).show();
Vivek Sekharb54614f2014-05-01 19:03:37 -0700315 return false;
kaiyizc4ada322013-07-30 09:58:07 +0800316 }
Vivek Sekharb54614f2014-05-01 19:03:37 -0700317
318 Intent intent;
319 // perform generic parsing of the URI to turn it into an Intent.
320 try {
321 intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
322 } catch (URISyntaxException ex) {
323 Log.w("Browser", "Bad URI " + url + ": " + ex.getMessage());
324 return false;
325 }
326
kaiyizc4ada322013-07-30 09:58:07 +0800327 try {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800328 getContext().startActivity(intent);
kaiyizc4ada322013-07-30 09:58:07 +0800329 } catch (ActivityNotFoundException ex) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800330 String downloadUrl = getContext().getResources().getString(R.string.estore_homepage);
kaiyizc4ada322013-07-30 09:58:07 +0800331 mUiController.loadUrl(mBaseUi.getActiveTab(), downloadUrl);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800332 Toast.makeText(getContext(), R.string.download_estore_app, Toast.LENGTH_LONG).show();
kaiyizc4ada322013-07-30 09:58:07 +0800333 }
Vivek Sekharb54614f2014-05-01 19:03:37 -0700334
335 return true;
kaiyizc4ada322013-07-30 09:58:07 +0800336 }
337
kaiyiz950eca22013-08-08 11:01:28 +0800338 private boolean isRtspTypeUrl(String url) {
339 String utf8Url = null;
340 try {
341 utf8Url = new String(url.getBytes("UTF-8"), "UTF-8");
342 } catch (UnsupportedEncodingException e) {
343 Log.e(TAG, "err " + e);
344 }
345 if (utf8Url != null && utf8Url.startsWith("rtsp://")) {
346 return true;
347 }
348 return false;
349 }
350
351 private boolean handleRtspTypeUrl(String url) {
352 Intent intent;
353 // perform generic parsing of the URI to turn it into an Intent.
354 try {
355 intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
356 } catch (URISyntaxException ex) {
357 Log.w("Browser", "Bad URI " + url + ": " + ex.getMessage());
358 return false;
359 }
360
361 try {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800362 getContext().startActivity(intent);
kaiyiz950eca22013-08-08 11:01:28 +0800363 } catch (ActivityNotFoundException ex) {
364 Log.w("Browser", "No resolveActivity " + url);
365 return false;
366 }
367 return true;
368 }
369
John Reck0f602f32011-07-07 15:38:43 -0700370 @Override
371 public void onDismiss() {
372 final Tab currentTab = mBaseUi.getActiveTab();
373 mBaseUi.hideTitleBar();
374 post(new Runnable() {
375 public void run() {
376 clearFocus();
Michael Kolb5ff5c8b2012-05-03 11:37:58 -0700377 if (currentTab != null) {
John Reck0f602f32011-07-07 15:38:43 -0700378 setDisplayTitle(currentTab.getUrl());
379 }
380 }
381 });
382 }
383
384 /**
385 * callback from the suggestion dropdown
386 * copy text to input field and stay in edit mode
387 */
388 @Override
389 public void onCopySuggestion(String text) {
390 mUrlInput.setText(text, true);
391 if (text != null) {
392 mUrlInput.setSelection(text.length());
393 }
394 }
395
396 public void setCurrentUrlIsBookmark(boolean isBookmark) {
397 }
398
399 @Override
400 public boolean dispatchKeyEventPreIme(KeyEvent evt) {
401 if (evt.getKeyCode() == KeyEvent.KEYCODE_BACK) {
402 // catch back key in order to do slightly more cleanup than usual
Michael Kolb0b129122012-06-04 16:31:58 -0700403 stopEditingUrl();
John Reck0f602f32011-07-07 15:38:43 -0700404 }
405 return super.dispatchKeyEventPreIme(evt);
406 }
407
John Reck0f602f32011-07-07 15:38:43 -0700408 /**
409 * called from the Ui when the user wants to edit
410 * @param clearInput clear the input field
411 */
Michael Kolb1f9b3562012-04-24 14:38:34 -0700412 void startEditingUrl(boolean clearInput, boolean forceIME) {
John Reck0f602f32011-07-07 15:38:43 -0700413 // editing takes preference of progress
414 setVisibility(View.VISIBLE);
John Reck0f602f32011-07-07 15:38:43 -0700415 if (!mUrlInput.hasFocus()) {
416 mUrlInput.requestFocus();
417 }
418 if (clearInput) {
419 mUrlInput.setText("");
John Reck0f602f32011-07-07 15:38:43 -0700420 }
Michael Kolb1f9b3562012-04-24 14:38:34 -0700421 if (forceIME) {
Michael Kolb4bb6fcb2012-04-13 14:25:27 -0700422 mUrlInput.showIME();
423 }
John Reck0f602f32011-07-07 15:38:43 -0700424 }
425
426 public void onProgressStarted() {
427 }
428
429 public void onProgressStopped() {
430 }
431
John Reck419f6b42011-08-16 16:10:51 -0700432 public void onTabDataChanged(Tab tab) {
Tarun Nainani8eb00912014-07-17 12:28:32 -0700433 mLocationButton.onTabDataChanged(tab);
John Reck419f6b42011-08-16 16:10:51 -0700434 }
435
Michael Kolb0b129122012-06-04 16:31:58 -0700436 public void onVoiceResult(String s) {
437 startEditingUrl(true, true);
438 onCopySuggestion(s);
439 }
440
Narayan Kamathf3174a52011-11-17 14:43:32 +0000441 @Override
442 public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
443
444 @Override
Michael Kolb5ff5c8b2012-05-03 11:37:58 -0700445 public void onTextChanged(CharSequence s, int start, int before, int count) { }
Narayan Kamathf3174a52011-11-17 14:43:32 +0000446
447 @Override
448 public void afterTextChanged(Editable s) { }
Michael Kolb0b129122012-06-04 16:31:58 -0700449
Enrico Ros1f5a0952014-11-18 20:15:48 -0800450 @Override
451 public void onStateChanged(int state) {
452 switch(state) {
453 case STATE_NORMAL:
454 mMore.setVisibility(mNeedsMenu ? View.VISIBLE : View.GONE);
455 break;
456 case STATE_HIGHLIGHTED:
457 mMore.setVisibility(View.GONE);
458 break;
459 case STATE_EDITED:
460 mMore.setVisibility(View.GONE);
461 break;
462 }
463 }
464
465 public boolean isMenuShowing() {
466 return mOverflowMenuShowing;
467 }
468
469
470 @Override
471 public void onDismiss(PopupMenu popupMenu) {
472 if (popupMenu == mPopupMenu) {
473 onMenuHidden();
474 }
475 }
476
477 private void onMenuHidden() {
478 mOverflowMenuShowing = false;
479 mBaseUi.showTitleBarForDuration();
480 }
481
482
483 @Override
484 public boolean onMenuItemClick(MenuItem item) {
485 return mUiController.onOptionsItemSelected(item);
486 }
John Reck0f602f32011-07-07 15:38:43 -0700487}