diff --git a/JGE/Dependencies/SDL/src/main/android/SDL_android_main.cpp b/JGE/Dependencies/SDL/src/main/android/SDL_android_main.cpp
index 2b9749bff..442363e1b 100644
--- a/JGE/Dependencies/SDL/src/main/android/SDL_android_main.cpp
+++ b/JGE/Dependencies/SDL/src/main/android/SDL_android_main.cpp
@@ -1,6 +1,7 @@
/* Include the SDL main definition header */
#include "SDL_main.h"
+#include "JGE.h"
/*******************************************************************************
Functions called by JNI
@@ -13,6 +14,8 @@ extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls);
// Library init
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
+ JGE *mEngine = JGE::GetInstance();
+ mEngine->setJVM(vm);
return JNI_VERSION_1_4;
}
diff --git a/JGE/include/JGE.h b/JGE/include/JGE.h
index d723d350e..8168821f3 100644
--- a/JGE/include/JGE.h
+++ b/JGE/include/JGE.h
@@ -126,6 +126,7 @@ class JGE
#endif
#if defined (ANDROID)
+ JavaVM * mJavaVM;
JNIEnv * mJNIEnv;
jclass mJNIClass;
jmethodID midSendCommand;
@@ -164,6 +165,10 @@ class JGE
static JGE* GetInstance();
static void Destroy();
+#ifdef ANDROID
+ JNIEnv * getJNIEnv();
+ void setJVM (JavaVM * vm);
+#endif
void Init();
void End();
@@ -377,6 +382,7 @@ class JGE
/// Access to JNI Environment
void SetJNIEnv(JNIEnv * env, jclass cls);
void sendJNICommand(std::string command);
+ std::string getFileSystemLocation();
#endif
protected:
diff --git a/JGE/include/JSoundSystem.h b/JGE/include/JSoundSystem.h
index 56bb335c2..a1a88e271 100644
--- a/JGE/include/JSoundSystem.h
+++ b/JGE/include/JSoundSystem.h
@@ -82,6 +82,7 @@ public:
SLObjectItf playerObject;
SLPlayItf playInterface;
SLSeekItf seekInterface;
+ SLVolumeItf musicVolumeInterface;
#else
void* mTrack;
#endif //WITH_FMOD
@@ -115,6 +116,7 @@ class JSample
#elif defined ANDROID
SLObjectItf playerObject;
SLPlayItf playInterface;
+ SLVolumeItf sampleVolumeInterface;
void* mSample;
#else
void* mSample;
@@ -242,9 +244,8 @@ protected:
private:
-#ifdef WIN32
JMusic *mCurrentMusic;
-#endif
+ JSample *mCurrentSample;
int mVolume;
int mMusicVolume;
diff --git a/JGE/src/JFileSystem.cpp b/JGE/src/JFileSystem.cpp
index a42336a33..7f4699582 100644
--- a/JGE/src/JFileSystem.cpp
+++ b/JGE/src/JFileSystem.cpp
@@ -16,6 +16,9 @@ User folder is the only one that is really needed to guarantee both read and wri
The content that users should not be touching.
*/
+#if defined(ANDROID)
+#include "../../include/PrecompiledHeader.h"
+#endif
#ifdef WIN32
#pragma warning(disable : 4786)
@@ -113,8 +116,10 @@ JFileSystem::JFileSystem(const string & _userPath, const string & _systemPath)
systemPath = [[documentsDirectory stringByAppendingString: @"/Res/"] cStringUsingEncoding:1];
#elif defined (ANDROID)
- userPath = "/sdcard/Wagic/Res/";
+ userPath = JGE::GetInstance()->getFileSystemLocation();
systemPath = "";
+
+ DebugTrace("User path " << userPath);
#elif defined (QT_CONFIG)
QDir dir(QDir::homePath());
dir.cd(USERDIR);
@@ -165,7 +170,7 @@ JFileSystem::JFileSystem(const string & _userPath, const string & _systemPath)
systemPath += '/';
}
- mUserFSPath = userPath;
+ mUserFSPath = userPath;
MAKEDIR(userPath.c_str());
mSystemFSPath = systemPath;
@@ -178,6 +183,7 @@ JFileSystem::JFileSystem(const string & _userPath, const string & _systemPath)
mPassword = NULL;
mFileSize = 0;
mCurrentFileInZip = NULL;
+
};
void JFileSystem::Destroy()
diff --git a/JGE/src/JGE.cpp b/JGE/src/JGE.cpp
index de5af017d..349ee200d 100644
--- a/JGE/src/JGE.cpp
+++ b/JGE/src/JGE.cpp
@@ -619,48 +619,68 @@ void JGE::SendCommand(std::string command, float& x, float& y, float& width, flo
#if defined (ANDROID)
-int getJNIEnv(JNIEnv *env)
+JNIEnv * JGE::getJNIEnv()
{
+ JNIEnv *env;
int status = mJavaVM->GetEnv((void **)&env, JNI_VERSION_1_4);
- if(status < 0)
+ if(status == JNI_ERR)
{
DebugTrace("Failed to get JNI environment, assuming native thread");
status = mJavaVM->AttachCurrentThread(&env, NULL);
- if(status < 0)
+ if(status == JNI_ERR)
{
- LogNativeToAndroidExt("callback_handler: failed to attach current thread");
- return JNI_ERR;
+ DebugTrace("callback_handler: failed to attach current thread");
+ return NULL;
}
}
-
- return JNI_VERSION_1_4;
+ else if (status == JNI_EDETACHED)
+ {
+ DebugTrace("env is detached. trying to attach it to the current thread");
+ jint attachSuccess = mJavaVM->AttachCurrentThread(&env,NULL);
+ if(attachSuccess == 0)
+ {
+ return env;
+ }
+ else
+ {
+ return NULL;
+ }//end if/els
+ }
+ else if (status == JNI_OK)
+ {
+ return env;
+ }
+
+ return NULL;
}
string JGE::getFileSystemLocation()
{
char result[512];
- JNIEnv * env;
- if (getJNIEnv(env) == JNI_ERR)
+ JNIEnv * env = getJNIEnv();
+ if (env == NULL)
{
DebugTrace("An Error Occurred in getting the JNI Environment whie trying to get the system folder location. Defaulting to /mnt/sdcard/net.wagic.app/Wagic");
return "/mnt/sdcard/net.wagic.app/Wagic";
};
- jmethodID methodId = env->GetStaticMethodID(mJNIClass, "getSystemFolderPath", "()Ljava/lang/String;");
+
+ jclass jniClass = env->FindClass("org/libsdl/app/SDLActivity");
+ jmethodID methodId = env->GetStaticMethodID( jniClass, "getSystemFolderPath", "()Ljava/lang/String;");
+
if (methodId == 0)
{
DebugTrace("An Error Occurred in getting the JNI methodID for getSystemFolderPath. Defaulting to /mnt/sdcard/net.wagic.app/Wagic");
return "/mnt/sdcard/net.wagic.app/Wagic";
};
-
- jstring systemPath = (jstring) env->CallStaticObjectMethod(mJNIClass, methodId);
- string retVal = "/mnt/sdcard/net.wagic.app/Wagic/";
- // Now convert the Java String to C++ char array
+
+ jstring systemPath = (jstring) env->CallStaticObjectMethod(jniClass, methodId);
+
+ // Now convert the Java String to C++ char array
const char* cstr = env->GetStringUTFChars(systemPath, 0);
- string val (cstr);
- retVal = val;
+ string retVal (cstr);
env->ReleaseStringUTFChars(systemPath, cstr);
- env->DeleteLocalRef(systemPath);
-
+ env->DeleteLocalRef(systemPath);
+
return retVal;
}
@@ -672,6 +692,11 @@ void JGE::SetJNIEnv(JNIEnv * env, jclass cls)
midSendCommand = mJNIEnv->GetStaticMethodID(mJNIClass,"jgeSendCommand","(Ljava/lang/String;)V");
}
+void JGE::setJVM( JavaVM *vm)
+{
+ mJavaVM = vm;
+}
+
void JGE::sendJNICommand(string command)
{
if (midSendCommand) {
diff --git a/JGE/src/android/JSfx.cpp b/JGE/src/android/JSfx.cpp
index f75a391ea..dec8039b6 100644
--- a/JGE/src/android/JSfx.cpp
+++ b/JGE/src/android/JSfx.cpp
@@ -22,7 +22,7 @@ static SLObjectItf outputMixObject = NULL;
//////////////////////////////////////////////////////////////////////////
JMusic::JMusic()
- : playerObject(0), playInterface(0), seekInterface(0)
+ : playerObject(0), playInterface(0), seekInterface(0), musicVolumeInterface(0)
{
}
@@ -42,6 +42,7 @@ JMusic::~JMusic()
playerObject = NULL;
playInterface = NULL;
seekInterface = NULL;
+ musicVolumeInterface = NULL;
}
}
@@ -194,9 +195,13 @@ JMusic *JSoundSystem::LoadMusic(const char *fileName)
DebugTrace("result " << result);
// get the volume interface
- //result = (*music->playerObject)->GetInterface(music->playerObject, SL_IID_VOLUME, &musicVolumeInterface);
+ //result = (*music->playerObject)->GetInterface(music->playerObject, SL_IID_VOLUME, (void *)&music->musicVolumeInterface);
+
DebugTrace("result " << result);
}
+
+ mCurrentMusic = music;
+
return music;
}
@@ -207,6 +212,8 @@ void JSoundSystem::PlayMusic(JMusic *music, bool looping)
{
SLresult result;
+ //(*music->musicVolumeInterface)->SetVolumeLevel(music->musicVolumeInterface, -1 * mVolume);
+
// enable whole file looping
result = (*music->seekInterface)->SetLoop(music->seekInterface,
looping?SL_BOOLEAN_TRUE:SL_BOOLEAN_FALSE, 0, SL_TIME_UNKNOWN);
@@ -250,10 +257,13 @@ void JSoundSystem::SetVolume(int volume)
void JSoundSystem::SetMusicVolume(int volume)
{
mVolume = volume;
+ //(*mCurrentMusic->musicVolumeInterface)->SetVolumeLevel(mCurrentMusic->musicVolumeInterface, -1 * mVolume);
}
void JSoundSystem::SetSfxVolume(int volume){
mSampleVolume = volume;
+
+ //(*mCurrentSample->sampleVolumeInterface)->SetVolumeLevel(mCurrentSample->sampleVolumeInterface, -1 * mSampleVolume);
SetMusicVolume(mVolume);
}
@@ -296,8 +306,11 @@ JSample *JSoundSystem::LoadSample(const char *fileName)
DebugTrace("result " << result);
// get the volume interface
- //result = (*sample->playerObject)->GetInterface(sample->playerObject, SL_IID_VOLUME, &sampleVolumeInterface);
+ //result = (*sample->playerObject)->GetInterface(sample->playerObject, SL_IID_VOLUME, &sample->sampleVolumeInterface);
}
+
+ mCurrentSample = sample;
+
return sample;
}
@@ -307,7 +320,7 @@ void JSoundSystem::PlaySample(JSample *sample)
if(sample && sample->playerObject && sample->playInterface)
{
SLresult result;
-
+ //(*sample->sampleVolumeInterface)->SetVolumeLevel(sample->sampleVolumeInterface, mSampleVolume);
result = (*sample->playInterface)->SetPlayState(sample->playInterface,
SL_PLAYSTATE_PLAYING);
}
diff --git a/projects/mtg/Android/AndroidManifest.xml b/projects/mtg/Android/AndroidManifest.xml
index 60cb3cf32..05d083ba8 100644
--- a/projects/mtg/Android/AndroidManifest.xml
+++ b/projects/mtg/Android/AndroidManifest.xml
@@ -17,9 +17,8 @@
-
+
-
+
diff --git a/projects/mtg/Android/default.properties b/projects/mtg/Android/default.properties
index 9a2c9f6c8..bdc22130b 100644
--- a/projects/mtg/Android/default.properties
+++ b/projects/mtg/Android/default.properties
@@ -8,4 +8,4 @@
# project structure.
# Project target.
-target=android-9
+target=Google Inc.:Google APIs:11
diff --git a/projects/mtg/Android/res/values/strings.xml b/projects/mtg/Android/res/values/strings.xml
index 15ce3c190..6caf40600 100644
--- a/projects/mtg/Android/res/values/strings.xml
+++ b/projects/mtg/Android/res/values/strings.xml
@@ -1,4 +1,5 @@
Wagic
+ Wagic v0.180\\nAll Rights Reserved.
diff --git a/projects/mtg/Android/src/net/wagic/utils/StorageOptions.java b/projects/mtg/Android/src/net/wagic/utils/StorageOptions.java
new file mode 100644
index 000000000..6802b2062
--- /dev/null
+++ b/projects/mtg/Android/src/net/wagic/utils/StorageOptions.java
@@ -0,0 +1,137 @@
+package net.wagic.utils;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+public class StorageOptions {
+ private static ArrayList mMounts = new ArrayList();
+ private static ArrayList mVold = new ArrayList();
+
+ public static String[] labels;
+ public static String[] paths;
+ public static int count = 0;
+
+ public static void determineStorageOptions() {
+ readMountsFile();
+ readVoldFile();
+ compareMountsWithVold();
+ testAndCleanMountsList();
+ setProperties();
+ }
+ private static void readMountsFile() {
+ /*
+ * Scan the /proc/mounts file and look for lines like this:
+ * /dev/block/vold/179:1 /mnt/sdcard vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0602,dmask=0602,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0
+ *
+ * When one is found, split it into its elements
+ * and then pull out the path to the that mount point
+ * and add it to the arraylist
+ */
+
+ try {
+ Scanner scanner = new Scanner(new File("/proc/mounts"));
+ while (scanner.hasNext()) {
+ String line = scanner.nextLine();
+ if (line.startsWith("/dev/block/vold/")) {
+ String[] lineElements = line.split(" ");
+ lineElements[1].replaceAll(":.*$", "");
+ mMounts.add(lineElements[1]);
+ }
+ }
+ } catch (Exception e) {
+ // Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private static void readVoldFile() {
+ /*
+ * Scan the /system/etc/vold.fstab file and look for lines like this:
+ * dev_mount sdcard /mnt/sdcard 1 /devices/platform/s3c-sdhci.0/mmc_host/mmc0
+ *
+ * When one is found, split it into its elements
+ * and then pull out the path to the that mount point
+ * and add it to the arraylist
+ */
+
+ try {
+ Scanner scanner = new Scanner(new File("/system/etc/vold.fstab"));
+ while (scanner.hasNext()) {
+ String line = scanner.nextLine();
+ if (line.startsWith("dev_mount")) {
+ String[] lineElements = line.split(" ");
+ lineElements[2] = lineElements[2].replaceAll(":.*$", "");
+ mVold.add(lineElements[2]);
+ }
+ }
+ } catch (Exception e) {
+ // Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private static void compareMountsWithVold() {
+ /*
+ * Sometimes the two lists of mount points will be different.
+ * We only want those mount points that are in both list.
+ *
+ * Compare the two lists together and remove items that are not in both lists.
+ */
+
+ for (int i = 0; i < mMounts.size(); i++) {
+ String mount = mMounts.get(i);
+ if (!mVold.contains(mount))
+ mMounts.remove(i--);
+ }
+
+ // donŐt need this anymore, clear the vold list to reduce memory
+ // use and to prepare it for the next time itŐs needed.
+ mVold.clear();
+ }
+
+ private static void testAndCleanMountsList() {
+ /*
+ * Now that we have a cleaned list of mount paths
+ * Test each one to make sure itŐs a valid and
+ * available path. If it is not, remove it from
+ * the list.
+ */
+
+ for (int i = 0; i < mMounts.size(); i++) {
+ String mount = mMounts.get(i);
+ File root = new File(mount);
+ if (!root.exists() || !root.isDirectory() || !root.canWrite())
+ mMounts.remove(i--);
+ }
+ }
+
+ private static void setProperties() {
+ /*
+ * At this point all the paths in the list should be
+ * valid. Build the public properties.
+ */
+
+ ArrayList mLabels = new ArrayList();
+
+ int i = 1;
+ for (String path: mMounts)
+ {
+ if ("/mnt/sdcard".equalsIgnoreCase(path))
+ mLabels.add("Built-in Storage");
+ else
+ mLabels.add("External SD Card " + i++);
+ }
+
+ labels = new String[mLabels.size()];
+ mLabels.toArray(labels);
+
+ paths = new String[mMounts.size()];
+ mMounts.toArray(paths);
+
+ count = Math.min(labels.length, paths.length);
+
+ // donŐt need this anymore, clear the mounts list to reduce memory
+ // use and to prepare it for the next time itŐs needed.
+ mMounts.clear();
+ }
+}
\ No newline at end of file
diff --git a/projects/mtg/Android/src/org/libsdl/app/SDLActivity.java b/projects/mtg/Android/src/org/libsdl/app/SDLActivity.java
index 6f306c1f4..e3d9efd9c 100644
--- a/projects/mtg/Android/src/org/libsdl/app/SDLActivity.java
+++ b/projects/mtg/Android/src/org/libsdl/app/SDLActivity.java
@@ -1,17 +1,28 @@
package org.libsdl.app;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
+import net.wagic.app.R;
+import net.wagic.utils.StorageOptions;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.hardware.Sensor;
@@ -29,31 +40,30 @@ import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.SubMenu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.View.OnKeyListener;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
-import com.google.ads.*;
-
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.net.URLConnection;
+import com.google.ads.AdRequest;
+import com.google.ads.AdSize;
+import com.google.ads.AdView;
/**
SDL Activity
*/
-public class SDLActivity extends Activity {
+public class SDLActivity extends Activity implements OnKeyListener{
+ // TAG used for debugging in DDMS
+ public static String TAG = Activity.class.getCanonicalName();
// Main components
private static AdView mAdView;
@@ -74,9 +84,220 @@ public class SDLActivity extends Activity {
public final static String RES_FOLDER = "/sdcard/Wagic/Res/";
public static final String RES_FILENAME = "core_0180.zip";
public static final String RES_URL = "http://wagic.googlecode.com/files/";
-
+
+ public String systemFolder = "/sdcard/Wagic/Res/";
+ private String userFolder;
+
+ // path to the onboard sd card that is not removable (typically /mnt/sdcard )
+ private String internalPath;
+ // path to removable sd card (on motorala devices /mnt/sdcard-ext, samsung devices: /mnt/sdcard/external_sd )
+ private String sdcardPath;
+
+ // Android only supports internal memory and internal sdcard. removable media is not currently accessible via API
+ // using StorageOptions for now gives us a temporary interface to scan all available mounted drives.
+ private Context mContext;
+
+ // Preferences
+ public static final String kWagicSharedPreferencesKey = "net.wagic.app.preferences.wagic";
+ public static final String kStoreDataOnRemovableSdCardPreference = "StoreDataOnRemovableStorage";
+ public static final String kSaveDataPathPreference = "StorageDataLocation";
+ public static final String kWagicDataStorageOptionsKey = "dataStorageOptions";
+ public static final int kStorageDataOptionsMenuId = 2000;
+ public static final int kOtherOptionsMenuId = 3000;
+
+ //Accessors
+ public String getSystemStorageLocation() {
+ return systemFolder;
+ }
+
+ public String getUserStorageLocation() {
+ return userFolder;
+ }
+
+ //setters
+ public void updateStorageLocations() {
+ boolean usesInternalSdCard = (!getSharedPreferences(kWagicSharedPreferencesKey, MODE_PRIVATE).getBoolean(kStoreDataOnRemovableSdCardPreference, false)) && Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
+
+ systemFolder = (usesInternalSdCard ? sdcardPath : internalPath) + "/Res/";
+ userFolder = (usesInternalSdCard ? sdcardPath : internalPath) + "/User/";
+ }
+
+ /**
+ * checks to see if the device has a memory card to write to that is in a valid state.
+ *
+ * @return true if the device can write to the sdcard, false if not.
+ */
+ public boolean checkStorageState()
+ {
+ SharedPreferences settings = getSharedPreferences(kWagicSharedPreferencesKey, MODE_PRIVATE);
+ boolean useSdCard = (!settings.getBoolean(kStoreDataOnRemovableSdCardPreference, false)) && Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
+ String systemStoragePath = getSystemStorageLocation();
+
+ if (useSdCard && (systemStoragePath.indexOf(sdcardPath) != -1))
+ {
+ Log.i(TAG, "Data will be written to sdcard.");
+ return true;
+ }
+
+ if (!useSdCard && (systemStoragePath.indexOf(internalPath) != -1))
+ {
+ Log.i(TAG, "Data will be written to internal storage.");
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean getRemovableMediaStorageState()
+ {
+ for (String extMediaPath: StorageOptions.paths)
+ {
+ File mediaPath = new File(extMediaPath);
+ if (mediaPath.canWrite())
+ return true;
+ }
+
+ return false;
+ }
+
+
+ private void displayStorageOptions()
+ {
+ AlertDialog.Builder setStorage = new AlertDialog.Builder(this);
+ setStorage.setTitle("Where would you like to store your data? On your removable SD Card or the built-in memory?");
+ StorageOptions.determineStorageOptions();
+ setStorage.setSingleChoiceItems(StorageOptions.labels, -1, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ savePathPreference(item);
+ }
+ });
+
+ setStorage.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ initStorage();
+ if (mSurface == null)
+ mSingleton.initializeGame();
+ }
+ });
+
+ setStorage.create().show();
+ }
+
+
+ private void checkStorageLocationPreference()
+ {
+ SharedPreferences settings = getSharedPreferences(kWagicSharedPreferencesKey, MODE_PRIVATE);
+ final SharedPreferences.Editor prefsEditor = settings.edit();
+ boolean hasRemovableMediaMounted = getRemovableMediaStorageState();
+
+ if ( !settings.contains(kStoreDataOnRemovableSdCardPreference))
+ {
+ if (hasRemovableMediaMounted)
+ {
+ displayStorageOptions();
+ }
+ else
+ {
+ prefsEditor.putBoolean(kStoreDataOnRemovableSdCardPreference, false);
+ prefsEditor.commit();
+ initStorage();
+ mSingleton.initializeGame();
+ }
+ }
+ else
+ {
+ boolean storeOnRemovableMedia = settings.getBoolean(kStoreDataOnRemovableSdCardPreference, false);
+ if ( storeOnRemovableMedia && !hasRemovableMediaMounted )
+ {
+ AlertDialog setStorage = new AlertDialog.Builder(this).create();
+ setStorage.setTitle("Storage Preference");
+ setStorage.setMessage("Removable Sd Card not detected. Saving data to internal memory.");
+
+ prefsEditor.putBoolean(kStoreDataOnRemovableSdCardPreference, false);
+ prefsEditor.commit();
+
+ initStorage();
+ mSingleton.initializeGame();
+ setStorage.show();
+ }
+ else
+ {
+ initStorage();
+ mSingleton.initializeGame();
+ }
+ }
+ }
+
+ private void initStorage()
+ {
+ //check the state of the external storage to ensure we can even write to it.
+ // we are going to assume that if an external location exists, and can be written to, use it.
+ // Otherwise use internal storage
+ try
+ {
+ //
+ // initialize where all the files are going to be stored.
+ //
+ File wagicMediaPath = null;
+
+ String packageName = mContext.getPackageName();
+ File externalFilesDir = Environment.getExternalStorageDirectory();
+ if ( externalFilesDir != null) {
+ internalPath = externalFilesDir.getAbsolutePath() + "/" + packageName + "/Wagic";
+ }
+
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state))
+ {
+ wagicMediaPath = new File(internalPath);
+ if (wagicMediaPath.canWrite())
+ wagicMediaPath.mkdirs();
+ }
+
+ // initialize the external mount
+ SharedPreferences settings = getSharedPreferences(kWagicSharedPreferencesKey, MODE_PRIVATE);
+ String selectedRemovableCardPath = settings.getString(kSaveDataPathPreference, internalPath);
+ if (selectedRemovableCardPath != null && !internalPath.equalsIgnoreCase(selectedRemovableCardPath))
+ {
+ wagicMediaPath = new File(selectedRemovableCardPath);
+ if (!wagicMediaPath.exists() || !wagicMediaPath.canWrite() )
+ {
+ Log.e(TAG, "Error in initializing system folder: " + selectedRemovableCardPath);
+ }
+ else
+ { // found a removable media location
+ sdcardPath = selectedRemovableCardPath + "/" + packageName + "/Wagic";
+ }
+ }
+
+ updateStorageLocations();
+ }
+ catch (Exception ioex)
+ {
+ Log.e( "SDL", "An error occurred in setting up the storage locations.");
+ }
+ }
+
+ private void savePathPreference( int selectedOption )
+ {
+ SharedPreferences settings = getSharedPreferences(kWagicSharedPreferencesKey, MODE_PRIVATE);
+ String selectedMediaPath = StorageOptions.paths[selectedOption];
+ final SharedPreferences.Editor prefsEditor = settings.edit();
+ boolean saveToRemovableMedia = !"/mnt/sdcard".equalsIgnoreCase(selectedMediaPath);
+
+ prefsEditor.putBoolean(kStoreDataOnRemovableSdCardPreference, saveToRemovableMedia);
+ prefsEditor.putString(kSaveDataPathPreference, selectedMediaPath);
+ prefsEditor.commit();
+
+ }
+
private void startDownload() {
String url = RES_URL + RES_FILENAME;
+ if ( !checkStorageState())
+ {
+ Log.e(TAG, "Error in initializing storage space.");
+ mSingleton.downloadError("Failed to initialize storage space for game. Please verify that your sdcard or internal memory is mounted properly.");
+ }
new DownloadFileAsync().execute(url);
}
@@ -85,6 +306,49 @@ public class SDLActivity extends Activity {
mErrorMessage = errorMessage;
}
+
+ private void buildStorageOptionsMenu(Menu menu)
+ {
+ StorageOptions.determineStorageOptions();
+ for (int idx = 0; idx < StorageOptions.count; idx++)
+ {
+ menu.add(kStorageDataOptionsMenuId, kStorageDataOptionsMenuId + idx, idx, StorageOptions.labels[idx]);
+ }
+ }
+
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ SubMenu settingsMenu = menu.addSubMenu(Menu.NONE, 1, 1, "Settings");
+ menu.add(Menu.NONE, 2, 2, "About");
+ settingsMenu.add(kStorageDataOptionsMenuId, kStorageDataOptionsMenuId, Menu.NONE, "Storage Data Options");
+// buildStorageOptionsMenu(settingsMenu);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle item selection
+ int itemId = item.getItemId();
+ if ( itemId == kStorageDataOptionsMenuId)
+ {
+ displayStorageOptions();
+ }
+ else if ( itemId == 2)
+ {
+ //display some info about the app
+ AlertDialog.Builder infoDialog = new AlertDialog.Builder(this);
+ infoDialog.setTitle("Wagic Info");
+ infoDialog.setMessage("Version 0.180");
+ infoDialog.show();
+
+ }
+ else
+ return super.onOptionsItemSelected(item);
+ return true;
+ }
+
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
@@ -169,8 +433,18 @@ public class SDLActivity extends Activity {
// So we can call stuff from static callbacks
mSingleton = this;
-
- File file = new File(RES_FOLDER + RES_FILENAME);
+ mContext = this.getApplicationContext();
+
+ StorageOptions.determineStorageOptions();
+ checkStorageLocationPreference();
+ }
+
+ public void initializeGame()
+ {
+ String coreFileLocation = getSystemStorageLocation() + RES_FILENAME;
+
+ File file = new File(coreFileLocation);
+
if (file.exists()) {
mainDisplay();
} else {
@@ -179,9 +453,9 @@ public class SDLActivity extends Activity {
new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
startDownload();
}
-
}
-
+
+
// Events
@Override
protected void onPause() {
@@ -232,7 +506,7 @@ public class SDLActivity extends Activity {
if (msg.arg1 == COMMAND_CHANGE_TITLE) {
setTitle((String)msg.obj);
}
- if (msg.arg1 == COMMAND_JGE_MSG) {
+ else if (msg.arg1 == COMMAND_JGE_MSG) {
processJGEMsg((String)msg.obj);
}
}
@@ -260,9 +534,19 @@ public class SDLActivity extends Activity {
public static native void onNativeAccel(float x, float y, float z);
public static native void nativeRunAudioThread();
-
// Java functions called from C
// Receive a message from the SDLMain thread
+ public static String getSystemFolderPath()
+ {
+ return mSingleton.getSystemStorageLocation();
+ }
+
+ public static String getUserFolderPath()
+ {
+ return mSingleton.getUserStorageLocation();
+ }
+
+
public static void jgeSendCommand(String command) {
mSingleton.sendCommand(COMMAND_JGE_MSG, command);
}
@@ -378,7 +662,9 @@ public class SDLActivity extends Activity {
}
- class DownloadFileAsync extends AsyncTask {
+ class DownloadFileAsync extends AsyncTask {
+ final String TAG1 = DownloadFileAsync.class.getCanonicalName();
+
@Override
protected void onPreExecute() {
super.onPreExecute();
@@ -386,43 +672,47 @@ public class SDLActivity extends Activity {
}
@Override
- protected String doInBackground(String... aurl) {
+ protected Long doInBackground(String... aurl) {
int count;
-
+ long totalBytes = 0;
+ OutputStream output = null;
+ InputStream input = null;
+
try {
//
// Prepare the sdcard folders in order to download the resource file
//
- String state = Environment.getExternalStorageState();
- if (! Environment.MEDIA_MOUNTED.equals(state)) {
- mSingleton.downloadError("cannot write to SD Card, please check your sd card");
- return null;
+
+ String storageLocation = mSingleton.getSystemStorageLocation();
+
+ File resDirectory = new File(storageLocation);
+ File userDirectory = new File(mSingleton.getUserStorageLocation());
+
+ if (!resDirectory.exists() && !resDirectory.mkdirs() || (!userDirectory.exists() && !userDirectory.mkdirs()))
+ {
+ throw new Exception ("Failed to initialize system and user directories.");
}
- File resDirectory = new File(RES_FOLDER); //TODO use getExternalStorageDirectory() and update the C++ code
- resDirectory.mkdirs();
URL url = new URL(aurl[0]);
+ String filename = url.getPath().substring( url.getPath().lastIndexOf( '/') + 1);
URLConnection conexion = url.openConnection();
conexion.connect();
- int lenghtOfFile = conexion.getContentLength();
- Log.d("ANDRO_ASYNC", "Length of file: " + lenghtOfFile);
+ int lengthOfFile = conexion.getContentLength();
+ Log.d("Wagic - " + TAG1, " Length of file: " + lengthOfFile);
- InputStream input = new BufferedInputStream(url.openStream());
+ input = new BufferedInputStream(url.openStream());
// create a File object for the output file
- File outputFile = new File(resDirectory, RES_FILENAME + ".tmp");
+ File outputFile = new File(resDirectory, filename + ".tmp");
- OutputStream output = new FileOutputStream(outputFile);
+ output = new FileOutputStream(outputFile);
byte data[] = new byte[1024];
-
- long total = 0;
-
while ((count = input.read(data)) != -1) {
- total += count;
- publishProgress(""+(int)((total*100)/lenghtOfFile));
+ totalBytes += count;
+ publishProgress((int)((totalBytes*100)/lengthOfFile));
output.write(data, 0, count);
}
@@ -430,33 +720,61 @@ public class SDLActivity extends Activity {
output.close();
input.close();
} catch (Exception e) {
- mSingleton.downloadError("An error happened while downloading the resources. It could be that our server is temporarily down, that your device is not connected to a network, or that we cannot write to " + RES_FOLDER + ". Please check your phone settings and try again. For more help please go to http://wagic.net");
+ String errorMessage = "An error happened while downloading the resources. It could be that our server is temporarily down, that your device is not connected to a network, or that we cannot write to " + mSingleton.getSystemStorageLocation() + ". Please check your phone settings and try again. For more help please go to http://wagic.net";
+ mSingleton.downloadError(errorMessage);
+ Log.e(TAG1, errorMessage);
+ Log.e(TAG1, e.getMessage());
}
- return null;
+
+ return new Long(totalBytes);
}
- protected void onProgressUpdate(String... progress) {
- Log.d("ANDRO_ASYNC",progress[0]);
- mProgressDialog.setProgress(Integer.parseInt(progress[0]));
+ protected void onProgressUpdate(Integer... progress) {
+ if (progress[0] != mProgressDialog.getProgress())
+ {
+ Log.d("Wagic - " + TAG1, "current progress : " + progress[0]);
+ mProgressDialog.setProgress(progress[0]);
+ }
}
@Override
- protected void onPostExecute(String unused) {
+ protected void onPostExecute(Long unused) {
if (mErrorHappened) {
dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
showDialog(DIALOG_DOWNLOAD_ERROR);
return;
}
//rename the temporary file into the final filename
- File preFile = new File(RES_FOLDER + RES_FILENAME + ".tmp");
- File postFile = new File(RES_FOLDER + RES_FILENAME);
- preFile.renameTo(postFile);
+ String storageLocation = getSystemStorageLocation();
+
+ File preFile = new File(storageLocation + RES_FILENAME + ".tmp");
+ File postFile = new File(storageLocation + RES_FILENAME);
+
+ if (preFile.exists())
+ preFile.renameTo(postFile);
dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
//Start game;
mSingleton.mainDisplay();
}
}
+
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if ((keyCode == KeyEvent.KEYCODE_MENU) && (KeyEvent.ACTION_DOWN == event.getAction()))
+ {
+ super.onKeyDown(keyCode, event);
+ return true;
+ }
+ else if ((keyCode == KeyEvent.KEYCODE_MENU) && (KeyEvent.ACTION_UP == event.getAction()))
+ {
+ super.onKeyUp(keyCode, event);
+ return true;
+ }
+
+ return false;
+ }
@@ -753,15 +1071,17 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
// Key events
public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_MENU)
+ return false;
if (event.getAction() == KeyEvent.ACTION_DOWN) {
- //Log.v("SDL", "key down: " + keyCode);
- SDLActivity.onNativeKeyDown(keyCode);
+ //Log.d("SDL", "key down: " + keyCode);
+ SDLActivity.onNativeKeyDown(keyCode);
return true;
}
else if (event.getAction() == KeyEvent.ACTION_UP) {
- //Log.v("SDL", "key up: " + keyCode);
- SDLActivity.onNativeKeyUp(keyCode);
+ //Log.d("SDL", "key up: " + keyCode);
+ SDLActivity.onNativeKeyUp(keyCode);
return true;
}
@@ -838,7 +1158,3 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
}
}
}
-
-
-
-
diff --git a/projects/mtg/include/GameStateDeckViewer.h b/projects/mtg/include/GameStateDeckViewer.h
index f12ba69e1..63d15592a 100644
--- a/projects/mtg/include/GameStateDeckViewer.h
+++ b/projects/mtg/include/GameStateDeckViewer.h
@@ -77,7 +77,7 @@ enum DECK_VIEWER_MENU_ITEMS
#define LOW_SPEED 1.5
#define MAX_SAVED_FILTERS Constants::NB_Colors + 1
-#define CARDS_DISPLAYED 10
+#define CARDS_DISPLAYED 5
class GameStateDeckViewer: public GameState, public JGuiListener
{
diff --git a/projects/mtg/src/GameStateShop.cpp b/projects/mtg/src/GameStateShop.cpp
index ad5d87c31..9647d83a6 100644
--- a/projects/mtg/src/GameStateShop.cpp
+++ b/projects/mtg/src/GameStateShop.cpp
@@ -44,7 +44,7 @@ BoosterDisplay::BoosterDisplay(int id, GameObserver* game, int x, int y, JGuiLis
bool BoosterDisplay::CheckUserInput(JButton key)
{
- if (JGE_BTN_UP == key || JGE_BTN_DOWN == key)
+ if (JGE_BTN_UP == key || JGE_BTN_DOWN == key || JGE_BTN_PRI == key)
return false;
return CardDisplay::CheckUserInput(key);
@@ -608,17 +608,6 @@ void GameStateShop::Update(float dt)
taskList = NEW TaskList();
taskList->Start();
}
- else if (btn == JGE_BTN_PRI)
- {
- srcCards->Shuffle();
- load();
- disablePurchase = false;
- clearInput = true;
- return;
-
- }
- else if (btn == JGE_BTN_CANCEL)
- options[Options::DISABLECARDS].number = !options[Options::DISABLECARDS].number;
else if (boosterDisplay)
{
if (btn == JGE_BTN_SEC)
@@ -630,6 +619,17 @@ void GameStateShop::Update(float dt)
}
return;
}
+ else if (btn == JGE_BTN_PRI) // so we don't shuffle while we view our newly purchased booster display.
+ {
+ srcCards->Shuffle();
+ load();
+ disablePurchase = false;
+ clearInput = true;
+ return;
+
+ }
+ else if (btn == JGE_BTN_CANCEL)
+ options[Options::DISABLECARDS].number = !options[Options::DISABLECARDS].number;
else if (btn == JGE_BTN_SEC)
{
bListCards = !bListCards;