package net.bible.android.view.activity.installzip;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import net.bible.android.activity.R;
import net.bible.android.view.activity.download.Download;
import org.crosswire.common.util.NetUtil;
import org.crosswire.jsword.book.BookDriver;
import org.crosswire.jsword.book.BookException;
import org.crosswire.jsword.book.sword.SwordBookDriver;
import org.crosswire.jsword.book.sword.SwordBookMetaData;
import org.crosswire.jsword.book.sword.SwordBookPath;
import org.crosswire.jsword.book.sword.SwordConstants;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.ProgressBar;
import android.widget.Toast;
/**
* Install SWORD module from a zip file
*
* @see gnu.lgpl.License for license details.<br>
* The copyright to this program is held by it's authors.
* @author Tuomas Airaksinen [tuomas.airaksinen at gmail dot com]
*/
class ModuleExists extends Exception {
private static final long serialVersionUID = 1L;
}
class InvalidModule extends Exception {
private static final long serialVersionUID = 1L;
}
class ZipHandler extends AsyncTask<Void, Integer, Integer> {
private static final int R_ERROR = 1;
private static final int R_INVALID_MODULE = 2;
private static final int R_MODULE_EXISTS = 3;
private static final int R_OK = 4;
private Uri uri;
private InstallZip parent;
private int total_entries = 0;
public ZipHandler(Uri _uri, InstallZip _parent) {
uri = _uri;
parent = _parent;
}
private void checkZipFile() throws IOException, ModuleExists, InvalidModule {
boolean mods_d_found = false;
boolean modules_found = false;
ZipEntry entry;
File targetDirectory = SwordBookPath.getSwordDownloadDir();
ZipInputStream zin = new ZipInputStream(parent.getContentResolver().openInputStream(uri));
while ((entry = zin.getNextEntry()) != null) {
total_entries++;
String name = entry.getName().replace('\\', '/');
File targetFile = new File(targetDirectory, name);
if (!entry.isDirectory() && targetFile.exists())
{
zin.close();
throw new ModuleExists();
}
if (name.startsWith(SwordConstants.DIR_CONF + "/")
&& name.endsWith(SwordConstants.EXTENSION_CONF))
mods_d_found = true;
else if (name.startsWith(SwordConstants.DIR_CONF + "/")){}
else if (name.startsWith(SwordConstants.DIR_DATA + "/"))
modules_found = true;
else {
{
zin.close();
throw new InvalidModule();
}
}
}
if (!(mods_d_found && modules_found))
{
zin.close();
throw new InvalidModule();
}
zin.close();
}
private void installZipFile() throws IOException, BookException {
ZipInputStream zin = new ZipInputStream(parent.getContentResolver().openInputStream(uri));
ArrayList<File> confFiles = new ArrayList<File>();
File targetDirectory = SwordBookPath.getSwordDownloadDir();
try {
ZipEntry ze;
int count;
int entry_num = 0;
byte[] buffer = new byte[8192];
while ((ze = zin.getNextEntry()) != null) {
String name = ze.getName().replace('\\','/');
File file = new File(targetDirectory, name);
if (name.startsWith(SwordConstants.DIR_CONF)
&& name.endsWith(SwordConstants.EXTENSION_CONF))
confFiles.add(file);
File dir = ze.isDirectory() ? file : file.getParentFile();
if (!dir.isDirectory() && !(dir.mkdirs() || dir.isDirectory()))
throw new IOException();
if (ze.isDirectory())
continue;
FileOutputStream fout = new FileOutputStream(file);
try {
while ((count = zin.read(buffer)) != -1)
fout.write(buffer, 0, count);
} finally {
fout.close();
}
publishProgress(++entry_num);
}
} finally {
zin.close();
}
// Load configuration files & register books
BookDriver book_driver = SwordBookDriver.instance();
for (File confFile : confFiles) {
SwordBookMetaData me = new SwordBookMetaData(confFile, NetUtil.getURI(targetDirectory));
me.setDriver(book_driver);
SwordBookDriver.registerNewBook(me);
}
}
@Override
protected Integer doInBackground(Void... params) {
try {
checkZipFile();
installZipFile();
} catch (IOException | BookException e) {
Log.e(parent.TAG, "Error occurred", e);
return R_ERROR;
} catch (InvalidModule e) {
return R_INVALID_MODULE;
} catch (ModuleExists e) {
return R_MODULE_EXISTS;
}
return R_OK;
}
@Override
protected void onPostExecute(Integer result) {
int finishResult = Download.RESULT_CANCELED;
switch (result) {
case R_ERROR:
Toast.makeText(this.parent, R.string.error_occurred, Toast.LENGTH_SHORT).show();
break;
case R_INVALID_MODULE:
Toast.makeText(this.parent, R.string.invalid_module, Toast.LENGTH_SHORT).show();
break;
case R_MODULE_EXISTS:
Toast.makeText(this.parent, R.string.module_already_installed, Toast.LENGTH_SHORT).show();
break;
case R_OK:
Toast.makeText(this.parent, R.string.install_zip_successfull, Toast.LENGTH_SHORT).show();
finishResult = Download.RESULT_OK;
break;
}
parent.setResult(finishResult);
parent.finish();
}
@Override
protected void onProgressUpdate(Integer... values) {
if (values[0] == 1)
parent.setTitle(R.string.extracting_zip_file);
int progress_now = (int) Math
.round(((float) values[0] / (float) total_entries)
* parent.progressBar.getMax());
parent.progressBar.setProgress(progress_now);
}
}
public class InstallZip extends Activity {
static final String TAG = "InstallZip";
private static final int PICK_FILE = 1;
public ProgressBar progressBar;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "Install from Zip starting");
setContentView(R.layout.activity_install_zip);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
startActivityForResult(intent, PICK_FILE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case PICK_FILE:
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
setTitle(R.string.checking_zip_file);
ZipHandler zh = new ZipHandler(uri, this);
zh.execute();
}
else if (resultCode == RESULT_CANCELED)
finish();
break;
}
}
@Override
public void onBackPressed() {
}
}