added a prefernces screen to handle media card selection on Android devices. Contains actual fix for 4297.

Added a place marker to allow volume change during app.  Right now it's either loud or off.  There isn't a way to allow the volume to gradually go up and odwn based on the values set in settings.
This commit is contained in:
techdragon.nguyen@gmail.com
2012-03-01 03:24:34 +00:00
parent 8b8020134d
commit 6124280f24
13 changed files with 604 additions and 97 deletions
@@ -1,6 +1,7 @@
/* Include the SDL main definition header */ /* Include the SDL main definition header */
#include "SDL_main.h" #include "SDL_main.h"
#include "JGE.h"
/******************************************************************************* /*******************************************************************************
Functions called by JNI Functions called by JNI
@@ -13,6 +14,8 @@ extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls);
// Library init // Library init
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{ {
JGE *mEngine = JGE::GetInstance();
mEngine->setJVM(vm);
return JNI_VERSION_1_4; return JNI_VERSION_1_4;
} }
+6
View File
@@ -126,6 +126,7 @@ class JGE
#endif #endif
#if defined (ANDROID) #if defined (ANDROID)
JavaVM * mJavaVM;
JNIEnv * mJNIEnv; JNIEnv * mJNIEnv;
jclass mJNIClass; jclass mJNIClass;
jmethodID midSendCommand; jmethodID midSendCommand;
@@ -164,6 +165,10 @@ class JGE
static JGE* GetInstance(); static JGE* GetInstance();
static void Destroy(); static void Destroy();
#ifdef ANDROID
JNIEnv * getJNIEnv();
void setJVM (JavaVM * vm);
#endif
void Init(); void Init();
void End(); void End();
@@ -377,6 +382,7 @@ class JGE
/// Access to JNI Environment /// Access to JNI Environment
void SetJNIEnv(JNIEnv * env, jclass cls); void SetJNIEnv(JNIEnv * env, jclass cls);
void sendJNICommand(std::string command); void sendJNICommand(std::string command);
std::string getFileSystemLocation();
#endif #endif
protected: protected:
+3 -2
View File
@@ -82,6 +82,7 @@ public:
SLObjectItf playerObject; SLObjectItf playerObject;
SLPlayItf playInterface; SLPlayItf playInterface;
SLSeekItf seekInterface; SLSeekItf seekInterface;
SLVolumeItf musicVolumeInterface;
#else #else
void* mTrack; void* mTrack;
#endif //WITH_FMOD #endif //WITH_FMOD
@@ -115,6 +116,7 @@ class JSample
#elif defined ANDROID #elif defined ANDROID
SLObjectItf playerObject; SLObjectItf playerObject;
SLPlayItf playInterface; SLPlayItf playInterface;
SLVolumeItf sampleVolumeInterface;
void* mSample; void* mSample;
#else #else
void* mSample; void* mSample;
@@ -242,9 +244,8 @@ protected:
private: private:
#ifdef WIN32
JMusic *mCurrentMusic; JMusic *mCurrentMusic;
#endif JSample *mCurrentSample;
int mVolume; int mVolume;
int mMusicVolume; int mMusicVolume;
+8 -2
View File
@@ -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. The content that users should not be touching.
*/ */
#if defined(ANDROID)
#include "../../include/PrecompiledHeader.h"
#endif
#ifdef WIN32 #ifdef WIN32
#pragma warning(disable : 4786) #pragma warning(disable : 4786)
@@ -113,8 +116,10 @@ JFileSystem::JFileSystem(const string & _userPath, const string & _systemPath)
systemPath = [[documentsDirectory stringByAppendingString: @"/Res/"] cStringUsingEncoding:1]; systemPath = [[documentsDirectory stringByAppendingString: @"/Res/"] cStringUsingEncoding:1];
#elif defined (ANDROID) #elif defined (ANDROID)
userPath = "/sdcard/Wagic/Res/"; userPath = JGE::GetInstance()->getFileSystemLocation();
systemPath = ""; systemPath = "";
DebugTrace("User path " << userPath);
#elif defined (QT_CONFIG) #elif defined (QT_CONFIG)
QDir dir(QDir::homePath()); QDir dir(QDir::homePath());
dir.cd(USERDIR); dir.cd(USERDIR);
@@ -165,7 +170,7 @@ JFileSystem::JFileSystem(const string & _userPath, const string & _systemPath)
systemPath += '/'; systemPath += '/';
} }
mUserFSPath = userPath; mUserFSPath = userPath;
MAKEDIR(userPath.c_str()); MAKEDIR(userPath.c_str());
mSystemFSPath = systemPath; mSystemFSPath = systemPath;
@@ -178,6 +183,7 @@ JFileSystem::JFileSystem(const string & _userPath, const string & _systemPath)
mPassword = NULL; mPassword = NULL;
mFileSize = 0; mFileSize = 0;
mCurrentFileInZip = NULL; mCurrentFileInZip = NULL;
}; };
void JFileSystem::Destroy() void JFileSystem::Destroy()
+39 -14
View File
@@ -619,45 +619,65 @@ void JGE::SendCommand(std::string command, float& x, float& y, float& width, flo
#if defined (ANDROID) #if defined (ANDROID)
int getJNIEnv(JNIEnv *env) JNIEnv * JGE::getJNIEnv()
{ {
JNIEnv *env;
int status = mJavaVM->GetEnv((void **)&env, JNI_VERSION_1_4); 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"); DebugTrace("Failed to get JNI environment, assuming native thread");
status = mJavaVM->AttachCurrentThread(&env, NULL); status = mJavaVM->AttachCurrentThread(&env, NULL);
if(status < 0) if(status == JNI_ERR)
{ {
LogNativeToAndroidExt("callback_handler: failed to attach current thread"); DebugTrace("callback_handler: failed to attach current thread");
return JNI_ERR; return NULL;
} }
} }
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 JNI_VERSION_1_4; return NULL;
} }
string JGE::getFileSystemLocation() string JGE::getFileSystemLocation()
{ {
char result[512]; char result[512];
JNIEnv * env; JNIEnv * env = getJNIEnv();
if (getJNIEnv(env) == JNI_ERR) 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"); 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"; 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) if (methodId == 0)
{ {
DebugTrace("An Error Occurred in getting the JNI methodID for getSystemFolderPath. Defaulting to /mnt/sdcard/net.wagic.app/Wagic"); 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"; return "/mnt/sdcard/net.wagic.app/Wagic";
}; };
jstring systemPath = (jstring) env->CallStaticObjectMethod(mJNIClass, methodId); jstring systemPath = (jstring) env->CallStaticObjectMethod(jniClass, methodId);
string retVal = "/mnt/sdcard/net.wagic.app/Wagic/";
// Now convert the Java String to C++ char array // Now convert the Java String to C++ char array
const char* cstr = env->GetStringUTFChars(systemPath, 0); const char* cstr = env->GetStringUTFChars(systemPath, 0);
string val (cstr); string retVal (cstr);
retVal = val;
env->ReleaseStringUTFChars(systemPath, cstr); env->ReleaseStringUTFChars(systemPath, cstr);
env->DeleteLocalRef(systemPath); env->DeleteLocalRef(systemPath);
@@ -672,6 +692,11 @@ void JGE::SetJNIEnv(JNIEnv * env, jclass cls)
midSendCommand = mJNIEnv->GetStaticMethodID(mJNIClass,"jgeSendCommand","(Ljava/lang/String;)V"); midSendCommand = mJNIEnv->GetStaticMethodID(mJNIClass,"jgeSendCommand","(Ljava/lang/String;)V");
} }
void JGE::setJVM( JavaVM *vm)
{
mJavaVM = vm;
}
void JGE::sendJNICommand(string command) void JGE::sendJNICommand(string command)
{ {
if (midSendCommand) { if (midSendCommand) {
+17 -4
View File
@@ -22,7 +22,7 @@ static SLObjectItf outputMixObject = NULL;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
JMusic::JMusic() JMusic::JMusic()
: playerObject(0), playInterface(0), seekInterface(0) : playerObject(0), playInterface(0), seekInterface(0), musicVolumeInterface(0)
{ {
} }
@@ -42,6 +42,7 @@ JMusic::~JMusic()
playerObject = NULL; playerObject = NULL;
playInterface = NULL; playInterface = NULL;
seekInterface = NULL; seekInterface = NULL;
musicVolumeInterface = NULL;
} }
} }
@@ -194,9 +195,13 @@ JMusic *JSoundSystem::LoadMusic(const char *fileName)
DebugTrace("result " << result); DebugTrace("result " << result);
// get the volume interface // 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); DebugTrace("result " << result);
} }
mCurrentMusic = music;
return music; return music;
} }
@@ -207,6 +212,8 @@ void JSoundSystem::PlayMusic(JMusic *music, bool looping)
{ {
SLresult result; SLresult result;
//(*music->musicVolumeInterface)->SetVolumeLevel(music->musicVolumeInterface, -1 * mVolume);
// enable whole file looping // enable whole file looping
result = (*music->seekInterface)->SetLoop(music->seekInterface, result = (*music->seekInterface)->SetLoop(music->seekInterface,
looping?SL_BOOLEAN_TRUE:SL_BOOLEAN_FALSE, 0, SL_TIME_UNKNOWN); 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) void JSoundSystem::SetMusicVolume(int volume)
{ {
mVolume = volume; mVolume = volume;
//(*mCurrentMusic->musicVolumeInterface)->SetVolumeLevel(mCurrentMusic->musicVolumeInterface, -1 * mVolume);
} }
void JSoundSystem::SetSfxVolume(int volume){ void JSoundSystem::SetSfxVolume(int volume){
mSampleVolume = volume; mSampleVolume = volume;
//(*mCurrentSample->sampleVolumeInterface)->SetVolumeLevel(mCurrentSample->sampleVolumeInterface, -1 * mSampleVolume);
SetMusicVolume(mVolume); SetMusicVolume(mVolume);
} }
@@ -296,8 +306,11 @@ JSample *JSoundSystem::LoadSample(const char *fileName)
DebugTrace("result " << result); DebugTrace("result " << result);
// get the volume interface // 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; return sample;
} }
@@ -307,7 +320,7 @@ void JSoundSystem::PlaySample(JSample *sample)
if(sample && sample->playerObject && sample->playInterface) if(sample && sample->playerObject && sample->playInterface)
{ {
SLresult result; SLresult result;
//(*sample->sampleVolumeInterface)->SetVolumeLevel(sample->sampleVolumeInterface, mSampleVolume);
result = (*sample->playInterface)->SetPlayState(sample->playInterface, result = (*sample->playInterface)->SetPlayState(sample->playInterface,
SL_PLAYSTATE_PLAYING); SL_PLAYSTATE_PLAYING);
} }
+2 -3
View File
@@ -17,9 +17,8 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.google.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation"/>
<activity android:name="com.google.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation"/>
</application> </application>
<uses-sdk android:minSdkVersion="9" /> <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="11"/>
</manifest> </manifest>
+1 -1
View File
@@ -8,4 +8,4 @@
# project structure. # project structure.
# Project target. # Project target.
target=android-9 target=Google Inc.:Google APIs:11
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">Wagic</string> <string name="app_name">Wagic</string>
<string name="info_text">Wagic v0.180\\nAll Rights Reserved.</string>
</resources> </resources>
@@ -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<String> mMounts = new ArrayList<String>();
private static ArrayList<String> mVold = new ArrayList<String>();
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<String> mLabels = new ArrayList<String>();
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();
}
}
@@ -1,17 +1,28 @@
package org.libsdl.app; 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.EGL10;
import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface; import javax.microedition.khronos.egl.EGLSurface;
import net.wagic.app.R;
import net.wagic.utils.StorageOptions;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.hardware.Sensor; import android.hardware.Sensor;
@@ -29,31 +40,30 @@ import android.os.Message;
import android.util.Log; import android.util.Log;
import android.view.Gravity; import android.view.Gravity;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.VelocityTracker; import android.view.VelocityTracker;
import android.view.View; import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams; import android.widget.FrameLayout.LayoutParams;
import com.google.ads.*; import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;
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;
/** /**
SDL Activity 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 // Main components
private static AdView mAdView; private static AdView mAdView;
@@ -75,8 +85,219 @@ public class SDLActivity extends Activity {
public static final String RES_FILENAME = "core_0180.zip"; public static final String RES_FILENAME = "core_0180.zip";
public static final String RES_URL = "http://wagic.googlecode.com/files/"; 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() { private void startDownload() {
String url = RES_URL + RES_FILENAME; 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); new DownloadFileAsync().execute(url);
} }
@@ -85,6 +306,49 @@ public class SDLActivity extends Activity {
mErrorMessage = errorMessage; 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 @Override
protected Dialog onCreateDialog(int id) { protected Dialog onCreateDialog(int id) {
switch (id) { switch (id) {
@@ -169,8 +433,18 @@ public class SDLActivity extends Activity {
// So we can call stuff from static callbacks // So we can call stuff from static callbacks
mSingleton = this; mSingleton = this;
mContext = this.getApplicationContext();
StorageOptions.determineStorageOptions();
checkStorageLocationPreference();
}
public void initializeGame()
{
String coreFileLocation = getSystemStorageLocation() + RES_FILENAME;
File file = new File(coreFileLocation);
File file = new File(RES_FOLDER + RES_FILENAME);
if (file.exists()) { if (file.exists()) {
mainDisplay(); mainDisplay();
} else { } else {
@@ -179,9 +453,9 @@ public class SDLActivity extends Activity {
new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
startDownload(); startDownload();
} }
} }
// Events // Events
@Override @Override
protected void onPause() { protected void onPause() {
@@ -232,7 +506,7 @@ public class SDLActivity extends Activity {
if (msg.arg1 == COMMAND_CHANGE_TITLE) { if (msg.arg1 == COMMAND_CHANGE_TITLE) {
setTitle((String)msg.obj); setTitle((String)msg.obj);
} }
if (msg.arg1 == COMMAND_JGE_MSG) { else if (msg.arg1 == COMMAND_JGE_MSG) {
processJGEMsg((String)msg.obj); 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 onNativeAccel(float x, float y, float z);
public static native void nativeRunAudioThread(); public static native void nativeRunAudioThread();
// Java functions called from C // Java functions called from C
// Receive a message from the SDLMain thread // 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) { public static void jgeSendCommand(String command) {
mSingleton.sendCommand(COMMAND_JGE_MSG, command); mSingleton.sendCommand(COMMAND_JGE_MSG, command);
} }
@@ -378,7 +662,9 @@ public class SDLActivity extends Activity {
} }
class DownloadFileAsync extends AsyncTask<String, String, String> { class DownloadFileAsync extends AsyncTask<String, Integer, Long> {
final String TAG1 = DownloadFileAsync.class.getCanonicalName();
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
super.onPreExecute(); super.onPreExecute();
@@ -386,43 +672,47 @@ public class SDLActivity extends Activity {
} }
@Override @Override
protected String doInBackground(String... aurl) { protected Long doInBackground(String... aurl) {
int count; int count;
long totalBytes = 0;
OutputStream output = null;
InputStream input = null;
try { try {
// //
// Prepare the sdcard folders in order to download the resource file // Prepare the sdcard folders in order to download the resource file
// //
String state = Environment.getExternalStorageState();
if (! Environment.MEDIA_MOUNTED.equals(state)) { String storageLocation = mSingleton.getSystemStorageLocation();
mSingleton.downloadError("cannot write to SD Card, please check your sd card");
return null; 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]); URL url = new URL(aurl[0]);
String filename = url.getPath().substring( url.getPath().lastIndexOf( '/') + 1);
URLConnection conexion = url.openConnection(); URLConnection conexion = url.openConnection();
conexion.connect(); conexion.connect();
int lenghtOfFile = conexion.getContentLength(); int lengthOfFile = conexion.getContentLength();
Log.d("ANDRO_ASYNC", "Length of file: " + lenghtOfFile); 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 // 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]; byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) { while ((count = input.read(data)) != -1) {
total += count; totalBytes += count;
publishProgress(""+(int)((total*100)/lenghtOfFile)); publishProgress((int)((totalBytes*100)/lengthOfFile));
output.write(data, 0, count); output.write(data, 0, count);
} }
@@ -430,27 +720,38 @@ public class SDLActivity extends Activity {
output.close(); output.close();
input.close(); input.close();
} catch (Exception e) { } 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) { protected void onProgressUpdate(Integer... progress) {
Log.d("ANDRO_ASYNC",progress[0]); if (progress[0] != mProgressDialog.getProgress())
mProgressDialog.setProgress(Integer.parseInt(progress[0])); {
Log.d("Wagic - " + TAG1, "current progress : " + progress[0]);
mProgressDialog.setProgress(progress[0]);
}
} }
@Override @Override
protected void onPostExecute(String unused) { protected void onPostExecute(Long unused) {
if (mErrorHappened) { if (mErrorHappened) {
dismissDialog(DIALOG_DOWNLOAD_PROGRESS); dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
showDialog(DIALOG_DOWNLOAD_ERROR); showDialog(DIALOG_DOWNLOAD_ERROR);
return; return;
} }
//rename the temporary file into the final filename //rename the temporary file into the final filename
File preFile = new File(RES_FOLDER + RES_FILENAME + ".tmp"); String storageLocation = getSystemStorageLocation();
File postFile = new File(RES_FOLDER + RES_FILENAME);
preFile.renameTo(postFile); 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); dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
//Start game; //Start game;
@@ -459,6 +760,23 @@ public class SDLActivity extends Activity {
} }
@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 // Key events
public boolean onKey(View v, int keyCode, KeyEvent event) { public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU)
return false;
if (event.getAction() == KeyEvent.ACTION_DOWN) { if (event.getAction() == KeyEvent.ACTION_DOWN) {
//Log.v("SDL", "key down: " + keyCode); //Log.d("SDL", "key down: " + keyCode);
SDLActivity.onNativeKeyDown(keyCode); SDLActivity.onNativeKeyDown(keyCode);
return true; return true;
} }
else if (event.getAction() == KeyEvent.ACTION_UP) { else if (event.getAction() == KeyEvent.ACTION_UP) {
//Log.v("SDL", "key up: " + keyCode); //Log.d("SDL", "key up: " + keyCode);
SDLActivity.onNativeKeyUp(keyCode); SDLActivity.onNativeKeyUp(keyCode);
return true; return true;
} }
@@ -838,7 +1158,3 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
} }
} }
} }
+1 -1
View File
@@ -77,7 +77,7 @@ enum DECK_VIEWER_MENU_ITEMS
#define LOW_SPEED 1.5 #define LOW_SPEED 1.5
#define MAX_SAVED_FILTERS Constants::NB_Colors + 1 #define MAX_SAVED_FILTERS Constants::NB_Colors + 1
#define CARDS_DISPLAYED 10 #define CARDS_DISPLAYED 5
class GameStateDeckViewer: public GameState, public JGuiListener class GameStateDeckViewer: public GameState, public JGuiListener
{ {
+12 -12
View File
@@ -44,7 +44,7 @@ BoosterDisplay::BoosterDisplay(int id, GameObserver* game, int x, int y, JGuiLis
bool BoosterDisplay::CheckUserInput(JButton key) 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 false;
return CardDisplay::CheckUserInput(key); return CardDisplay::CheckUserInput(key);
@@ -608,17 +608,6 @@ void GameStateShop::Update(float dt)
taskList = NEW TaskList(); taskList = NEW TaskList();
taskList->Start(); 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) else if (boosterDisplay)
{ {
if (btn == JGE_BTN_SEC) if (btn == JGE_BTN_SEC)
@@ -630,6 +619,17 @@ void GameStateShop::Update(float dt)
} }
return; 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) else if (btn == JGE_BTN_SEC)
{ {
bListCards = !bListCards; bListCards = !bListCards;