/* * Copyright (C) 2010 Geometer Plus <contact@geometerplus.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ package org.geometerplus.android.fbreader.network.browser; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.provider.SearchRecentSuggestions; import android.view.*; import android.webkit.*; import android.widget.TextView; import android.widget.Toast; import org.geometerplus.zlibrary.core.resources.ZLResource; import org.geometerplus.zlibrary.core.util.ZLNetworkUtil; import org.geometerplus.zlibrary.ui.android.R; import org.geometerplus.fbreader.network.NetworkLibrary; import org.geometerplus.android.fbreader.network.BookDownloaderService; import org.geometerplus.android.fbreader.network.NetworkLibraryActivity; public class BrowserActivity extends Activity { protected final ZLResource myResource = ZLResource.resource("browser"); private String myStoreInRecentUrls; private Object myStoreInRecentUrlsLock = new Object(); private void setStoreInRecentUrls(String url) { synchronized (myStoreInRecentUrlsLock) { myStoreInRecentUrls = url; } } private void storeUrlInRecents() { synchronized (myStoreInRecentUrlsLock) { if (myStoreInRecentUrls != null) { SearchRecentSuggestions suggestions = new SearchRecentSuggestions( getApplicationContext(), RecentUrlsProvider.AUTHORITY, RecentUrlsProvider.MODE); suggestions.saveRecentQuery(myStoreInRecentUrls, null); } myStoreInRecentUrls = null; } } private void downloadBook(String url) { startService( new Intent(Intent.ACTION_VIEW, Uri.parse(url), getApplicationContext(), BookDownloaderService.class) //.putExtra(BookDownloaderService.BOOK_FORMAT_KEY, ref.BookFormat) //.putExtra(BookDownloaderService.REFERENCE_TYPE_KEY, resolvedType) //.putExtra(BookDownloaderService.CLEAN_URL_KEY, ref.cleanURL()) //.putExtra(BookDownloaderService.TITLE_KEY, book.Title) //.putExtra(BookDownloaderService.SSL_CERTIFICATE_KEY, sslCertificate) ); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Thread.setDefaultUncaughtExceptionHandler(new org.geometerplus.zlibrary.ui.android.library.UncaughtExceptionHandler(this)); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); requestWindowFeature(Window.FEATURE_PROGRESS); setContentView(R.layout.browser); setTitle(ZLResource.resource("networkView").getResource("browser").getValue()); final WebView view = (WebView) findViewById(R.id.webview); view.setWebChromeClient(new ChromeClient()); view.setWebViewClient(new ViewClient()); view.getSettings().setJavaScriptEnabled(true); view.getSettings().setUserAgentString(ZLNetworkUtil.getUserAgent() + " Mobile Browser"); view.getSettings().setBuiltInZoomControls(true); view.getSettings().setUseWideViewPort(true); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); final Uri uri = intent.getData(); if (uri != null) { String url = uri.toString(); setStoreInRecentUrls(url); final NetworkLibrary library = NetworkLibrary.Instance(); final String newUrl = library.rewriteUrl(url, true); if (newUrl != null) { url = newUrl; } final WebView view = (WebView) findViewById(R.id.webview); view.loadUrl(url); library.NetworkBrowserPageOption.setValue(url); } } @Override protected void onResume() { super.onResume(); NetworkLibraryActivity.tryInitializeNetworkView(this, "loadingBrowser", new Runnable() { public void run() { final WebView view = (WebView) findViewById(R.id.webview); if (view.getUrl() == null) { final Intent intent = getIntent(); final Uri uri = intent.getData(); intent.setData(null); final NetworkLibrary library = NetworkLibrary.Instance(); String url; if (uri != null) { url = uri.toString(); setStoreInRecentUrls(url); } else { url = library.NetworkBrowserPageOption.getValue(); } final String newUrl = library.rewriteUrl(url, true); if (newUrl != null) { url = newUrl; } view.loadUrl(url); library.NetworkBrowserPageOption.setValue(url); } } }); } @Override protected void onDestroy() { NetworkLibraryActivity.tryStopInitialization(); super.onDestroy(); } private class ChromeClient extends WebChromeClient { @Override public void onReceivedTitle(WebView view, String title) { BrowserActivity.this.setTitle(title); } @Override public void onProgressChanged(WebView view, int newProgress) { final boolean inProgress = newProgress < 100; setProgressBarIndeterminateVisibility(inProgress); setProgress(100 * newProgress); // title progress is in range 0..10000 } } private class ViewClient extends WebViewClient { private String[] mySupportedBooksExtensions = {".epub", ".fb2", ".fb2.zip"}; private boolean shouldLoadBook(String url) { final Uri uri = Uri.parse(url); String path = uri.getPath(); if (path != null) { path = path.toLowerCase(); for (String ext: mySupportedBooksExtensions) { if (path.endsWith(ext)) { return true; } } } return false; } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { final String errorText = myResource.getResource("errorText").getValue().replaceAll("%s", description); Toast.makeText(BrowserActivity.this, errorText, Toast.LENGTH_LONG).show(); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (shouldLoadBook(url)) { downloadBook(url); setStoreInRecentUrls(null); return true; } final NetworkLibrary library = NetworkLibrary.Instance(); final String newUrl = library.rewriteUrl(url, true); if (newUrl != null && !newUrl.equals(url)) { view.loadUrl(newUrl); return true; } return false; } @Override public void onPageFinished(WebView view, String url) { storeUrlInRecents(); NetworkLibrary.Instance().NetworkBrowserPageOption.setValue(view.getUrl()); // using current URL (not every loaded URL opens new page) } @Override public void onFormResubmission(WebView view, final Message dontResend, final Message resend) { final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { resend.sendToTarget(); } else { dontResend.sendToTarget(); } } }; final ZLResource buttonResource = ZLResource.resource("dialog").getResource("button"); new AlertDialog.Builder(BrowserActivity.this) .setTitle(myResource.getResource("confirmation").getValue()) .setMessage(myResource.getResource("resubmitForm").getValue()) .setPositiveButton(buttonResource.getResource("ok").getValue(), listener) .setNegativeButton(buttonResource.getResource("cancel").getValue(), listener) .setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { listener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE); } }).create().show(); } @Override public void onReceivedHttpAuthRequest(WebView view, final HttpAuthHandler handler, String host, String realm) { final View layout = getLayoutInflater().inflate(R.layout.browser_authentication_dialog, null); setupLabel(layout, R.id.login_text, "login", R.id.login); setupLabel(layout, R.id.password_text, "password", R.id.password); final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { TextView loginView = (TextView) layout.findViewById(R.id.login); TextView passwordView = (TextView) layout.findViewById(R.id.password); handler.proceed(loginView.getText().toString(), passwordView.getText().toString()); } else { handler.cancel(); } } }; final ZLResource buttonResource = ZLResource.resource("dialog").getResource("button"); new AlertDialog.Builder(BrowserActivity.this) .setView(layout) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle(myResource.getResource("authenticationRequired") .getValue().replaceAll("%s1", host).replaceAll("%s2", realm)) .setPositiveButton(buttonResource.getResource("ok").getValue(), listener) .setNegativeButton(buttonResource.getResource("cancel").getValue(), listener) .setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { listener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE); } }).create().show(); } } private void setupLabel(View layout, int labelId, String key, int labelForId) { final View viewFor = layout.findViewById(labelForId); viewFor.measure(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); final TextView label = (TextView) layout.findViewById(labelId); label.setText(myResource.getResource(key).getValue()); label.getLayoutParams().height = viewFor.getMeasuredHeight(); } private MenuItem addMenuItem(Menu menu, int index, String resourceKey, int iconId) { final String label = myResource.getResource("menu").getResource(resourceKey).getValue(); return menu.add(0, index, Menu.NONE, label)/*.setIcon(iconId)*/; } private static final int OPTION_GO = 1; private static final int OPTION_STOP = 2; private static final int OPTION_RELOAD = 3; private static final int OPTION_BACK = 4; private static final int OPTION_FORWARD = 5; @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); addMenuItem(menu, OPTION_GO, "go", 0); addMenuItem(menu, OPTION_STOP, "stop", 0); addMenuItem(menu, OPTION_RELOAD, "reload", 0); addMenuItem(menu, OPTION_BACK, "back", 0); addMenuItem(menu, OPTION_FORWARD, "forward", 0); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); WebView view = (WebView) findViewById(R.id.webview); final boolean loading = view.getOriginalUrl() != null && view.getProgress() < 100; menu.findItem(OPTION_GO).setEnabled(!loading).setVisible(!loading); menu.findItem(OPTION_STOP).setEnabled(loading).setVisible(loading); menu.findItem(OPTION_RELOAD).setEnabled(!loading && view.getUrl() != null); menu.findItem(OPTION_BACK).setEnabled(!loading && view.canGoBack()); menu.findItem(OPTION_FORWARD).setEnabled(!loading && view.canGoForward()); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { WebView view = (WebView) findViewById(R.id.webview); switch (item.getItemId()) { default: return true; case OPTION_GO: return onSearchRequested(); case OPTION_STOP: view.stopLoading(); return true; case OPTION_RELOAD: view.reload(); return true; case OPTION_BACK: view.goBack(); return true; case OPTION_FORWARD: view.goForward(); return true; } } @Override public boolean onSearchRequested() { WebView view = (WebView) findViewById(R.id.webview); startSearch(view.getUrl(), true, null, false); return true; } }