android 编写简单浏览器带下载 支持多触点 支持下载功能
转自:http://www.cmd59.com/html/2182.html
package org.badboy.browser; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import org.metalev.multitouch.controller.MultiTouchController; import org.metalev.multitouch.controller.MultiTouchController.MultiTouchObjectCanvas; import org.metalev.multitouch.controller.MultiTouchController.PointInfo; import org.metalev.multitouch.controller.MultiTouchController.PositionAndScale; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.app.SearchManager; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.webkit.DownloadListener; import android.webkit.URLUtil; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Toast; /*** * 使用WebView对象创建一个简单网页浏览器。 * @author BadBoy * */ public class BrowserActivity extends Activity implements MultiTouchObjectCanvas<Object>{ private final static int MENU_NEW_WEB = Menu.FIRST; private final static int MENU_SET_MAIN_PAGE = MENU_NEW_WEB + 1; private String defaultGoogleUrl = ""; private String defaultUCWebUrl = ""; private String defaultUrl = ""; private WebView mWebView; //储存默认网址文件 private String fileUrl = "fileUrl.txt"; //对话框标识 private final static int PROGRESS_DIALOG = 110; private final static int SET_DEFAULT_URL_DIALOG = 111; //显示网页加载进度 private ProgressDialog mDialog; private ProgressBar bar; //多点触摸 private MultiTouchController<Object> mMultiTouchController; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //下面四条语句要在setContentView()方法之前调用,否则程序会出错,在本程序中,加入以下的语句貌似还没有什么影响,或者有我还没发现 this.requestWindowFeature(Window.FEATURE_LEFT_ICON); this.requestWindowFeature(Window.FEATURE_RIGHT_ICON); this.requestWindowFeature(Window.FEATURE_PROGRESS); this.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.main); initWebView(); performSearchIntent(getIntent()); } @Override protected void onNewIntent(Intent intent) { setIntent(intent); performSearchIntent(intent); } /** * 执行搜索,打开网页 */ private void performSearchIntent(Intent intent) { if(Intent.ACTION_SEARCH.equals(intent.getAction())){ String query = intent.getStringExtra(SearchManager.QUERY); //还没有对网址进行严格的解析 if(!query.startsWith("http://")){ mWebView.loadUrl("http://"+query); } if(query.startsWith("http://")){ mWebView.loadUrl(query); } /*else{ Toast.makeText(this, R.string.url_error, Toast.LENGTH_SHORT).show(); }*/ } } private void initWebView() { defaultGoogleUrl = this.getResources().getString(R.string.default_google_url); defaultUCWebUrl = this.getResources().getString(R.string.default_ucweb_url); setDefaultURL(); bar = (ProgressBar)findViewById(R.id.progress_bar); mMultiTouchController = new MultiTouchController<Object>(this,false); mWebView = (WebView)findViewById(R.id.webview); //使用mWebView的getSettings()方法设置支持JavaScript为true mWebView.getSettings().setJavaScriptEnabled(true); mWebView.setScrollBarStyle(0); //用loadUrl方法加载网址 mWebView.loadUrl(defaultUrl); //对mWebView设置WebViewClient对象,如果不设置此对象那么当单击mWebView中的链接时将由系统 //默认的Browser来响应链接,即由默认的Browser打开链接,而不是你自己写的Browser来打开 //故为了mWebView自己处理页面中的所有链接,则要扩展WebViewClient类,重载shouldOverrideUrlLoading()方法 mWebView.setWebViewClient(new MyWebViewClient()); // mWebView.setWebChromeClient(new MyWebChromeClient()); //实现下载监听 mWebView.setDownloadListener(new DownloadListener(){ public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { /*Uri uri = Uri.parse(url); Intent intent = new Intent(Intent.ACTION_VIEW,uri); startActivity(intent); */ downloadFile(url, mimetype, mimetype, mimetype, contentLength); } }); } /* * 下列代码实现网络文件下载功能,目前下载的文件时存储在/data/data/org.badboy.browser/files目录下的。 * 后续还会更新这个方法,将其下载到SDCard上来。思路是这样子的:下载文件时先检查是否由sdcard或udisk外存储设备, * 若有则直接下载到外存储设备,否则存储到/data/data/org.badboy.browser/files目录中。最后还要增加一个功能:就是 * 列出已下载文件,以及对文件copy,delete等操作 * 2011-3-4 */ private void downloadFile(String url,String userAgent, String contentDisposition, String mimetype, long contentLength) { /*String filename = URLUtil.guessFileName(url, contentDisposition, mimetype); // Check to see if we have an SDCard String status = Environment.getExternalStorageState(); if (!status.equals(Environment.MEDIA_MOUNTED)) { int title; String msg; // Check to see if the SDCard is busy, same as the music app if (status.equals(Environment.MEDIA_SHARED)) { msg = getString(R.string.download_sdcard_busy_dlg_msg); title = R.string.download_sdcard_busy_dlg_title; } else { msg = getString(R.string.download_no_sdcard_dlg_msg, filename); title = R.string.download_no_sdcard_dlg_title; } new AlertDialog.Builder(this) .setTitle(title) .setIcon(android.R.drawable.ic_dialog_alert) .setMessage(msg) .setPositiveButton(R.string.ok, null) .show(); return; }*/ try { String filename = URLUtil.guessFileName(url, contentDisposition, mimetype); URL url2 = new URL(url); HttpURLConnection conn = (HttpURLConnection) url2.openConnection(); conn.setDoInput(true); conn.connect(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream is = conn.getInputStream(); FileOutputStream fos = this.openFileOutput(filename, Context.MODE_APPEND); int len = 0; byte[] buf = new byte[1024]; while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); } is.close(); fos.close(); } else { Toast.makeText(this, R.string.net_error, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { e.printStackTrace(); } } private void setDefaultURL() { try { //android中使用openFileInput()方法得到文件输入流 FileInputStream fis = this.openFileInput(fileUrl); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while((len = fis.read(buffer))!=-1){ baos.write(buffer, 0, len); } //defaultUrl = new String(buffer,0,len); defaultUrl = baos.toString(); fis.close(); baos.close(); } catch (Exception e) { e.printStackTrace(); } //如果还是为空,则使用defaultUCWebUrl if(defaultUrl.equals("")){ defaultUrl = defaultUCWebUrl; } } /** * 按键事件处理 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //按返回键可退回之前浏览过的网页 if((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()){ mWebView.goBack(); return true; } //搜索按键 if(keyCode == KeyEvent.KEYCODE_SEARCH){ onSearchRequested(); } return super.onKeyDown(keyCode, event); } /** * 重写WebChromeClient类 */ private class MyWebChromeClient extends WebChromeClient { //设置网页加载进度条 @Override public void onProgressChanged(WebView webview, int newProgress){ BrowserActivity.this.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, 100); //以下注释代码是用来ProgressDialog显示网页加载进度的 /*showDialog(PROGRESS_DIALOG); mDialog.setProgress(newProgress); if(newProgress==100){ dismissDialog(PROGRESS_DIALOG); }*/ //以下代码是用来ProgressBar显示网页加载进度的 bar.setProgress(newProgress); bar.setVisibility(View.VISIBLE); if(bar.getProgress()==100){ bar.setVisibility(View.GONE); } super.onProgressChanged(webview, newProgress); } } /** * 重写 WebViewClient类,由本Browser处理网页中的链接 */ private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } } /** * Menu 按键的添加和事件处理 */ @Override public boolean onCreateOptionsMenu(Menu menu) { //打开网址输入栏 menu.add(0,MENU_NEW_WEB,0,R.string.new_web_page) .setIcon(R.drawable.search_icon); //设置默认网址 menu.add(0,MENU_SET_MAIN_PAGE,0,R.string.set_default_url) .setIcon(R.drawable.browser_icon); return super.onCreateOptionsMenu(menu); } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { switch(item.getItemId()){ case MENU_NEW_WEB: onSearchRequested(); return true; case MENU_SET_MAIN_PAGE: this.showDialog(SET_DEFAULT_URL_DIALOG); break; } return super.onMenuItemSelected(featureId, item); } /** * 重写onSearchRequested(),可实现调用Search Bar */ @Override public boolean onSearchRequested() { //本程序还没处理Bundle对象传来的数据,注释下列三行代码 /*Bundle appData = new Bundle(); appData.putBoolean("search",true); this.startSearch(null, false, appData, false);*/ this.startSearch(null, false, null, false); return true; } /** * 当要调用this.showDialog(int id)方法来显示Dialog时,要重写下列方法 */ @Override protected Dialog onCreateDialog(int id) { switch(id){ case PROGRESS_DIALOG: mDialog = new ProgressDialog(this); //mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mDialog.setMessage("Page is loading..."); return mDialog; case SET_DEFAULT_URL_DIALOG: return createDefaultUrlDialog(); default: return super.onCreateDialog(id); } } private Dialog createDefaultUrlDialog() { final Dialog dialog = new Dialog(this); dialog.setContentView(R.layout.default_url_dialog); dialog.setTitle(R.string.dialog_title); final EditText url = (EditText)dialog.findViewById(R.id.url); Button btnOK = (Button)dialog.findViewById(R.id.ok_btn); btnOK.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { defaultUrl = url.getText().toString(); try { FileOutputStream fos = BrowserActivity.this.openFileOutput(fileUrl, Context.MODE_PRIVATE); byte[] buffer = defaultUrl.getBytes(); fos.write(buffer); fos.close(); } catch (Exception e) { e.printStackTrace(); } dialog.dismiss(); mWebView.loadUrl(defaultUrl); } }); Button btnCancel = (Button)dialog.findViewById(R.id.cancel_btn); btnCancel.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { dialog.dismiss(); } }); return dialog; } /** * 屏幕旋转时,程序会重新调用onCreate()方法,即重新加载程序。当不需要这么做时, * 可在manifest文件中的Activity标签中加入android:configChanges="orientation|keyboardHidden" * 属性,并且重写下列方法。该方法中可以处理屏幕旋转时发生的动作 */ @Override public void onConfigurationChanged(Configuration newConfig) { /*if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { }*/ super.onConfigurationChanged(newConfig); } //-------------multitouch stuff ------------------------------------ private int mCurrentZoom = 0; private static final double ZOOM_SENSITIVITY = 1.6; private static final float ZOOM_LOG_BASE_INV = 1.0f / (float) Math.log(2.0 / ZOOM_SENSITIVITY); private boolean isMultiTouchScale = false; @Override public boolean dispatchTouchEvent(MotionEvent event) { if (mMultiTouchController.onTouchEvent(event)) { if (!isMultiTouchScale) { event.setAction(MotionEvent.ACTION_CANCEL); super.dispatchTouchEvent(event); } }else{ isMultiTouchScale = true; if (super.dispatchTouchEvent(event)) { return true; } return false; } return true; } public Object getDraggableObjectAtPoint(PointInfo touchPoint) { return new Object(); } public void getPositionAndScale(Object obj, PositionAndScale objPosAndScaleOut) { objPosAndScaleOut.set(0.0f, 0.0f, true, 1.0f, false, 0.0f, 0.0f, false, 0.0f); mCurrentZoom = 0; } public void selectObject(Object obj, PointInfo touchPoint) { } public boolean setPositionAndScale(Object obj, PositionAndScale newObjPosAndScale, PointInfo touchPoint) { float newRelativeScale = newObjPosAndScale.getScale(); int targetZoom = (int) Math.round(Math.log(newRelativeScale) * ZOOM_LOG_BASE_INV); while (mCurrentZoom > targetZoom) { mCurrentZoom--; mWebView.zoomOut(); } while (mCurrentZoom < targetZoom) { mCurrentZoom++; mWebView.zoomIn(); } return true; } }