Java tutorial
/* Copyright (C) 2010 Haowen Ning 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.liberty.android.fantastischmemo.downloader; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Comparator; import java.util.Stack; import javax.inject.Inject; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONObject; import org.liberty.android.fantastischmemo.AMEnv; import org.liberty.android.fantastischmemo.AnyMemoDBOpenHelper; import org.liberty.android.fantastischmemo.AnyMemoDBOpenHelperManager; import org.liberty.android.fantastischmemo.R; import org.liberty.android.fantastischmemo.utils.AMZipUtils; import org.liberty.android.fantastischmemo.utils.RecentListUtil; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.DialogInterface; import android.os.Handler; import android.text.Html; import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.View; import android.widget.ListView; import android.widget.TextView; public class DownloaderAnyMemo extends DownloaderBase { private static final String TAG = "org.liberty.android.fantastischmemo.downloader.DownloaderAnyMemo"; private DownloadListAdapter dlAdapter; /* * dlStack caches the previous result so user can press * back button to go back */ private Stack<ArrayList<DownloadItem>> dlStack; private ListView listView; private ProgressDialog mProgressDialog; private int mDownloadProgress; private Handler mHandler; private final static String WEBSITE_JSON = "http://anymemo.org/pages/json.php"; private final static String WEBSITE_DOWNLOAD = "http://anymemo.org/pages/download.php?wordlistname=DatabasesTable&filename="; private static final int BUFFER_SIZE = 8192; private RecentListUtil recentListUtil; @Inject public void setRecentListUtil(RecentListUtil recentListUtil) { this.recentListUtil = recentListUtil; } @Override protected void initialRetrieve() { dlAdapter = new DownloadListAdapter(this, R.layout.filebrowser_item); dlStack = new Stack<ArrayList<DownloadItem>>(); mHandler = new Handler(); listView = (ListView) findViewById(R.id.file_list); listView.setAdapter(dlAdapter); mProgressDialog = ProgressDialog.show(this, getString(R.string.loading_please_wait), getString(R.string.loading_connect_net), true, true, new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { finish(); } }); new Thread() { public void run() { try { final ArrayList<DownloadItem> list = obtainCategories(); mHandler.post(new Runnable() { public void run() { dlAdapter.addList(list); sortAdapter(); mProgressDialog.dismiss(); } }); } catch (final Exception e) { mHandler.post(new Runnable() { public void run() { Log.e(TAG, "Error obtaining categories", e); new AlertDialog.Builder(DownloaderAnyMemo.this) .setTitle(getString(R.string.downloader_connection_error)) .setMessage( getString(R.string.downloader_connection_error_message) + e.toString()) .setNeutralButton(getString(R.string.back_menu_text), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { finish(); } }) .create().show(); } }); } } }.start(); } @Override protected void openCategory(final DownloadItem di) { mProgressDialog = ProgressDialog.show(this, getString(R.string.loading_please_wait), getString(R.string.loading_connect_net), true, true, new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { finish(); } }); new Thread() { public void run() { try { final ArrayList<DownloadItem> list = obtainDatabases(di); dlStack.push(dlAdapter.getList()); mHandler.post(new Runnable() { public void run() { dlAdapter.clear(); dlAdapter.addList(list); sortAdapter(); listView.setSelection(0); mProgressDialog.dismiss(); } }); } catch (final Exception e) { mHandler.post(new Runnable() { public void run() { Log.e(TAG, "Error obtaining databases", e); new AlertDialog.Builder(DownloaderAnyMemo.this) .setTitle(getString(R.string.downloader_connection_error)) .setMessage( getString(R.string.downloader_connection_error_message) + e.toString()) .setNeutralButton(getString(R.string.back_menu_text), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { finish(); } }) .create().show(); } }); } } }.start(); } @Override protected DownloadItem getDownloadItem(final int position) { return dlAdapter.getItem(position); } @Override protected void goBack() { if (dlStack == null || dlStack.empty()) { finish(); } else { dlAdapter.clear(); dlAdapter.addList(dlStack.pop()); listView.setSelection(0); } } @Override protected void fetchDatabase(final DownloadItem di) { final Thread downloadThread = new Thread() { @Override public void run() { String filename = di.getExtras("filename"); try { downloadDatabase(di); filename = filename.replace(".zip", ".db"); String sdpath = AMEnv.DEFAULT_ROOT_PATH; final File dbFile = new File(sdpath + filename); mHandler.post(new Runnable() { public void run() { new AlertDialog.Builder(DownloaderAnyMemo.this) .setTitle(R.string.downloader_download_success) .setMessage(getString(R.string.downloader_download_success_message) + dbFile.toString()) .setPositiveButton(R.string.ok_text, null).create().show(); } }); } catch (final Exception e) { mHandler.post(new Runnable() { public void run() { new AlertDialog.Builder(DownloaderAnyMemo.this) .setTitle(R.string.downloader_download_fail) .setMessage(getString(R.string.downloader_download_fail_message) + " " + e.toString()) .setPositiveButton(R.string.ok_text, null).create().show(); } }); } } }; View alertView = View.inflate(DownloaderAnyMemo.this, R.layout.link_alert, null); TextView textView = (TextView) alertView.findViewById(R.id.link_alert_message); textView.setMovementMethod(LinkMovementMethod.getInstance()); textView.setText( Html.fromHtml(getString(R.string.downloader_download_alert_message) + di.getDescription())); new AlertDialog.Builder(this).setView(alertView) .setTitle(getString(R.string.downloader_download_alert) + di.getExtras("filename")) .setPositiveButton(getString(R.string.yes_text), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { downloadThread.start(); } }).setNegativeButton(getString(R.string.no_text), null).show(); } private void downloadDatabase(final DownloadItem di) throws Exception { String filename = di.getExtras("filename"); if (filename == null) { throw new Exception("Could not get filename"); } String sdpath = AMEnv.DEFAULT_ROOT_PATH; File outFile = new File(sdpath + filename); mHandler.post(new Runnable() { public void run() { mProgressDialog = new ProgressDialog(DownloaderAnyMemo.this); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setMessage(getString(R.string.loading_downloading)); mProgressDialog.show(); } }); try { OutputStream out; if (outFile.exists()) { throw new IOException("Database already exist!"); } try { outFile.createNewFile(); out = new FileOutputStream(outFile); URL myURL = new URL(di.getAddress()); Log.v(TAG, "URL IS: " + myURL); URLConnection ucon = myURL.openConnection(); final int fileSize = ucon.getContentLength(); mHandler.post(new Runnable() { public void run() { mProgressDialog.setMax(fileSize); } }); byte[] buf = new byte[BUFFER_SIZE]; InputStream is = ucon.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE); Runnable increaseProgress = new Runnable() { public void run() { mProgressDialog.setProgress(mDownloadProgress); } }; int len = 0; int lenSum = 0; while ((len = bis.read(buf)) != -1) { out.write(buf, 0, len); lenSum += len; if (lenSum > fileSize / 50) { /* This is tricky. * The UI thread can not be updated too often. * So we update it only 50 times */ mDownloadProgress += lenSum; lenSum = 0; mHandler.post(increaseProgress); } } out.close(); is.close(); /* Uncompress the zip file that contains images */ if (filename.endsWith(".zip")) { mHandler.post(new Runnable() { public void run() { mProgressDialog.setProgress(fileSize); mProgressDialog.setMessage(getString(R.string.downloader_extract_zip)); } }); AMZipUtils.unZipFile(outFile, new File(AMEnv.DEFAULT_ROOT_PATH)); /* Delete the zip file if it is successfully decompressed */ outFile.delete(); } /* We do not check ttf file as db */ if (!filename.toLowerCase().endsWith(".ttf")) { /* Check if the db is correct */ filename = filename.replace(".zip", ".db"); String fullpath = sdpath + filename; AnyMemoDBOpenHelper helper = AnyMemoDBOpenHelperManager.getHelper(DownloaderAnyMemo.this, fullpath); try { long count = helper.getCardDao().getTotalCount(null); if (count <= 0L) { throw new RuntimeException("Downloaded empty db."); } } finally { AnyMemoDBOpenHelperManager.releaseHelper(helper); } /* Add downloaded item to file list */ recentListUtil.addToRecentList(fullpath); } } catch (Exception e) { if (outFile.exists()) { outFile.delete(); } throw new Exception(e); } } catch (Exception e) { Log.e(TAG, "Error downloading", e); throw new Exception(e); } finally { mHandler.post(new Runnable() { public void run() { mProgressDialog.dismiss(); } }); } } private ArrayList<DownloadItem> obtainCategories() throws Exception { ArrayList<DownloadItem> categoryList = new ArrayList<DownloadItem>(); HttpClient httpclient = new DefaultHttpClient(); String url = WEBSITE_JSON; url += "?action=getcategory"; HttpGet httpget = new HttpGet(url); HttpResponse response; response = httpclient.execute(httpget); //Log.i(TAG, "Response: " + response.getStatusLine().toString()); HttpEntity entity = response.getEntity(); if (entity != null) { InputStream instream = entity.getContent(); // Now convert stream to string BufferedReader reader = new BufferedReader(new InputStreamReader(instream)); StringBuilder sb = new StringBuilder(); String line = null; String result = null; while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } result = sb.toString(); // Log.i(TAG, "RESULT" + result); JSONArray jsonArray = new JSONArray(result); for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonItem = jsonArray.getJSONObject(i); String dbcategory = jsonItem.getString("DBCategory"); DownloadItem di = new DownloadItem(); di.setType(DownloadItem.ItemType.Category); di.setTitle(dbcategory); di.setAddress(WEBSITE_JSON + "?action=getdb&category=" + URLEncoder.encode(dbcategory, "UTF-8")); categoryList.add(di); } instream.close(); } else { throw new Exception("Http Entity is null"); } return categoryList; } private ArrayList<DownloadItem> obtainDatabases(DownloadItem category) throws Exception { ArrayList<DownloadItem> databaseList = new ArrayList<DownloadItem>(); HttpClient httpclient = new DefaultHttpClient(); String url = category.getAddress(); Log.v(TAG, "URL: " + url); HttpGet httpget = new HttpGet(url); HttpResponse response; response = httpclient.execute(httpget); //Log.i(TAG, "Response: " + response.getStatusLine().toString()); HttpEntity entity = response.getEntity(); if (entity != null) { InputStream instream = entity.getContent(); // Now convert stream to string BufferedReader reader = new BufferedReader(new InputStreamReader(instream)); StringBuilder sb = new StringBuilder(); String line = null; String result = null; while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } result = sb.toString(); // Log.i(TAG, "RESULT" + result); JSONArray jsonArray = new JSONArray(result); for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonItem = jsonArray.getJSONObject(i); String dbname = jsonItem.getString("DBName"); String dbnote = jsonItem.getString("DBNote"); String filename = jsonItem.getString("FileName"); DownloadItem di = new DownloadItem(); di.setType(DownloadItem.ItemType.Database); di.setTitle(dbname); di.setDescription(dbnote); di.setAddress(WEBSITE_DOWNLOAD + URLEncoder.encode(filename, "UTF-8")); di.setExtras("filename", filename); databaseList.add(di); } instream.close(); } else { throw new Exception("Http Entity is null"); } return databaseList; } private void sortAdapter() { dlAdapter.sort(new Comparator<DownloadItem>() { public int compare(DownloadItem di1, DownloadItem di2) { return (di1.getTitle().toLowerCase()).compareTo(di2.getTitle().toLowerCase()); } }); } }