From 08339c92e2b71814bcd186667b421ed2973e12eb Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Sat, 5 Feb 2011 15:15:45 +0000 Subject: [PATCH] Minor fixes for mac compilation. Android stuff. --- amalgamation/juce_amalgamated_template.cpp | 4 +- .../Project/jucer_ProjectExport_Android.h | 6 +- juce_amalgamated.cpp | 1041 ++++++++++------- juce_amalgamated.h | 30 +- src/application/juce_Application.cpp | 2 + .../plugins/formats/juce_VSTPluginFormat.cpp | 2 +- src/core/juce_Initialisation.cpp | 17 +- src/io/streams/juce_MemoryInputStream.cpp | 28 +- src/memory/juce_Atomic.h | 27 +- .../android/java/ComponentPeerView.java | 94 ++ src/native/android/java/JuceAppActivity.java | 131 +++ src/native/android/juce_android_Files.cpp | 47 +- .../android/juce_android_GraphicsContext.cpp | 96 +- src/native/android/juce_android_Messaging.cpp | 2 +- src/native/android/juce_android_Misc.cpp | 10 +- .../android/juce_android_NativeCode.cpp | 244 +++- .../android/juce_android_SystemStats.cpp | 5 +- src/native/android/juce_android_Windowing.cpp | 41 +- src/native/common/juce_posix_SharedCode.h | 10 +- src/native/mac/juce_mac_NativeCode.mm | 2 + src/text/juce_CharPointer_UTF8.h | 4 +- src/text/juce_String.cpp | 2 +- src/utilities/juce_UnitTest.cpp | 4 +- 23 files changed, 1233 insertions(+), 616 deletions(-) create mode 100644 src/native/android/java/ComponentPeerView.java create mode 100644 src/native/android/java/JuceAppActivity.java diff --git a/amalgamation/juce_amalgamated_template.cpp b/amalgamation/juce_amalgamated_template.cpp index 1f48416711..b98f35769f 100644 --- a/amalgamation/juce_amalgamated_template.cpp +++ b/amalgamation/juce_amalgamated_template.cpp @@ -150,8 +150,6 @@ #include "../src/threads/juce_Thread.cpp" #include "../src/threads/juce_ThreadPool.cpp" #include "../src/threads/juce_TimeSliceThread.cpp" - #include "../src/utilities/juce_DeletedAtShutdown.cpp" - #include "../src/utilities/juce_UnitTest.cpp" #endif #if JUCE_BUILD_MISC @@ -166,6 +164,8 @@ #include "../src/utilities/juce_FileBasedDocument.cpp" #include "../src/utilities/juce_RecentlyOpenedFilesList.cpp" #include "../src/utilities/juce_UndoManager.cpp" + #include "../src/utilities/juce_UnitTest.cpp" + #include "../src/utilities/juce_DeletedAtShutdown.cpp" #include "../src/audio/audio_file_formats/juce_AiffAudioFormat.cpp" #include "../src/audio/audio_file_formats/juce_AudioFormat.cpp" #include "../src/audio/audio_file_formats/juce_AudioFormatReader.cpp" diff --git a/extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_Android.h b/extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_Android.h index 05cb736eea..71a8327546 100644 --- a/extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_Android.h +++ b/extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_Android.h @@ -209,11 +209,13 @@ private: for (int i = 0; i < files.size(); ++i) out << " ../" << escapeSpaces (files.getReference(i).toUnixStyle()) << "\\" << newLine; + String cFlags ("-fsigned-char"); + out << newLine << "ifeq ($(CONFIG),Debug)" << newLine - << " LOCAL_CFLAGS +=" << createPreprocessorDefs (true) << newLine + << " LOCAL_CFLAGS += -g " << cFlags << createPreprocessorDefs (true) << newLine << "else" << newLine - << " LOCAL_CFLAGS +=" << createPreprocessorDefs (false) << newLine + << " LOCAL_CFLAGS += " << cFlags << createPreprocessorDefs (false) << newLine << "endif" << newLine << newLine << "include $(BUILD_SHARED_LIBRARY)" << newLine; diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 1e5ebb2cf8..de5535bfc5 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -2308,18 +2308,28 @@ public: expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211); expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211)); - beginTest ("Atomic types"); + beginTest ("Atomic int"); AtomicTester ::testInteger (*this); + beginTest ("Atomic unsigned int"); AtomicTester ::testInteger (*this); + beginTest ("Atomic int32"); AtomicTester ::testInteger (*this); + beginTest ("Atomic uint32"); AtomicTester ::testInteger (*this); + beginTest ("Atomic long"); AtomicTester ::testInteger (*this); + beginTest ("Atomic void*"); AtomicTester ::testInteger (*this); + beginTest ("Atomic int*"); AtomicTester ::testInteger (*this); + beginTest ("Atomic float"); AtomicTester ::testFloat (*this); #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms + beginTest ("Atomic int64"); AtomicTester ::testInteger (*this); + beginTest ("Atomic uint64"); AtomicTester ::testInteger (*this); + beginTest ("Atomic double"); AtomicTester ::testFloat (*this); #endif } @@ -2334,10 +2344,15 @@ public: { Atomic a, b; a.set ((Type) 10); + test.expect (a.value == (Type) 10); + test.expect (a.get() == (Type) 10); a += (Type) 15; + test.expect (a.get() == (Type) 25); a.memoryBarrier(); a -= (Type) 5; + test.expect (a.get() == (Type) 20); ++a; ++a; --a; + test.expect (a.get() == (Type) 21); a.memoryBarrier(); testFloat (test); @@ -10246,9 +10261,7 @@ public: int randomInt = Random::getSystemRandom().nextInt(); int64 randomInt64 = Random::getSystemRandom().nextInt64(); double randomDouble = Random::getSystemRandom().nextDouble(); - String randomString; - for (int i = 50; --i >= 0;) - randomString << (juce_wchar) (Random::getSystemRandom().nextInt() & 0xffff); + String randomString (createRandomWideCharString()); MemoryOutputStream mo; mo.writeInt (randomInt); @@ -10264,12 +10277,34 @@ public: expect (mi.readInt() == randomInt); expect (mi.readIntBigEndian() == randomInt); expect (mi.readCompressedInt() == randomInt); - expect (mi.readString() == randomString); + expectEquals (mi.readString(), randomString); expect (mi.readInt64() == randomInt64); expect (mi.readInt64BigEndian() == randomInt64); expect (mi.readDouble() == randomDouble); expect (mi.readDoubleBigEndian() == randomDouble); } + + static const String createRandomWideCharString() + { + juce_wchar buffer [50]; + zerostruct (buffer); + + for (int i = 0; i < numElementsInArray (buffer) - 1; ++i) + { + if (Random::getSystemRandom().nextBool()) + { + do + { + buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); + } + while (! CharPointer_UTF16::canRepresent (buffer[i])); + } + else + buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0xff)); + } + + return buffer; + } }; static MemoryStreamTests memoryInputStreamUnitTests; @@ -13510,7 +13545,7 @@ public: { buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); } - while (buffer[i] >= 0xd800 && buffer[i] <= 0xdfff); // (these code-points are illegal in UTF-16) + while (! CharPointer_UTF16::canRepresent (buffer[i])); } else buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0xff)); @@ -17046,267 +17081,6 @@ void TimeSliceThread::run() END_JUCE_NAMESPACE /*** End of inlined file: juce_TimeSliceThread.cpp ***/ - -/*** Start of inlined file: juce_DeletedAtShutdown.cpp ***/ -BEGIN_JUCE_NAMESPACE - -DeletedAtShutdown::DeletedAtShutdown() -{ - const ScopedLock sl (getLock()); - getObjects().add (this); -} - -DeletedAtShutdown::~DeletedAtShutdown() -{ - const ScopedLock sl (getLock()); - getObjects().removeValue (this); -} - -void DeletedAtShutdown::deleteAll() -{ - // make a local copy of the array, so it can't get into a loop if something - // creates another DeletedAtShutdown object during its destructor. - Array localCopy; - - { - const ScopedLock sl (getLock()); - localCopy = getObjects(); - } - - for (int i = localCopy.size(); --i >= 0;) - { - JUCE_TRY - { - DeletedAtShutdown* deletee = localCopy.getUnchecked(i); - - // double-check that it's not already been deleted during another object's destructor. - { - const ScopedLock sl (getLock()); - if (! getObjects().contains (deletee)) - deletee = 0; - } - - delete deletee; - } - JUCE_CATCH_EXCEPTION - } - - // if no objects got re-created during shutdown, this should have been emptied by their - // destructors - jassert (getObjects().size() == 0); - - getObjects().clear(); // just to make sure the array doesn't have any memory still allocated -} - -CriticalSection& DeletedAtShutdown::getLock() -{ - static CriticalSection lock; - return lock; -} - -Array & DeletedAtShutdown::getObjects() -{ - static Array objects; - return objects; -} - -END_JUCE_NAMESPACE -/*** End of inlined file: juce_DeletedAtShutdown.cpp ***/ - - -/*** Start of inlined file: juce_UnitTest.cpp ***/ -BEGIN_JUCE_NAMESPACE - -UnitTest::UnitTest (const String& name_) - : name (name_), runner (0) -{ - getAllTests().add (this); -} - -UnitTest::~UnitTest() -{ - getAllTests().removeValue (this); -} - -Array& UnitTest::getAllTests() -{ - static Array tests; - return tests; -} - -void UnitTest::initialise() {} -void UnitTest::shutdown() {} - -void UnitTest::performTest (UnitTestRunner* const runner_) -{ - jassert (runner_ != 0); - runner = runner_; - - initialise(); - runTest(); - shutdown(); -} - -void UnitTest::logMessage (const String& message) -{ - runner->logMessage (message); -} - -void UnitTest::beginTest (const String& testName) -{ - runner->beginNewTest (this, testName); -} - -void UnitTest::expect (const bool result, const String& failureMessage) -{ - if (result) - runner->addPass(); - else - runner->addFail (failureMessage); -} - -UnitTestRunner::UnitTestRunner() - : currentTest (0), assertOnFailure (false) -{ -} - -UnitTestRunner::~UnitTestRunner() -{ -} - -int UnitTestRunner::getNumResults() const throw() -{ - return results.size(); -} - -const UnitTestRunner::TestResult* UnitTestRunner::getResult (int index) const throw() -{ - return results [index]; -} - -void UnitTestRunner::resultsUpdated() -{ -} - -void UnitTestRunner::runTests (const Array& tests, const bool assertOnFailure_) -{ - results.clear(); - assertOnFailure = assertOnFailure_; - resultsUpdated(); - - for (int i = 0; i < tests.size(); ++i) - { - try - { - tests.getUnchecked(i)->performTest (this); - } - catch (...) - { - addFail ("An unhandled exception was thrown!"); - } - } - - endTest(); -} - -void UnitTestRunner::runAllTests (const bool assertOnFailure_) -{ - runTests (UnitTest::getAllTests(), assertOnFailure_); -} - -void UnitTestRunner::logMessage (const String& message) -{ - Logger::writeToLog (message); -} - -void UnitTestRunner::beginNewTest (UnitTest* const test, const String& subCategory) -{ - endTest(); - currentTest = test; - - TestResult* const r = new TestResult(); - r->unitTestName = test->getName(); - r->subcategoryName = subCategory; - r->passes = 0; - r->failures = 0; - results.add (r); - - logMessage ("-----------------------------------------------------------------"); - logMessage ("Starting test: " + r->unitTestName + " / " + subCategory + "..."); - - resultsUpdated(); -} - -void UnitTestRunner::endTest() -{ - if (results.size() > 0) - { - TestResult* const r = results.getLast(); - - if (r->failures > 0) - { - String m ("FAILED!!"); - m << r->failures << (r->failures == 1 ? "test" : "tests") - << " failed, out of a total of " << (r->passes + r->failures); - - logMessage (String::empty); - logMessage (m); - logMessage (String::empty); - } - else - { - logMessage ("All tests completed successfully"); - } - } -} - -void UnitTestRunner::addPass() -{ - { - const ScopedLock sl (results.getLock()); - - TestResult* const r = results.getLast(); - jassert (r != 0); // You need to call UnitTest::beginTest() before performing any tests! - - r->passes++; - - String message ("Test "); - message << (r->failures + r->passes) << " passed"; - logMessage (message); - } - - resultsUpdated(); -} - -void UnitTestRunner::addFail (const String& failureMessage) -{ - { - const ScopedLock sl (results.getLock()); - - TestResult* const r = results.getLast(); - jassert (r != 0); // You need to call UnitTest::beginTest() before performing any tests! - - r->failures++; - - String message ("!!! Test "); - message << (r->failures + r->passes) << " failed"; - - if (failureMessage.isNotEmpty()) - message << ": " << failureMessage; - - r->messages.add (message); - - logMessage (message); - } - - resultsUpdated(); - - if (assertOnFailure) { jassertfalse } -} - -END_JUCE_NAMESPACE -/*** End of inlined file: juce_UnitTest.cpp ***/ - #endif #if JUCE_BUILD_MISC @@ -18603,6 +18377,7 @@ void JUCEApplication::appWillTerminateByForce() shutdownJuce_GUI(); } +#if ! JUCE_ANDROID int JUCEApplication::main (const String& commandLine) { ScopedJuceInitialiser_GUI libraryInitialiser; @@ -18655,6 +18430,7 @@ int JUCEApplication::main (int argc, const char* argv[]) return JUCEApplication::main (cmd); #endif } +#endif END_JUCE_NAMESPACE /*** End of inlined file: juce_Application.cpp ***/ @@ -20217,6 +19993,267 @@ END_JUCE_NAMESPACE /*** End of inlined file: juce_UndoManager.cpp ***/ +/*** Start of inlined file: juce_UnitTest.cpp ***/ +BEGIN_JUCE_NAMESPACE + +UnitTest::UnitTest (const String& name_) + : name (name_), runner (0) +{ + getAllTests().add (this); +} + +UnitTest::~UnitTest() +{ + getAllTests().removeValue (this); +} + +Array& UnitTest::getAllTests() +{ + static Array tests; + return tests; +} + +void UnitTest::initialise() {} +void UnitTest::shutdown() {} + +void UnitTest::performTest (UnitTestRunner* const runner_) +{ + jassert (runner_ != 0); + runner = runner_; + + initialise(); + runTest(); + shutdown(); +} + +void UnitTest::logMessage (const String& message) +{ + runner->logMessage (message); +} + +void UnitTest::beginTest (const String& testName) +{ + runner->beginNewTest (this, testName); +} + +void UnitTest::expect (const bool result, const String& failureMessage) +{ + if (result) + runner->addPass(); + else + runner->addFail (failureMessage); +} + +UnitTestRunner::UnitTestRunner() + : currentTest (0), assertOnFailure (false) +{ +} + +UnitTestRunner::~UnitTestRunner() +{ +} + +int UnitTestRunner::getNumResults() const throw() +{ + return results.size(); +} + +const UnitTestRunner::TestResult* UnitTestRunner::getResult (int index) const throw() +{ + return results [index]; +} + +void UnitTestRunner::resultsUpdated() +{ +} + +void UnitTestRunner::runTests (const Array& tests, const bool assertOnFailure_) +{ + results.clear(); + assertOnFailure = assertOnFailure_; + resultsUpdated(); + + for (int i = 0; i < tests.size(); ++i) + { + try + { + tests.getUnchecked(i)->performTest (this); + } + catch (...) + { + addFail ("An unhandled exception was thrown!"); + } + } + + endTest(); +} + +void UnitTestRunner::runAllTests (const bool assertOnFailure_) +{ + runTests (UnitTest::getAllTests(), assertOnFailure_); +} + +void UnitTestRunner::logMessage (const String& message) +{ + Logger::writeToLog (message); +} + +void UnitTestRunner::beginNewTest (UnitTest* const test, const String& subCategory) +{ + endTest(); + currentTest = test; + + TestResult* const r = new TestResult(); + r->unitTestName = test->getName(); + r->subcategoryName = subCategory; + r->passes = 0; + r->failures = 0; + results.add (r); + + logMessage ("-----------------------------------------------------------------"); + logMessage ("Starting test: " + r->unitTestName + " / " + subCategory + "..."); + + resultsUpdated(); +} + +void UnitTestRunner::endTest() +{ + if (results.size() > 0) + { + TestResult* const r = results.getLast(); + + if (r->failures > 0) + { + String m ("FAILED!! "); + m << r->failures << (r->failures == 1 ? " test" : " tests") + << " failed, out of a total of " << (r->passes + r->failures); + + logMessage (String::empty); + logMessage (m); + logMessage (String::empty); + } + else + { + logMessage ("All tests completed successfully"); + } + } +} + +void UnitTestRunner::addPass() +{ + { + const ScopedLock sl (results.getLock()); + + TestResult* const r = results.getLast(); + jassert (r != 0); // You need to call UnitTest::beginTest() before performing any tests! + + r->passes++; + + String message ("Test "); + message << (r->failures + r->passes) << " passed"; + logMessage (message); + } + + resultsUpdated(); +} + +void UnitTestRunner::addFail (const String& failureMessage) +{ + { + const ScopedLock sl (results.getLock()); + + TestResult* const r = results.getLast(); + jassert (r != 0); // You need to call UnitTest::beginTest() before performing any tests! + + r->failures++; + + String message ("!!! Test "); + message << (r->failures + r->passes) << " failed"; + + if (failureMessage.isNotEmpty()) + message << ": " << failureMessage; + + r->messages.add (message); + + logMessage (message); + } + + resultsUpdated(); + + if (assertOnFailure) { jassertfalse } +} + +END_JUCE_NAMESPACE +/*** End of inlined file: juce_UnitTest.cpp ***/ + + +/*** Start of inlined file: juce_DeletedAtShutdown.cpp ***/ +BEGIN_JUCE_NAMESPACE + +DeletedAtShutdown::DeletedAtShutdown() +{ + const ScopedLock sl (getLock()); + getObjects().add (this); +} + +DeletedAtShutdown::~DeletedAtShutdown() +{ + const ScopedLock sl (getLock()); + getObjects().removeValue (this); +} + +void DeletedAtShutdown::deleteAll() +{ + // make a local copy of the array, so it can't get into a loop if something + // creates another DeletedAtShutdown object during its destructor. + Array localCopy; + + { + const ScopedLock sl (getLock()); + localCopy = getObjects(); + } + + for (int i = localCopy.size(); --i >= 0;) + { + JUCE_TRY + { + DeletedAtShutdown* deletee = localCopy.getUnchecked(i); + + // double-check that it's not already been deleted during another object's destructor. + { + const ScopedLock sl (getLock()); + if (! getObjects().contains (deletee)) + deletee = 0; + } + + delete deletee; + } + JUCE_CATCH_EXCEPTION + } + + // if no objects got re-created during shutdown, this should have been emptied by their + // destructors + jassert (getObjects().size() == 0); + + getObjects().clear(); // just to make sure the array doesn't have any memory still allocated +} + +CriticalSection& DeletedAtShutdown::getLock() +{ + static CriticalSection lock; + return lock; +} + +Array & DeletedAtShutdown::getObjects() +{ + static Array objects; + return objects; +} + +END_JUCE_NAMESPACE +/*** End of inlined file: juce_DeletedAtShutdown.cpp ***/ + + /*** Start of inlined file: juce_AiffAudioFormat.cpp ***/ BEGIN_JUCE_NAMESPACE @@ -33147,7 +33184,7 @@ public: { FSRef fn; - if (FSPathMakeRef ((UInt8*) filename.toUTF8(), &fn, 0) == noErr) + if (FSPathMakeRef ((UInt8*) filename.toUTF8().getAddress(), &fn, 0) == noErr) { resFileId = FSOpenResFile (&fn, fsRdPerm); @@ -253775,8 +253812,7 @@ void FileOutputStream::flushInternal() const File juce_getExecutableFile() { #if JUCE_ANDROID - // TODO - return File::nonexistent; + return File (android.appFile); #else Dl_info exeInfo; dladdr ((void*) juce_getExecutableFile, &exeInfo); // (can't be a const void* on android) @@ -253991,6 +254027,11 @@ void JUCE_API juce_threadEntryPoint (void*); void* threadEntryProc (void* userData) { JUCE_AUTORELEASEPOOL + + #if JUCE_ANDROID + const AndroidThreadScope androidEnv; + #endif + juce_threadEntryPoint (userData); return 0; } @@ -254028,7 +254069,7 @@ void Thread::killThread() void Thread::setCurrentThreadName (const String& name) { - #if JUCE_MAC + #if JUCE_MAC && defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 pthread_setname_np (name.toUTF8()); #elif JUCE_LINUX prctl (PR_SET_NAME, name.toUTF8().getAddress(), 0, 0, 0); @@ -262094,6 +262135,7 @@ BEGIN_JUCE_NAMESPACE #undef Point +#if ! JUCE_ONLY_BUILD_CORE_LIBRARY namespace { template @@ -262181,6 +262223,7 @@ private: static_cast (info)->runLoopCallback(); } }; +#endif #define JUCE_INCLUDED_FILE 1 @@ -263683,8 +263726,7 @@ void FileOutputStream::flushInternal() const File juce_getExecutableFile() { #if JUCE_ANDROID - // TODO - return File::nonexistent; + return File (android.appFile); #else Dl_info exeInfo; dladdr ((void*) juce_getExecutableFile, &exeInfo); // (can't be a const void* on android) @@ -263899,6 +263941,11 @@ void JUCE_API juce_threadEntryPoint (void*); void* threadEntryProc (void* userData) { JUCE_AUTORELEASEPOOL + + #if JUCE_ANDROID + const AndroidThreadScope androidEnv; + #endif + juce_threadEntryPoint (userData); return 0; } @@ -263936,7 +263983,7 @@ void Thread::killThread() void Thread::setCurrentThreadName (const String& name) { - #if JUCE_MAC + #if JUCE_MAC && defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 pthread_setname_np (name.toUTF8()); #elif JUCE_LINUX prctl (PR_SET_NAME, name.toUTF8().getAddress(), 0, 0, 0); @@ -278614,10 +278661,11 @@ BEGIN_JUCE_NAMESPACE JAVACLASS (rectClass, "android/graphics/Rect") \ JAVACLASS (regionClass, "android/graphics/Region") \ JAVACLASS (shaderClass, "android/graphics/Shader") \ + JAVACLASS (shaderTileModeClass, "android/graphics/Shader$TileMode") \ JAVACLASS (linearGradientClass, "android/graphics/LinearGradient") \ JAVACLASS (radialGradientClass, "android/graphics/RadialGradient") \ -#define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD) \ +#define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ \ STATICMETHOD (activityClass, printToConsole, "printToConsole", "(Ljava/lang/String;)V") \ METHOD (activityClass, createNewView, "createNewView", "()Lcom/juce/ComponentPeerView;") \ @@ -278659,8 +278707,10 @@ BEGIN_JUCE_NAMESPACE METHOD (paintClass, paintClassConstructor, "", "()V") \ METHOD (paintClass, setColor, "setColor", "(I)V") \ METHOD (paintClass, setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \ + METHOD (paintClass, setAntiAlias, "setAntiAlias", "(Z)V") \ \ METHOD (shaderClass, setLocalMatrix, "setLocalMatrix", "(Landroid/graphics/Matrix;)V") \ + STATICFIELD (shaderTileModeClass, clampMode, "CLAMP", "Landroid/graphics/Shader$TileMode;") \ \ METHOD (pathClass, pathClassConstructor, "", "()V") \ METHOD (pathClass, moveTo, "moveTo", "(FF)V") \ @@ -278685,23 +278735,113 @@ BEGIN_JUCE_NAMESPACE METHOD (regionClass, regionConstructor, "", "()V"); \ METHOD (regionClass, regionUnion, "union", "(Landroid/graphics/Rect;)Z"); \ +class ThreadLocalJNIEnvHolder +{ +public: + ThreadLocalJNIEnvHolder() + : jvm (0) + { + zeromem (threads, sizeof (threads)); + zeromem (envs, sizeof (envs)); + } + + void initialise (JNIEnv* env) + { + env->GetJavaVM (&jvm); + addEnv (env); + } + + void attach() + { + JNIEnv* env = 0; + jvm->AttachCurrentThread (&env, 0); + + if (env != 0) + addEnv (env); + } + + void detach() + { + jvm->DetachCurrentThread(); + + const pthread_t thisThread = pthread_self(); + + ScopedLock sl (addRemoveLock); + for (int i = 0; i < maxThreads; ++i) + if (threads[i] == thisThread) + threads[i] = 0; + } + + JNIEnv* get() const throw() + { + const pthread_t thisThread = pthread_self(); + + for (int i = 0; i < maxThreads; ++i) + if (threads[i] == thisThread) + return envs[i]; + + return 0; + } + + enum { maxThreads = 16 }; + +private: + JavaVM* jvm; + pthread_t threads [maxThreads]; + JNIEnv* envs [maxThreads]; + CriticalSection addRemoveLock; + + void addEnv (JNIEnv* env) + { + ScopedLock sl (addRemoveLock); + + if (get() == 0) + { + const pthread_t thisThread = pthread_self(); + + for (int i = 0; i < maxThreads; ++i) + { + if (threads[i] == 0) + { + envs[i] = env; + threads[i] = thisThread; + return; + } + } + } + + jassertfalse; // too many threads! + } +}; + +static ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder; + +struct AndroidThreadScope +{ + AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } + ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } +}; + +static inline JNIEnv* getEnv() throw() +{ + return threadLocalJNIEnvHolder.get(); +} + class GlobalRef { public: - GlobalRef() - : env (0), obj (0) + inline GlobalRef() throw() + : obj (0) { } - GlobalRef (JNIEnv* const env_, jobject obj_) - : env (env_), - obj (retain (env_, obj_)) + inline explicit GlobalRef (jobject obj_) + : obj (retain (obj_)) { } - GlobalRef (const GlobalRef& other) - : env (other.env), - obj (retain (other.env, other.obj)) + inline GlobalRef (const GlobalRef& other) + : obj (retain (other.obj)) { } @@ -278710,34 +278850,28 @@ public: clear(); } - void clear() + inline void clear() { - if (env != 0) - { - env->DeleteGlobalRef (obj); - env = 0; - obj = 0; - } + if (obj != 0) + getEnv()->DeleteGlobalRef (obj); } - GlobalRef& operator= (const GlobalRef& other) + inline GlobalRef& operator= (const GlobalRef& other) { clear(); - env = other.env; - obj = retain (env, other.obj); + obj = retain (other.obj); return *this; } inline operator jobject() const throw() { return obj; } inline jobject get() const throw() { return obj; } - inline JNIEnv* getEnv() const throw() { return env; } #define DECLARE_CALL_TYPE_METHOD(returnType, typeName) \ returnType call##typeName##Method (jmethodID methodID, ... ) const \ { \ va_list args; \ va_start (args, methodID); \ - returnType result = env->Call##typeName##MethodV (obj, methodID, args); \ + returnType result = getEnv()->Call##typeName##MethodV (obj, methodID, args); \ va_end (args); \ return result; \ } @@ -278757,32 +278891,97 @@ public: { va_list args; va_start (args, methodID); - env->CallVoidMethodV (obj, methodID, args); + getEnv()->CallVoidMethodV (obj, methodID, args); va_end (args); } private: - JNIEnv* env; jobject obj; - static jobject retain (JNIEnv* const env, jobject obj_) + static inline jobject retain (jobject obj_) { - return env == 0 ? 0 : env->NewGlobalRef (obj_); + return obj_ == 0 ? 0 : getEnv()->NewGlobalRef (obj_); } }; +template +class LocalRef +{ +public: + explicit inline LocalRef (JavaType obj_) throw() + : obj (obj_) + { + } + + inline LocalRef (const LocalRef& other) throw() + : obj (retain (other.obj)) + { + } + + ~LocalRef() + { + if (obj != 0) + getEnv()->DeleteLocalRef (obj); + } + + LocalRef& operator= (const LocalRef& other) + { + if (obj != other.obj) + { + if (obj != 0) + getEnv()->DeleteLocalRef (obj); + + obj = retain (other.obj); + } + + return *this; + } + + inline operator JavaType() const throw() { return obj; } + inline JavaType get() const throw() { return obj; } + +private: + JavaType obj; + + static JavaType retain (JavaType obj_) + { + return obj_ == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj_); + } +}; + +static const String juceString (jstring s) +{ + JNIEnv* env = getEnv(); + + jboolean isCopy; + const char* const utf8 = env->GetStringUTFChars (s, &isCopy); + CharPointer_UTF8 utf8CP (utf8); + const String result (utf8CP); + env->ReleaseStringUTFChars (s, utf8); + return result; +} + +static const LocalRef javaString (const String& s) +{ + return LocalRef (getEnv()->NewStringUTF (s.toUTF8())); +} + class AndroidJavaCallbacks { public: - AndroidJavaCallbacks() : env (0), screenWidth (0), screenHeight (0) + AndroidJavaCallbacks() : screenWidth (0), screenHeight (0) { } - void initialise (JNIEnv* env_, jobject activity_, int screenWidth_, int screenHeight_) + void initialise (JNIEnv* env, jobject activity_, + jstring appFile_, jstring appDataDir_, + int screenWidth_, int screenHeight_) { - env = env_; - activity = GlobalRef (env, activity_); + threadLocalJNIEnvHolder.initialise (env); + activity = GlobalRef (activity_); + appFile = juceString (appFile_); + appDataDir = juceString (appDataDir_); screenWidth = screenWidth_; screenHeight = screenHeight_; @@ -278801,12 +279000,17 @@ public: #define CREATE_JNI_FIELD(ownerClass, fieldID, stringName, signature) \ fieldID = env->GetFieldID (ownerClass, stringName, signature); \ jassert (fieldID != 0); - JUCE_JNI_METHODS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD); + #define CREATE_JNI_STATICFIELD(ownerClass, fieldID, stringName, signature) \ + fieldID = env->GetStaticFieldID (ownerClass, stringName, signature); \ + jassert (fieldID != 0); + JUCE_JNI_METHODS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); #undef CREATE_JNI_METHOD } void shutdown() { + JNIEnv* env = getEnv(); + if (env != 0) { #define RELEASE_JNI_CLASS(className, path) env->DeleteGlobalRef (className); @@ -278814,27 +279018,11 @@ public: #undef RELEASE_JNI_CLASS activity.clear(); - env = 0; } } - const String juceString (jstring s) const - { - jboolean isCopy; - const char* const utf8 = env->GetStringUTFChars (s, &isCopy); - CharPointer_UTF8 utf8CP (utf8); - const String result (utf8CP); - env->ReleaseStringUTFChars (s, utf8); - return result; - } - - jstring javaString (const String& s) const - { - return env->NewStringUTF (s.toUTF8()); - } - - JNIEnv* env; GlobalRef activity; + String appFile, appDataDir; int screenWidth, screenHeight; #define DECLARE_JNI_CLASS(className, path) jclass className; @@ -278843,7 +279031,7 @@ public: #define DECLARE_JNI_METHOD(ownerClass, methodID, stringName, params) jmethodID methodID; #define DECLARE_JNI_FIELD(ownerClass, fieldID, stringName, signature) jfieldID fieldID; - JUCE_JNI_METHODS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD); + JUCE_JNI_METHODS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); #undef DECLARE_JNI_METHOD }; @@ -278862,9 +279050,11 @@ END_JUCE_NAMESPACE extern JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication(); // (from START_JUCE_APPLICATION) BEGIN_JUCE_NAMESPACE -JUCE_JNI_CALLBACK (JuceAppActivity, launchApp, void, (JNIEnv* env, jobject activity, int screenWidth, int screenHeight)) +JUCE_JNI_CALLBACK (JuceAppActivity, launchApp, void, (JNIEnv* env, jobject activity, + jstring appFile, jstring appDataDir, + int screenWidth, int screenHeight)) { - android.initialise (env, activity, screenWidth, screenHeight); + android.initialise (env, activity, appFile, appDataDir, screenWidth, screenHeight); JUCEApplication::createInstance = &juce_CreateApplication; @@ -278888,8 +279078,8 @@ void PlatformUtilities::beep() void Logger::outputDebugString (const String& text) { - android.env->CallStaticVoidMethod (android.activityClass, android.printToConsole, - android.javaString (text)); + getEnv()->CallStaticVoidMethod (android.activityClass, android.printToConsole, + javaString (text).get()); } void SystemClipboard::copyTextToClipboard (const String& text) @@ -278963,8 +279153,6 @@ int SystemStats::getCpuSpeedInMegaherz() int SystemStats::getMemorySizeInMegabytes() { - // TODO - struct sysinfo sysi; if (sysinfo (&sysi) == 0) @@ -279009,8 +279197,7 @@ void SystemStats::initialiseStats() cpuFlags.hasSSE2 = flags.contains ("sse2"); cpuFlags.has3DNow = flags.contains ("3dnow"); - // TODO - cpuFlags.numCpus = AndroidStatsHelpers::getCpuInfo ("processor").getIntValue() + 1; + cpuFlags.numCpus = jmax (1, sysconf (_SC_NPROCESSORS_ONLN)); } void PlatformUtilities::fpuReset() {} @@ -279507,8 +279694,7 @@ void FileOutputStream::flushInternal() const File juce_getExecutableFile() { #if JUCE_ANDROID - // TODO - return File::nonexistent; + return File (android.appFile); #else Dl_info exeInfo; dladdr ((void*) juce_getExecutableFile, &exeInfo); // (can't be a const void* on android) @@ -279723,6 +279909,11 @@ void JUCE_API juce_threadEntryPoint (void*); void* threadEntryProc (void* userData) { JUCE_AUTORELEASEPOOL + + #if JUCE_ANDROID + const AndroidThreadScope androidEnv; + #endif + juce_threadEntryPoint (userData); return 0; } @@ -279760,7 +279951,7 @@ void Thread::killThread() void Thread::setCurrentThreadName (const String& name) { - #if JUCE_MAC + #if JUCE_MAC && defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 pthread_setname_np (name.toUTF8()); #elif JUCE_LINUX prctl (PR_SET_NAME, name.toUTF8().getAddress(), 0, 0, 0); @@ -279918,70 +280109,34 @@ const File File::getLinkedTarget() const return juce_readlink (getFullPathName().toUTF8(), *this); } -const char* juce_Argv0 = 0; // referenced from juce_Application.cpp - const File File::getSpecialLocation (const SpecialLocationType type) { - - // TODO - switch (type) { case userHomeDirectory: - { - const char* homeDir = getenv ("HOME"); - - if (homeDir == 0) - { - struct passwd* const pw = getpwuid (getuid()); - if (pw != 0) - homeDir = pw->pw_dir; - } - - return File (String::fromUTF8 (homeDir)); - } - case userDocumentsDirectory: case userMusicDirectory: case userMoviesDirectory: case userApplicationDataDirectory: - return File ("~"); + return File (android.appDataDir); case userDesktopDirectory: return File ("~/Desktop"); case commonApplicationDataDirectory: - return File ("/var"); + return File (android.appDataDir); case globalApplicationsDirectory: return File ("/usr"); case tempDirectory: - { - File tmp ("/var/tmp"); - - if (! tmp.isDirectory()) - { - tmp = "/tmp"; - - if (! tmp.isDirectory()) - tmp = File::getCurrentWorkingDirectory(); - } - - return tmp; - } + return File ("~/.temp"); case invokedExecutableFile: - if (juce_Argv0 != 0) - return File (String::fromUTF8 (juce_Argv0)); - // deliberate fall-through... - case currentExecutableFile: case currentApplicationFile: - return juce_getExecutableFile(); - case hostApplicationPath: - return juce_readlink ("/proc/self/exe", juce_getExecutableFile()); + return juce_getExecutableFile(); default: jassertfalse; // unknown type? @@ -280463,7 +280618,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages bool juce_postMessageToSystemQueue (Message* message) { - android.activity.callVoidMethod (android.postMessage, (jlong) (pointer_sized_uint) message); + getEnv()->CallVoidMethod (android.activity, android.postMessage, (jlong) (pointer_sized_uint) message); return true; } @@ -280596,15 +280751,13 @@ const Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) // compiled on its own). #if JUCE_INCLUDED_FILE -// TODO class AndroidLowLevelGraphicsContext : public LowLevelGraphicsContext { public: AndroidLowLevelGraphicsContext (const GlobalRef& canvas_) : canvas (canvas_), - currentState (new SavedState()), + currentState (new SavedState()) { - paintStack.add (new GlobalRef()); setFill (Colours::black); } @@ -280621,7 +280774,7 @@ public: void addTransform (const AffineTransform& transform) { - canvas.callVoidMethod (android.concat, createMatrix (canvas.getEnv(), transform)); + canvas.callVoidMethod (android.concat, createMatrix (getEnv(), transform).get()); } float getScaleFactor() @@ -280636,7 +280789,7 @@ public: bool clipToRectangleList (const RectangleList& clipRegion) { - return canvas.callBooleanMethod (android.clipRegion, createRegion (canvas.getEnv(), clipRegion)); + return canvas.callBooleanMethod (android.clipRegion, createRegion (getEnv(), clipRegion).get()); } void excludeClipRectangle (const Rectangle& r) @@ -280645,7 +280798,7 @@ public: void clipToPath (const Path& path, const AffineTransform& transform) { - (void) canvas.callBooleanMethod (android.clipPath, createPath (canvas.getEnv(), path, transform)); + (void) canvas.callBooleanMethod (android.clipPath, createPath (getEnv(), path, transform).get()); } void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) @@ -280659,20 +280812,21 @@ public: const Rectangle getClipBounds() const { - jobject rect = canvas.callObjectMethod (android.getClipBounds2); + JNIEnv* env = getEnv(); + const LocalRef rect (canvas.callObjectMethod (android.getClipBounds2)); - const int left = canvas.getEnv()->GetIntField (rect, android.rectLeft); - const int top = canvas.getEnv()->GetIntField (rect, android.rectTop); - const int right = canvas.getEnv()->GetIntField (rect, android.rectRight); - const int bottom = canvas.getEnv()->GetIntField (rect, android.rectBottom); + const int left = env->GetIntField (rect, android.rectLeft); + const int top = env->GetIntField (rect, android.rectTop); + const int right = env->GetIntField (rect, android.rectRight); + const int bottom = env->GetIntField (rect, android.rectBottom); return Rectangle (left, top, right - left, bottom - top); } bool isClipEmpty() const { - return ! canvas.callBooleanMethod (android.getClipBounds, - canvas.getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); + LocalRef tempRect (getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); + return ! canvas.callBooleanMethod (android.getClipBounds, tempRect.get()); } void setFill (const FillType& fillType) @@ -280692,13 +280846,13 @@ public: { canvas.callVoidMethod (android.drawRect, (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom(), - getCurrentPaint().get()); + getCurrentPaint()); } void fillPath (const Path& path, const AffineTransform& transform) { - canvas.callVoidMethod (android.drawPath, createPath (canvas.getEnv(), path, transform), - getCurrentPaint().get()); + canvas.callVoidMethod (android.drawPath, createPath (getEnv(), path, transform).get(), + getCurrentPaint()); } void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles) @@ -280709,17 +280863,17 @@ public: { canvas.callVoidMethod (android.drawLine, line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY(), - getCurrentPaint().get()); + getCurrentPaint()); } void drawVerticalLine (int x, float top, float bottom) { - canvas.callVoidMethod (android.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint().get()); + canvas.callVoidMethod (android.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint()); } void drawHorizontalLine (int y, float left, float right) { - canvas.callVoidMethod (android.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint().get()); + canvas.callVoidMethod (android.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint()); } void setFont (const Font& newFont) @@ -280786,21 +280940,26 @@ public: fillType = newType; } - jobject getPaint (JNIEnv* env) + jobject getPaint() { if (needsUpdate) { + JNIEnv* env = getEnv(); + if (paint.get() == 0) - paint = GlobalRef (env, env->NewObject (android.paintClass, android.paintClassConstructor)); + { + paint = GlobalRef (env->NewObject (android.paintClass, android.paintClassConstructor)); + paint.callVoidMethod (android.setAntiAlias, true); + } if (fillType.isColour()) { - paint.callVoidMethod (android.setShader, (jobject) 0); + paint.callObjectMethod (android.setShader, (jobject) 0); paint.callVoidMethod (android.setColor, colourToInt (fillType.colour)); } else if (fillType.isGradient()) { - const ColourGradient& g = fillType.gradient; + const ColourGradient& g = *fillType.gradient; const Point p1 (g.point1); const Point p2 (g.point2); @@ -280814,7 +280973,7 @@ public: for (int i = 0; i < numColours; ++i) { - colours[i] = g.getColour (i); + colours[i] = colourToInt (g.getColour (i)); positions[i] = (float) g.getColourPosition(i); } @@ -280822,7 +280981,7 @@ public: env->SetFloatArrayRegion (positionsArray, 0, numColours, positions.getData()); } - jobject tileMode = xxxx + jobject tileMode = env->GetStaticObjectField (android.shaderTileModeClass, android.clampMode); jobject shader; if (fillType.gradient->isRadial) @@ -280832,7 +280991,7 @@ public: p1.getX(), p1.getY(), p1.getDistanceFrom (p2), coloursArray, positionsArray, - tileMode)); + tileMode); } else { @@ -280840,14 +280999,19 @@ public: android.linearGradientConstructor, p1.getX(), p1.getY(), p2.getX(), p2.getY(), coloursArray, positionsArray, - tileMode)); + tileMode); } - env->CallVoidMethod (shader, android.setLocalMatrix, createMatrix (fillType.transform)); - paint.callVoidMethod (android.setShader, shader); + env->DeleteLocalRef (coloursArray); + env->DeleteLocalRef (positionsArray); + + env->CallVoidMethod (shader, android.setLocalMatrix, createMatrix (env, fillType.transform).get()); + paint.callObjectMethod (android.setShader, shader); + + env->DeleteLocalRef (shader); } else - {x + { } } @@ -280867,9 +281031,12 @@ private: ScopedPointer currentState; OwnedArray stateStack; - GlobalRef& getCurrentPaint() throw() { return *paintStack.getUnchecked (paintStack.size() - 1); } + jobject getCurrentPaint() const + { + return currentState->getPaint(); + } - static jobject createPath (JNIEnv* env, const Path& path) + static const LocalRef createPath (JNIEnv* env, const Path& path) { jobject p = env->NewObject (android.pathClass, android.pathClassConstructor); @@ -280888,10 +281055,10 @@ private: } } - return p; + return LocalRef (p); } - static jobject createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) + static const LocalRef createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) { if (transform.isIdentity()) return createPath (env, path); @@ -280901,7 +281068,7 @@ private: return createPath (env, tempPath); } - static jobject createMatrix (JNIEnv* env, const AffineTransform& t) + static const LocalRef createMatrix (JNIEnv* env, const AffineTransform& t) { jobject m = env->NewObject (android.matrixClass, android.matrixClassConstructor); @@ -280915,25 +281082,25 @@ private: env->CallVoidMethod (m, android.setValues, javaArray); env->DeleteLocalRef (javaArray); - return m; + return LocalRef (m); } - static jobject createRect (JNIEnv* env, const Rectangle& r) + static const LocalRef createRect (JNIEnv* env, const Rectangle& r) { - return env->NewObject (android.rectClass, android.rectConstructor, - r.getX(), r.getY(), r.getRight(), r.getBottom()); + return LocalRef (env->NewObject (android.rectClass, android.rectConstructor, + r.getX(), r.getY(), r.getRight(), r.getBottom())); } - static jobject createRegion (JNIEnv* env, const RectangleList& list) + static const LocalRef createRegion (JNIEnv* env, const RectangleList& list) { jobject region = env->NewObject (android.regionClass, android.regionConstructor); const int numRects = list.getNumRectangles(); for (int i = 0; i < numRects; ++i) - env->CallVoidMethod (region, android.regionUnion, createRect (env, list.getRectangle(i))); + env->CallVoidMethod (region, android.regionUnion, createRect (env, list.getRectangle(i)).get()); - return region; + return LocalRef (region); } static int colourToInt (const Colour& col) throw() @@ -280953,14 +281120,16 @@ private: // compiled on its own). #if JUCE_INCLUDED_FILE +static ModifierKeys currentModifiers; + class AndroidComponentPeer : public ComponentPeer { public: AndroidComponentPeer (Component* const component, const int windowStyleFlags) - : ComponentPeer (component, windowStyleFlags) + : ComponentPeer (component, windowStyleFlags), + view (android.activity.callObjectMethod (android.createNewView)) { - view = GlobalRef (android.env, android.activity.callObjectMethod (android.createNewView)); } ~AndroidComponentPeer() @@ -280981,7 +281150,7 @@ public: void setTitle (const String& title) { - view.callVoidMethod (android.setViewName, android.javaString (title)); + view.callVoidMethod (android.setViewName, javaString (title).get()); } void setPosition (int x, int y) @@ -281011,7 +281180,7 @@ public: const Point getScreenPosition() const { - JNIEnv* const env = view.getEnv(); + JNIEnv* const env = getEnv(); jintArray pos = env->NewIntArray (2); view.callVoidMethod (android.getLocationOnScreen, pos); @@ -281093,6 +281262,25 @@ public: // TODO } + void handleMouseDownCallback (float x, float y, int64 time) + { + currentModifiers = currentModifiers.withoutMouseButtons(); + handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); + handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + } + + void handleMouseDragCallback (float x, float y, int64 time) + { + handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + } + + void handleMouseUpCallback (float x, float y, int64 time) + { + currentModifiers = currentModifiers.withoutMouseButtons(); + handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + } + bool isFocused() const { return view.callBooleanMethod (android.hasFocus); @@ -281110,7 +281298,8 @@ public: void handlePaintCallback (JNIEnv* env, jobject canvas) { - AndroidLowLevelGraphicsContext g (GlobalRef (env, canvas)); + GlobalRef canvasRef (canvas); + AndroidLowLevelGraphicsContext g (canvasRef); handlePaint (g); } @@ -281161,6 +281350,13 @@ private: JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject view, jobject canvas), handlePaintCallback (env, canvas)) +JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), + handleMouseDownCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), + handleMouseDragCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), + handleMouseUpCallback ((float) x, (float) y, (int64) time)) + ComponentPeer* Component::createNewPeer (int styleFlags, void*) { return new AndroidComponentPeer (this, styleFlags); @@ -281209,8 +281405,7 @@ void ModifierKeys::updateCurrentModifiers() throw() const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw() { - // TODO - return ModifierKeys(); + return currentModifiers; } bool Process::isForegroundProcess() diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 7225233ecf..79fda20482 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -2245,6 +2245,10 @@ private: #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 #endif +#elif JUCE_ANDROID + #define JUCE_ATOMICS_ANDROID 1 // Android atomic functions + #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 + #elif JUCE_GCC #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics @@ -2306,8 +2310,8 @@ inline Type Atomic::get() const throw() #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0)) : castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0)); - #elif JUCE_ANDROID - return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (value), castTo32Bit (value), (volatile int*) &value)); + #elif JUCE_ATOMICS_ANDROID + return value; #elif JUCE_ATOMICS_GCC return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); @@ -2317,7 +2321,7 @@ inline Type Atomic::get() const throw() template inline Type Atomic::exchange (const Type newValue) throw() { - #if JUCE_ANDROID + #if JUCE_ATOMICS_ANDROID return castFrom32Bit (__atomic_swap (castTo32Bit (newValue), (volatile int*) &value)); #elif JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC Type currentVal = value; @@ -2338,7 +2342,7 @@ inline Type Atomic::operator+= (const Type amountToAdd) throw() #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd) : (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd); - #elif JUCE_ANDROID + #elif JUCE_ATOMICS_ANDROID for (;;) { const Type oldValue (value); @@ -2366,7 +2370,7 @@ inline Type Atomic::operator++() throw() #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value) : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value); - #elif JUCE_ANDROID + #elif JUCE_ATOMICS_ANDROID return (Type) __atomic_inc ((volatile int*) &value); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, 1); @@ -2382,7 +2386,7 @@ inline Type Atomic::operator--() throw() #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value) : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value); - #elif JUCE_ANDROID + #elif JUCE_ATOMICS_ANDROID return (Type) __atomic_dec ((volatile int*) &value); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, -1); @@ -2395,8 +2399,10 @@ inline bool Atomic::compareAndSetBool (const Type newValue, const Type val #if JUCE_ATOMICS_MAC return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); - #elif JUCE_ATOMICS_WINDOWS || JUCE_ANDROID + #elif JUCE_ATOMICS_WINDOWS return compareAndSetValue (newValue, valueToCompare) == valueToCompare; + #elif JUCE_ATOMICS_ANDROID + return __atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value) == 0; #elif JUCE_ATOMICS_GCC return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); @@ -2406,8 +2412,8 @@ inline bool Atomic::compareAndSetBool (const Type newValue, const Type val template inline Type Atomic::compareAndSetValue (const Type newValue, const Type valueToCompare) throw() { - #if JUCE_ATOMICS_MAC - for (;;) // Annoying workaround for OSX only having a bool CAS operation.. + #if JUCE_ATOMICS_MAC || JUCE_ATOMICS_ANDROID + for (;;) // Annoying workaround for only having a bool CAS operation.. { if (compareAndSetBool (newValue, valueToCompare)) return valueToCompare; @@ -2420,8 +2426,6 @@ inline Type Atomic::compareAndSetValue (const Type newValue, const Type va #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare))) : castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare))); - #elif JUCE_ANDROID - return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value)); #elif JUCE_ATOMICS_GCC return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); @@ -2638,11 +2642,11 @@ public: for (;;) { - const int n = *d++; + const uint32 n = (uint32) (uint8) *d++; if ((n & 0x80) != 0) { - int bit = 0x40; + uint32 bit = 0x40; while ((n & bit) != 0) { diff --git a/src/application/juce_Application.cpp b/src/application/juce_Application.cpp index 26d3e27bdd..799c78afe7 100644 --- a/src/application/juce_Application.cpp +++ b/src/application/juce_Application.cpp @@ -211,6 +211,7 @@ void JUCEApplication::appWillTerminateByForce() } //============================================================================== +#if ! JUCE_ANDROID int JUCEApplication::main (const String& commandLine) { ScopedJuceInitialiser_GUI libraryInitialiser; @@ -263,5 +264,6 @@ int JUCEApplication::main (int argc, const char* argv[]) return JUCEApplication::main (cmd); #endif } +#endif END_JUCE_NAMESPACE diff --git a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp index 9d84d1fd8e..f442197d75 100644 --- a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp +++ b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp @@ -539,7 +539,7 @@ public: { FSRef fn; - if (FSPathMakeRef ((UInt8*) filename.toUTF8(), &fn, 0) == noErr) + if (FSPathMakeRef ((UInt8*) filename.toUTF8().getAddress(), &fn, 0) == noErr) { resFileId = FSOpenResFile (&fn, fsRdPerm); diff --git a/src/core/juce_Initialisation.cpp b/src/core/juce_Initialisation.cpp index 0ff27436f1..6e7ec7d890 100644 --- a/src/core/juce_Initialisation.cpp +++ b/src/core/juce_Initialisation.cpp @@ -188,18 +188,28 @@ public: expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211); expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211)); - beginTest ("Atomic types"); + beginTest ("Atomic int"); AtomicTester ::testInteger (*this); + beginTest ("Atomic unsigned int"); AtomicTester ::testInteger (*this); + beginTest ("Atomic int32"); AtomicTester ::testInteger (*this); + beginTest ("Atomic uint32"); AtomicTester ::testInteger (*this); + beginTest ("Atomic long"); AtomicTester ::testInteger (*this); + beginTest ("Atomic void*"); AtomicTester ::testInteger (*this); + beginTest ("Atomic int*"); AtomicTester ::testInteger (*this); + beginTest ("Atomic float"); AtomicTester ::testFloat (*this); #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms + beginTest ("Atomic int64"); AtomicTester ::testInteger (*this); + beginTest ("Atomic uint64"); AtomicTester ::testInteger (*this); + beginTest ("Atomic double"); AtomicTester ::testFloat (*this); #endif } @@ -214,10 +224,15 @@ public: { Atomic a, b; a.set ((Type) 10); + test.expect (a.value == (Type) 10); + test.expect (a.get() == (Type) 10); a += (Type) 15; + test.expect (a.get() == (Type) 25); a.memoryBarrier(); a -= (Type) 5; + test.expect (a.get() == (Type) 20); ++a; ++a; --a; + test.expect (a.get() == (Type) 21); a.memoryBarrier(); testFloat (test); diff --git a/src/io/streams/juce_MemoryInputStream.cpp b/src/io/streams/juce_MemoryInputStream.cpp index 526182a030..01f34a497b 100644 --- a/src/io/streams/juce_MemoryInputStream.cpp +++ b/src/io/streams/juce_MemoryInputStream.cpp @@ -111,9 +111,7 @@ public: int randomInt = Random::getSystemRandom().nextInt(); int64 randomInt64 = Random::getSystemRandom().nextInt64(); double randomDouble = Random::getSystemRandom().nextDouble(); - String randomString; - for (int i = 50; --i >= 0;) - randomString << (juce_wchar) (Random::getSystemRandom().nextInt() & 0xffff); + String randomString (createRandomWideCharString()); MemoryOutputStream mo; mo.writeInt (randomInt); @@ -129,12 +127,34 @@ public: expect (mi.readInt() == randomInt); expect (mi.readIntBigEndian() == randomInt); expect (mi.readCompressedInt() == randomInt); - expect (mi.readString() == randomString); + expectEquals (mi.readString(), randomString); expect (mi.readInt64() == randomInt64); expect (mi.readInt64BigEndian() == randomInt64); expect (mi.readDouble() == randomDouble); expect (mi.readDoubleBigEndian() == randomDouble); } + + static const String createRandomWideCharString() + { + juce_wchar buffer [50]; + zerostruct (buffer); + + for (int i = 0; i < numElementsInArray (buffer) - 1; ++i) + { + if (Random::getSystemRandom().nextBool()) + { + do + { + buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); + } + while (! CharPointer_UTF16::canRepresent (buffer[i])); + } + else + buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0xff)); + } + + return buffer; + } }; static MemoryStreamTests memoryInputStreamUnitTests; diff --git a/src/memory/juce_Atomic.h b/src/memory/juce_Atomic.h index db0f47c4f6..bb927c2bbb 100644 --- a/src/memory/juce_Atomic.h +++ b/src/memory/juce_Atomic.h @@ -180,6 +180,11 @@ private: #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 #endif +//============================================================================== +#elif JUCE_ANDROID + #define JUCE_ATOMICS_ANDROID 1 // Android atomic functions + #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 + //============================================================================== #elif JUCE_GCC #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics @@ -244,8 +249,8 @@ inline Type Atomic::get() const throw() #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0)) : castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0)); - #elif JUCE_ANDROID - return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (value), castTo32Bit (value), (volatile int*) &value)); + #elif JUCE_ATOMICS_ANDROID + return value; #elif JUCE_ATOMICS_GCC return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); @@ -255,7 +260,7 @@ inline Type Atomic::get() const throw() template inline Type Atomic::exchange (const Type newValue) throw() { - #if JUCE_ANDROID + #if JUCE_ATOMICS_ANDROID return castFrom32Bit (__atomic_swap (castTo32Bit (newValue), (volatile int*) &value)); #elif JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC Type currentVal = value; @@ -276,7 +281,7 @@ inline Type Atomic::operator+= (const Type amountToAdd) throw() #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd) : (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd); - #elif JUCE_ANDROID + #elif JUCE_ATOMICS_ANDROID for (;;) { const Type oldValue (value); @@ -304,7 +309,7 @@ inline Type Atomic::operator++() throw() #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value) : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value); - #elif JUCE_ANDROID + #elif JUCE_ATOMICS_ANDROID return (Type) __atomic_inc ((volatile int*) &value); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, 1); @@ -320,7 +325,7 @@ inline Type Atomic::operator--() throw() #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value) : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value); - #elif JUCE_ANDROID + #elif JUCE_ATOMICS_ANDROID return (Type) __atomic_dec ((volatile int*) &value); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, -1); @@ -333,8 +338,10 @@ inline bool Atomic::compareAndSetBool (const Type newValue, const Type val #if JUCE_ATOMICS_MAC return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); - #elif JUCE_ATOMICS_WINDOWS || JUCE_ANDROID + #elif JUCE_ATOMICS_WINDOWS return compareAndSetValue (newValue, valueToCompare) == valueToCompare; + #elif JUCE_ATOMICS_ANDROID + return __atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value) == 0; #elif JUCE_ATOMICS_GCC return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); @@ -344,8 +351,8 @@ inline bool Atomic::compareAndSetBool (const Type newValue, const Type val template inline Type Atomic::compareAndSetValue (const Type newValue, const Type valueToCompare) throw() { - #if JUCE_ATOMICS_MAC - for (;;) // Annoying workaround for OSX only having a bool CAS operation.. + #if JUCE_ATOMICS_MAC || JUCE_ATOMICS_ANDROID + for (;;) // Annoying workaround for only having a bool CAS operation.. { if (compareAndSetBool (newValue, valueToCompare)) return valueToCompare; @@ -358,8 +365,6 @@ inline Type Atomic::compareAndSetValue (const Type newValue, const Type va #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare))) : castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare))); - #elif JUCE_ANDROID - return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value)); #elif JUCE_ATOMICS_GCC return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); diff --git a/src/native/android/java/ComponentPeerView.java b/src/native/android/java/ComponentPeerView.java new file mode 100644 index 0000000000..9f8e120852 --- /dev/null +++ b/src/native/android/java/ComponentPeerView.java @@ -0,0 +1,94 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-10 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online at www.gnu.org/licenses. + + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +package com.juce; + +import android.content.Context; +import android.view.*; +import android.graphics.*; + +//============================================================================== +public class ComponentPeerView extends View +{ + public ComponentPeerView (Context context) + { + super (context); + } + + //============================================================================== + private native void handlePaint (Canvas canvas); + + @Override + public void draw (Canvas canvas) + { + handlePaint (canvas); + } + + //============================================================================== + private native void handleMouseDown (float x, float y, long time); + private native void handleMouseDrag (float x, float y, long time); + private native void handleMouseUp (float x, float y, long time); + + @Override + public boolean onTouchEvent (MotionEvent event) + { + System.out.println (event.toString()); + + switch (event.getAction()) + { + case MotionEvent.ACTION_DOWN: handleMouseDown (event.getX(), event.getY(), event.getEventTime()); return true; + case MotionEvent.ACTION_MOVE: handleMouseDrag (event.getX(), event.getY(), event.getEventTime()); return true; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: handleMouseUp (event.getX(), event.getY(), event.getEventTime()); return true; + default: break; + } + + return false; + } + + //============================================================================== + @Override + protected void onSizeChanged (int w, int h, int oldw, int oldh) + { + } + + @Override + protected void onLayout (boolean changed, int left, int top, int right, int bottom) + { + } + + public void setViewName (String newName) + { + } + + public boolean isVisible() + { + return true; + } + + public void setVisible (boolean b) + { + } +} diff --git a/src/native/android/java/JuceAppActivity.java b/src/native/android/java/JuceAppActivity.java new file mode 100644 index 0000000000..8287e8e762 --- /dev/null +++ b/src/native/android/java/JuceAppActivity.java @@ -0,0 +1,131 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-10 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online at www.gnu.org/licenses. + + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +package com.juce; + +import android.app.Activity; +import android.os.Bundle; +import android.content.*; +import android.view.*; +import com.juce.ComponentPeerView; + +//============================================================================== +public class JuceAppActivity extends Activity +{ + //============================================================================== + static + { + System.loadLibrary ("juce_jni"); + } + + @Override + public void onCreate (Bundle savedInstanceState) + { + super.onCreate (savedInstanceState); + + messageHandler = new android.os.Handler(); + + viewHolder = new ViewHolder (this); + setContentView (viewHolder); + + WindowManager wm = (WindowManager) getSystemService (WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + + launchApp (getApplicationInfo().publicSourceDir, + getApplicationInfo().dataDir, + display.getWidth(), display.getHeight()); + } + + @Override + protected void onDestroy() + { + quitApp(); + super.onDestroy(); + } + + //============================================================================== + public native void launchApp (String appFile, String appDataDir, + int screenWidth, int screenHeight); + public native void quitApp(); + + //============================================================================== + public static void printToConsole (String s) + { + System.out.println (s); + } + + //============================================================================== + public native void deliverMessage (long value); + private android.os.Handler messageHandler; + + public void postMessage (long value) + { + messageHandler.post (new MessageCallback (this, value)); + } + + class MessageCallback implements java.lang.Runnable + { + public MessageCallback (JuceAppActivity app_, long value_) + { + app = app_; + value = value_; + } + + public void run() + { + app.deliverMessage (value); + } + + private JuceAppActivity app; + private long value; + } + + //============================================================================== + private ViewHolder viewHolder; + + public ComponentPeerView createNewView() + { + ComponentPeerView v = new ComponentPeerView (this); + viewHolder.addView (v); + return v; + } + + public void deleteView (ComponentPeerView view) + { + viewHolder.removeView (view); + } + + class ViewHolder extends ViewGroup + { + public ViewHolder (Context context) + { + super (context); + } + + protected void onLayout (boolean changed, int left, int top, int right, int bottom) + { + } + } +} diff --git a/src/native/android/juce_android_Files.cpp b/src/native/android/juce_android_Files.cpp index 8f85a3649d..c72afb3ad6 100644 --- a/src/native/android/juce_android_Files.cpp +++ b/src/native/android/juce_android_Files.cpp @@ -108,73 +108,34 @@ const File File::getLinkedTarget() const } //============================================================================== -const char* juce_Argv0 = 0; // referenced from juce_Application.cpp - const File File::getSpecialLocation (const SpecialLocationType type) { - - - // TODO - - - switch (type) { case userHomeDirectory: - { - const char* homeDir = getenv ("HOME"); - - if (homeDir == 0) - { - struct passwd* const pw = getpwuid (getuid()); - if (pw != 0) - homeDir = pw->pw_dir; - } - - return File (String::fromUTF8 (homeDir)); - } - case userDocumentsDirectory: case userMusicDirectory: case userMoviesDirectory: case userApplicationDataDirectory: - return File ("~"); + return File (android.appDataDir); case userDesktopDirectory: return File ("~/Desktop"); case commonApplicationDataDirectory: - return File ("/var"); + return File (android.appDataDir); case globalApplicationsDirectory: return File ("/usr"); case tempDirectory: - { - File tmp ("/var/tmp"); - - if (! tmp.isDirectory()) - { - tmp = "/tmp"; - - if (! tmp.isDirectory()) - tmp = File::getCurrentWorkingDirectory(); - } - - return tmp; - } + return File ("~/.temp"); case invokedExecutableFile: - if (juce_Argv0 != 0) - return File (String::fromUTF8 (juce_Argv0)); - // deliberate fall-through... - case currentExecutableFile: case currentApplicationFile: - return juce_getExecutableFile(); - case hostApplicationPath: - return juce_readlink ("/proc/self/exe", juce_getExecutableFile()); + return juce_getExecutableFile(); default: jassertfalse; // unknown type? diff --git a/src/native/android/juce_android_GraphicsContext.cpp b/src/native/android/juce_android_GraphicsContext.cpp index 3660815012..f98a70eaf5 100644 --- a/src/native/android/juce_android_GraphicsContext.cpp +++ b/src/native/android/juce_android_GraphicsContext.cpp @@ -29,15 +29,13 @@ //============================================================================== -// TODO class AndroidLowLevelGraphicsContext : public LowLevelGraphicsContext { public: AndroidLowLevelGraphicsContext (const GlobalRef& canvas_) : canvas (canvas_), - currentState (new SavedState()), + currentState (new SavedState()) { - paintStack.add (new GlobalRef()); setFill (Colours::black); } @@ -55,7 +53,7 @@ public: void addTransform (const AffineTransform& transform) { - canvas.callVoidMethod (android.concat, createMatrix (canvas.getEnv(), transform)); + canvas.callVoidMethod (android.concat, createMatrix (getEnv(), transform).get()); } float getScaleFactor() @@ -70,7 +68,7 @@ public: bool clipToRectangleList (const RectangleList& clipRegion) { - return canvas.callBooleanMethod (android.clipRegion, createRegion (canvas.getEnv(), clipRegion)); + return canvas.callBooleanMethod (android.clipRegion, createRegion (getEnv(), clipRegion).get()); } void excludeClipRectangle (const Rectangle& r) @@ -79,7 +77,7 @@ public: void clipToPath (const Path& path, const AffineTransform& transform) { - (void) canvas.callBooleanMethod (android.clipPath, createPath (canvas.getEnv(), path, transform)); + (void) canvas.callBooleanMethod (android.clipPath, createPath (getEnv(), path, transform).get()); } void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) @@ -93,20 +91,21 @@ public: const Rectangle getClipBounds() const { - jobject rect = canvas.callObjectMethod (android.getClipBounds2); + JNIEnv* env = getEnv(); + const LocalRef rect (canvas.callObjectMethod (android.getClipBounds2)); - const int left = canvas.getEnv()->GetIntField (rect, android.rectLeft); - const int top = canvas.getEnv()->GetIntField (rect, android.rectTop); - const int right = canvas.getEnv()->GetIntField (rect, android.rectRight); - const int bottom = canvas.getEnv()->GetIntField (rect, android.rectBottom); + const int left = env->GetIntField (rect, android.rectLeft); + const int top = env->GetIntField (rect, android.rectTop); + const int right = env->GetIntField (rect, android.rectRight); + const int bottom = env->GetIntField (rect, android.rectBottom); return Rectangle (left, top, right - left, bottom - top); } bool isClipEmpty() const { - return ! canvas.callBooleanMethod (android.getClipBounds, - canvas.getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); + LocalRef tempRect (getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); + return ! canvas.callBooleanMethod (android.getClipBounds, tempRect.get()); } //============================================================================== @@ -128,13 +127,13 @@ public: { canvas.callVoidMethod (android.drawRect, (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom(), - getCurrentPaint().get()); + getCurrentPaint()); } void fillPath (const Path& path, const AffineTransform& transform) { - canvas.callVoidMethod (android.drawPath, createPath (canvas.getEnv(), path, transform), - getCurrentPaint().get()); + canvas.callVoidMethod (android.drawPath, createPath (getEnv(), path, transform).get(), + getCurrentPaint()); } void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles) @@ -145,17 +144,17 @@ public: { canvas.callVoidMethod (android.drawLine, line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY(), - getCurrentPaint().get()); + getCurrentPaint()); } void drawVerticalLine (int x, float top, float bottom) { - canvas.callVoidMethod (android.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint().get()); + canvas.callVoidMethod (android.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint()); } void drawHorizontalLine (int y, float left, float right) { - canvas.callVoidMethod (android.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint().get()); + canvas.callVoidMethod (android.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint()); } void setFont (const Font& newFont) @@ -223,21 +222,26 @@ public: fillType = newType; } - jobject getPaint (JNIEnv* env) + jobject getPaint() { if (needsUpdate) { + JNIEnv* env = getEnv(); + if (paint.get() == 0) - paint = GlobalRef (env, env->NewObject (android.paintClass, android.paintClassConstructor)); + { + paint = GlobalRef (env->NewObject (android.paintClass, android.paintClassConstructor)); + paint.callVoidMethod (android.setAntiAlias, true); + } if (fillType.isColour()) { - paint.callVoidMethod (android.setShader, (jobject) 0); + paint.callObjectMethod (android.setShader, (jobject) 0); paint.callVoidMethod (android.setColor, colourToInt (fillType.colour)); } else if (fillType.isGradient()) { - const ColourGradient& g = fillType.gradient; + const ColourGradient& g = *fillType.gradient; const Point p1 (g.point1); const Point p2 (g.point2); @@ -251,7 +255,7 @@ public: for (int i = 0; i < numColours; ++i) { - colours[i] = g.getColour (i); + colours[i] = colourToInt (g.getColour (i)); positions[i] = (float) g.getColourPosition(i); } @@ -259,7 +263,7 @@ public: env->SetFloatArrayRegion (positionsArray, 0, numColours, positions.getData()); } - jobject tileMode = xxxx + jobject tileMode = env->GetStaticObjectField (android.shaderTileModeClass, android.clampMode); jobject shader; if (fillType.gradient->isRadial) @@ -269,7 +273,7 @@ public: p1.getX(), p1.getY(), p1.getDistanceFrom (p2), coloursArray, positionsArray, - tileMode)); + tileMode); } else { @@ -277,14 +281,19 @@ public: android.linearGradientConstructor, p1.getX(), p1.getY(), p2.getX(), p2.getY(), coloursArray, positionsArray, - tileMode)); + tileMode); } - env->CallVoidMethod (shader, android.setLocalMatrix, createMatrix (fillType.transform)); - paint.callVoidMethod (android.setShader, shader); + env->DeleteLocalRef (coloursArray); + env->DeleteLocalRef (positionsArray); + + env->CallVoidMethod (shader, android.setLocalMatrix, createMatrix (env, fillType.transform).get()); + paint.callObjectMethod (android.setShader, shader); + + env->DeleteLocalRef (shader); } else - {x + { } } @@ -304,9 +313,12 @@ private: ScopedPointer currentState; OwnedArray stateStack; - GlobalRef& getCurrentPaint() throw() { return *paintStack.getUnchecked (paintStack.size() - 1); } + jobject getCurrentPaint() const + { + return currentState->getPaint(); + } - static jobject createPath (JNIEnv* env, const Path& path) + static const LocalRef createPath (JNIEnv* env, const Path& path) { jobject p = env->NewObject (android.pathClass, android.pathClassConstructor); @@ -325,10 +337,10 @@ private: } } - return p; + return LocalRef (p); } - static jobject createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) + static const LocalRef createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) { if (transform.isIdentity()) return createPath (env, path); @@ -338,7 +350,7 @@ private: return createPath (env, tempPath); } - static jobject createMatrix (JNIEnv* env, const AffineTransform& t) + static const LocalRef createMatrix (JNIEnv* env, const AffineTransform& t) { jobject m = env->NewObject (android.matrixClass, android.matrixClassConstructor); @@ -352,25 +364,25 @@ private: env->CallVoidMethod (m, android.setValues, javaArray); env->DeleteLocalRef (javaArray); - return m; + return LocalRef (m); } - static jobject createRect (JNIEnv* env, const Rectangle& r) + static const LocalRef createRect (JNIEnv* env, const Rectangle& r) { - return env->NewObject (android.rectClass, android.rectConstructor, - r.getX(), r.getY(), r.getRight(), r.getBottom()); + return LocalRef (env->NewObject (android.rectClass, android.rectConstructor, + r.getX(), r.getY(), r.getRight(), r.getBottom())); } - static jobject createRegion (JNIEnv* env, const RectangleList& list) + static const LocalRef createRegion (JNIEnv* env, const RectangleList& list) { jobject region = env->NewObject (android.regionClass, android.regionConstructor); const int numRects = list.getNumRectangles(); for (int i = 0; i < numRects; ++i) - env->CallVoidMethod (region, android.regionUnion, createRect (env, list.getRectangle(i))); + env->CallVoidMethod (region, android.regionUnion, createRect (env, list.getRectangle(i)).get()); - return region; + return LocalRef (region); } static int colourToInt (const Colour& col) throw() diff --git a/src/native/android/juce_android_Messaging.cpp b/src/native/android/juce_android_Messaging.cpp index 82fbb53f8c..c6e643fd86 100644 --- a/src/native/android/juce_android_Messaging.cpp +++ b/src/native/android/juce_android_Messaging.cpp @@ -61,7 +61,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages //============================================================================== bool juce_postMessageToSystemQueue (Message* message) { - android.activity.callVoidMethod (android.postMessage, (jlong) (pointer_sized_uint) message); + getEnv()->CallVoidMethod (android.activity, android.postMessage, (jlong) (pointer_sized_uint) message); return true; } diff --git a/src/native/android/juce_android_Misc.cpp b/src/native/android/juce_android_Misc.cpp index 7fda1d2e1c..742226277c 100644 --- a/src/native/android/juce_android_Misc.cpp +++ b/src/native/android/juce_android_Misc.cpp @@ -32,9 +32,11 @@ extern JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication(); // (from START BEGIN_JUCE_NAMESPACE //============================================================================== -JUCE_JNI_CALLBACK (JuceAppActivity, launchApp, void, (JNIEnv* env, jobject activity, int screenWidth, int screenHeight)) +JUCE_JNI_CALLBACK (JuceAppActivity, launchApp, void, (JNIEnv* env, jobject activity, + jstring appFile, jstring appDataDir, + int screenWidth, int screenHeight)) { - android.initialise (env, activity, screenWidth, screenHeight); + android.initialise (env, activity, appFile, appDataDir, screenWidth, screenHeight); JUCEApplication::createInstance = &juce_CreateApplication; @@ -60,8 +62,8 @@ void PlatformUtilities::beep() //============================================================================== void Logger::outputDebugString (const String& text) { - android.env->CallStaticVoidMethod (android.activityClass, android.printToConsole, - android.javaString (text)); + getEnv()->CallStaticVoidMethod (android.activityClass, android.printToConsole, + javaString (text).get()); } //============================================================================== diff --git a/src/native/android/juce_android_NativeCode.cpp b/src/native/android/juce_android_NativeCode.cpp index 8ffab85bcd..57e8650221 100644 --- a/src/native/android/juce_android_NativeCode.cpp +++ b/src/native/android/juce_android_NativeCode.cpp @@ -107,11 +107,12 @@ BEGIN_JUCE_NAMESPACE JAVACLASS (rectClass, "android/graphics/Rect") \ JAVACLASS (regionClass, "android/graphics/Region") \ JAVACLASS (shaderClass, "android/graphics/Shader") \ + JAVACLASS (shaderTileModeClass, "android/graphics/Shader$TileMode") \ JAVACLASS (linearGradientClass, "android/graphics/LinearGradient") \ JAVACLASS (radialGradientClass, "android/graphics/RadialGradient") \ //============================================================================== -#define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD) \ +#define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ \ STATICMETHOD (activityClass, printToConsole, "printToConsole", "(Ljava/lang/String;)V") \ METHOD (activityClass, createNewView, "createNewView", "()Lcom/juce/ComponentPeerView;") \ @@ -153,8 +154,10 @@ BEGIN_JUCE_NAMESPACE METHOD (paintClass, paintClassConstructor, "", "()V") \ METHOD (paintClass, setColor, "setColor", "(I)V") \ METHOD (paintClass, setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \ + METHOD (paintClass, setAntiAlias, "setAntiAlias", "(Z)V") \ \ METHOD (shaderClass, setLocalMatrix, "setLocalMatrix", "(Landroid/graphics/Matrix;)V") \ + STATICFIELD (shaderTileModeClass, clampMode, "CLAMP", "Landroid/graphics/Shader$TileMode;") \ \ METHOD (pathClass, pathClassConstructor, "", "()V") \ METHOD (pathClass, moveTo, "moveTo", "(FF)V") \ @@ -180,24 +183,116 @@ BEGIN_JUCE_NAMESPACE METHOD (regionClass, regionUnion, "union", "(Landroid/graphics/Rect;)Z"); \ +//============================================================================== +class ThreadLocalJNIEnvHolder +{ +public: + ThreadLocalJNIEnvHolder() + : jvm (0) + { + zeromem (threads, sizeof (threads)); + zeromem (envs, sizeof (envs)); + } + + void initialise (JNIEnv* env) + { + env->GetJavaVM (&jvm); + addEnv (env); + } + + void attach() + { + JNIEnv* env = 0; + jvm->AttachCurrentThread (&env, 0); + + if (env != 0) + addEnv (env); + } + + void detach() + { + jvm->DetachCurrentThread(); + + const pthread_t thisThread = pthread_self(); + + ScopedLock sl (addRemoveLock); + for (int i = 0; i < maxThreads; ++i) + if (threads[i] == thisThread) + threads[i] = 0; + } + + JNIEnv* get() const throw() + { + const pthread_t thisThread = pthread_self(); + + for (int i = 0; i < maxThreads; ++i) + if (threads[i] == thisThread) + return envs[i]; + + return 0; + } + + enum { maxThreads = 16 }; + +private: + JavaVM* jvm; + pthread_t threads [maxThreads]; + JNIEnv* envs [maxThreads]; + CriticalSection addRemoveLock; + + void addEnv (JNIEnv* env) + { + ScopedLock sl (addRemoveLock); + + if (get() == 0) + { + const pthread_t thisThread = pthread_self(); + + for (int i = 0; i < maxThreads; ++i) + { + if (threads[i] == 0) + { + envs[i] = env; + threads[i] = thisThread; + return; + } + } + } + + jassertfalse; // too many threads! + } +}; + +static ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder; + +struct AndroidThreadScope +{ + AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } + ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } +}; + +static inline JNIEnv* getEnv() throw() +{ + return threadLocalJNIEnvHolder.get(); +} + + //============================================================================== class GlobalRef { public: - GlobalRef() - : env (0), obj (0) + inline GlobalRef() throw() + : obj (0) { } - GlobalRef (JNIEnv* const env_, jobject obj_) - : env (env_), - obj (retain (env_, obj_)) + inline explicit GlobalRef (jobject obj_) + : obj (retain (obj_)) { } - GlobalRef (const GlobalRef& other) - : env (other.env), - obj (retain (other.env, other.obj)) + inline GlobalRef (const GlobalRef& other) + : obj (retain (other.obj)) { } @@ -206,28 +301,22 @@ public: clear(); } - void clear() + inline void clear() { - if (env != 0) - { - env->DeleteGlobalRef (obj); - env = 0; - obj = 0; - } + if (obj != 0) + getEnv()->DeleteGlobalRef (obj); } - GlobalRef& operator= (const GlobalRef& other) + inline GlobalRef& operator= (const GlobalRef& other) { clear(); - env = other.env; - obj = retain (env, other.obj); + obj = retain (other.obj); return *this; } //============================================================================== inline operator jobject() const throw() { return obj; } inline jobject get() const throw() { return obj; } - inline JNIEnv* getEnv() const throw() { return env; } //============================================================================== #define DECLARE_CALL_TYPE_METHOD(returnType, typeName) \ @@ -235,7 +324,7 @@ public: { \ va_list args; \ va_start (args, methodID); \ - returnType result = env->Call##typeName##MethodV (obj, methodID, args); \ + returnType result = getEnv()->Call##typeName##MethodV (obj, methodID, args); \ va_end (args); \ return result; \ } @@ -255,33 +344,101 @@ public: { va_list args; va_start (args, methodID); - env->CallVoidMethodV (obj, methodID, args); + getEnv()->CallVoidMethodV (obj, methodID, args); va_end (args); } private: //============================================================================== - JNIEnv* env; jobject obj; - static jobject retain (JNIEnv* const env, jobject obj_) + static inline jobject retain (jobject obj_) { - return env == 0 ? 0 : env->NewGlobalRef (obj_); + return obj_ == 0 ? 0 : getEnv()->NewGlobalRef (obj_); } }; +//============================================================================== +template +class LocalRef +{ +public: + explicit inline LocalRef (JavaType obj_) throw() + : obj (obj_) + { + } + + inline LocalRef (const LocalRef& other) throw() + : obj (retain (other.obj)) + { + } + + ~LocalRef() + { + if (obj != 0) + getEnv()->DeleteLocalRef (obj); + } + + LocalRef& operator= (const LocalRef& other) + { + if (obj != other.obj) + { + if (obj != 0) + getEnv()->DeleteLocalRef (obj); + + obj = retain (other.obj); + } + + return *this; + } + + inline operator JavaType() const throw() { return obj; } + inline JavaType get() const throw() { return obj; } + +private: + JavaType obj; + + static JavaType retain (JavaType obj_) + { + return obj_ == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj_); + } +}; + +//============================================================================== +static const String juceString (jstring s) +{ + JNIEnv* env = getEnv(); + + jboolean isCopy; + const char* const utf8 = env->GetStringUTFChars (s, &isCopy); + CharPointer_UTF8 utf8CP (utf8); + const String result (utf8CP); + env->ReleaseStringUTFChars (s, utf8); + return result; +} + +static const LocalRef javaString (const String& s) +{ + return LocalRef (getEnv()->NewStringUTF (s.toUTF8())); +} + + //============================================================================== class AndroidJavaCallbacks { public: - AndroidJavaCallbacks() : env (0), screenWidth (0), screenHeight (0) + AndroidJavaCallbacks() : screenWidth (0), screenHeight (0) { } - void initialise (JNIEnv* env_, jobject activity_, int screenWidth_, int screenHeight_) + void initialise (JNIEnv* env, jobject activity_, + jstring appFile_, jstring appDataDir_, + int screenWidth_, int screenHeight_) { - env = env_; - activity = GlobalRef (env, activity_); + threadLocalJNIEnvHolder.initialise (env); + activity = GlobalRef (activity_); + appFile = juceString (appFile_); + appDataDir = juceString (appDataDir_); screenWidth = screenWidth_; screenHeight = screenHeight_; @@ -300,12 +457,17 @@ public: #define CREATE_JNI_FIELD(ownerClass, fieldID, stringName, signature) \ fieldID = env->GetFieldID (ownerClass, stringName, signature); \ jassert (fieldID != 0); - JUCE_JNI_METHODS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD); + #define CREATE_JNI_STATICFIELD(ownerClass, fieldID, stringName, signature) \ + fieldID = env->GetStaticFieldID (ownerClass, stringName, signature); \ + jassert (fieldID != 0); + JUCE_JNI_METHODS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); #undef CREATE_JNI_METHOD } void shutdown() { + JNIEnv* env = getEnv(); + if (env != 0) { #define RELEASE_JNI_CLASS(className, path) env->DeleteGlobalRef (className); @@ -313,29 +475,12 @@ public: #undef RELEASE_JNI_CLASS activity.clear(); - env = 0; } } //============================================================================== - const String juceString (jstring s) const - { - jboolean isCopy; - const char* const utf8 = env->GetStringUTFChars (s, &isCopy); - CharPointer_UTF8 utf8CP (utf8); - const String result (utf8CP); - env->ReleaseStringUTFChars (s, utf8); - return result; - } - - jstring javaString (const String& s) const - { - return env->NewStringUTF (s.toUTF8()); - } - - //============================================================================== - JNIEnv* env; GlobalRef activity; + String appFile, appDataDir; int screenWidth, screenHeight; //============================================================================== @@ -345,13 +490,12 @@ public: #define DECLARE_JNI_METHOD(ownerClass, methodID, stringName, params) jmethodID methodID; #define DECLARE_JNI_FIELD(ownerClass, fieldID, stringName, signature) jfieldID fieldID; - JUCE_JNI_METHODS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD); + JUCE_JNI_METHODS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); #undef DECLARE_JNI_METHOD }; static AndroidJavaCallbacks android; - //============================================================================== #define JUCE_INCLUDED_FILE 1 diff --git a/src/native/android/juce_android_SystemStats.cpp b/src/native/android/juce_android_SystemStats.cpp index d6f6144374..a531cab97e 100644 --- a/src/native/android/juce_android_SystemStats.cpp +++ b/src/native/android/juce_android_SystemStats.cpp @@ -77,8 +77,6 @@ int SystemStats::getCpuSpeedInMegaherz() int SystemStats::getMemorySizeInMegabytes() { - // TODO - struct sysinfo sysi; if (sysinfo (&sysi) == 0) @@ -125,8 +123,7 @@ void SystemStats::initialiseStats() cpuFlags.hasSSE2 = flags.contains ("sse2"); cpuFlags.has3DNow = flags.contains ("3dnow"); - // TODO - cpuFlags.numCpus = AndroidStatsHelpers::getCpuInfo ("processor").getIntValue() + 1; + cpuFlags.numCpus = jmax (1, sysconf (_SC_NPROCESSORS_ONLN)); } void PlatformUtilities::fpuReset() {} diff --git a/src/native/android/juce_android_Windowing.cpp b/src/native/android/juce_android_Windowing.cpp index b3f7e0c62e..d38ecbbcc9 100644 --- a/src/native/android/juce_android_Windowing.cpp +++ b/src/native/android/juce_android_Windowing.cpp @@ -27,6 +27,7 @@ // compiled on its own). #if JUCE_INCLUDED_FILE +static ModifierKeys currentModifiers; //============================================================================== class AndroidComponentPeer : public ComponentPeer @@ -34,9 +35,9 @@ class AndroidComponentPeer : public ComponentPeer public: //============================================================================== AndroidComponentPeer (Component* const component, const int windowStyleFlags) - : ComponentPeer (component, windowStyleFlags) + : ComponentPeer (component, windowStyleFlags), + view (android.activity.callObjectMethod (android.createNewView)) { - view = GlobalRef (android.env, android.activity.callObjectMethod (android.createNewView)); } ~AndroidComponentPeer() @@ -57,7 +58,7 @@ public: void setTitle (const String& title) { - view.callVoidMethod (android.setViewName, android.javaString (title)); + view.callVoidMethod (android.setViewName, javaString (title).get()); } void setPosition (int x, int y) @@ -87,7 +88,7 @@ public: const Point getScreenPosition() const { - JNIEnv* const env = view.getEnv(); + JNIEnv* const env = getEnv(); jintArray pos = env->NewIntArray (2); view.callVoidMethod (android.getLocationOnScreen, pos); @@ -169,6 +170,26 @@ public: // TODO } + //============================================================================== + void handleMouseDownCallback (float x, float y, int64 time) + { + currentModifiers = currentModifiers.withoutMouseButtons(); + handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); + handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + } + + void handleMouseDragCallback (float x, float y, int64 time) + { + handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + } + + void handleMouseUpCallback (float x, float y, int64 time) + { + currentModifiers = currentModifiers.withoutMouseButtons(); + handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + } + //============================================================================== bool isFocused() const { @@ -188,7 +209,8 @@ public: //============================================================================== void handlePaintCallback (JNIEnv* env, jobject canvas) { - AndroidLowLevelGraphicsContext g (GlobalRef (env, canvas)); + GlobalRef canvasRef (canvas); + AndroidLowLevelGraphicsContext g (canvasRef); handlePaint (g); } @@ -241,6 +263,12 @@ private: JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject view, jobject canvas), handlePaintCallback (env, canvas)) +JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), + handleMouseDownCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), + handleMouseDragCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), + handleMouseUpCallback ((float) x, (float) y, (int64) time)) //============================================================================== ComponentPeer* Component::createNewPeer (int styleFlags, void*) @@ -294,8 +322,7 @@ void ModifierKeys::updateCurrentModifiers() throw() const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw() { - // TODO - return ModifierKeys(); + return currentModifiers; } //============================================================================== diff --git a/src/native/common/juce_posix_SharedCode.h b/src/native/common/juce_posix_SharedCode.h index caf6a0f24d..ca89ea3ef0 100644 --- a/src/native/common/juce_posix_SharedCode.h +++ b/src/native/common/juce_posix_SharedCode.h @@ -486,8 +486,7 @@ void FileOutputStream::flushInternal() const File juce_getExecutableFile() { #if JUCE_ANDROID - // TODO - return File::nonexistent; + return File (android.appFile); #else Dl_info exeInfo; dladdr ((void*) juce_getExecutableFile, &exeInfo); // (can't be a const void* on android) @@ -707,6 +706,11 @@ void JUCE_API juce_threadEntryPoint (void*); void* threadEntryProc (void* userData) { JUCE_AUTORELEASEPOOL + + #if JUCE_ANDROID + const AndroidThreadScope androidEnv; + #endif + juce_threadEntryPoint (userData); return 0; } @@ -744,7 +748,7 @@ void Thread::killThread() void Thread::setCurrentThreadName (const String& name) { - #if JUCE_MAC + #if JUCE_MAC && defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 pthread_setname_np (name.toUTF8()); #elif JUCE_LINUX prctl (PR_SET_NAME, name.toUTF8().getAddress(), 0, 0, 0); diff --git a/src/native/mac/juce_mac_NativeCode.mm b/src/native/mac/juce_mac_NativeCode.mm index 67e7743d86..bd3dd2d9dc 100644 --- a/src/native/mac/juce_mac_NativeCode.mm +++ b/src/native/mac/juce_mac_NativeCode.mm @@ -95,6 +95,7 @@ BEGIN_JUCE_NAMESPACE #include "../common/juce_MidiDataConcatenator.h" #undef Point +#if ! JUCE_ONLY_BUILD_CORE_LIBRARY namespace { template @@ -183,6 +184,7 @@ private: static_cast (info)->runLoopCallback(); } }; +#endif //============================================================================== #define JUCE_INCLUDED_FILE 1 diff --git a/src/text/juce_CharPointer_UTF8.h b/src/text/juce_CharPointer_UTF8.h index 53b84854e1..05f926d490 100644 --- a/src/text/juce_CharPointer_UTF8.h +++ b/src/text/juce_CharPointer_UTF8.h @@ -213,11 +213,11 @@ public: for (;;) { - const int n = *d++; + const uint32 n = (uint32) (uint8) *d++; if ((n & 0x80) != 0) { - int bit = 0x40; + uint32 bit = 0x40; while ((n & bit) != 0) { diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp index 7d637dbf98..2f37ff5913 100644 --- a/src/text/juce_String.cpp +++ b/src/text/juce_String.cpp @@ -2241,7 +2241,7 @@ public: { buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); } - while (buffer[i] >= 0xd800 && buffer[i] <= 0xdfff); // (these code-points are illegal in UTF-16) + while (! CharPointer_UTF16::canRepresent (buffer[i])); } else buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0xff)); diff --git a/src/utilities/juce_UnitTest.cpp b/src/utilities/juce_UnitTest.cpp index aab5913c4e..80ce2ea841 100644 --- a/src/utilities/juce_UnitTest.cpp +++ b/src/utilities/juce_UnitTest.cpp @@ -161,8 +161,8 @@ void UnitTestRunner::endTest() if (r->failures > 0) { - String m ("FAILED!!"); - m << r->failures << (r->failures == 1 ? "test" : "tests") + String m ("FAILED!! "); + m << r->failures << (r->failures == 1 ? " test" : " tests") << " failed, out of a total of " << (r->passes + r->failures); logMessage (String::empty);