mirror of
https://github.com/jamessanford/kegs.git
synced 2025-08-15 12:27:38 +00:00
New DiskLoader with gzip and zip support.
Flow of disk image selection now goes through DiskLoader with onImageReady/onImageCancelled callbacks. DiskLoader handles downloading, ungzipping, and extracting from zipfile.
This commit is contained in:
@@ -20,41 +20,51 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<intent-filter android:priority="999">
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="file" android:pathPattern=".*\\.2mg" />
|
|
||||||
</intent-filter>
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.zip" />
|
||||||
<intent-filter android:priority="999">
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.ZIP" />
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<!-- Yeah, this is pretty much awful. Blame PatternMatcher -->
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
<data android:scheme="file" android:pathPattern=".*\\.dsk" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.2mg" />
|
||||||
</intent-filter>
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.dsk" />
|
||||||
<intent-filter android:priority="999">
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.nib" />
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.hdv" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.po" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.do" />
|
||||||
<data android:scheme="file" android:pathPattern=".*\\.nib" />
|
|
||||||
</intent-filter>
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.2MG" />
|
||||||
<intent-filter android:priority="999">
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.DSK" />
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.NIB" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.HDV" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.PO" />
|
||||||
<data android:scheme="file" android:pathPattern=".*\\.hdv" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.DO" />
|
||||||
</intent-filter>
|
|
||||||
<intent-filter android:priority="999">
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.2mg.gz" />
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.dsk.gz" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.nib.gz" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.hdv.gz" />
|
||||||
<data android:scheme="file" android:pathPattern=".*\\.po" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.po.gz" />
|
||||||
</intent-filter>
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.do.gz" />
|
||||||
<intent-filter android:priority="999">
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.2MG.gz" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.DSK.gz" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.NIB.gz" />
|
||||||
<data android:scheme="file" android:pathPattern=".*\\.do" />
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.HDV.gz" />
|
||||||
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.PO.gz" />
|
||||||
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.DO.gz" />
|
||||||
|
|
||||||
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.2MG.GZ" />
|
||||||
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.DSK.GZ" />
|
||||||
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.NIB.GZ" />
|
||||||
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.HDV.GZ" />
|
||||||
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.PO.GZ" />
|
||||||
|
<data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.DO.GZ" />
|
||||||
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
@@ -263,7 +263,7 @@ void android_config_init(char *output, int maxlen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_froop_app_kegs_AssetImages_nativeSync( JNIEnv* env, jobject thiz) {
|
Java_com_froop_app_kegs_DiskLoader_nativeSync( JNIEnv* env, jobject thiz) {
|
||||||
sync();
|
sync();
|
||||||
sync();
|
sync();
|
||||||
}
|
}
|
||||||
|
BIN
res/drawable-xhdpi/ic_dialog_alert_holo_dark.png
Normal file
BIN
res/drawable-xhdpi/ic_dialog_alert_holo_dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@@ -6,6 +6,9 @@
|
|||||||
<string name="rom_title">Checking for ROM</string>
|
<string name="rom_title">Checking for ROM</string>
|
||||||
<string name="rom_check">Checking for ROM...</string>
|
<string name="rom_check">Checking for ROM...</string>
|
||||||
<string name="rom_error">Unable to obtain ROM. Find ROM.01 or ROM.03 and put it in /Android/data/com.froop.app.kegs/files/ on your SD Card.</string>
|
<string name="rom_error">Unable to obtain ROM. Find ROM.01 or ROM.03 and put it in /Android/data/com.froop.app.kegs/files/ on your SD Card.</string>
|
||||||
|
<string name="image_error">Unable to load requested disk image.</string>
|
||||||
|
<string name="error_title">Error</string>
|
||||||
|
<string name="dialog_ok">OK</string>
|
||||||
|
|
||||||
<string-array name="rom_choices">
|
<string-array name="rom_choices">
|
||||||
<item>I have a ROM 01</item>
|
<item>I have a ROM 01</item>
|
||||||
@@ -21,7 +24,8 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="diskimage_title">Choose a disk</string>
|
<string name="diskimage_title">Choose a disk</string>
|
||||||
<string name="asset_loading">Preparing disk image...</string>
|
<string name="progress_message">Preparing disk image...</string>
|
||||||
|
<string name="zipfile_nomatches">No disk images found</string>
|
||||||
|
|
||||||
<string-array name="swapdisk_choices">
|
<string-array name="swapdisk_choices">
|
||||||
<item>Ignore this disk</item>
|
<item>Ignore this disk</item>
|
||||||
|
@@ -46,7 +46,6 @@ class AssetImages extends AsyncTask<Void, Void, Boolean> {
|
|||||||
mConfigFile.ensureAssetCopied(mConfigFile.getImagePath(),
|
mConfigFile.ensureAssetCopied(mConfigFile.getImagePath(),
|
||||||
"System 6 Shareware.zip", "System 6.hdv");
|
"System 6 Shareware.zip", "System 6.hdv");
|
||||||
// TODO: could check to make sure they actually exist now.
|
// TODO: could check to make sure they actually exist now.
|
||||||
nativeSync();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +56,4 @@ class AssetImages extends AsyncTask<Void, Void, Boolean> {
|
|||||||
protected void onPostExecute(final Boolean result) {
|
protected void onPostExecute(final Boolean result) {
|
||||||
mNotify.onAssetsReady(result);
|
mNotify.onAssetsReady(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// See jni/android_driver.c:nativeSync()
|
|
||||||
private native void nativeSync();
|
|
||||||
}
|
}
|
||||||
|
@@ -35,6 +35,10 @@ class ConfigFile {
|
|||||||
return mConfigPath + "/images";
|
return mConfigPath + "/images";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCachePath() {
|
||||||
|
return mContext.getExternalCacheDir().getPath();
|
||||||
|
}
|
||||||
|
|
||||||
public void ensureAssetCopied(String destPath, String zipfile, String exampleFile) {
|
public void ensureAssetCopied(String destPath, String zipfile, String exampleFile) {
|
||||||
// We only check for a local copy of a single file before unzipping...
|
// We only check for a local copy of a single file before unzipping...
|
||||||
final File local_copy = new File(destPath, exampleFile);
|
final File local_copy = new File(destPath, exampleFile);
|
||||||
|
53
src/com/froop/app/kegs/ErrorDialogFragment.java
Normal file
53
src/com/froop/app/kegs/ErrorDialogFragment.java
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockDialogFragment;
|
||||||
|
|
||||||
|
class ErrorDialogFragment extends SherlockDialogFragment {
|
||||||
|
private int mMessage;
|
||||||
|
private Runnable mRunnable;
|
||||||
|
|
||||||
|
public ErrorDialogFragment(int textId, Runnable runnable) {
|
||||||
|
super();
|
||||||
|
mMessage = textId;
|
||||||
|
mRunnable = runnable; // ok if null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
builder.setTitle(R.string.error_title);
|
||||||
|
builder.setIcon(R.drawable.ic_dialog_alert_holo_dark);
|
||||||
|
builder.setMessage(mMessage);
|
||||||
|
builder.setPositiveButton(R.string.dialog_ok,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int button) {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
final AlertDialog dialog = builder.create();
|
||||||
|
dialog.setCanceledOnTouchOutside(false); // prevent accidental dismissal
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
super.onCancel(dialog);
|
||||||
|
if (mRunnable != null) {
|
||||||
|
mRunnable.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismiss(DialogInterface dialog) {
|
||||||
|
super.onDismiss(dialog);
|
||||||
|
if (mRunnable != null) {
|
||||||
|
mRunnable.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -26,14 +26,17 @@ import com.actionbarsherlock.app.SherlockDialogFragment;
|
|||||||
import com.actionbarsherlock.view.Menu;
|
import com.actionbarsherlock.view.Menu;
|
||||||
import com.actionbarsherlock.view.MenuItem;
|
import com.actionbarsherlock.view.MenuItem;
|
||||||
|
|
||||||
public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.StickyReset, AssetImages.AssetsReady, DownloadImage.DownloadReady {
|
import java.util.ArrayDeque;
|
||||||
|
|
||||||
|
public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.StickyReset, AssetImages.AssetsReady, DiskLoader.ImageReady {
|
||||||
private static final String FRAGMENT_ROM = "rom";
|
private static final String FRAGMENT_ROM = "rom";
|
||||||
private static final String FRAGMENT_DOWNLOAD = "download";
|
private static final String FRAGMENT_DOWNLOAD = "download";
|
||||||
private static final String FRAGMENT_ERROR = "error";
|
private static final String FRAGMENT_ERROR = "error";
|
||||||
private static final String FRAGMENT_SPEED = "speed";
|
private static final String FRAGMENT_SPEED = "speed";
|
||||||
private static final String FRAGMENT_DISKIMAGE = "diskimage";
|
private static final String FRAGMENT_DISKIMAGE = "diskimage";
|
||||||
private static final String FRAGMENT_ASSET = "asset";
|
|
||||||
private static final String FRAGMENT_SWAPDISK = "swapdisk";
|
private static final String FRAGMENT_SWAPDISK = "swapdisk";
|
||||||
|
private static final String FRAGMENT_ZIPDISK = "zipdisk";
|
||||||
|
private static final String FRAGMENT_LOADING = "loading";
|
||||||
|
|
||||||
private ConfigFile mConfigFile;
|
private ConfigFile mConfigFile;
|
||||||
private KegsThread mKegsThread;
|
private KegsThread mKegsThread;
|
||||||
@@ -45,16 +48,27 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S
|
|||||||
private KegsKeyboard mKegsKeyboard;
|
private KegsKeyboard mKegsKeyboard;
|
||||||
private TouchJoystick mJoystick;
|
private TouchJoystick mJoystick;
|
||||||
|
|
||||||
private boolean mAssetsReady = false;
|
|
||||||
private boolean mDownloadReady = false;
|
|
||||||
private boolean mDownloadStarted = false;
|
|
||||||
private boolean mDownloadAborted = false;
|
|
||||||
|
|
||||||
private boolean mModeMouse = true;
|
private boolean mModeMouse = true;
|
||||||
private boolean mHaveNewIntent = false;
|
|
||||||
|
|
||||||
private long mScreenSizeTime = 0;
|
private long mScreenSizeTime = 0;
|
||||||
|
|
||||||
|
private boolean mPaused = false;
|
||||||
|
final ArrayDeque<Runnable> mResumeQueue = new ArrayDeque<Runnable>();
|
||||||
|
|
||||||
|
private DiskLoader mDiskLoader = null;
|
||||||
|
|
||||||
|
private void withUIActive(final Runnable runnable) {
|
||||||
|
if(!mPaused) {
|
||||||
|
runnable.run();
|
||||||
|
} else {
|
||||||
|
mResumeQueue.add(runnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAssetsReady(boolean result) {
|
||||||
|
// TODO: deal with error conditions from assets as a warning.
|
||||||
|
}
|
||||||
|
|
||||||
private View.OnClickListener mButtonClick = new View.OnClickListener() {
|
private View.OnClickListener mButtonClick = new View.OnClickListener() {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
final int click_id = v.getId();
|
final int click_id = v.getId();
|
||||||
@@ -106,81 +120,109 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S
|
|||||||
((ToggleButton)findViewById(R.id.key_closed_apple)).setChecked(false);
|
((ToggleButton)findViewById(R.id.key_closed_apple)).setChecked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onAssetsReady(boolean success) {
|
protected void loadDiskImage(final DiskImage image) {
|
||||||
// TODO FIXME: this needs to throw an error if it fails.
|
if (image.action == DiskImage.BOOT) {
|
||||||
mAssetsReady = success;
|
getThread().doPowerOff();
|
||||||
}
|
}
|
||||||
|
loadDiskImageWhenReady(image);
|
||||||
public void onDownloadReady(boolean success) {
|
|
||||||
// TODO FIXME: this needs to throw an error if it fails.
|
|
||||||
mDownloadReady = success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadDiskImageWhenReady(final DiskImage image) {
|
private void loadDiskImageWhenReady(final DiskImage image) {
|
||||||
final AssetFragment frag = (AssetFragment)getSupportFragmentManager().findFragmentByTag(FRAGMENT_ASSET);
|
|
||||||
|
|
||||||
// Only start download when the assets are ready.
|
|
||||||
if (mAssetsReady && !mDownloadStarted) {
|
|
||||||
mDownloadStarted = true;
|
|
||||||
final String imagePath = mConfigFile.getImagePath();
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
|
||||||
new DownloadImage(this, imagePath, image).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
||||||
} else {
|
|
||||||
new DownloadImage(this, imagePath, image).execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This code is lame.
|
|
||||||
if (mDownloadAborted) {
|
|
||||||
if (frag != null) {
|
|
||||||
frag.dismiss();
|
|
||||||
}
|
|
||||||
if (image.primary) {
|
|
||||||
getThread().allowPowerOn();
|
|
||||||
}
|
|
||||||
return; // don't schedule another pass.
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean nativeReady;
|
boolean nativeReady;
|
||||||
if (image.primary) {
|
if (image.action == DiskImage.BOOT) {
|
||||||
nativeReady = getThread().nowWaitingForPowerOn();
|
nativeReady = getThread().nowWaitingForPowerOn();
|
||||||
} else {
|
} else {
|
||||||
nativeReady = true;
|
nativeReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nativeReady || !mAssetsReady || !mDownloadReady) {
|
if (!nativeReady) {
|
||||||
if (frag == null && (!mAssetsReady || !mDownloadReady)) {
|
|
||||||
// Only the asset part will take time, so only show the dialog
|
|
||||||
// when waiting for the asset.
|
|
||||||
final SherlockDialogFragment assetProgress = new AssetFragment();
|
|
||||||
assetProgress.show(getSupportFragmentManager(), FRAGMENT_ASSET);
|
|
||||||
}
|
|
||||||
mKegsView.postDelayed(new Runnable() {
|
mKegsView.postDelayed(new Runnable() {
|
||||||
public void run() { loadDiskImageWhenReady(image); }
|
public void run() {
|
||||||
}, 100);
|
loadDiskImageWhenReady(image);
|
||||||
} else {
|
|
||||||
if (frag != null) {
|
|
||||||
frag.dismiss();
|
|
||||||
}
|
}
|
||||||
if (image.primary) {
|
}, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
withUIActive(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (image.action == DiskImage.BOOT) {
|
||||||
mConfigFile.setConfig(image);
|
mConfigFile.setConfig(image);
|
||||||
getThread().allowPowerOn();
|
getThread().allowPowerOn();
|
||||||
} else {
|
} else if (image.action == DiskImage.SWAP) {
|
||||||
getThread().getEventQueue().add(image.getDiskImageEvent());
|
getThread().getEventQueue().add(image.getDiskImageEvent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void loadDiskImage(DiskImage image) {
|
public void onImageReady(final boolean result, final DiskImage image) {
|
||||||
if (image.primary) {
|
mDiskLoader = null;
|
||||||
getThread().doPowerOff();
|
withUIActive(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
dismissFragment(FRAGMENT_LOADING);
|
||||||
|
if (!result) {
|
||||||
|
// TODO: Consider not showing the error if it was cancelled.
|
||||||
|
new ErrorDialogFragment(R.string.image_error, null).show(getSupportFragmentManager(), FRAGMENT_ERROR);
|
||||||
|
} else if (image.action != DiskImage.ASK) {
|
||||||
|
loadDiskImage(image);
|
||||||
|
} else {
|
||||||
|
new SwapDiskFragment(image).show(getSupportFragmentManager(),
|
||||||
|
FRAGMENT_SWAPDISK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
mDownloadStarted = false;
|
public void prepareDiskImage(DiskImage image) {
|
||||||
mDownloadReady = false;
|
dismissFragment(FRAGMENT_ROM); // Note: should probably bail if visible.
|
||||||
mDownloadAborted = false;
|
dismissFragment(FRAGMENT_SPEED);
|
||||||
|
dismissFragment(FRAGMENT_DISKIMAGE);
|
||||||
|
dismissFragment(FRAGMENT_SWAPDISK);
|
||||||
|
dismissFragment(FRAGMENT_ZIPDISK);
|
||||||
|
|
||||||
loadDiskImageWhenReady(image);
|
if (image.filename.endsWith(".zip") || image.filename.endsWith(".ZIP")) {
|
||||||
|
final ZipDiskFragment zip = new ZipDiskFragment(image);
|
||||||
|
if (zip.needsDialog()) {
|
||||||
|
zip.show(getSupportFragmentManager(), FRAGMENT_ZIPDISK);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
image = zip.getFirstImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runDiskLoader(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
// So that other fragments can transition into the DiskLoader.
|
||||||
|
public void runDiskLoader(final DiskImage image) {
|
||||||
|
final Runnable cancel = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (mDiskLoader != null) {
|
||||||
|
mDiskLoader.cancel(true);
|
||||||
|
mDiskLoader = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final DiskLoader.ImageReady notify = this;
|
||||||
|
withUIActive(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
// In case there was already another DiskLoader.
|
||||||
|
cancel.run();
|
||||||
|
dismissFragment(FRAGMENT_LOADING);
|
||||||
|
|
||||||
|
mDiskLoader = new DiskLoader(notify, mConfigFile, image);
|
||||||
|
if (mDiskLoader.willBeSlow()) {
|
||||||
|
new SpecialProgressDialog(cancel).show(getSupportFragmentManager(),
|
||||||
|
FRAGMENT_LOADING);
|
||||||
|
}
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||||
|
mDiskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
} else {
|
||||||
|
mDiskLoader.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private DiskImage getBootDiskImage(Intent intent) {
|
private DiskImage getBootDiskImage(Intent intent) {
|
||||||
@@ -200,14 +242,20 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S
|
|||||||
private void boot() {
|
private void boot() {
|
||||||
final DiskImage image = getBootDiskImage(getIntent());
|
final DiskImage image = getBootDiskImage(getIntent());
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
loadDiskImage(image);
|
prepareDiskImage(image);
|
||||||
} else {
|
} else {
|
||||||
mConfigFile.defaultConfig();
|
mConfigFile.defaultConfig();
|
||||||
getThread().allowPowerOn();
|
getThread().allowPowerOn();
|
||||||
mKegsView.postDelayed(new Runnable() { public void run() {
|
mKegsView.postDelayed(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
withUIActive(new Runnable() {
|
||||||
|
public void run() {
|
||||||
new DiskImageFragment().show(getSupportFragmentManager(),
|
new DiskImageFragment().show(getSupportFragmentManager(),
|
||||||
FRAGMENT_DISKIMAGE);
|
FRAGMENT_DISKIMAGE);
|
||||||
} }, 1000);
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,20 +277,24 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S
|
|||||||
"http://jsan.co/KEGS/" + mRomfile,
|
"http://jsan.co/KEGS/" + mRomfile,
|
||||||
mConfigFile.getConfigPath() + "/" + mRomfile);
|
mConfigFile.getConfigPath() + "/" + mRomfile);
|
||||||
}
|
}
|
||||||
protected void onPostExecute(Boolean success) {
|
protected void onPostExecute(final Boolean success) {
|
||||||
|
withUIActive(new Runnable() {
|
||||||
|
public void run() {
|
||||||
final SherlockDialogFragment frag = (SherlockDialogFragment)getSupportFragmentManager().findFragmentByTag(FRAGMENT_DOWNLOAD);
|
final SherlockDialogFragment frag = (SherlockDialogFragment)getSupportFragmentManager().findFragmentByTag(FRAGMENT_DOWNLOAD);
|
||||||
if (frag != null) {
|
if (frag != null) {
|
||||||
frag.dismiss();
|
frag.dismiss();
|
||||||
}
|
}
|
||||||
if (!success) {
|
if (!success) {
|
||||||
if (!isCancelled()) {
|
if (!isCancelled()) {
|
||||||
final SherlockDialogFragment dialog = new ErrorDialogFragment();
|
final Runnable runnable = new Runnable() { public void run() { finish(); } };
|
||||||
dialog.show(getSupportFragmentManager(), FRAGMENT_ERROR);
|
new ErrorDialogFragment(R.string.rom_error, runnable).show(getSupportFragmentManager(), FRAGMENT_ERROR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
boot();
|
boot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DownloadDialogFragment extends SherlockDialogFragment {
|
class DownloadDialogFragment extends SherlockDialogFragment {
|
||||||
@@ -269,53 +321,6 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ErrorDialogFragment extends SherlockDialogFragment {
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
|
||||||
builder.setMessage(getResources().getText(R.string.rom_error));
|
|
||||||
final AlertDialog dialog = builder.create();
|
|
||||||
dialog.setCanceledOnTouchOutside(false); // prevent accidental dismissal
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
super.onCancel(dialog);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDismiss(DialogInterface dialog) {
|
|
||||||
super.onDismiss(dialog);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AssetFragment extends SherlockDialogFragment {
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
ProgressDialog dialog = new ProgressDialog(getActivity());
|
|
||||||
// TODO: should probably use an XML layout for this.
|
|
||||||
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
|
||||||
dialog.setMessage(getResources().getText(R.string.asset_loading));
|
|
||||||
dialog.setProgressNumberFormat(null);
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
|
||||||
dialog.setProgressPercentFormat(null);
|
|
||||||
}
|
|
||||||
dialog.setIndeterminate(true);
|
|
||||||
dialog.setCancelable(false);
|
|
||||||
dialog.setCanceledOnTouchOutside(false);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
super.onCancel(dialog);
|
|
||||||
mDownloadAborted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public KegsThread getThread() {
|
public KegsThread getThread() {
|
||||||
return mKegsThread;
|
return mKegsThread;
|
||||||
}
|
}
|
||||||
@@ -447,22 +452,18 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S
|
|||||||
if (image == null) {
|
if (image == null) {
|
||||||
return; // Nothing to do.
|
return; // Nothing to do.
|
||||||
}
|
}
|
||||||
dismissFragment(FRAGMENT_ROM); // Note: should probably bail if visible.
|
image.action = DiskImage.ASK;
|
||||||
dismissFragment(FRAGMENT_SPEED);
|
prepareDiskImage(image);
|
||||||
dismissFragment(FRAGMENT_DISKIMAGE);
|
|
||||||
dismissFragment(FRAGMENT_SWAPDISK);
|
|
||||||
|
|
||||||
// Ask the user what to do with this new disk image.
|
|
||||||
new SwapDiskFragment(image).show(getSupportFragmentManager(),
|
|
||||||
FRAGMENT_SWAPDISK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onNewIntent(Intent intent) {
|
protected void onNewIntent(final Intent intent) {
|
||||||
// "An activity will always be paused before receiving a new intent."
|
// "An activity will always be paused before receiving a new intent."
|
||||||
// Being paused means we can't show a dialog here. Tell onResume to do it.
|
withUIActive(new Runnable() {
|
||||||
setIntent(intent);
|
public void run() {
|
||||||
mHaveNewIntent = true;
|
handleNewIntent(intent);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -530,8 +531,7 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S
|
|||||||
|
|
||||||
final String romfile = mConfigFile.whichRomFile();
|
final String romfile = mConfigFile.whichRomFile();
|
||||||
if (romfile == null) {
|
if (romfile == null) {
|
||||||
final SherlockDialogFragment chooseRom = new RomDialogFragment();
|
new RomDialogFragment().show(getSupportFragmentManager(), FRAGMENT_ROM);
|
||||||
chooseRom.show(getSupportFragmentManager(), FRAGMENT_ROM);
|
|
||||||
} else {
|
} else {
|
||||||
boot();
|
boot();
|
||||||
}
|
}
|
||||||
@@ -544,6 +544,7 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S
|
|||||||
if (mKegsView instanceof KegsViewGL) {
|
if (mKegsView instanceof KegsViewGL) {
|
||||||
mKegsView.onPause();
|
mKegsView.onPause();
|
||||||
}
|
}
|
||||||
|
mPaused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -553,15 +554,18 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S
|
|||||||
if (mKegsView instanceof KegsViewGL) {
|
if (mKegsView instanceof KegsViewGL) {
|
||||||
mKegsView.onResume();
|
mKegsView.onResume();
|
||||||
}
|
}
|
||||||
if (mHaveNewIntent) {
|
mPaused = false;
|
||||||
mHaveNewIntent = false;
|
|
||||||
handleNewIntent(getIntent());
|
Runnable runnable;
|
||||||
|
while ((runnable = mResumeQueue.poll()) != null) {
|
||||||
|
runnable.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
mResumeQueue.clear();
|
||||||
Log.w("kegs", "onDestroy called, halting");
|
Log.w("kegs", "onDestroy called, halting");
|
||||||
// Force process to exit. We cannot handle another onCreate
|
// Force process to exit. We cannot handle another onCreate
|
||||||
// once a KegsView has been active. (JNI kegsmain has already run)
|
// once a KegsView has been active. (JNI kegsmain has already run)
|
||||||
|
42
src/com/froop/app/kegs/SpecialProgressDialog.java
Normal file
42
src/com/froop/app/kegs/SpecialProgressDialog.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockDialogFragment;
|
||||||
|
|
||||||
|
// A predefined progress dialog that calls a Runner when it's cancelled.
|
||||||
|
|
||||||
|
public class SpecialProgressDialog extends SherlockDialogFragment {
|
||||||
|
private Runnable mCancelRunnable;
|
||||||
|
|
||||||
|
public SpecialProgressDialog(Runnable runnable) {
|
||||||
|
super();
|
||||||
|
mCancelRunnable = runnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
ProgressDialog dialog = new ProgressDialog(getActivity());
|
||||||
|
// TODO: should probably use an XML layout for this.
|
||||||
|
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
dialog.setMessage(getResources().getText(R.string.progress_message));
|
||||||
|
dialog.setProgressNumberFormat(null);
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||||
|
dialog.setProgressPercentFormat(null);
|
||||||
|
}
|
||||||
|
dialog.setIndeterminate(true);
|
||||||
|
dialog.setCancelable(false);
|
||||||
|
dialog.setCanceledOnTouchOutside(false);
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
super.onCancel(dialog);
|
||||||
|
mCancelRunnable.run();
|
||||||
|
}
|
||||||
|
}
|
@@ -28,9 +28,10 @@ public class SwapDiskFragment extends SherlockDialogFragment {
|
|||||||
if (item == 0) {
|
if (item == 0) {
|
||||||
// ignore this image
|
// ignore this image
|
||||||
} else if (item == 1) {
|
} else if (item == 1) {
|
||||||
mImage.primary = false; // just a disk insert
|
mImage.action = DiskImage.SWAP; // just a disk insert
|
||||||
((KegsMain)getActivity()).loadDiskImage(mImage);
|
((KegsMain)getActivity()).loadDiskImage(mImage);
|
||||||
} else if (item == 2) {
|
} else if (item == 2) {
|
||||||
|
mImage.action = DiskImage.BOOT; // was ASK
|
||||||
((KegsMain)getActivity()).loadDiskImage(mImage);
|
((KegsMain)getActivity()).loadDiskImage(mImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,24 +5,40 @@ import java.lang.Integer;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
class DiskImage {
|
class DiskImage {
|
||||||
|
// template
|
||||||
public static final String BOOT_SLOT_5 = "boot_slot_5";
|
public static final String BOOT_SLOT_5 = "boot_slot_5";
|
||||||
public static final String BOOT_SLOT_6 = "boot_slot_6";
|
public static final String BOOT_SLOT_6 = "boot_slot_6";
|
||||||
public static final String BOOT_SLOT_7 = "boot_slot_7";
|
public static final String BOOT_SLOT_7 = "boot_slot_7";
|
||||||
|
|
||||||
public boolean primary = true;
|
// origin
|
||||||
|
public static final int ASSET = 0;
|
||||||
|
public static final int DOWNLOAD = 1;
|
||||||
|
public static final int LOCALFILE = 2;
|
||||||
|
public static final int ERROR = 3;
|
||||||
|
|
||||||
|
// action
|
||||||
|
public static final int BOOT = 0;
|
||||||
|
public static final int SWAP = 1;
|
||||||
|
public static final int ASK = 2;
|
||||||
|
|
||||||
public String filename;
|
public String filename;
|
||||||
public String drive;
|
public String drive;
|
||||||
public int speed;
|
public int speed;
|
||||||
public String template;
|
public String template;
|
||||||
|
public int origin;
|
||||||
|
public int action;
|
||||||
|
public String extract_filename = null; // for extracting from zipfiles
|
||||||
|
|
||||||
// Example:
|
// Example:
|
||||||
// DiskImage("XMAS_DEMO.2MG", "s5d1", 2, "boot_slot_5");
|
// DiskImage("XMAS_DEMO.2MG", "s5d1", 2, "boot_slot_5", LOCALFILE);
|
||||||
public DiskImage(final String filename, final String drive,
|
public DiskImage(final String filename, final String drive,
|
||||||
final int speed, final String template) {
|
final int speed, final String template, final int origin) {
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
this.drive = drive;
|
this.drive = drive;
|
||||||
this.speed = speed;
|
this.speed = speed;
|
||||||
this.template = template;
|
this.template = template;
|
||||||
|
this.origin = origin;
|
||||||
|
this.action = BOOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DiskImage fromPath(String path) {
|
public static DiskImage fromPath(String path) {
|
||||||
@@ -32,19 +48,44 @@ class DiskImage {
|
|||||||
return null;
|
return null;
|
||||||
} else if (length >= 1024 * 1024) {
|
} else if (length >= 1024 * 1024) {
|
||||||
// TODO: should insert the disk and use the System 6 template
|
// TODO: should insert the disk and use the System 6 template
|
||||||
return new DiskImage(path, "s7d1", 3, BOOT_SLOT_7);
|
return new DiskImage(path, "s7d1", 3, BOOT_SLOT_7, LOCALFILE);
|
||||||
} else if (length >= 400 * 1024) {
|
} else if (length >= 400 * 1024) {
|
||||||
return new DiskImage(path, "s5d1", 2, BOOT_SLOT_5);
|
return new DiskImage(path, "s5d1", 2, BOOT_SLOT_5, LOCALFILE);
|
||||||
} else if (length > 0) {
|
} else if (length > 0) {
|
||||||
return new DiskImage(path, "s6d1", 1, BOOT_SLOT_6);
|
return new DiskImage(path, "s6d1", 1, BOOT_SLOT_6, LOCALFILE);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isDiskImageFilename(String filename) {
|
||||||
|
if (filename.endsWith(".2mg") ||
|
||||||
|
filename.endsWith(".dsk") ||
|
||||||
|
filename.endsWith(".nib") ||
|
||||||
|
filename.endsWith(".hdv") ||
|
||||||
|
filename.endsWith(".po") ||
|
||||||
|
filename.endsWith(".do") ||
|
||||||
|
filename.endsWith(".bin") ||
|
||||||
|
filename.endsWith(".2MG") ||
|
||||||
|
filename.endsWith(".DSK") ||
|
||||||
|
filename.endsWith(".NIB") ||
|
||||||
|
filename.endsWith(".HDV") ||
|
||||||
|
filename.endsWith(".PO") ||
|
||||||
|
filename.endsWith(".DO") ||
|
||||||
|
filename.endsWith(".BIN")) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBaseFilename() {
|
||||||
|
int pos = this.filename.lastIndexOf("/");
|
||||||
|
return this.filename.substring(pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
int pos = this.filename.lastIndexOf("/") + 1;
|
return getBaseFilename();
|
||||||
return this.filename.substring(pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getIconId() {
|
public int getIconId() {
|
||||||
|
@@ -32,16 +32,16 @@ public class DiskImageFragment extends SherlockDialogFragment {
|
|||||||
DiskImage image = null;
|
DiskImage image = null;
|
||||||
|
|
||||||
if (item == 0) {
|
if (item == 0) {
|
||||||
image = new DiskImage("System 6.hdv", "s7d1", 3, DiskImage.BOOT_SLOT_7);
|
image = new DiskImage("System 6.hdv", "s7d1", 3, DiskImage.BOOT_SLOT_7, DiskImage.ASSET);
|
||||||
} else if (item == 1) {
|
} else if (item == 1) {
|
||||||
image = new DiskImage("XMAS_DEMO.2MG", "s5d1", 2, DiskImage.BOOT_SLOT_5);
|
image = new DiskImage("XMAS_DEMO.2MG", "s5d1", 2, DiskImage.BOOT_SLOT_5, DiskImage.ASSET);
|
||||||
} else if (item == 2) {
|
} else if (item == 2) {
|
||||||
// TODO: There should be an adapter on the ListView instead.
|
// TODO: There should be an adapter on the ListView instead.
|
||||||
image = new DiskImage("prince.2mg", "s5d1", 2, DiskImage.BOOT_SLOT_5);
|
image = new DiskImage("prince.2mg", "s5d1", 2, DiskImage.BOOT_SLOT_5, DiskImage.DOWNLOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
((KegsMain)getActivity()).loadDiskImage(image);
|
((KegsMain)getActivity()).prepareDiskImage(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
146
src/com/froop/app/kegs/diskimage/DiskLoader.java
Normal file
146
src/com/froop/app/kegs/diskimage/DiskLoader.java
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
class DiskLoader extends AsyncTask<Void, Void, Boolean> {
|
||||||
|
interface ImageReady {
|
||||||
|
void onImageReady(boolean result, DiskImage image);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageReady mNotify;
|
||||||
|
private DiskImage mImage;
|
||||||
|
|
||||||
|
private boolean mSlow = false;
|
||||||
|
private String mDestPath;
|
||||||
|
|
||||||
|
DiskLoader(final ImageReady notify, final ConfigFile config,
|
||||||
|
final DiskImage image) {
|
||||||
|
mNotify = notify;
|
||||||
|
mImage = image;
|
||||||
|
|
||||||
|
if (image.filename.endsWith(".gz") ||
|
||||||
|
image.filename.endsWith(".zip") ||
|
||||||
|
image.filename.endsWith(".GZ") ||
|
||||||
|
image.filename.endsWith(".ZIP") ||
|
||||||
|
image.origin == DiskImage.ASSET ||
|
||||||
|
image.origin == DiskImage.DOWNLOAD) {
|
||||||
|
mSlow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.origin == DiskImage.ASSET ||
|
||||||
|
image.origin == DiskImage.DOWNLOAD) {
|
||||||
|
mDestPath = config.getImagePath();
|
||||||
|
|
||||||
|
final File local_copy = new File(mDestPath, image.filename);
|
||||||
|
if (local_copy != null && local_copy.exists()) {
|
||||||
|
// Assume whatever is there will work.
|
||||||
|
mSlow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.origin == DiskImage.LOCALFILE) {
|
||||||
|
// If we need to extract it, it will go here.
|
||||||
|
mDestPath = config.getCachePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean willBeSlow() {
|
||||||
|
return mSlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPreExecute() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean extractImage() {
|
||||||
|
if (mImage.origin == DiskImage.ERROR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mImage.origin == DiskImage.ASSET) {
|
||||||
|
// Just keep polling waiting for it, AssetImages is working on it.
|
||||||
|
final File local_copy = new File(mDestPath, mImage.filename);
|
||||||
|
while (!local_copy.exists()) {
|
||||||
|
try { Thread.sleep(1000); } catch (InterruptedException e) {}
|
||||||
|
if (isCancelled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mImage.origin == DiskImage.DOWNLOAD) {
|
||||||
|
final File local_copy = new File(mDestPath, mImage.filename);
|
||||||
|
if (local_copy != null && local_copy.exists()) {
|
||||||
|
// Assume whatever is there will work.
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return new DownloadHelper().save(
|
||||||
|
"http://jsan.co/KEGS/images/" + mImage.filename,
|
||||||
|
local_copy.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mImage.filename.endsWith(".gz") || mImage.filename.endsWith(".GZ")) {
|
||||||
|
final String old_filename = mImage.getBaseFilename();
|
||||||
|
final String filename = old_filename.substring(0, old_filename.lastIndexOf("."));
|
||||||
|
try {
|
||||||
|
GZIPInputStream zipStream = new GZIPInputStream(new BufferedInputStream(new FileInputStream(new File(mImage.filename))));
|
||||||
|
new CopyHelper(zipStream, mDestPath, filename).copy();
|
||||||
|
} catch (java.io.IOException e) {
|
||||||
|
Log.e("kegs", Log.getStackTraceString(e));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mImage.filename = new File(mDestPath, filename).getPath();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mImage.filename.endsWith(".zip") || mImage.filename.endsWith(".ZIP")) {
|
||||||
|
final int pos = mImage.extract_filename.lastIndexOf("/");
|
||||||
|
final String filename = mImage.extract_filename.substring(pos + 1);
|
||||||
|
try {
|
||||||
|
final ZipFile zip = new ZipFile(mImage.filename);
|
||||||
|
final ZipEntry extract = zip.getEntry(mImage.extract_filename);
|
||||||
|
if (extract == null) {
|
||||||
|
zip.close();
|
||||||
|
Log.e("kegs", mImage.filename + " has no " + mImage.extract_filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
new CopyHelper(zip.getInputStream(extract), mDestPath, filename).copy();
|
||||||
|
zip.close();
|
||||||
|
} catch (java.io.IOException e) {
|
||||||
|
Log.e("kegs", Log.getStackTraceString(e));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mImage.filename = new File(mDestPath, filename).getPath();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No special handling required, finish up and run onImageReady.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
Boolean result = extractImage();
|
||||||
|
nativeSync(); // Flush new disk images before claiming they are ready.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onCancelled(final Boolean result) {
|
||||||
|
mNotify.onImageReady(result, mImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPostExecute(final Boolean result) {
|
||||||
|
mNotify.onImageReady(result, mImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See jni/android_driver.c:nativeSync()
|
||||||
|
private native void nativeSync();
|
||||||
|
}
|
@@ -1,56 +0,0 @@
|
|||||||
package com.froop.app.kegs;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
class DownloadImage extends AsyncTask<Void, Void, Boolean> {
|
|
||||||
interface DownloadReady {
|
|
||||||
void onDownloadReady(boolean result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DownloadReady mNotify;
|
|
||||||
private DiskImage mImage;
|
|
||||||
private File mDest;
|
|
||||||
private boolean mLocalPath = false;
|
|
||||||
|
|
||||||
DownloadImage(DownloadReady notify, String imagePath, DiskImage image) {
|
|
||||||
mNotify = notify;
|
|
||||||
mImage = image;
|
|
||||||
|
|
||||||
if (imagePath == null || image.filename.startsWith("/")) {
|
|
||||||
mLocalPath = true;
|
|
||||||
mDest = new File(image.filename);
|
|
||||||
} else {
|
|
||||||
mDest = new File(imagePath, image.filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mLocalPath || mDest.exists()) {
|
|
||||||
// Assume whatever is there will work.
|
|
||||||
// So the caller will immediately see that it's already done.
|
|
||||||
mNotify.onDownloadReady(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onPreExecute() {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Boolean doInBackground(Void... params) {
|
|
||||||
if (mLocalPath || mDest.exists()) {
|
|
||||||
// Assume whatever is there will work.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DownloadHelper().save(
|
|
||||||
"http://jsan.co/KEGS/images/" + mImage.filename, mDest.getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onCancelled(final Boolean result) {
|
|
||||||
mNotify.onDownloadReady(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onPostExecute(final Boolean result) {
|
|
||||||
mNotify.onDownloadReady(result);
|
|
||||||
}
|
|
||||||
}
|
|
105
src/com/froop/app/kegs/diskimage/ZipDiskFragment.java
Normal file
105
src/com/froop/app/kegs/diskimage/ZipDiskFragment.java
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockDialogFragment;
|
||||||
|
|
||||||
|
public class ZipDiskFragment extends SherlockDialogFragment {
|
||||||
|
private ArrayList<String> mFiles = new ArrayList<String>();
|
||||||
|
private ArrayList<String> mTitles = new ArrayList<String>();
|
||||||
|
private DiskImage mImage;
|
||||||
|
|
||||||
|
public ZipDiskFragment(DiskImage image) {
|
||||||
|
super();
|
||||||
|
mImage = image;
|
||||||
|
|
||||||
|
// NOTE: We extract the zipfile table of contents in the UI thread.
|
||||||
|
getTableOfContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getTableOfContents() {
|
||||||
|
try {
|
||||||
|
final ZipFile zip = new ZipFile(mImage.filename);
|
||||||
|
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = entries.nextElement();
|
||||||
|
final String filename = entry.getName();
|
||||||
|
if (DiskImage.isDiskImageFilename(filename)) {
|
||||||
|
mFiles.add(filename);
|
||||||
|
int pos = filename.lastIndexOf("/");
|
||||||
|
mTitles.add(filename.substring(pos + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zip.close();
|
||||||
|
} catch (java.io.IOException e) {
|
||||||
|
Log.e("kegs", Log.getStackTraceString(e));
|
||||||
|
// Do not show any results.
|
||||||
|
mFiles.clear();
|
||||||
|
mTitles.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caller may use getFirstImage when there is only one item
|
||||||
|
public boolean needsDialog() {
|
||||||
|
return mTitles.size() != 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiskImage getFirstImage() {
|
||||||
|
mImage.extract_filename = mFiles.get(0);
|
||||||
|
return mImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forceDiskLoaderError() {
|
||||||
|
// TODO: Ick. All this just so that whoever opened this fragment
|
||||||
|
// will get a DiskLoader callback.
|
||||||
|
mImage.filename = "";
|
||||||
|
mImage.origin = DiskImage.ERROR;
|
||||||
|
((KegsMain)getActivity()).runDiskLoader(mImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
|
||||||
|
// Force 3.5 inch disk icon instead of .getIconId()
|
||||||
|
// TODO: Could also show a special zipfile icon...?
|
||||||
|
builder.setIcon(R.drawable.ic_menu_save);
|
||||||
|
builder.setTitle(mImage.getTitle());
|
||||||
|
|
||||||
|
if (mTitles.size() == 0) {
|
||||||
|
builder.setMessage(R.string.zipfile_nomatches);
|
||||||
|
builder.setPositiveButton(R.string.dialog_ok,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int button) {
|
||||||
|
dismiss();
|
||||||
|
forceDiskLoaderError();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
builder.setItems(mTitles.toArray(new String[0]), new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int item) {
|
||||||
|
dismiss();
|
||||||
|
mImage.extract_filename = mFiles.get(item);
|
||||||
|
((KegsMain)getActivity()).runDiskLoader(mImage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
super.onCancel(dialog);
|
||||||
|
forceDiskLoaderError();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user