/*
* Copyright (C) 2012 The Serval Project
*
* This file is part of the Serval Maps Software
*
* Serval Maps Software 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 source code 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 source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.servalproject.maps.stats;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.servalproject.maps.R;
import org.servalproject.maps.utils.FileUtils;
import org.servalproject.maps.utils.HttpUtils;
import org.servalproject.maps.utils.TimeUtils;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* a class to undertake the collection and upload of statistics
*/
public class StatsAsyncTask extends AsyncTask<Void, Integer, Integer> {
/*
* private class level constants
*/
private final int COLLECTING_STATS = 0;
private final int UPLOADING_STATS = 1;
private final int COLLECTION_FAILED = 100;
private final int UPLOAD_FAILED = 101;
private final int UPLOAD_SUCCESS = 102;
private final boolean V_LOG = false;
private final String TAG = "StatsTask";
/*
* private class level variables
*/
private ProgressBar progressBar;
private TextView progressText;
private String[] stats;
private String[] labels;
private Context context;
/**
* construct a new StatsAsyncTask
*
* @param progressBar a ProgressBar used to indicate that the task is running
* @param progressText a TextView used to display progress text
* @param stats an array containing statistics
* @param labels an array containing labels for the statistics values
* @param context a context to be used to gain access to system resources
*
* @throws IllegalArgumentException if any of the parameters is missing
*/
public StatsAsyncTask(ProgressBar progressBar, TextView progressText, String[] stats, String[] labels, Context context) {
super();
// check on the parameters
if(progressBar == null) {
throw new IllegalArgumentException("the progressBar parameter is required");
}
if(progressText == null) {
throw new IllegalArgumentException("the progressText parameter is required");
}
if(stats == null || stats.length == 0) {
throw new IllegalArgumentException("the stats array parameter is required");
}
if(labels == null || labels.length == 0) {
throw new IllegalArgumentException("the labels array parameter is required");
}
if(context == null) {
throw new IllegalArgumentException("the context parameter is required");
}
this.progressBar = progressBar;
this.progressText = progressText;
this.stats = stats;
this.labels = labels;
this.context = context;
}
/*
* (non-Javadoc)
* @see android.os.AsyncTask#onProgressUpdate(Progress[])
*/
@Override
protected void onProgressUpdate(Integer... progress) {
if(V_LOG) {
Log.v(TAG, "onProgressUpdate called: " + progress[0].toString());
}
// update the progress related views
super.onProgressUpdate(progress[0]);
switch(progress[0]) {
case COLLECTING_STATS:
progressBar.setVisibility(View.VISIBLE);
progressText.setVisibility(View.VISIBLE);
progressText.setText(context.getString(R.string.stats_ui_progress_collecting));
break;
case UPLOADING_STATS:
progressText.setText(context.getString(R.string.stats_ui_progress_uploading));
break;
}
}
/*
* (non-Javadoc)
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(Integer result) {
if(V_LOG) {
Log.v(TAG, "onPostExecute called: ");
}
// hide the progress related views
progressBar.setVisibility(View.INVISIBLE);
progressText.setVisibility(View.INVISIBLE);
String mMessage = null;
switch(result) {
case COLLECTION_FAILED:
mMessage = context.getString(R.string.stats_ui_dialog_zip_fail);
break;
case UPLOAD_FAILED:
mMessage = context.getString(R.string.stats_ui_dialog_upload_fail);
break;
case UPLOAD_SUCCESS:
//mMessage = context.getString(R.string.stats_ui_dialog_upload_success);
mMessage = String.format(
context.getString(R.string.stats_ui_dialog_upload_success),
context.getString(R.string.system_path_export_data)
);
break;
}
AlertDialog.Builder mBuilder = new AlertDialog.Builder(context);
mBuilder.setMessage(mMessage)
.setCancelable(false)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
mBuilder.create().show();
}
/*
* (non-Javadoc)
* @see android.os.AsyncTask#doInBackground(Params[])
*/
@Override
protected Integer doInBackground(Void... arg0) {
// create the zip file
File mZipFile;
publishProgress(COLLECTING_STATS);
try {
File[] mFiles = new File[2];
mFiles[0] = createStatsFile();
mFiles[1] = createPrefsFile();
mZipFile = createZipFile(mFiles);
// copy the zip file to the export directory for transparency
String mExportPath = Environment.getExternalStorageDirectory().getPath();
mExportPath += context.getString(R.string.system_path_export_data);
FileUtils.copyFileToDir(mZipFile.getCanonicalPath(), mExportPath);
} catch(IOException e) {
Log.e(TAG, "creation of the zip file failed", e);
return COLLECTION_FAILED;
}
// upload the zip file
publishProgress(UPLOADING_STATS);
try {
String mResponse = HttpUtils.doHttpUpload(mZipFile, context.getString(R.string.system_url_file_upload));
if(mResponse.contains("error") == true) {
Log.e(TAG, "upload of the zip file failed");
return UPLOAD_FAILED;
}
}catch (IOException e) {
Log.e(TAG, "upload of the zip file failed", e);
return UPLOAD_FAILED;
}
return UPLOAD_SUCCESS;
}
private File createStatsFile() throws IOException {
// get a temp directory to create the file
File mCacheDir = context.getCacheDir();
// get the output file
File mOutputFile = new File(mCacheDir.getCanonicalPath() + "/stats.txt");
PrintWriter mPrinter = new PrintWriter(new FileWriter(mOutputFile, false));
mPrinter.println("Data Collected: " + TimeUtils.getTodayWithTime());
for(int i = 0; i < stats.length; i++) {
mPrinter.println(labels[i] + " " + stats[i]);
}
mPrinter.close();
if(V_LOG) {
Log.v(TAG, mOutputFile.getCanonicalPath());
}
// return the file handle
return mOutputFile;
}
private File createPrefsFile() throws IOException {
// get a temp directory to create the file
File mCacheDir = context.getCacheDir();
// get the output file
File mOutputFile = new File(mCacheDir.getCanonicalPath() + "/prefs.txt");
// cast the context to an activity to use getBaseContext method
Activity mActivity = (Activity) context;
// get a handle on the important shared preferences
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mActivity.getBaseContext());
Map<String, ?> mPrefMap = mPreferences.getAll();
// open the file
PrintWriter mPrinter = new PrintWriter(new FileWriter(mOutputFile, false));
for (Map.Entry<String, ?> mEntry: mPrefMap.entrySet()) {
mPrinter.println(mEntry.getKey() + ": " + mEntry.getValue().toString());
}
mPrinter.close();
if(V_LOG) {
Log.v(TAG, mOutputFile.getCanonicalPath());
}
// return the file handle
return mOutputFile;
}
private File createZipFile(File[] fileList) throws IOException {
// get a temp directory to create the file
File mCacheDir = context.getCacheDir();
// get the output file
File mOutputFile = new File(mCacheDir.getCanonicalPath() + "/statistics.zip");
ZipOutputStream mOutputStream = new ZipOutputStream(new FileOutputStream(mOutputFile));
for(File mFile : fileList) {
// add the file to the zip file
addFileToZip(mOutputStream, mFile);
}
mOutputStream.close();
return mOutputFile;
}
private void addFileToZip(ZipOutputStream outputStream, File inputFile) throws IOException {
int mLength;
byte[] mBuffer = new byte[1024];
// add the file
outputStream.putNextEntry(new ZipEntry(inputFile.getName()));
FileInputStream mInputStream = new FileInputStream(inputFile);
while((mLength = mInputStream.read(mBuffer)) > 0)
{
outputStream.write(mBuffer, 0, mLength);
}
outputStream.closeEntry();
mInputStream.close();
}
}