Skip to content

Instantly share code, notes, and snippets.

@TakamiChie
Created March 20, 2013 02:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TakamiChie/5201798 to your computer and use it in GitHub Desktop.
Save TakamiChie/5201798 to your computer and use it in GitHub Desktop.
/**
* http://outcesticide.hatenablog.com/entries/2012/12/12
* の記事を参考にしています。
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.res.AssetFileDescriptor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
public class AssetInstaller extends AsyncTask<String, Object, Boolean> {
/**
* インストールがキャンセルされた(現時点のバージョンでは起こりえません)
*/
public final static int CANCELLED = -1;
/**
* すでにインストールされていたため、処理をスキップした
*/
public final static int INSTALLED = 0;
/**
* インストールが正常終了した
*/
public final static int SUCCESSED = 1;
/**
* インストールが完了したときに呼び出されるコールバックインタフェース
* @author 知英
*/
public interface FinishedListener {
/**
* インストールが完了したときにコールバックされるメソッド。
* もし指定したファイルがインストール済みであった場合、何もせずにこのメソッドを呼び出す。
* @param state インストール状態。CANCELLED, INSTALLED, SUCCESSEDのいずれか。
*/
void installFinished(int state);
}
public final static String TAG = AssetInstaller.class.getSimpleName();
private FragmentActivity mActivity;
private File mBaseDir;
private ArrayList<String> mZippedFiles;
private int mTotalSize;
private ProgressDialogFragment mDialogFragment;
private FinishedListener mFinishedListener;
private String mDialogTitle;
private String mDialogMessage;
public AssetInstaller(FragmentActivity activity, File baseDir,
FinishedListener finished) {
this.mActivity = activity;
this.mBaseDir = baseDir;
this.mFinishedListener = finished;
}
public void setProgressTitle(String title) {
this.mDialogTitle = title;
}
public void setProgressMessage(String message) {
this.mDialogMessage = message;
}
@Override
protected Boolean doInBackground(String... params) {
boolean result = false;
for (String param : params) {
Log.d(TAG, "install " + param + "?");
try {
File dir = new File(mBaseDir, param);
if (checkToCopyFile(dir, param)) {
Log.d(TAG, "install " + param + ".");
result |= startCopyToFile(dir, param);
} else {
continue;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
@Override
protected void onProgressUpdate(Object... values) {
Log.i(TAG, "progress update");
if (values.length == 0) {
Log.i(TAG, "filesize:" + mTotalSize);
showProgress(mTotalSize);
} else if (values[0] instanceof Integer) {
updateProgress((Integer) values[0]);
} else if (values[0] instanceof String) {
updateMessage((String) values[0]);
}
}
@Override
protected void onPostExecute(Boolean result) {
Log.d(TAG, "executed");
dismissProgress();
if (mFinishedListener != null) {
mFinishedListener.installFinished(result ? SUCCESSED : INSTALLED);
}
}
@Override
protected void onCancelled() {
Log.d(TAG, "cancelled");
if (mFinishedListener != null) {
mFinishedListener.installFinished(CANCELLED);
}
}
// プログレスバー処理
/**
* プログレスダイアログを表示する
*
* @param max
* プログレスの最大値
*/
private void showProgress(int max) {
mDialogFragment = new ProgressDialogFragment();
Bundle arguments = new Bundle();
arguments.putInt(ProgressDialogFragment.PARAM_MAX, max);
if (mDialogTitle != null) {
arguments.putString(ProgressDialogFragment.PARAM_TITLE,
mDialogTitle);
}
mDialogFragment.setArguments(arguments);
mDialogFragment.show(mActivity.getSupportFragmentManager(), "");
}
/**
* プログレスダイアログの値を更新する
*
* @param value
* 更新する値
*/
private void updateProgress(int value) {
mDialogFragment.updateProgress(value);
}
/**
* プログレスダイアログのメッセージを更新する。
* <ul>
* <li>メッセージ内の%1$sは展開するアーカイブファイル名
* <li>メッセージ内の%2$sは現在展開中のZipEntryファイル名
* </ul>
* に展開される
*
* @param string
*/
private void updateMessage(String message) {
mDialogFragment.updateMessage(message);
}
/**
* プログレスダイアログを破棄する
*/
private void dismissProgress() {
if (mDialogFragment != null) {
mDialogFragment.dismiss();
}
}
// ユーティリティメソッド
/**
* Assetフォルダ内のZIPファイルを開き、そのストリームを返す
*
* @param fileName
* ファイル名(拡張子抜き)
* @return ZIPストリーム
* @throws IOException
*/
private ZipInputStream getAssetZipInputStream(String fileName)
throws IOException {
AssetFileDescriptor fd = mActivity.getResources().getAssets()
.openFd(fileName + ".zip");
return new ZipInputStream(new BufferedInputStream(
fd.createInputStream()));
}
/**
* Assetフォルダ内のZIPファイルを展開する必要があるかどうか確認する
*
* @param dir
* ベースディレクトリを示す{@link File}オブジェクト
* @param fileName
* 展開対象のファイル名
* @return ファイルを展開する必要がある場合、trueを返す
* @throws IOException
*/
private boolean checkToCopyFile(File dir, String fileName)
throws IOException {
mZippedFiles = new ArrayList<String>();
mTotalSize = 0;
ZipInputStream zis = null;
try {
zis = getAssetZipInputStream(fileName);
ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null) {
if (zipEntry.isDirectory()) {
zis.closeEntry();
continue;
}
long zipEntrySize = zipEntry.getSize();
String zipEntryName = zipEntry.getName();
Log.i(TAG, "check:" + zipEntryName);
File unzippedFile = new File(dir, zipEntryName);
long unzippedFileSize = unzippedFile.length();
if (zipEntrySize != unzippedFileSize) {
Log.i(TAG, "unzip needed");
mZippedFiles.add(zipEntryName);
mTotalSize += zipEntrySize;
}
}
} finally {
if (zis != null)
zis.close();
}
return !mZippedFiles.isEmpty();
}
/**
* ZIPファイルを展開し、実フォルダに配置する
*
* @param dir
* ベースディレクトリを示す{@link File}オブジェクト
* @param fileName
* 展開対象のファイル名
* @return ファイルが正しく展開された場合、trueを返す
* @throws IOException
*/
private boolean startCopyToFile(File dir, String fileName)
throws IOException {
return copyFiles(dir, fileName);
}
/**
* ZIPファイルを展開し、実フォルダに配置する
*
* @param dir
* ベースディレクトリを示す{@link File}オブジェクト
* @param fileName
* 展開対象のファイル名
* @return ファイルが正しく展開された場合、trueを返す
* @throws IOException
*/
private boolean copyFiles(File dir, String fileName) throws IOException {
boolean result = false;
publishProgress();
ZipInputStream zis = null;
int sizes = 0;
try {
zis = getAssetZipInputStream(fileName);
ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null) {
if (zipEntry.isDirectory()) {
zis.closeEntry();
continue;
}
String zipEntryName = zipEntry.getName();
if (mDialogMessage != null) {
publishProgress(String.format(mDialogMessage, fileName,
zipEntryName));
}
File unzippedFile = new File(dir, zipEntryName);
if (!unzippedFile.getParentFile().exists()) {
unzippedFile.getParentFile().mkdirs();
}
if (unzippedFile.exists()) {
unzippedFile.delete();
}
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(
unzippedFile));
byte[] buf = new byte[1024];
int len;
while ((len = zis.read(buf, 0, buf.length)) != -1) {
os.write(buf, 0, len);
sizes += len;
publishProgress(sizes);
}
os.flush();
} finally {
if (os != null) {
os.close();
}
}
unzippedFile.setReadable(true, false);
unzippedFile.setWritable(true, false);
zis.closeEntry();
result = true;
}
} finally {
if (zis != null) {
zis.close();
}
}
return result;
}
}
/**
* プログレスダイアログフラグメント
* @author 知英
*/
class ProgressDialogFragment extends DialogFragment {
/**
* プログレスバーの最大値
*/
public final static String PARAM_MAX = "max";
/**
* プログレスダイアログの値
*/
public final static String PARAM_TITLE = "title";
private int mStoredProgress = 0;
private String mStoredMessage = "";
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setIndeterminate(false);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
dialog.incrementProgressBy(0);
setCancelable(false);
Bundle bundle = getArguments();
if (bundle.containsKey(PARAM_TITLE)) {
dialog.setTitle(bundle.getString(PARAM_TITLE));
}
dialog.setMessage(mStoredMessage);
dialog.setMax(bundle.getInt(PARAM_MAX));
dialog.setProgress(mStoredProgress);
return dialog;
}
/**
* ダイアログのプログレスバー値を更新する
* @param progress プログレスバー値
*/
public void updateProgress(int progress) {
Dialog d = getDialog();
if (d != null) {
((ProgressDialog) d).setProgress(progress);
} else {
mStoredProgress = progress;
}
}
/**
* ダイアログのメッセージを更新する
* @param message メッセージ
*/
public void updateMessage(String message) {
Dialog d = getDialog();
if (d != null) {
((ProgressDialog) d).setMessage(message);
} else {
mStoredMessage = message;
}
}
}
/**
* インストールがキャンセルされた(現時点のバージョンでは起こりえません)
*/
public final static int CANCELLED = -1;
/**
* すでにインストールされていたため、処理をスキップした
*/
public final static int INSTALLED = 0;
/**
* インストールが正常終了した
*/
public final static int SUCCESSED = 1;
/**
* インストールが完了したときに呼び出されるコールバックインタフェース
* @author 知英
*/
public interface FinishedListener {
/**
* インストールが完了したときにコールバックされるメソッド。
* もし指定したファイルがインストール済みであった場合、何もせずにこのメソッドを呼び出す。
* @param state インストール状態。CANCELLED, INSTALLED, SUCCESSEDのいずれか。
*/
void installFinished(int state);
}
public final static String TAG = AssetInstaller.class.getSimpleName();
private FragmentActivity mActivity;
private File mBaseDir;
private ArrayList<String> mZippedFiles;
private int mTotalSize;
private ProgressDialogFragment mDialogFragment;
private FinishedListener mFinishedListener;
private String mDialogTitle;
private String mDialogMessage;
public AssetInstaller(FragmentActivity activity, File baseDir,
FinishedListener finished) {
this.mActivity = activity;
this.mBaseDir = baseDir;
this.mFinishedListener = finished;
}
public void setProgressTitle(String title) {
this.mDialogTitle = title;
}
public void setProgressMessage(String message) {
this.mDialogMessage = message;
}
@Override
protected Boolean doInBackground(String... params) {
boolean result = false;
for (String param : params) {
Log.d(TAG, "install " + param + "?");
try {
File dir = new File(mBaseDir, param);
if (checkToCopyFile(dir, param)) {
Log.d(TAG, "install " + param + ".");
result |= startCopyToFile(dir, param);
} else {
continue;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
@Override
protected void onProgressUpdate(Object... values) {
Log.i(TAG, "progress update");
if (values.length == 0) {
Log.i(TAG, "filesize:" + mTotalSize);
showProgress(mTotalSize);
} else if (values[0] instanceof Integer) {
updateProgress((Integer) values[0]);
} else if (values[0] instanceof String) {
updateMessage((String) values[0]);
}
}
@Override
protected void onPostExecute(Boolean result) {
Log.d(TAG, "executed");
dismissProgress();
if (mFinishedListener != null) {
mFinishedListener.installFinished(result ? SUCCESSED : INSTALLED);
}
}
@Override
protected void onCancelled() {
Log.d(TAG, "cancelled");
if (mFinishedListener != null) {
mFinishedListener.installFinished(CANCELLED);
}
}
// プログレスバー処理
/**
* プログレスダイアログを表示する
*
* @param max
* プログレスの最大値
*/
private void showProgress(int max) {
mDialogFragment = new ProgressDialogFragment();
Bundle arguments = new Bundle();
arguments.putInt(ProgressDialogFragment.PARAM_MAX, max);
if (mDialogTitle != null) {
arguments.putString(ProgressDialogFragment.PARAM_TITLE,
mDialogTitle);
}
mDialogFragment.setArguments(arguments);
mDialogFragment.show(mActivity.getSupportFragmentManager(), "");
}
/**
* プログレスダイアログの値を更新する
*
* @param value
* 更新する値
*/
private void updateProgress(int value) {
mDialogFragment.updateProgress(value);
}
/**
* プログレスダイアログのメッセージを更新する。
* <ul>
* <li>メッセージ内の%1$sは展開するアーカイブファイル名
* <li>メッセージ内の%2$sは現在展開中のZipEntryファイル名
* </ul>
* に展開される
*
* @param string
*/
private void updateMessage(String message) {
mDialogFragment.updateMessage(message);
}
/**
* プログレスダイアログを破棄する
*/
private void dismissProgress() {
if (mDialogFragment != null) {
mDialogFragment.dismiss();
}
}
// ユーティリティメソッド
/**
* Assetフォルダ内のZIPファイルを開き、そのストリームを返す
*
* @param fileName
* ファイル名(拡張子抜き)
* @return ZIPストリーム
* @throws IOException
*/
private ZipInputStream getAssetZipInputStream(String fileName)
throws IOException {
AssetFileDescriptor fd = mActivity.getResources().getAssets()
.openFd(fileName + ".zip");
return new ZipInputStream(new BufferedInputStream(
fd.createInputStream()));
}
/**
* Assetフォルダ内のZIPファイルを展開する必要があるかどうか確認する
*
* @param dir
* ベースディレクトリを示す{@link File}オブジェクト
* @param fileName
* 展開対象のファイル名
* @return ファイルを展開する必要がある場合、trueを返す
* @throws IOException
*/
private boolean checkToCopyFile(File dir, String fileName)
throws IOException {
mZippedFiles = new ArrayList<String>();
mTotalSize = 0;
ZipInputStream zis = null;
try {
zis = getAssetZipInputStream(fileName);
ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null) {
if (zipEntry.isDirectory()) {
zis.closeEntry();
continue;
}
long zipEntrySize = zipEntry.getSize();
String zipEntryName = zipEntry.getName();
Log.i(TAG, "check:" + zipEntryName);
File unzippedFile = new File(dir, zipEntryName);
long unzippedFileSize = unzippedFile.length();
if (zipEntrySize != unzippedFileSize) {
Log.i(TAG, "unzip needed");
mZippedFiles.add(zipEntryName);
mTotalSize += zipEntrySize;
}
}
} finally {
if (zis != null)
zis.close();
}
return !mZippedFiles.isEmpty();
}
/**
* ZIPファイルを展開し、実フォルダに配置する
*
* @param dir
* ベースディレクトリを示す{@link File}オブジェクト
* @param fileName
* 展開対象のファイル名
* @return ファイルが正しく展開された場合、trueを返す
* @throws IOException
*/
private boolean startCopyToFile(File dir, String fileName)
throws IOException {
return copyFiles(dir, fileName);
}
/**
* ZIPファイルを展開し、実フォルダに配置する
*
* @param dir
* ベースディレクトリを示す{@link File}オブジェクト
* @param fileName
* 展開対象のファイル名
* @return ファイルが正しく展開された場合、trueを返す
* @throws IOException
*/
private boolean copyFiles(File dir, String fileName) throws IOException {
boolean result = false;
publishProgress();
ZipInputStream zis = null;
int sizes = 0;
try {
zis = getAssetZipInputStream(fileName);
ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null) {
if (zipEntry.isDirectory()) {
zis.closeEntry();
continue;
}
String zipEntryName = zipEntry.getName();
if (mDialogMessage != null) {
publishProgress(String.format(mDialogMessage, fileName,
zipEntryName));
}
File unzippedFile = new File(dir, zipEntryName);
if (!unzippedFile.getParentFile().exists()) {
unzippedFile.getParentFile().mkdirs();
}
if (unzippedFile.exists()) {
unzippedFile.delete();
}
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(
unzippedFile));
byte[] buf = new byte[1024];
int len;
while ((len = zis.read(buf, 0, buf.length)) != -1) {
os.write(buf, 0, len);
sizes += len;
publishProgress(sizes);
}
os.flush();
} finally {
if (os != null) {
os.close();
}
}
unzippedFile.setReadable(true, false);
unzippedFile.setWritable(true, false);
zis.closeEntry();
result = true;
}
} finally {
if (zis != null) {
zis.close();
}
}
return result;
}
/**
* プログレスバーの最大値
*/
public final static String PARAM_MAX = "max";
/**
* プログレスダイアログの値
*/
public final static String PARAM_TITLE = "title";
private int mStoredProgress = 0;
private String mStoredMessage = "";
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setIndeterminate(false);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
dialog.incrementProgressBy(0);
setCancelable(false);
Bundle bundle = getArguments();
if (bundle.containsKey(PARAM_TITLE)) {
dialog.setTitle(bundle.getString(PARAM_TITLE));
}
dialog.setMessage(mStoredMessage);
dialog.setMax(bundle.getInt(PARAM_MAX));
dialog.setProgress(mStoredProgress);
return dialog;
}
/**
* ダイアログのプログレスバー値を更新する
* @param progress プログレスバー値
*/
public void updateProgress(int progress) {
Dialog d = getDialog();
if (d != null) {
((ProgressDialog) d).setProgress(progress);
} else {
mStoredProgress = progress;
}
}
/**
* ダイアログのメッセージを更新する
* @param message メッセージ
*/
public void updateMessage(String message) {
Dialog d = getDialog();
if (d != null) {
((ProgressDialog) d).setMessage(message);
} else {
mStoredMessage = message;
}
}
public class MainActivity extends FragmentActivity implements AssetInstaller.FinishedListener {
protected void onCreate(Bundle savedInstanceState) {
・・・
AssetInstaller installer = new AssetInstaller(this, getFilesDir(), this);
installer.setProgressTitle("文字解析に必要なファイルをインストールしています。");
installer.setProgressMessage("%1$s.zipの%2$sを展開中");
installer.execute("tessdata");
}
・・・
@Override
public void installFinished(int state) {
if (state != AssetInstaller.CANCELLED) {
/* インストールしたファイルの利用 */
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment