From f7432b5481cfe180c560288fa42e7ab8f494e3db Mon Sep 17 00:00:00 2001 From: James Sanford Date: Sun, 28 Oct 2012 00:14:52 -0700 Subject: [PATCH] Initial support for downloaded images. --- assets/boot_slot_5 | 5 -- assets/boot_slot_7 | 5 -- src/com/froop/app/kegs/AssetImages.java | 45 +++++++----- src/com/froop/app/kegs/ConfigFile.java | 34 +++++---- src/com/froop/app/kegs/CopyHelper.java | 19 +++-- src/com/froop/app/kegs/KegsMain.java | 70 ++++++++++++++++--- .../froop/app/kegs/diskimage/DiskImage.java | 23 ++++++ .../app/kegs/diskimage/DiskImageFragment.java | 15 +++- .../app/kegs/diskimage/DownloadImage.java | 49 +++++++++++++ 9 files changed, 207 insertions(+), 58 deletions(-) create mode 100644 src/com/froop/app/kegs/diskimage/DiskImage.java create mode 100644 src/com/froop/app/kegs/diskimage/DownloadImage.java diff --git a/assets/boot_slot_5 b/assets/boot_slot_5 index 2e1a772..4a518ac 100644 --- a/assets/boot_slot_5 +++ b/assets/boot_slot_5 @@ -1,8 +1,3 @@ - -g_limit_speed = 2 - -s5d1 = XMAS_DEMO.2MG - bram1[00] = 00 00 00 01 00 00 0d 06 02 01 01 00 01 00 00 00 bram1[10] = 00 00 07 06 02 01 01 00 00 00 0f 06 06 00 05 06 bram1[20] = 01 00 00 00 00 00 00 01 05 00 00 00 03 02 02 02 diff --git a/assets/boot_slot_7 b/assets/boot_slot_7 index 3e54837..ca3d617 100644 --- a/assets/boot_slot_7 +++ b/assets/boot_slot_7 @@ -1,8 +1,3 @@ - -g_limit_speed = 3 - -s7d1 = System 6.hdv - bram1[00] = 00 00 00 01 00 00 0d 06 02 01 01 00 01 00 00 00 bram1[10] = 00 00 07 06 02 01 01 00 00 00 0f 06 06 00 05 06 bram1[20] = 01 00 00 00 00 00 00 01 07 00 00 00 03 02 02 02 diff --git a/src/com/froop/app/kegs/AssetImages.java b/src/com/froop/app/kegs/AssetImages.java index 8468490..c16cc84 100644 --- a/src/com/froop/app/kegs/AssetImages.java +++ b/src/com/froop/app/kegs/AssetImages.java @@ -3,43 +3,50 @@ package com.froop.app.kegs; import android.util.Log; import android.os.AsyncTask; +import java.io.File; + class AssetImages extends AsyncTask { interface AssetsReady { - void onAssetsReady(boolean success); + void onAssetsReady(boolean result); } - private KegsMain mContext; + private AssetsReady mNotify; private ConfigFile mConfigFile; - AssetImages(KegsMain context, ConfigFile config) { - mContext = context; + AssetImages(AssetsReady notify, ConfigFile config) { + mNotify = notify; mConfigFile = config; } + private void checkOldImagePath(String filename) { + final File oldPath = new File(mConfigFile.getConfigPath(), filename); + final File newPath = new File(mConfigFile.getImagePath(), filename); + if (oldPath != null && oldPath.exists()) { + new File(mConfigFile.getImagePath()).mkdirs(); + oldPath.renameTo(newPath); + } + } + protected void onPreExecute() { + // We used to drop images directly into the config dir. + // Make sure any images in the config dir get moved to the images dir. + checkOldImagePath("XMAS_DEMO.2MG"); + checkOldImagePath("System 6.hdv"); } protected Boolean doInBackground(Void... params) { - mConfigFile.ensureAssetCopied("XMAS_DEMO.2MG"); - mConfigFile.ensureAssetCopied("System 6 Shareware.zip", - "System 6.hdv"); + mConfigFile.ensureAssetCopied(mConfigFile.getImagePath(), "XMAS_DEMO.2MG"); + mConfigFile.ensureAssetCopied(mConfigFile.getImagePath(), + "System 6 Shareware.zip", "System 6.hdv"); // TODO: could check to make sure they actually exist now. - -// For testing: -// try { Thread.sleep(20000); } catch (InterruptedException e) {} - return true; } - protected void onCancelled(final Boolean success) { - mContext.runOnUiThread(new Runnable() { - public void run() { mContext.onAssetsReady(false); } - }); + protected void onCancelled(final Boolean result) { + mNotify.onAssetsReady(false); } - protected void onPostExecute(final Boolean success) { - mContext.runOnUiThread(new Runnable() { - public void run() { mContext.onAssetsReady(success); } - }); + protected void onPostExecute(final Boolean result) { + mNotify.onAssetsReady(result); } } diff --git a/src/com/froop/app/kegs/ConfigFile.java b/src/com/froop/app/kegs/ConfigFile.java index bb74252..93b74fe 100644 --- a/src/com/froop/app/kegs/ConfigFile.java +++ b/src/com/froop/app/kegs/ConfigFile.java @@ -31,9 +31,13 @@ class ConfigFile { return mConfigPath; } - public void ensureAssetCopied(String zipfile, String exampleFile) { + public String getImagePath() { + return mConfigPath + "/images"; + } + + public void ensureAssetCopied(String destPath, String zipfile, String exampleFile) { // We only check for a local copy of a single file before unzipping... - final File local_copy = new File(mConfigPath, exampleFile); + final File local_copy = new File(destPath, exampleFile); if (local_copy != null && local_copy.exists()) { // Assume that whatever is there will work. return; @@ -44,8 +48,8 @@ class ConfigFile { ZipInputStream zipStream = new ZipInputStream(new BufferedInputStream(mContext.getAssets().open(zipfile))); ZipEntry zipEntry; while ((zipEntry = zipStream.getNextEntry()) != null) { - new CopyHelper(zipStream, false, - mConfigPath, zipEntry.getName()).copy(); + new CopyHelper(zipStream, destPath, + zipEntry.getName()).withClose(false).copy(); } } catch (java.io.IOException e) { // KEGS will just fail. @@ -54,9 +58,9 @@ class ConfigFile { } } - public void ensureAssetCopied(String assetName) { + public void ensureAssetCopied(String destPath, String assetName) { // Make sure there's a user-readable copy of whatever from assets. - final File local_copy = new File(mConfigPath, assetName); + final File local_copy = new File(destPath, assetName); if (local_copy != null && local_copy.exists()) { // Assume that whatever is there will work. return; @@ -64,7 +68,7 @@ class ConfigFile { try { new CopyHelper(mContext.getAssets().open(assetName), - mConfigPath, assetName).copy(); + destPath, assetName).copy(); } catch (java.io.IOException e) { // KEGS will just fail. Log.e("kegs", Log.getStackTraceString(e)); @@ -73,7 +77,7 @@ class ConfigFile { } public void defaultConfig() { - ensureAssetCopied(mConfigDefault); + ensureAssetCopied(mConfigPath, mConfigDefault); // Then, copy whatever is there over to the actual 'config.kegs' file. try { new CopyHelper(new FileInputStream(new File(mConfigPath, mConfigDefault)), @@ -85,11 +89,17 @@ class ConfigFile { } } - public void internalConfig(String configName) { - // Overwrite 'config.kegs' with a config from the assets directory. + public byte[] getConfigPreface(final DiskImage image) { + return String.format("g_limit_speed = %d\n%s = %s/%s\n\n", + image.speed, image.drive, + getImagePath(), image.filename).getBytes(); + } + + public void setConfig(DiskImage image) { + // Overwrite 'config.kegs' with a config based on a template. try { - new CopyHelper(mContext.getAssets().open(configName), - mConfigPath, mConfigFile).copy(); + new CopyHelper(mContext.getAssets().open(image.template), mConfigPath, + mConfigFile).withPreface(getConfigPreface(image)).copy(); } catch (java.io.IOException e) { // KEGS will just fail. Log.e("kegs", Log.getStackTraceString(e)); diff --git a/src/com/froop/app/kegs/CopyHelper.java b/src/com/froop/app/kegs/CopyHelper.java index 47e6f9f..0e48883 100644 --- a/src/com/froop/app/kegs/CopyHelper.java +++ b/src/com/froop/app/kegs/CopyHelper.java @@ -6,21 +6,29 @@ import java.io.InputStream; import java.io.FileOutputStream; public class CopyHelper { + private byte[] mPreface; private InputStream mInput; private boolean mClose; private String mDir; private String mFile; private static final String mTmp = "tmp_"; - CopyHelper(InputStream input, boolean close, String dir, String filename) { + CopyHelper(InputStream input, String dir, String filename) { + mPreface = null; mInput = input; - mClose = close; + mClose = true; mDir = dir; mFile = filename; } - CopyHelper(InputStream input, String dir, String filename) { - this(input, true, dir, filename); + public CopyHelper withPreface(byte[] preface) { + mPreface = preface; + return this; + } + + public CopyHelper withClose(boolean close) { + mClose = close; + return this; } // This leaves a partial temporary file on error and doesn't let you know @@ -43,6 +51,9 @@ public class CopyHelper { byte buf[] = new byte[4096]; FileOutputStream out = new FileOutputStream(output_file); + if (mPreface != null) { + out.write(mPreface, 0, mPreface.length); + } do { int numread = mInput.read(buf); if (numread <= 0) { diff --git a/src/com/froop/app/kegs/KegsMain.java b/src/com/froop/app/kegs/KegsMain.java index 07daf9c..86d1992 100644 --- a/src/com/froop/app/kegs/KegsMain.java +++ b/src/com/froop/app/kegs/KegsMain.java @@ -24,7 +24,7 @@ import com.actionbarsherlock.app.SherlockDialogFragment; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; -public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.StickyReset, AssetImages.AssetsReady { +public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.StickyReset, AssetImages.AssetsReady, DownloadImage.DownloadReady { private static final String FRAGMENT_ROM = "rom"; private static final String FRAGMENT_DOWNLOAD = "download"; private static final String FRAGMENT_ERROR = "error"; @@ -43,6 +43,9 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S private TouchJoystick mJoystick; private boolean mAssetsReady = false; + private boolean mDownloadReady = false; + private boolean mDownloadAborted = false; + private boolean mModeMouse = true; private long mScreenSizeTime = 0; @@ -99,34 +102,75 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S } public void onAssetsReady(boolean success) { + // TODO FIXME: this needs to throw an error if it fails. mAssetsReady = success; } - private void loadConfigWhenReady(final String configfile) { + public void onDownloadReady(boolean success) { + // TODO FIXME: this needs to throw an error if it fails. + mDownloadReady = success; + } + + private void loadDiskImageWhenReady(final DiskImage image) { final AssetFragment frag = (AssetFragment)getSupportFragmentManager().findFragmentByTag(FRAGMENT_ASSET); - if (!getThread().nowWaitingForPowerOn() || !mAssetsReady) { - if (frag == null && !mAssetsReady) { + // This code is lame. + if (mDownloadAborted) { + if (frag != null) { + frag.dismiss(); + } + if (image.primary) { + getThread().allowPowerOn(); + } + return; // don't schedule another pass. + } + + boolean nativeReady; + if (image.primary) { + nativeReady = getThread().nowWaitingForPowerOn(); + } else { + nativeReady = true; + } + + if (!nativeReady || !mAssetsReady || !mDownloadReady) { + 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() { - public void run() { loadConfigWhenReady(configfile); } + public void run() { loadDiskImageWhenReady(image); } }, 100); } else { if (frag != null) { frag.dismiss(); } - mConfigFile.internalConfig(configfile); - getThread().allowPowerOn(); + if (image.primary) { + mConfigFile.setConfig(image); + getThread().allowPowerOn(); + } else { + // TODO FIXME: eject/insert the new disk. + } } } - protected void loadConfig(String configfile) { - getThread().doPowerOff(); - loadConfigWhenReady(configfile); + protected void loadDiskImage(DiskImage image) { + if (image.primary) { + getThread().doPowerOff(); + } + + mDownloadReady = false; + mDownloadAborted = false; + + 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(); + } + + loadDiskImageWhenReady(image); } protected void getRomFile(String romfile) { @@ -230,6 +274,12 @@ public class KegsMain extends SherlockFragmentActivity implements KegsKeyboard.S dialog.setCanceledOnTouchOutside(false); return dialog; } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + mDownloadAborted = true; + } } public KegsThread getThread() { diff --git a/src/com/froop/app/kegs/diskimage/DiskImage.java b/src/com/froop/app/kegs/diskimage/DiskImage.java new file mode 100644 index 0000000..5263fec --- /dev/null +++ b/src/com/froop/app/kegs/diskimage/DiskImage.java @@ -0,0 +1,23 @@ +package com.froop.app.kegs; + +class DiskImage { + 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_7 = "boot_slot_7"; + + public boolean primary = true; + public String filename; + public String drive; + public int speed; + public String template; + + // Example: + // DiskImage("XMAS_DEMO.2MG", "s5d1", 2, "boot_slot_5"); + public DiskImage(final String filename, final String drive, + final int speed, final String template) { + this.filename = filename; + this.drive = drive; + this.speed = speed; + this.template = template; + } +} diff --git a/src/com/froop/app/kegs/diskimage/DiskImageFragment.java b/src/com/froop/app/kegs/diskimage/DiskImageFragment.java index 6a85ae6..60f9213 100644 --- a/src/com/froop/app/kegs/diskimage/DiskImageFragment.java +++ b/src/com/froop/app/kegs/diskimage/DiskImageFragment.java @@ -19,7 +19,7 @@ import com.actionbarsherlock.app.SherlockDialogFragment; public class DiskImageFragment extends SherlockDialogFragment { private String[] mImages = { - "System 6", "X-MAS Demo (FTA)"}; + "System 6", "X-MAS Demo (FTA)", "Prince of Persia"}; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { @@ -29,10 +29,19 @@ public class DiskImageFragment extends SherlockDialogFragment { builder.setItems(mImages, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { dismiss(); + DiskImage image = null; + if (item == 0) { - ((KegsMain)getActivity()).loadConfig("boot_slot_7"); + image = new DiskImage("System 6.hdv", "s7d1", 3, DiskImage.BOOT_SLOT_7); } else if (item == 1) { - ((KegsMain)getActivity()).loadConfig("boot_slot_5"); + image = new DiskImage("XMAS_DEMO.2MG", "s5d1", 2, DiskImage.BOOT_SLOT_5); + } else if (item == 2) { + // TODO: There should be an adapter on the ListView instead. + image = new DiskImage("prince.2mg", "s5d1", 2, DiskImage.BOOT_SLOT_5); + } + + if (image != null) { + ((KegsMain)getActivity()).loadDiskImage(image); } } }); diff --git a/src/com/froop/app/kegs/diskimage/DownloadImage.java b/src/com/froop/app/kegs/diskimage/DownloadImage.java new file mode 100644 index 0000000..3571340 --- /dev/null +++ b/src/com/froop/app/kegs/diskimage/DownloadImage.java @@ -0,0 +1,49 @@ +package com.froop.app.kegs; + +import android.util.Log; +import android.os.AsyncTask; + +import java.io.File; + +class DownloadImage extends AsyncTask { + interface DownloadReady { + void onDownloadReady(boolean result); + } + + private DownloadReady mNotify; + private DiskImage mImage; + private File mDest; + + DownloadImage(DownloadReady notify, String imagePath, DiskImage image) { + mNotify = notify; + mImage = image; + mDest = new File(imagePath + "/" + mImage.filename); + + if (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 (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); + } +}