/* * GeoSolutions map - Digital field mapping on Android based devices * Copyright (C) 2013 - 2014 GeoSolutions (www.geo-solutions.it) * * 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 3 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, see <http://www.gnu.org/licenses/>. */ package it.geosolutions.android.map.utils; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; import java.util.zip.*; import it.geosolutions.android.map.BuildConfig; import it.geosolutions.android.map.MapsActivity; import it.geosolutions.android.map.R; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.AsyncTask; import android.util.Log; /** Class to manage download and decompression of a sample data test archive from web. * This class manager uses two class that extend AsyncTask to perform computations in background. * @author Jacopo Pianigiani (jacopo.pianigiani85@gmail.com). * * Introduced the ability to set a custom message and title * @author Lorenzo Pini (lorenzo.pini@geo-solutions.it) */ public class ZipFileManager { /** * Tag for logging */ private static String TAG = "ZipFileManager"; private AlertDialog download_dialog; private AlertDialog error_dialog; public Activity activity; //Necessary for the dialog /** * Temporary Archive name, once extracted it will be deleted */ private final static String file_name = "data_test_archive.zip"; /** * Uses default message values * @param activity * @param dir_path */ public ZipFileManager(Activity activity, String dir_path, String dest_dir, String url){ this(activity, dir_path, dest_dir, url, null, null); } /** * Custom values for dialog message and title can be set * If one of the dialog title of message is null, the default library value will be used * @param activity * @param dir_path */ public ZipFileManager(Activity activity, String dir_path, String dest_dir, String url, String dialogTitle, String dialogMessage){ this.activity = activity; File f = new File(dir_path + dest_dir); if(!f.exists()){ f.mkdir(); } if(f.isDirectory()){ askForDownload(activity, dir_path, url, dialogTitle, dialogMessage); }else{ Log.e(TAG, "could not create directory "+ f.getAbsolutePath()); } } /** * Creates an AlertDialog.Builder with default parameters * @param context * @return */ private AlertDialog.Builder setupAlertDialogBuilder(Context context, CharSequence dialogTitle, CharSequence dialogMessage){ AlertDialog.Builder download_dialog_builder = new AlertDialog.Builder(context); // Set the given title, or use the default one if(dialogTitle != null){ download_dialog_builder.setTitle(dialogTitle); }else{ download_dialog_builder.setTitle(R.string.dialog_title); } // Set the given message, or use the default one if(dialogMessage != null){ download_dialog_builder.setMessage(dialogMessage); }else{ download_dialog_builder.setMessage(R.string.dialog_message); } download_dialog_builder.setCancelable(false); return download_dialog_builder; } /** * @param activity * @param dir_path * @param url * @param dialogTitle * @param dialogMessage */ public void askForDownload( Activity activity, final String dir_path, final String url, CharSequence dialogTitle, CharSequence dialogMessage) { AlertDialog.Builder download_dialog_builder = setupAlertDialogBuilder(activity, dialogTitle, dialogMessage); download_dialog_builder.setPositiveButton(R.string.button_download, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { new DownloadFileAsyncTask().execute(url,dir_path); download_dialog.dismiss(); } }); download_dialog_builder.setNegativeButton(R.string.button_undownload, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { download_dialog.dismiss(); launchMainActivity(false); } }); download_dialog = download_dialog_builder.create(); //Show an alert dialog to ask user if wants to download data test archive from web download_dialog.show(); } /** * This method launch the main activity of MapStore Mobile(In View mode) once that archive is available, * and center the map around the coordinate passed by intent. */ public void launchMainActivity(final boolean success){ Intent launch = new Intent(activity,MapsActivity.class); launch.setAction(Intent.ACTION_VIEW); launch.putExtra(MapsActivity.PARAMETERS.LAT, 43.68411); launch.putExtra(MapsActivity.PARAMETERS.LON, 10.84899); launch.putExtra(MapsActivity.PARAMETERS.ZOOM_LEVEL, (byte)13); //For the future, passing a marker /*ArrayList<MarkerDTO> markers = new ArrayList(1); MarkerDTO markerDTO1 = new MarkerDTO(43.7242359188,10.9463005959, MarkerDTO.MARKER_RED); markerDTO1.setId("AB123456789"); markerDTO1.setDescription("Segnalazione 1"); boolean add = markers.add(markerDTO1); launch.putParcelableArrayListExtra(MapsActivity.PARAMETERS.MARKERS, markers);*/ activity.startActivity(launch); activity.finish(); } /** * Class DownloadFileAsyncTask downloads a data test archive from web. * @author Jacopo Pianigiani (jacopo.pianigiani85@gmail.com). */ class DownloadFileAsyncTask extends AsyncTask<String,Integer,Boolean>{ private ProgressDialog barDialog; //Dialog to show progress of download private String dir_path; //Directory where the archive will be downloaded private String path_file; //Complete path of archive downloaded /** * This method will be executed before the task is executed: It creates a progress dialog * to show to user progress of download. */ @Override protected void onPreExecute(){ super.onPreExecute(); barDialog = new ProgressDialog(activity); barDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); String message = (String)activity.getApplicationContext().getResources().getString(R.string.progress_dialog_title); CharSequence msg = (CharSequence)message; barDialog.setTitle(msg); message = (String)activity.getApplicationContext().getResources().getString(R.string.progress_dialog_message); msg = (CharSequence)message; barDialog.setMessage(msg); barDialog.setCancelable(false); barDialog.show(); } /** * Performs download of archive in background, this computation can requests long time depending by * the size of archive. * @ param Data */ @Override protected Boolean doInBackground(String ... Data) { dir_path = Data[1]; int count; Boolean success = false; InputStream input = null; OutputStream output = null; try { URL url = new URL(Data[0]); URLConnection conexion = url.openConnection(); conexion.connect(); int file_length = conexion.getContentLength(); input = new BufferedInputStream(url.openStream()); path_file = dir_path + "/" + file_name; output = new FileOutputStream(path_file); byte data[] = new byte[1024]; long total = 0; while ((count = input.read(data)) != -1) { total += count; publishProgress((int)((total*100)/file_length)); output.write(data, 0, count); } output.flush(); success = true; } catch (IOException e) { success = false; if(BuildConfig.DEBUG){ Log.e(TAG, e.getLocalizedMessage(), e); } }finally{ if(input != null){ try { input.close(); } catch (IOException e) { // ignore } } if(output != null){ try { output.close(); } catch (IOException e) { // ignore } } } return success; } /** * Updates the progress of download showed on Progress Dialog while the computation continues * in background. * @param progress */ protected void onProgressUpdate(Integer... progress) { barDialog.setProgress(progress[0]); } /** * This method will be executed after the background computation finishes. * @ param unused */ @Override protected void onPostExecute(Boolean success) { barDialog.dismiss(); if(success != null && success == true){ String[] data = {path_file, dir_path}; new UnzipFileAsyncTask().execute(data); }else{ // Something went wrong AlertDialog.Builder download_dialog_builder; download_dialog_builder = new AlertDialog.Builder(activity); download_dialog_builder.setTitle(R.string.dialog_title); download_dialog_builder.setMessage(R.string.download_error_message); download_dialog_builder.setCancelable(false); download_dialog_builder.setPositiveButton(R.string.button_close_content, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { error_dialog.dismiss(); } }); error_dialog = download_dialog_builder.create(); //Show an alert dialog to notify user that an error occurred error_dialog.show(); } } } /** * UnzipFileAsyncTask class extracts all files contained in archive in the root directory. * @author Jacopo Pianigiani (jacopo.pianigiani85@gmail.com). */ class UnzipFileAsyncTask extends AsyncTask<String,Integer,String>{ private ProgressDialog zipDialog; //Dialog to show progress of decompression private String dir_path; //path of directory where the archive has been downloaded /** * This method will be executed before the task is executed, it creates a progress dialog * to notify to user that the decompression is in progress. */ @Override protected void onPreExecute(){ super.onPreExecute(); zipDialog = new ProgressDialog(activity); String message = (String)activity.getApplicationContext().getResources().getString(R.string.progress_dialog_title); CharSequence msg = (CharSequence)message; zipDialog.setTitle(msg); message = (String)activity.getApplicationContext().getResources().getString(R.string.progress_dialog_unzipping); msg = (CharSequence)message; zipDialog.setMessage(msg); zipDialog.setCancelable(false); zipDialog.show(); } /** * Performs decompression of archive, already downloaded from web, in background. * @ param path */ @Override protected String doInBackground(String ... path) { this.dir_path = path[1]; FileInputStream fis = null; ZipInputStream zis = null; FileOutputStream fout = null; try { fis = new FileInputStream(path[0]); zis = new ZipInputStream(fis); ZipEntry ze = null; while((ze = zis.getNextEntry())!=null){ if(ze.isDirectory()) dirChecker(path[1]+ "/" + ze.getName()); else{ //do not overwrite the local sqlite db //TODO parametrize ? if(ze.getName().contains("genova.sqlite")){ continue; } fout = new FileOutputStream(path[1] + "/" + ze.getName(),false); byte[] buffer = new byte[1024]; for (int lenght = zis.read(buffer); lenght != -1; lenght = zis.read(buffer)){ fout.write(buffer,0,lenght); } //zis.closeEntry(); fout.close(); } } }catch(Exception e ){ if(BuildConfig.DEBUG){ Log.e(TAG, e.getLocalizedMessage(), e); } }finally{ if(zis != null){ try { zis.close(); } catch (IOException e) { // ignore } } if(fis != null){ try { fis.close(); } catch (IOException e) { // ignore } } if(fout != null){ try { fout.close(); } catch (IOException e) { // ignore } } } return null; } /** This method checks if a directory(location is her path) already exists, if not, creates it using * the path passed by argument. * @param location */ private void dirChecker(String location) { File f = new File(location); if(!f.exists()){ f.mkdirs(); } } /** * This method will be executed after the background computation finishes. * @ param unused */ @Override protected void onPostExecute(String unused) { //Delete downloaded archive File file = new File(dir_path+"/"+file_name); if(file.exists()){ file.delete(); } zipDialog.dismiss(); launchMainActivity(true); } } }